loxxy 0.0.21 → 0.0.26

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.
@@ -51,6 +51,14 @@ 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
+
54
62
  # Visit event. The visitor is about to visit a variable declaration statement.
55
63
  # @param aPrintStmt [AST::LOXVarStmt] the variable declaration node to visit
56
64
  def visit_var_stmt(aVarStmt)
@@ -75,6 +83,30 @@ module Loxxy
75
83
  broadcast(:after_print_stmt, aPrintStmt)
76
84
  end
77
85
 
86
+ # Visit event. The visitor is about to visit a while statement node.
87
+ # @param aWhileStmt [AST::LOXWhileStmt] the while statement node to visit
88
+ def visit_while_stmt(aWhileStmt)
89
+ broadcast(:before_while_stmt, aWhileStmt)
90
+ traverse_subnodes(aWhileStmt) # The condition is visited/evaluated here...
91
+ broadcast(:after_while_stmt, aWhileStmt, self)
92
+ end
93
+
94
+ # Visit event. The visitor is about to visit a block statement.
95
+ # @param aBlockStmt [AST::LOXBlockStmt] the print statement node to visit
96
+ def visit_block_stmt(aBlockStmt)
97
+ broadcast(:before_block_stmt, aBlockStmt)
98
+ traverse_subnodes(aBlockStmt)
99
+ broadcast(:after_block_stmt, aBlockStmt)
100
+ end
101
+
102
+ # Visit event. The visitor is visiting an assignment node
103
+ # @param aLiteralExpr [AST::LoxAssignExpr] the variable assignment node to visit.
104
+ def visit_assign_expr(anAssignExpr)
105
+ broadcast(:before_assign_expr, anAssignExpr)
106
+ traverse_subnodes(anAssignExpr)
107
+ broadcast(:after_assign_expr, anAssignExpr)
108
+ end
109
+
78
110
  # Visit event. The visitor is about to visit a logical expression.
79
111
  # Since logical expressions may take shorcuts by not evaluating all their
80
112
  # sub-expressiosns, they are responsible for visiting or not their children.
@@ -121,8 +153,22 @@ module Loxxy
121
153
  broadcast(:after_literal_expr, aLiteralExpr)
122
154
  end
123
155
 
156
+ # Visit event. The visitor is visiting a variable usage node
157
+ # @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
158
+ def visit_variable_expr(aVariableExpr)
159
+ broadcast(:before_variable_expr, aVariableExpr)
160
+ broadcast(:after_variable_expr, aVariableExpr, self)
161
+ end
162
+
163
+ # Visit event. The visitor is about to visit the given terminal datatype value.
164
+ # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
165
+ def visit_builtin(aValue)
166
+ broadcast(:before_visit_builtin, aValue)
167
+ broadcast(:after_visit_builtin, aValue)
168
+ end
169
+
124
170
  # Visit event. The visitor is about to visit the given non terminal node.
125
- # @param aNonTerminalNode [Rley::PTre::NonTerminalNode] the node to visit.
171
+ # @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
126
172
  def visit_nonterminal(_non_terminal_node)
127
173
  # Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
128
174
  # 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
@@ -32,4 +32,4 @@ module Loxxy
32
32
  end
33
33
  end # class
34
34
  end # module
35
- 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
@@ -13,7 +13,7 @@ module Loxxy
13
13
  # @param aName [String] name of the variable
14
14
  # @param aValue [Loxxy::Ast::LoxNode, NilClass] initial value for the variable
15
15
  def initialize(aPosition, aName, aValue)
16
- initial_value = aValue ? [aValue] : []
16
+ initial_value = aValue ? [aValue] : [Datatype::Nil.instance]
17
17
  super(aPosition, initial_value)
18
18
  @name = aName
19
19
  end
@@ -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
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_compound_expr'
4
+
5
+ module Loxxy
6
+ module Ast
7
+ class LoxWhileStmt < LoxCompoundExpr
8
+ # @return [LoxNode] body of the while loop (as a statement)
9
+ attr_reader :body
10
+
11
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
12
+ # @param condExpr [Loxxy::Ast::LoxNode] iteration condition
13
+ # @param theBody [Loxxy::Ast::LoxNode]
14
+ def initialize(aPosition, condExpr, theBody)
15
+ super(aPosition, [condExpr])
16
+ @body = theBody
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_while_stmt(self)
23
+ end
24
+
25
+ # Accessor to the condition expression
26
+ # @return [LoxNode]
27
+ def condition
28
+ subnodes[0]
29
+ end
30
+ end # class
31
+ end # module
32
+ end # module
@@ -41,6 +41,11 @@ module Loxxy
41
41
  ##########################################################################
42
42
  # Visit event handling
43
43
  ##########################################################################
