loxxy 0.0.18 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +94 -30
- data/README.md +72 -4
- data/lib/loxxy/ast/all_lox_nodes.rb +5 -0
- data/lib/loxxy/ast/ast_builder.rb +49 -2
- data/lib/loxxy/ast/ast_visitor.rb +47 -1
- data/lib/loxxy/ast/lox_grouping_expr.rb +23 -0
- data/lib/loxxy/ast/lox_if_stmt.rb +35 -0
- data/lib/loxxy/ast/lox_seq_decl.rb +17 -0
- data/lib/loxxy/ast/lox_var_stmt.rb +28 -0
- data/lib/loxxy/ast/lox_variable_expr.rb +26 -0
- data/lib/loxxy/back_end/engine.rb +44 -1
- data/lib/loxxy/back_end/entry.rb +41 -0
- data/lib/loxxy/back_end/environment.rb +66 -0
- data/lib/loxxy/back_end/symbol_table.rb +135 -0
- data/lib/loxxy/back_end/variable.rb +25 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +6 -0
- data/lib/loxxy/front_end/grammar.rb +9 -9
- data/lib/loxxy/interpreter.rb +1 -1
- data/lib/loxxy/version.rb +1 -1
- data/spec/back_end/engine_spec.rb +9 -0
- data/spec/back_end/environment_spec.rb +74 -0
- data/spec/back_end/symbol_table_spec.rb +142 -0
- data/spec/back_end/variable_spec.rb +79 -0
- data/spec/front_end/parser_spec.rb +21 -19
- data/spec/interpreter_spec.rb +74 -1
- metadata +17 -2
@@ -51,6 +51,30 @@ module Loxxy
|
|
51
51
|
broadcast(:after_ptree, aParseTree)
|
52
52
|
end
|
53
53
|
|
54
|
+
# Visit event. The visitor is about to visit a variable declaration statement.
|
55
|
+
# @param aPrintStmt [AST::LOXVarStmt] the variable declaration node to visit
|
56
|
+
def visit_seq_decl(aSeqDecls)
|
57
|
+
broadcast(:before_seq_decl, aSeqDecls)
|
58
|
+
traverse_subnodes(aSeqDecls)
|
59
|
+
broadcast(:after_seq_decl, aSeqDecls)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Visit event. The visitor is about to visit a variable declaration statement.
|
63
|
+
# @param aPrintStmt [AST::LOXVarStmt] the variable declaration node to visit
|
64
|
+
def visit_var_stmt(aVarStmt)
|
65
|
+
broadcast(:before_var_stmt, aVarStmt)
|
66
|
+
traverse_subnodes(aVarStmt)
|
67
|
+
broadcast(:after_var_stmt, aVarStmt)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Visit event. The visitor is about to visit a if statement.
|
71
|
+
# @param anIfStmt [AST::LOXIfStmt] the if statement node to visit
|
72
|
+
def visit_if_stmt(anIfStmt)
|
73
|
+
broadcast(:before_if_stmt, anIfStmt)
|
74
|
+
traverse_subnodes(anIfStmt) # The condition is visited/evaluated here...
|
75
|
+
broadcast(:after_if_stmt, anIfStmt, self)
|
76
|
+
end
|
77
|
+
|
54
78
|
# Visit event. The visitor is about to visit a print statement.
|
55
79
|
# @param aPrintStmt [AST::LOXPrintStmt] the print statement node to visit
|
56
80
|
def visit_print_stmt(aPrintStmt)
|
@@ -89,6 +113,14 @@ module Loxxy
|
|
89
113
|
broadcast(:after_unary_expr, anUnaryExpr)
|
90
114
|
end
|
91
115
|
|
116
|
+
# Visit event. The visitor is about to visit a grouping expression.
|
117
|
+
# @param aGroupingExpr [AST::LoxGroupingExpr] grouping expression to visit
|
118
|
+
def visit_grouping_expr(aGroupingExpr)
|
119
|
+
broadcast(:before_grouping_expr, aGroupingExpr)
|
120
|
+
traverse_subnodes(aGroupingExpr)
|
121
|
+
broadcast(:after_grouping_expr, aGroupingExpr)
|
122
|
+
end
|
123
|
+
|
92
124
|
# Visit event. The visitor is visiting the
|
93
125
|
# given terminal node containing a datatype object.
|
94
126
|
# @param aLiteralExpr [AST::LoxLiteralExpr] the leaf node to visit.
|
@@ -97,8 +129,22 @@ module Loxxy
|
|
97
129
|
broadcast(:after_literal_expr, aLiteralExpr)
|
98
130
|
end
|
99
131
|
|
132
|
+
# Visit event. The visitor is visiting a variable reference node
|
133
|
+
# @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
|
134
|
+
def visit_variable_expr(aVariableExpr)
|
135
|
+
broadcast(:before_variable_expr, aVariableExpr)
|
136
|
+
broadcast(:after_variable_expr, aVariableExpr, self)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Visit event. The visitor is about to visit the given terminal datatype value.
|
140
|
+
# @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
|
141
|
+
def visit_builtin(aValue)
|
142
|
+
broadcast(:before_visit_builtin, aValue)
|
143
|
+
broadcast(:after_visit_builtin, aValue)
|
144
|
+
end
|
145
|
+
|
100
146
|
# Visit event. The visitor is about to visit the given non terminal node.
|
101
|
-
# @param aNonTerminalNode [Rley::
|
147
|
+
# @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
|
102
148
|
def visit_nonterminal(_non_terminal_node)
|
103
149
|
# Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
|
104
150
|
# that it cannot handle.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxGroupingExpr < LoxCompoundExpr
|
8
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
9
|
+
# @param subExpr [Loxxy::Ast::LoxNode]
|
10
|
+
def initialize(aPosition, subExpr)
|
11
|
+
super(aPosition, [subExpr])
|
12
|
+
end
|
13
|
+
|
14
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
15
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
16
|
+
def accept(visitor)
|
17
|
+
visitor.visit_grouping_expr(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias operands subnodes
|
21
|
+
end # class
|
22
|
+
end # module
|
23
|
+
end # module
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxIfStmt < LoxCompoundExpr
|
8
|
+
# @return [LoxNode] code of then branch
|
9
|
+
attr_reader :then_stmt
|
10
|
+
|
11
|
+
# @return [LoxNode, NilClass] code of else branch
|
12
|
+
attr_reader :else_stmt
|
13
|
+
|
14
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
15
|
+
# @param subExpr [Loxxy::Ast::LoxNode]
|
16
|
+
def initialize(aPosition, condExpr, thenStmt, elseStmt)
|
17
|
+
super(aPosition, [condExpr])
|
18
|
+
@then_stmt = thenStmt
|
19
|
+
@else_stmt = elseStmt
|
20
|
+
end
|
21
|
+
|
22
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
23
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
24
|
+
def accept(visitor)
|
25
|
+
visitor.visit_if_stmt(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Accessor to the condition expression
|
29
|
+
# @return [LoxNode]
|
30
|
+
def condition
|
31
|
+
subnodes[0]
|
32
|
+
end
|
33
|
+
end # class
|
34
|
+
end # module
|
35
|
+
end # module
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxSeqDecl < LoxCompoundExpr
|
8
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
9
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
10
|
+
def accept(visitor)
|
11
|
+
visitor.visit_seq_decl(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias operands subnodes
|
15
|
+
end # class
|
16
|
+
end # module
|
17
|
+
end # module
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
# This AST node represents a variable declaration
|
8
|
+
class LoxVarStmt < LoxCompoundExpr
|
9
|
+
# @return [String] variable name
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
13
|
+
# @param aName [String] name of the variable
|
14
|
+
# @param aValue [Loxxy::Ast::LoxNode, NilClass] initial value for the variable
|
15
|
+
def initialize(aPosition, aName, aValue)
|
16
|
+
initial_value = aValue ? [aValue] : [Datatype::Nil.instance]
|
17
|
+
super(aPosition, initial_value)
|
18
|
+
@name = aName
|
19
|
+
end
|
20
|
+
|
21
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
22
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
23
|
+
def accept(visitor)
|
24
|
+
visitor.visit_var_stmt(self)
|
25
|
+
end
|
26
|
+
end # class
|
27
|
+
end # module
|
28
|
+
end # module
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_node'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
# This AST node represents a mention of a variable
|
8
|
+
class LoxVariableExpr < LoxNode
|
9
|
+
# @return [String] variable name
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
13
|
+
# @param aName [String] name of the variable
|
14
|
+
def initialize(aPosition, aName)
|
15
|
+
super(aPosition)
|
16
|
+
@name = aName
|
17
|
+
end
|
18
|
+
|
19
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
20
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
21
|
+
def accept(visitor)
|
22
|
+
visitor.visit_variable_expr(self)
|
23
|
+
end
|
24
|
+
end # class
|
25
|
+
end # module
|
26
|
+
end # module
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
# Load all the classes implementing AST nodes
|
4
4
|
require_relative '../ast/all_lox_nodes'
|
5
|
+
require_relative 'symbol_table'
|
5
6
|
|
6
7
|
module Loxxy
|
7
8
|
module BackEnd
|
@@ -12,13 +13,17 @@ module Loxxy
|
|
12
13
|
# @return [Hash] A set of configuration options
|
13
14
|
attr_reader :config
|
14
15
|
|
15
|
-
# @return [
|
16
|
+
# @return [BackEnd::SymbolTable]
|
17
|
+
attr_reader :symbol_table
|
18
|
+
|
19
|
+
# @return [Array<Datatype::BuiltinDatatyp>] Stack for the values of expr
|
16
20
|
attr_reader :stack
|
17
21
|
|
18
22
|
# @param theOptions [Hash]
|
19
23
|
def initialize(theOptions)
|
20
24
|
@config = theOptions
|
21
25
|
@ostream = config.include?(:ostream) ? config[:ostream] : $stdout
|
26
|
+
@symbol_table = SymbolTable.new
|
22
27
|
@stack = []
|
23
28
|
end
|
24
29
|
|
@@ -33,7 +38,28 @@ module Loxxy
|
|
33
38
|
stack.empty? ? Datatype::Nil.instance : stack.pop
|
34
39
|
end
|
35
40
|
|
41
|
+
##########################################################################
|
36
42
|
# Visit event handling
|
43
|
+
##########################################################################
|
44
|
+
|
45
|
+
def after_seq_decl(aSeqDecls)
|
46
|
+
# Do nothing, subnodes were already evaluated
|
47
|
+
end
|
48
|
+
|
49
|
+
def after_var_stmt(aVarStmt)
|
50
|
+
new_var = Variable.new(aVarStmt.name, aVarStmt.subnodes[0])
|
51
|
+
symbol_table.insert(new_var)
|
52
|
+
end
|
53
|
+
|
54
|
+
def after_if_stmt(anIfStmt, aVisitor)
|
55
|
+
# Retrieve the result of the condition evaluation
|
56
|
+
condition = stack.pop
|
57
|
+
if condition.truthy?
|
58
|
+
anIfStmt.then_stmt.accept(aVisitor)
|
59
|
+
elsif anIfStmt.else_stmt
|
60
|
+
anIfStmt.else_stmt.accept(aVisitor)
|
61
|
+
end
|
62
|
+
end
|
37
63
|
|
38
64
|
def after_print_stmt(_printStmt)
|
39
65
|
tos = stack.pop
|
@@ -95,10 +121,27 @@ module Loxxy
|
|
95
121
|
end
|
96
122
|
end
|
97
123
|
|
124
|
+
def after_grouping_expr(_groupingExpr)
|
125
|
+
# Do nothing: work was already done by visiting /evaluating the subexpression
|
126
|
+
end
|
127
|
+
|
128
|
+
def after_variable_expr(aVarExpr, aVisitor)
|
129
|
+
var_name = aVarExpr.name
|
130
|
+
var = symbol_table.lookup(var_name)
|
131
|
+
raise StandardError, "Unknown variable #{var_name}" unless var
|
132
|
+
|
133
|
+
var.value.accept(aVisitor) # Evaluate the variable value
|
134
|
+
end
|
135
|
+
|
98
136
|
# @param literalExpr [Ast::LoxLiteralExpr]
|
99
137
|
def before_literal_expr(literalExpr)
|
100
138
|
stack.push(literalExpr.literal)
|
101
139
|
end
|
140
|
+
|
141
|
+
# @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
|
142
|
+
def before_visit_builtin(aValue)
|
143
|
+
stack.push(aValue)
|
144
|
+
end
|
102
145
|
end # class
|
103
146
|
end # module
|
104
147
|
end # module
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Loxxy
|
4
|
+
module BackEnd
|
5
|
+
# Mix-in module that implements the expected common behaviour of entries
|
6
|
+
# placed in the symbol table.
|
7
|
+
module Entry
|
8
|
+
# @return [String] User-defined name of the entry.
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
=begin
|
12
|
+
# @return [String] Suffix for building the internal name of the entry.
|
13
|
+
attr_accessor :suffix
|
14
|
+
=end
|
15
|
+
|
16
|
+
# Initialize the entry with given name
|
17
|
+
# @param aName [String] The name of the entry
|
18
|
+
def init_name(aName)
|
19
|
+
@name = aName.dup
|
20
|
+
@name.freeze
|
21
|
+
end
|
22
|
+
=begin
|
23
|
+
# Return the internal name of the entry
|
24
|
+
# Internal names used to disambiguate entry names.
|
25
|
+
# There might be homonyns between variable because:
|
26
|
+
# - A child Scope may have a entry with same name as one of its
|
27
|
+
# ancestor(s).
|
28
|
+
# - Multiple calls to same defrel or procedure may imply multiple creation
|
29
|
+
# of a entry given name...
|
30
|
+
# @return [String] internal name
|
31
|
+
def i_name
|
32
|
+
if suffix =~ /^_/
|
33
|
+
label + suffix
|
34
|
+
else
|
35
|
+
(suffix.nil? || suffix.empty?) ? label : suffix
|
36
|
+
end
|
37
|
+
end
|
38
|
+
=end
|
39
|
+
end # module
|
40
|
+
end # module
|
41
|
+
end # module
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'variable'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module BackEnd
|
7
|
+
# A environment is a name space that corresponds either to a specific
|
8
|
+
# delimited region in Loxxy source code or to an activation record
|
9
|
+
# of a relation or a relation definition.
|
10
|
+
# It contains a map of names to the objects they name (e.g. logical var)
|
11
|
+
class Environment
|
12
|
+
# The parent (enclosing) environment.
|
13
|
+
# @return [Environment, NilClass]
|
14
|
+
attr_accessor :parent
|
15
|
+
|
16
|
+
# Mapping from user-defined name to related definition
|
17
|
+
# (say, a variable object)
|
18
|
+
# @return [Hash{String => Variable}] Pairs of the kind
|
19
|
+
attr_reader :defns
|
20
|
+
|
21
|
+
# Construct a environment instance.
|
22
|
+
# @param aParent [Environment, NilClass] Parent environment to this one.
|
23
|
+
def initialize(aParent = nil)
|
24
|
+
@parent = aParent
|
25
|
+
@defns = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add a new variable to the environment.
|
29
|
+
# @param anEntry [BackEnd::Variable]
|
30
|
+
# @return [BackEnd::Variable] the variable
|
31
|
+
def insert(anEntry)
|
32
|
+
e = validated_entry(anEntry)
|
33
|
+
# e.suffix = default_suffix if e.kind_of?(BackEnd::Variable)
|
34
|
+
defns[e.name] = e
|
35
|
+
|
36
|
+
e
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns a string with a human-readable representation of the object.
|
40
|
+
# @return [String]
|
41
|
+
def inspect
|
42
|
+
+"#<#{self.class}:#{object_id.to_s(16)}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def validated_entry(anEntry)
|
48
|
+
name = anEntry.name
|
49
|
+
unless name.kind_of?(String) && !name.empty?
|
50
|
+
err_msg = 'Invalid variable name argument.'
|
51
|
+
raise StandardError, err_msg
|
52
|
+
end
|
53
|
+
if defns.include?(name) && !anEntry.kind_of?(Variable)
|
54
|
+
err_msg = "Variable with name '#{name}' already exists."
|
55
|
+
raise StandardError, err_msg
|
56
|
+
end
|
57
|
+
|
58
|
+
anEntry
|
59
|
+
end
|
60
|
+
|
61
|
+
# def default_suffix
|
62
|
+
# @default_suffix ||= "_#{object_id.to_s(16)}"
|
63
|
+
# end
|
64
|
+
end # class
|
65
|
+
end # module
|
66
|
+
end # module
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'environment'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module BackEnd
|
7
|
+
# A symbol table is basically a mapping from a name onto an object
|
8
|
+
# that holds information associated with that name. It is a data structure
|
9
|
+
# that keeps track of variables and their respective environment where they are
|
10
|
+
# declared. The key requirements for the symbol are:
|
11
|
+
# - To perform fast lookup operations: given a name, retrieve the corresponding
|
12
|
+
# object.
|
13
|
+
# - To allow the efficient insertion of names and related information
|
14
|
+
# - To support the nesting of environments
|
15
|
+
# - To handle the entry environment and exit environment events,
|
16
|
+
# - To cope with variable redefinition in nested environment
|
17
|
+
# The terminology 'symbol table' comes from the compiler design
|
18
|
+
# community.
|
19
|
+
class SymbolTable
|
20
|
+
# Mapping between a name and the environment(s) where it is defined
|
21
|
+
# @return [Hash{String => Array<Environment>}]
|
22
|
+
attr_reader :name2envs
|
23
|
+
|
24
|
+
# @return [Environment] The top-level environment (= root of environment tree)
|
25
|
+
attr_reader :root
|
26
|
+
|
27
|
+
# @return [Environment] The current environment.
|
28
|
+
attr_reader :current_env
|
29
|
+
|
30
|
+
# Build symbol table with given environment as root.
|
31
|
+
# @param anEnv [BackEnd::Environment,NilClass] The top-level Environment
|
32
|
+
def initialize(anEnv = nil)
|
33
|
+
@name2envs = {}
|
34
|
+
init_root(anEnv) # Set default (global) environment
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns iff there is no entry in the symbol table
|
38
|
+
# @return [Boolean]
|
39
|
+
def empty?
|
40
|
+
name2envs.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Use this method to signal the interpreter that a given environment
|
44
|
+
# to be a child of current environment and to be itself the new current environment.
|
45
|
+
# @param anEnv [BackEnd::Environment] the Environment that
|
46
|
+
def enter_environment(anEnv)
|
47
|
+
anEnv.parent = current_env
|
48
|
+
@current_env = anEnv
|
49
|
+
end
|
50
|
+
|
51
|
+
def leave_environment
|
52
|
+
current_env.defns.each_pair do |nm, _item|
|
53
|
+
environments = name2envs[nm]
|
54
|
+
if environments.size == 1
|
55
|
+
name2envs.delete(nm)
|
56
|
+
else
|
57
|
+
environments.pop
|
58
|
+
name2envs[nm] = environments
|
59
|
+
end
|
60
|
+
end
|
61
|
+
raise StandardError, 'Cannot remove root environment.' if current_env == root
|
62
|
+
|
63
|
+
@current_env = current_env.parent
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add an entry with given name to current environment.
|
67
|
+
# @param anEntry [Variable]
|
68
|
+
# @return [String] Internal name of the entry
|
69
|
+
def insert(anEntry)
|
70
|
+
current_env.insert(anEntry)
|
71
|
+
name = anEntry.name
|
72
|
+
if name2envs.include?(name)
|
73
|
+
name2envs[name] << current_env
|
74
|
+
else
|
75
|
+
name2envs[name] = [current_env]
|
76
|
+
end
|
77
|
+
|
78
|
+
anEntry.name # anEntry.i_name
|
79
|
+
end
|
80
|
+
|
81
|
+
# Search for the object with the given name
|
82
|
+
# @param aName [String]
|
83
|
+
# @return [BackEnd::Variable]
|
84
|
+
def lookup(aName)
|
85
|
+
environments = name2envs.fetch(aName, nil)
|
86
|
+
return nil if environments.nil?
|
87
|
+
|
88
|
+
sc = environments.last
|
89
|
+
sc.defns[aName]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Search for the object with the given i_name
|
93
|
+
# @param anIName [String]
|
94
|
+
# @return [BackEnd::Variable]
|
95
|
+
# def lookup_i_name(anIName)
|
96
|
+
# found = nil
|
97
|
+
# environment = current_env
|
98
|
+
|
99
|
+
# begin
|
100
|
+
# found = environment.defns.values.find { |e| e.i_name == anIName }
|
101
|
+
# break if found
|
102
|
+
|
103
|
+
# environment = environment.parent
|
104
|
+
# end while environment
|
105
|
+
|
106
|
+
# found
|
107
|
+
# end
|
108
|
+
|
109
|
+
# Return all variables defined in the current .. root chain.
|
110
|
+
# Variables are sorted top-down and left-to-right.
|
111
|
+
def all_variables
|
112
|
+
vars = []
|
113
|
+
skope = current_env
|
114
|
+
while skope
|
115
|
+
vars_of_environment = skope.defns.select { |_, item| item.kind_of?(Variable) }
|
116
|
+
vars = vars_of_environment.values.concat(vars)
|
117
|
+
skope = skope.parent
|
118
|
+
end
|
119
|
+
|
120
|
+
vars
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def init_root(anEnv)
|
126
|
+
@root = valid_environment(anEnv)
|
127
|
+
@current_env = @root
|
128
|
+
end
|
129
|
+
|
130
|
+
def valid_environment(anEnv)
|
131
|
+
anEnv.nil? ? Environment.new : anEnv
|
132
|
+
end
|
133
|
+
end # class
|
134
|
+
end # module
|
135
|
+
end # module
|