loxxy 0.0.23 → 0.0.24

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aeb2808649debaf9bdbca836e459b0f7991442c90aad6bb4b174374fb66234df
4
- data.tar.gz: 78b1b43091b11b5bde2b2444dd785e3c464252af044167acade6f04b830f95fa
3
+ metadata.gz: 6085bf18afb919e5ef4d327162470c9d5ca95dde67e00dce78bb26abd6563dec
4
+ data.tar.gz: f1c7732a34b6df2721c20d82404c6ce83bdc8a75b695e4bbe13c51f62d9ac371
5
5
  SHA512:
6
- metadata.gz: 24113720fa7bcd7d711cf03668c86af5a10de3b06dcf9b02d6a5c3550d86e0a19d5374b0d0de6c641afd2a5a9de7c7baccee9da96f97fece6aaf37864d91a0d3
7
- data.tar.gz: 0103b262f03272b23f297a57b7d0735c513f6ef0b82e9a2f13e20068845e0cb6ac1952c46a404247b23dde37e75c3fbc48b45f44c1b07470078e4554d5ed54c5
6
+ metadata.gz: 7546a14b935700e5050411a7805c2b2d00ccfc99160e3241b512289a6cc1762df2f39b7c9845c6ffe7fb95f1412865ef373f5308c9cf333fd72e2025a4a17ed8
7
+ data.tar.gz: 3675956929831e52963759862e8f9d40e5ebd3df471dee87d82784c2d1230ce6057882368042c907741be1038d300b7c83c27ed4bb8d979f5efa2ac79eaa3b1a
@@ -1,3 +1,13 @@
1
+ ## [0.0.24] - 2021-01-20
2
+ - The interpreter implements the assignment of variables.
3
+
4
+ ### Added
5
+ - Class `Ast::LoxAssignExpr` a node that represents the assignment of a value to a variable
6
+ - Method `Ast::ASTBuilder#reduce_assign_expr` creates an `Ast::LoxAssignExpr` node
7
+ - Method `Ast::ASTVisitor#visit_assign_expr` for visiting an `Ast::LoxAssignExpr` node
8
+ - Method `BackEnd::Engine#after_assign_expr` implementation of the assignment
9
+ - Method `BackEnd::Variable#assign` to assign a value to a variable
10
+
1
11
  ## [0.0.23] - 2021-01-20
2
12
  - Fix for variables without explicit initialization.
3
13
 
