loxxy 0.0.20 → 0.0.25
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 +92 -31
- data/README.md +47 -10
- data/lib/loxxy/ast/all_lox_nodes.rb +5 -0
- data/lib/loxxy/ast/ast_builder.rb +42 -2
- data/lib/loxxy/ast/ast_visitor.rb +47 -1
- data/lib/loxxy/ast/lox_assign_expr.rb +27 -0
- data/lib/loxxy/ast/lox_block_stmt.rb +23 -0
- data/lib/loxxy/ast/lox_if_stmt.rb +1 -1
- 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 +49 -2
- 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 +30 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +6 -0
- data/lib/loxxy/front_end/grammar.rb +7 -7
- 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 +83 -4
- metadata +17 -2
@@ -51,6 +51,22 @@ 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
|
+
|
54
70
|
# Visit event. The visitor is about to visit a if statement.
|
55
71
|
# @param anIfStmt [AST::LOXIfStmt] the if statement node to visit
|
56
72
|
def visit_if_stmt(anIfStmt)
|
@@ -67,6 +83,22 @@ module Loxxy
|
|
67
83
|
broadcast(:after_print_stmt, aPrintStmt)
|
68
84
|
end
|
69
85
|
|
86
|
+
# Visit event. The visitor is about to visit a block statement.
|
87
|
+
# @param aBlockStmt [AST::LOXBlockStmt] the print statement node to visit
|
88
|
+
def visit_block_stmt(aBlockStmt)
|
89
|
+
broadcast(:before_block_stmt, aBlockStmt)
|
90
|
+
traverse_subnodes(aBlockStmt)
|
91
|
+
broadcast(:after_block_stmt, aBlockStmt)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Visit event. The visitor is visiting an assignment node
|
95
|
+
# @param aLiteralExpr [AST::LoxAssignExpr] the variable assignment node to visit.
|
96
|
+
def visit_assign_expr(anAssignExpr)
|
97
|
+
broadcast(:before_assign_expr, anAssignExpr)
|
98
|
+
traverse_subnodes(anAssignExpr)
|
99
|
+
broadcast(:after_assign_expr, anAssignExpr)
|
100
|
+
end
|
101
|
+
|
70
102
|
# Visit event. The visitor is about to visit a logical expression.
|
71
103
|
# Since logical expressions may take shorcuts by not evaluating all their
|
72
104
|
# sub-expressiosns, they are responsible for visiting or not their children.
|
@@ -113,8 +145,22 @@ module Loxxy
|
|
113
145
|
broadcast(:after_literal_expr, aLiteralExpr)
|
114
146
|
end
|
115
147
|
|
148
|
+
# Visit event. The visitor is visiting a variable usage node
|
149
|
+
# @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
|
150
|
+
def visit_variable_expr(aVariableExpr)
|
151
|
+
broadcast(:before_variable_expr, aVariableExpr)
|
152
|
+
broadcast(:after_variable_expr, aVariableExpr, self)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Visit event. The visitor is about to visit the given terminal datatype value.
|
156
|
+
# @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
|
157
|
+
def visit_builtin(aValue)
|
158
|
+
broadcast(:before_visit_builtin, aValue)
|
159
|
+
broadcast(:after_visit_builtin, aValue)
|
160
|
+
end
|
161
|
+
|
116
162
|
# Visit event. The visitor is about to visit the given non terminal node.
|
117
|
-
# @param aNonTerminalNode [Rley::
|
163
|
+
# @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
|
118
164
|
def visit_nonterminal(_non_terminal_node)
|
119
165
|
# Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
|
120
166
|
# that it cannot handle.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
# This AST node represents the assignment of a value to a variable
|
8
|
+
class LoxAssignExpr < 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] value to assign
|
15
|
+
def initialize(aPosition, aName, aValue)
|
16
|
+
super(aPosition, [aValue])
|
17
|
+
@name = aName
|
18
|
+
end
|
19
|
+
|
20
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
21
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
22
|
+
def accept(visitor)
|
23
|
+
visitor.visit_assign_expr(self)
|
24
|
+
end
|
25
|
+
end # class
|
26
|
+
end # module
|
27
|
+
end # module
|
@@ -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 LoxBlockStmt < LoxCompoundExpr
|
8
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
9
|
+
# @param operand [Loxxy::Ast::LoxSeqDecl]
|
10
|
+
def initialize(aPosition, decls)
|
11
|
+
super(aPosition, [decls])
|
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_block_stmt(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias operands subnodes
|
21
|
+
end # class
|
22
|
+
end # module
|
23
|
+
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
|
|
@@ -36,11 +41,21 @@ module Loxxy
|
|
36
41
|
##########################################################################
|
37
42
|
# Visit event handling
|
38
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
|
+
|
39
54
|
def after_if_stmt(anIfStmt, aVisitor)
|
40
55
|
# Retrieve the result of the condition evaluation
|
41
56
|
condition = stack.pop
|
42
57
|
if condition.truthy?
|
43
|
-
|
58
|
+
anIfStmt.then_stmt.accept(aVisitor)
|
44
59
|
elsif anIfStmt.else_stmt
|
45
60
|
anIfStmt.else_stmt.accept(aVisitor)
|
46
61
|
end
|
@@ -51,6 +66,25 @@ module Loxxy
|
|
51
66
|
@ostream.print tos.to_str
|
52
67
|
end
|
53
68
|
|
69
|
+
def before_block_stmt(_aBlockStmt)
|
70
|
+
new_env = Environment.new
|
71
|
+
symbol_table.enter_environment(new_env)
|
72
|
+
end
|
73
|
+
|
74
|
+
def after_block_stmt(_aBlockStmt)
|
75
|
+
symbol_table.leave_environment
|
76
|
+
end
|
77
|
+
|
78
|
+
def after_assign_expr(anAssignExpr)
|
79
|
+
var_name = anAssignExpr.name
|
80
|
+
variable = symbol_table.lookup(var_name)
|
81
|
+
raise StandardError, "Unknown variable #{var_name}" unless variable
|
82
|
+
|
83
|
+
value = stack.pop
|
84
|
+
variable.assign(value)
|
85
|
+
stack.push value # An expression produces a value
|
86
|
+
end
|
87
|
+
|
54
88
|
def after_logical_expr(aLogicalExpr, visitor)
|
55
89
|
op = aLogicalExpr.operator
|
56
90
|
operand1 = stack.pop # only first operand was evaluated
|
@@ -110,10 +144,23 @@ module Loxxy
|
|
110
144
|
# Do nothing: work was already done by visiting /evaluating the subexpression
|
111
145
|
end
|
112
146
|
|
147
|
+
def after_variable_expr(aVarExpr, aVisitor)
|
148
|
+
var_name = aVarExpr.name
|
149
|
+
var = symbol_table.lookup(var_name)
|
150
|
+
raise StandardError, "Unknown variable #{var_name}" unless var
|
151
|
+
|
152
|
+
var.value.accept(aVisitor) # Evaluate the variable value
|
153
|
+
end
|
154
|
+
|
113
155
|
# @param literalExpr [Ast::LoxLiteralExpr]
|
114
156
|
def before_literal_expr(literalExpr)
|
115
157
|
stack.push(literalExpr.literal)
|
116
158
|
end
|
159
|
+
|
160
|
+
# @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
|
161
|
+
def before_visit_builtin(aValue)
|
162
|
+
stack.push(aValue)
|
163
|
+
end
|
117
164
|
end # class
|
118
165
|
end # module
|
119
166
|
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 enclosing (parent) environment.
|
13
|
+
# @return [Environment, NilClass]
|
14
|
+
attr_accessor :enclosing
|
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
|
+
@enclosing = 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.enclosing = 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.enclosing
|
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.enclosing
|
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
|