44
+
45
+ def after_seq_decl(aSeqDecls)
46
+ # Do nothing, subnodes were already evaluated
47
+ end
48
+
44
49
  def after_var_stmt(aVarStmt)
45
50
  new_var = Variable.new(aVarStmt.name, aVarStmt.subnodes[0])
46
51
  symbol_table.insert(new_var)
@@ -50,7 +55,7 @@ module Loxxy
50
55
  # Retrieve the result of the condition evaluation
51
56
  condition = stack.pop
52
57
  if condition.truthy?
53
- result = anIfStmt.then_stmt.accept(aVisitor)
58
+ anIfStmt.then_stmt.accept(aVisitor)
54
59
  elsif anIfStmt.else_stmt
55
60
  anIfStmt.else_stmt.accept(aVisitor)
56
61
  end
@@ -61,6 +66,35 @@ module Loxxy
61
66
  @ostream.print tos.to_str
62
67
  end
63
68
 
69
+ def after_while_stmt(aWhileStmt, aVisitor)
70
+ loop do
71
+ condition = stack.pop
72
+ break unless condition.truthy?
73
+
74
+ aWhileStmt.body.accept(aVisitor)
75
+ aWhileStmt.condition.accept(aVisitor)
76
+ end
77
+ end
78
+
79
+ def before_block_stmt(_aBlockStmt)
80
+ new_env = Environment.new
81
+ symbol_table.enter_environment(new_env)
82
+ end
83
+
84
+ def after_block_stmt(_aBlockStmt)
85
+ symbol_table.leave_environment
86
+ end
87
+
88
+ def after_assign_expr(anAssignExpr)
89
+ var_name = anAssignExpr.name
90
+ variable = symbol_table.lookup(var_name)
91
+ raise StandardError, "Unknown variable #{var_name}" unless variable
92
+
93
+ value = stack.pop
94
+ variable.assign(value)
95
+ stack.push value # An expression produces a value
96
+ end
97
+
64
98
  def after_logical_expr(aLogicalExpr, visitor)
65
99
  op = aLogicalExpr.operator
66
100
  operand1 = stack.pop # only first operand was evaluated
@@ -120,10 +154,23 @@ module Loxxy
120
154
  # Do nothing: work was already done by visiting /evaluating the subexpression
121
155
  end
122
156
 
157
+ def after_variable_expr(aVarExpr, aVisitor)
158
+ var_name = aVarExpr.name
159
+ var = symbol_table.lookup(var_name)
160
+ raise StandardError, "Unknown variable #{var_name}" unless var
161
+
162
+ var.value.accept(aVisitor) # Evaluate the variable value
163
+ end
164
+
123
165
  # @param literalExpr [Ast::LoxLiteralExpr]
124
166
  def before_literal_expr(literalExpr)
125
167
  stack.push(literalExpr.literal)
126
168
  end
169
+
170
+ # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
171
+ def before_visit_builtin(aValue)
172
+ stack.push(aValue)
173
+ end
127
174
  end # class
128
175
  end # module
129
176
  end # module
@@ -11,7 +11,7 @@ module Loxxy
11
11
  =begin
12
12
  # @return [String] Suffix for building the internal name of the entry.
13
13
  attr_accessor :suffix
14
- =end
14
+ =end
15
15
 
16
16
  # Initialize the entry with given name
17
17
  # @param aName [String] The name of the entry
@@ -35,7 +35,7 @@ module Loxxy
35
35
  (suffix.nil? || suffix.empty?) ? label : suffix
36
36
  end
37
37
  end
38
- =end
38
+ =end
39
39
  end # module
40
40
  end # module
41
41
  end # module
@@ -9,9 +9,9 @@ module Loxxy
9
9
  # of a relation or a relation definition.
10
10
  # It contains a map of names to the objects they name (e.g. logical var)
11
11
  class Environment
12
- # The parent (enclosing) environment.
12
+ # The enclosing (parent) environment.
13
13
  # @return [Environment, NilClass]
14
- attr_accessor :parent
14
+ attr_accessor :enclosing
15
15
 
16
16
  # Mapping from user-defined name to related definition
17
17
  # (say, a variable object)
@@ -21,7 +21,7 @@ module Loxxy
21
21
  # Construct a environment instance.
22
22
  # @param aParent [Environment, NilClass] Parent environment to this one.
23
23
  def initialize(aParent = nil)
24
- @parent = aParent
24
+ @enclosing = aParent
25
25
  @defns = {}
26
26
  end
27
27
 
@@ -44,7 +44,7 @@ module Loxxy
44
44
  # to be a child of current environment and to be itself the new current environment.
45
45
  # @param anEnv [BackEnd::Environment] the Environment that
46
46
  def enter_environment(anEnv)