data/README.md CHANGED
@@ -176,7 +176,7 @@ Loxxy supports the following statements:
176
176
  -[Comparison expressions](#comparison-expressions)
177
177
  -[Logical expressions](#logical-expressions)
178
178
  -[Grouping expressions](#grouping-expressions)
179
- -[Variable expressions](#variable-expressions)
179
+ -[Variable expressions and assignments](#variable-expressions)
180
180
 
181
181
  -[Variable declarations](#var-statement)
182
182
  -[If Statement](#if-statement)
@@ -259,13 +259,17 @@ print 3 + 4 * 5; // => 23
259
259
  print (3 + 4) * 5; // => 35
260
260
  ```
261
261
 
262
- #### Variable expressions
262
+ #### Variable expressions and assignments
263
263
  In __Lox__, a variable expression is nothing than retrieving the value of a variable.
264
264
  ``` javascript
265
265
  var foo = "bar;" // Variable declaration
266
- foo; // Varible expression (= retrieving its value)
266
+ print foo; // Variable expression (= use its value)
267
+ foo = "baz"; // Variable assignment
268
+ print foo; // Output: baz
267
269
  ```
268
270
 
271
+
272
+
269
273
  #### Variable declarations
270
274
  ``` javascript
271
275
  var iAmAVariable = "my-initial-value";
@@ -273,10 +277,6 @@ var iAmNil; // __Lox__ initializes variables to nil by default;
273
277
  print iAmNil; // output: nil
274
278
  ```
275
279
 
276
- Warning: current version cannot assign a value to an existing variable.
277
- Expect this capability to be implemented in the coming days.
278
-
279
-
280
280
  #### If statement
281
281
 
282
282
  Based on a given condition, an if statement executes one of two statements:
@@ -7,6 +7,7 @@ require_relative 'lox_grouping_expr'
7
7
  require_relative 'lox_unary_expr'
8
8
  require_relative 'lox_binary_expr'
9
9
  require_relative 'lox_logical_expr'
10
+ require_relative 'lox_assign_expr'
10
11
  require_relative 'lox_print_stmt'
11
12
  require_relative 'lox_if_stmt'
12
13
  require_relative 'lox_var_stmt'
@@ -193,6 +193,12 @@ module Loxxy
193
193
  Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
194
194
  end
195
195
 
196
+ # rule('assignment' => 'owner_opt IDENTIFIER EQUAL assignment')
197
+ def reduce_assign_expr(_production, _range, tokens, theChildren)
198
+ var_name = theChildren[1].token.lexeme.dup
199
+ Ast::LoxAssignExpr.new(tokens[1].position, var_name, theChildren[3])
200
+ end
201
+
196
202
  # rule('logic_or' => 'logic_and disjunct_plus')
197
203
  def reduce_logic_or_plus(production, range, tokens, theChildren)
198
204
  reduce_logical_expr(production, range, tokens, theChildren)
@@ -83,6 +83,14 @@ module Loxxy
83
83
  broadcast(:after_print_stmt, aPrintStmt)
84
84
  end
85
85
 
86
+ # Visit event. The visitor is visiting an assignment node
87
+ # @param aLiteralExpr [AST::LoxAssignExpr] the variable assignment node to visit.
88
+ def visit_assign_expr(anAssignExpr)
89
+ broadcast(:before_assign_expr, anAssignExpr)
90
+ traverse_subnodes(anAssignExpr)
91
+ broadcast(:after_assign_expr, anAssignExpr)
92
+ end
93
+
86
94
  # Visit event. The visitor is about to visit a logical expression.
87
95
  # Since logical expressions may take shorcuts by not evaluating all their
88
96
  # sub-expressiosns, they are responsible for visiting or not their children.
@@ -129,7 +137,7 @@ module Loxxy
129
137
  broadcast(:after_literal_expr, aLiteralExpr)
130
138
  end
131
139
 
132
- # Visit event. The visitor is visiting a variable reference node
140
+ # Visit event. The visitor is visiting a variable usage node
133
141
  # @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
134
142
  def visit_variable_expr(aVariableExpr)
135
143
  broadcast(:before_variable_expr, aVariableExpr)
@@ -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
@@ -66,6 +66,15 @@ module Loxxy
66
66
  @ostream.print tos.to_str
67
67
  end
68
68
 
69
+ def after_assign_expr(anAssignExpr)
70
+ var_name = anAssignExpr.name
71
+ variable = symbol_table.lookup(var_name)
72
+ raise StandardError, "Unknown variable #{var_name}" unless variable
73
+ value = stack.pop
74
+ variable.assign(value)
75
+ stack.push value # An expression produces a value
76
+ end
77
+
69
78
  def after_logical_expr(aLogicalExpr, visitor)
70
79
  op = aLogicalExpr.operator
71
80
  operand1 = stack.pop # only first operand was evaluated
@@ -11,13 +11,18 @@ module Loxxy
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
@@ -83,7 +83,7 @@ module Loxxy
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' => [])
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.0.23'
4
+ VERSION = '0.0.24'
5
5
  end
@@ -277,13 +277,28 @@ LOX_END
277
277
 
278
278
  it 'should set uninitialized variables to nil' do
279
279
  program = <<-LOX_END
280
- var foo;
281
- print foo; // => nil
280
+ var a;
281
+ print a; // => nil
282
282
  LOX_END
283
283
  expect { subject.evaluate(program) }.not_to raise_error
284
284
  expect(sample_cfg[:ostream].string).to eq('nil')
285
285
  end
286
286
 
287
+ it 'should accept assignments to a global variable' do
288
+ program = <<-LOX_END
289
+ var a = "before";
290
+ print a; // output: before
291
+
292
+ a = "after";
293
+ print a; // output: after
294
+
295
+ print a = "arg"; // output: arg
296
+ print a; // output: arg
297
+ LOX_END
298
+ expect { subject.evaluate(program) }.not_to raise_error
299
+ expect(sample_cfg[:ostream].string).to eq('beforeafterargarg')
300
+ end
301
+
287
302
  it 'should print the hello world message' do
288
303
  expect { subject.evaluate(hello_world) }.not_to raise_error
289
304
  expect(sample_cfg[:ostream].string).to eq('Hello, world!')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loxxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
@@ -87,6 +87,7 @@ files:
87
87
  - lib/loxxy/ast/all_lox_nodes.rb
88
88
  - lib/loxxy/ast/ast_builder.rb
89
89
  - lib/loxxy/ast/ast_visitor.rb
90
+ - lib/loxxy/ast/lox_assign_expr.rb
90
91
  - lib/loxxy/ast/lox_binary_expr.rb
91
92
  - lib/loxxy/ast/lox_compound_expr.rb
92
93
  - lib/loxxy/ast/lox_grouping_expr.rb