47
- anEnv.parent = current_env
47
+ anEnv.enclosing = current_env
48
48
  @current_env = anEnv
49
49
  end
50
50
 
@@ -60,7 +60,7 @@ module Loxxy
60
60
  end
61
61
  raise StandardError, 'Cannot remove root environment.' if current_env == root
62
62
 
63
- @current_env = current_env.parent
63
+ @current_env = current_env.enclosing
64
64
  end
65
65
 
66
66
  # Add an entry with given name to current environment.
@@ -114,7 +114,7 @@ module Loxxy
114
114
  while skope
115
115
  vars_of_environment = skope.defns.select { |_, item| item.kind_of?(Variable) }
116
116
  vars = vars_of_environment.values.concat(vars)
117
- skope = skope.parent
117
+ skope = skope.enclosing
118
118
  end
119
119
 
120
120
  vars
@@ -9,15 +9,20 @@ module Loxxy
9
9
  # It is a named slot that can be associated with a value at the time.
10
10
  class Variable
11
11
  include Entry # Add expected behaviour for symbol table entries
12
-
12
+
13
13
  # @return [Datatype::BuiltinDatatype] the value assigned to the variable
14
- attr_accessor :value
14
+ attr_reader :value
15
15
 
16
16
  # Create a variable with given name and initial value
17
17
  # @param aName [String] The name of the variable
18
18
  # @param aValue [Datatype::BuiltinDatatype] the initial assigned value
19
19
  def initialize(aName, aValue = Datatype::Nil.instance)
20
20
  init_name(aName)
21
+ assign(aValue)
22
+ end
23
+
24
+ # @param aValue [Datatype::BuiltinDatatype] the assigned value
25
+ def assign(aValue)
21
26
  @value = aValue
22
27
  end
23
28
  end # class
@@ -62,6 +62,12 @@ module Loxxy
62
62
  value.to_s # Default implementation...
63
63
  end
64
64
 
65
+ # Part of the 'visitee' role in Visitor design pattern.
66
+ # @param visitor [Ast::ASTVisitor] the visitor
67
+ def accept(visitor)
68
+ visitor.visit_builtin(self)
69
+ end
70
+
65
71
  protected
66
72
 
67
73
  def validated_value(aValue)
@@ -30,8 +30,8 @@ module Loxxy
30
30
  rule('program' => 'declaration_plus EOF').as 'lox_program'
31
31
 
32
32
  # Declarations: bind an identifier to something
33
- rule('declaration_plus' => 'declaration_plus declaration')
34
- rule('declaration_plus' => 'declaration')
33
+ rule('declaration_plus' => 'declaration_plus declaration').as 'declaration_plus_more'
34
+ rule('declaration_plus' => 'declaration').as 'declaration_plus_end'
35
35
  rule('declaration' => 'classDecl')
36
36
  rule('declaration' => 'funDecl')
37
37
  rule('declaration' => 'varDecl')
@@ -75,15 +75,15 @@ module Loxxy
75
75
 
76
76
  rule('printStmt' => 'PRINT expression SEMICOLON').as 'print_stmt'
77
77
  rule('returnStmt' => 'RETURN expression_opt SEMICOLON')
78
- rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement')
79
- rule('block' => 'LEFT_BRACE declaration_plus RIGHT_BRACE')
78
+ rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement').as 'while_stmt'
79
+ rule('block' => 'LEFT_BRACE declaration_plus RIGHT_BRACE').as 'block_stmt'
80
80
  rule('block' => 'LEFT_BRACE RIGHT_BRACE')
81
81
 
82
82
  # Expressions: produce values
83
83
  rule('expression_opt' => 'expression')
84
84
  rule('expression_opt' => [])
85
85
  rule('expression' => 'assignment')
86
- rule('assignment' => 'owner_opt IDENTIFIER EQUAL assignment')
86
+ rule('assignment' => 'owner_opt IDENTIFIER EQUAL assignment').as 'assign_expr'
87
87
  rule('assignment' => 'logic_or')
88
88
  rule('owner_opt' => 'call DOT')
89
89
  rule('owner_opt' => [])
@@ -137,7 +137,7 @@ module Loxxy
137
137
  rule('primary' => 'THIS')
138
138
  rule('primary' => 'NUMBER').as 'literal_expr'
139
139
  rule('primary' => 'STRING').as 'literal_expr'
140
- rule('primary' => 'IDENTIFIER')
140
+ rule('primary' => 'IDENTIFIER').as 'variable_expr'
141
141
  rule('primary' => 'LEFT_PAREN expression RIGHT_PAREN').as 'grouping_expr'
142
142
  rule('primary' => 'SUPER DOT IDENTIFIER')
143
143
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.0.21'
4
+ VERSION = '0.0.26'
5
5
  end