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.
@@ -34,6 +34,7 @@ module Loxxy
34
34
  let(:var_decl) { Ast::LoxVarStmt.new(sample_pos, 'greeting', greeting) }
35
35
  let(:lit_expr) { Ast::LoxLiteralExpr.new(sample_pos, greeting) }
36
36
 
37
+
37
38
  it "should react to 'after_var_stmt' event" do
38
39
  expect { subject.after_var_stmt(var_decl) }.not_to raise_error
39
40
  current_env = subject.symbol_table.current_env
@@ -9,7 +9,7 @@ module Loxxy
9
9
  module BackEnd
10
10
  describe Environment do
11
11
  let(:foo) { Datatype::LXString.new('foo') }
12
- let(:bar) { Datatype::LXString.new('bar') }
12
+ let(:bar) { Datatype::LXString.new('bar') }
13
13
  let(:mother) { Environment.new }
14
14
  subject { Environment.new(mother) }
15
15
 
@@ -32,7 +32,7 @@ module Loxxy
32
32
  end
33
33
 
34
34
  it 'should know its parent (if any)' do
35
- expect(subject.parent).to eq(mother)
35
+ expect(subject.enclosing).to eq(mother)
36
36
  end
37
37
  end # context
38
38
 
@@ -46,8 +46,8 @@ module Loxxy
46
46
  end
47
47
 
48
48
  it 'should allow the addition of several labels for same env' do
49
- i_name = subject.insert(var('q'))
50
- #expect(i_name).to match(/^q_[0-9a-z]*$/)
49
+ subject.insert(var('q'))
50
+ # expect(i_name).to match(/^q_[0-9a-z]*$/)
51
51
 
52
52
  expect { subject.insert(var('x')) }.not_to raise_error
53
53
  expect(subject.name2envs['x']).to be_kind_of(Array)
@@ -60,7 +60,7 @@ module Loxxy
60
60
  new_env = BackEnd::Environment.new
61
61
  expect { subject.enter_environment(new_env) }.not_to raise_error
62
62
  expect(subject.current_env).to eq(new_env)
63
- expect(subject.current_env.parent).to eq(subject.root)
63
+ expect(subject.current_env.enclosing).to eq(subject.root)
64
64
  expect(subject.name2envs['q']).to eq([subject.root])
65
65
  end
66
66
 
@@ -17,10 +17,10 @@ module Loxxy
17
17
  it 'should be initialized with a name and a value, or...' do
18
18
  expect { Variable.new(sample_name, sample_value) }.not_to raise_error
19
19
  end
20
-
20
+
21
21
  it 'should be initialized with just a name' do
22
22
  expect { Variable.new(sample_name) }.not_to raise_error
23
- end
23
+ end
24
24
 
25
25
  it 'should know its name' do
26
26
  expect(subject.name).to eq(sample_name)
@@ -29,11 +29,11 @@ module Loxxy
29
29
  it 'should have a frozen name' do
30
30
  expect(subject.name).to be_frozen
31
31
  end
32
-
32
+
33
33
  it 'should know its value (if provided)' do
34
34
  expect(subject.value).to eq(sample_value)
35
35
  end
36
-
36
+
37
37
  it 'should have a nil value otherwise' do
38
38
  instance = Variable.new(sample_name)
39
39
  expect(instance.value).to eq(Datatype::Nil.instance)
@@ -64,7 +64,8 @@ module Loxxy
64
64
  it 'should parse a false literal' do
65
65
  input = 'false;'
66
66
  ptree = subject.parse(input)
67
- leaf = ptree.root
67
+ expect(ptree.root).to be_kind_of(Ast::LoxSeqDecl)
68
+ leaf = ptree.root.subnodes[0]
68
69
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
69
70
  expect(leaf.literal).to be_equal(Datatype::False.instance)
70
71
  end
@@ -72,7 +73,8 @@ module Loxxy
72
73
  it 'should parse a true literal' do
73
74
  input = 'true;'
74
75
  ptree = subject.parse(input)
75
- leaf = ptree.root
76
+ expect(ptree.root).to be_kind_of(Ast::LoxSeqDecl)
77
+ leaf = ptree.root.subnodes[0]
76
78
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
77
79
  expect(leaf.literal).to be_equal(Datatype::True.instance)
78
80
  end
@@ -81,7 +83,7 @@ module Loxxy
81
83
  inputs = %w[1234; 12.34;]
82
84
  inputs.each do |source|
83
85
  ptree = subject.parse(source)
84
- leaf = ptree.root
86
+ leaf = ptree.root.subnodes[0]
85
87
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
86
88
  expect(leaf.literal).to be_kind_of(Datatype::Number)
87
89
  expect(leaf.literal.value).to eq(source.to_f)
@@ -96,7 +98,7 @@ module Loxxy
96
98
  ]
97
99
  inputs.each do |source|
98
100
  ptree = subject.parse(source)
99
- leaf = ptree.root
101
+ leaf = ptree.root.subnodes[0]
100
102
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
101
103
  expect(leaf.literal).to be_kind_of(Datatype::LXString)
102
104
  expect(leaf.literal.value).to eq(source.gsub(/(^")|(";$)/, ''))
@@ -106,7 +108,7 @@ module Loxxy
106
108
  it 'should parse a nil literal' do
107
109
  input = 'nil;'
108
110
  ptree = subject.parse(input)
109
- leaf = ptree.root
111
+ leaf = ptree.root.subnodes[0]
110
112
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
111
113
  expect(leaf.literal).to be_equal(Datatype::Nil.instance)
112
114
  end
@@ -119,7 +121,7 @@ module Loxxy
119
121
  print "Hello, world!";
120
122
  LOX_END
121
123
  ptree = subject.parse(program)
122
- prnt_stmt = ptree.root
124
+ prnt_stmt = ptree.root.subnodes[0]
123
125
  expect(prnt_stmt).to be_kind_of(Ast::LoxPrintStmt)
124
126
  expect(prnt_stmt.subnodes[0]).to be_kind_of(Ast::LoxLiteralExpr)
125
127
  expect(prnt_stmt.subnodes[0].literal).to be_kind_of(Loxxy::Datatype::LXString)
@@ -131,7 +133,7 @@ LOX_END
131
133
  it 'should parse the addition of two number literals' do
132
134
  input = '123 + 456;'
133
135
  ptree = subject.parse(input)
134
- expr = ptree.root
136
+ expr = ptree.root.subnodes[0]
135
137
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
136
138
  expect(expr.operator).to eq(:+)
137
139
  expect(expr.operands[0].literal.value).to eq(123)
@@ -141,7 +143,7 @@ LOX_END
141
143
  it 'should parse the subtraction of two number literals' do
142
144
  input = '4 - 3;'
143
145
  ptree = subject.parse(input)
144
- expr = ptree.root
146
+ expr = ptree.root.subnodes[0]
145
147
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
146
148
  expect(expr.operator).to eq(:-)
147
149
  expect(expr.operands[0].literal.value).to eq(4)
@@ -151,7 +153,7 @@ LOX_END
151
153
  it 'should parse multiple additive operations' do
152
154
  input = '5 + 2 - 3;'
153
155
  ptree = subject.parse(input)
154
- expr = ptree.root
156
+ expr = ptree.root.subnodes[0]
155
157
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
156
158
  expect(expr.operator).to eq(:-)
157
159
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -164,7 +166,7 @@ LOX_END
164
166
  it 'should parse the division of two number literals' do
165
167
  input = '8 / 2;'
166
168
  ptree = subject.parse(input)
167
- expr = ptree.root
169
+ expr = ptree.root.subnodes[0]
168
170
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
169
171
  expect(expr.operator).to eq(:/)
170
172
  expect(expr.operands[0].literal.value).to eq(8)
@@ -174,7 +176,7 @@ LOX_END
174
176
  it 'should parse the product of two number literals' do
175
177
  input = '12.34 * 0.3;'
176
178
  ptree = subject.parse(input)
177
- expr = ptree.root
179
+ expr = ptree.root.subnodes[0]
178
180
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
179
181
  expect(expr.operator).to eq(:*)
180
182
  expect(expr.operands[0].literal.value).to eq(12.34)
@@ -184,7 +186,7 @@ LOX_END
184
186
  it 'should parse multiple multiplicative operations' do
185
187
  input = '5 * 2 / 3;'
186
188
  ptree = subject.parse(input)
187
- expr = ptree.root
189
+ expr = ptree.root.subnodes[0]
188
190
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
189
191
  expect(expr.operator).to eq(:/)
190
192
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -197,7 +199,7 @@ LOX_END
197
199
  it 'should parse combination of terms and factors' do
198
200
  input = '5 + 2 / 3;'
199
201
  ptree = subject.parse(input)
200
- expr = ptree.root
202
+ expr = ptree.root.subnodes[0]
201
203
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
202
204
  expect(expr.operator).to eq(:+)
203
205
  expect(expr.operands[0].literal.value).to eq(5)
@@ -212,7 +214,7 @@ LOX_END
212
214
  it 'should parse the concatenation of two string literals' do
213
215
  input = '"Lo" + "ve";'
214
216
  ptree = subject.parse(input)
215
- expr = ptree.root
217
+ expr = ptree.root.subnodes[0]
216
218
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
217
219
  expect(expr.operator).to eq(:+)
218
220
  expect(expr.operands[0].literal.value).to eq('Lo')
@@ -225,7 +227,7 @@ LOX_END
225
227
  %w[> >= < <=].each do |predicate|
226
228
  input = "3 #{predicate} 2;"
227
229
  ptree = subject.parse(input)
228
- expr = ptree.root
230
+ expr = ptree.root.subnodes[0]
229
231
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
230
232
  expect(expr.operator).to eq(predicate.to_sym)
231
233
  expect(expr.operands[0].literal.value).to eq(3)
@@ -239,7 +241,7 @@ LOX_END
239
241
  %w[!= ==].each do |predicate|
240
242
  input = "3 #{predicate} 2;"
241
243
  ptree = subject.parse(input)
242
- expr = ptree.root
244
+ expr = ptree.root.subnodes[0]
243
245
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
244
246
  expect(expr.operator).to eq(predicate.to_sym)
245
247
  expect(expr.operands[0].literal.value).to eq(3)
@@ -250,7 +252,7 @@ LOX_END
250
252
  it 'should parse combination of equality expressions' do
251
253
  input = '5 != 2 == false; // A bit contrived example'
252
254
  ptree = subject.parse(input)
253
- expr = ptree.root
255
+ expr = ptree.root.subnodes[0]
254
256
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
255
257
  expect(expr.operator).to eq(:==)
256
258
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -266,7 +268,7 @@ LOX_END
266
268
  %w[or and].each do |connector|
267
269
  input = "5 > 2 #{connector} 3 <= 4;"
268
270
  ptree = subject.parse(input)
269
- expr = ptree.root
271
+ expr = ptree.root.subnodes[0]
270
272
  expect(expr).to be_kind_of(Ast::LoxLogicalExpr)
271
273
  expect(expr.operator).to eq(connector.to_sym)
272
274
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -283,7 +285,7 @@ LOX_END
283
285
  it 'should parse a combinations of logical expressions' do
284
286
  input = '4 > 3 and 1 < 2 or 4 >= 5;'
285
287
  ptree = subject.parse(input)
286
- expr = ptree.root
288
+ expr = ptree.root.subnodes[0]
287
289
  expect(expr).to be_kind_of(Ast::LoxLogicalExpr)
288
290
  expect(expr.operator).to eq(:or) # or has lower precedence than and
289
291
  expect(expr.operands[0]).to be_kind_of(Ast::LoxLogicalExpr)
@@ -52,7 +52,14 @@ module Loxxy
52
52
  end # context
53
53
 
54
54
  context 'Evaluating Lox code:' do
55
- let(:hello_world) { 'print "Hello, world!";' }
55
+ let(:hello_world) do
56
+ lox = <<-LOX_END
57
+ var greeting = "Hello"; // Declaring a variable
58
+ print greeting + ", " + "world!"; // ... Playing with concatenation
59
+ LOX_END
60
+
61
+ lox
62
+ end
56
63
 
57
64
  it 'should evaluate core data types' do
58
65
  result = subject.evaluate('true; // Not false')
@@ -235,7 +242,7 @@ module Loxxy
235
242
  ['if (true) print "then-branch"; else print "else-branch";', 'then-branch'],
236
243
  ['if (false) print "then-branch"; else print "else-branch";', 'else-branch'],
237
244
  ['if (0) print "then-branch"; else print "else-branch";', 'then-branch'],
238
- ['if (nil) print "then-branch"; else print "else-branch";', 'else-branch'],
245
+ ['if (nil) print "then-branch"; else print "else-branch";', 'else-branch']
239
246
  # TODO: test with else block body
240
247
 
241
248
  # TODO: A dangling else binds to the right-most if.
@@ -245,7 +252,7 @@ module Loxxy
245
252
  io = StringIO.new
246
253
  cfg = { ostream: io }
247
254
  lox = Loxxy::Interpreter.new(cfg)
248
- result = lox.evaluate(source)
255
+ lox.evaluate(source)
249
256
  expect(io.string).to eq(predicted)
250
257
  end
251
258
  end
@@ -259,6 +266,98 @@ module Loxxy
259
266
  expect { subject.evaluate('var iAmNil;') }.not_to raise_error
260
267
  end
261
268
 
269
+ it 'should accept variable mention' do
270
+ program = <<-LOX_END
271
+ var foo = "bar";
272
+ print foo; // => bar
273
+ LOX_END
274
+ expect { subject.evaluate(program) }.not_to raise_error
275
+ expect(sample_cfg[:ostream].string).to eq('bar')
276
+ end
277
+
278
+ it 'should set uninitialized variables to nil' do
279
+ program = <<-LOX_END
280
+ var a;
281
+ print a; // => nil
282
+ LOX_END
283
+ expect { subject.evaluate(program) }.not_to raise_error
284
+ expect(sample_cfg[:ostream].string).to eq('nil')
285
+ end
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
+
302
+ it 'should support variables local to a block' do
303
+ program = <<-LOX_END
304
+ {
305
+ var a = "first";
306
+ print a;
307
+ }
308
+ {
309
+ var a = "second";
310
+ print a;
311
+ }
312
+ LOX_END
313
+ expect { subject.evaluate(program) }.not_to raise_error
314
+ expect(sample_cfg[:ostream].string).to eq('firstsecond')
315
+ end
316
+
317
+ it 'should support the shadowing of variables in a block' do
318
+ program = <<-LOX_END
319
+ var a = "outer";
320
+
321
+ {
322
+ var a = "inner";
323
+ print a; // output: inner
324
+ }
325
+
326
+ print a; // output: outer
327
+ LOX_END
328
+ expect { subject.evaluate(program) }.not_to raise_error
329
+ expect(sample_cfg[:ostream].string).to eq('innerouter')
330
+ end
331
+
332
+ it 'should implement single statement while loops' do
333
+ program = <<-LOX_END
334
+ // Single-expression body.
335
+ var c = 0;
336
+ while (c < 3) print c = c + 1;
337
+ // output: 1
338
+ // output: 2
339
+ // output: 3
340
+ LOX_END
341
+ expect { subject.evaluate(program) }.not_to raise_error
342
+ expect(sample_cfg[:ostream].string).to eq('123')
343
+ end
344
+
345
+ it 'should implement block body while loops' do
346
+ program = <<-LOX_END
347
+ // Block body.
348
+ var a = 0;
349
+ while (a < 3) {
350
+ print a;
351
+ a = a + 1;
352
+ }
353
+ // output: 0
354
+ // output: 1
355
+ // output: 2
356
+ LOX_END
357
+ expect { subject.evaluate(program) }.not_to raise_error
358
+ expect(sample_cfg[:ostream].string).to eq('012')
359
+ end
360
+
262
361
  it 'should print the hello world message' do
263
362
  expect { subject.evaluate(hello_world) }.not_to raise_error
264
363
  expect(sample_cfg[:ostream].string).to eq('Hello, world!')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loxxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-16 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -87,7 +87,9 @@ 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
92
+ - lib/loxxy/ast/lox_block_stmt.rb
91
93
  - lib/loxxy/ast/lox_compound_expr.rb
92
94
  - lib/loxxy/ast/lox_grouping_expr.rb
93
95
  - lib/loxxy/ast/lox_if_stmt.rb
@@ -96,8 +98,11 @@ files:
96
98
  - lib/loxxy/ast/lox_node.rb
97
99
  - lib/loxxy/ast/lox_noop_expr.rb
98
100
  - lib/loxxy/ast/lox_print_stmt.rb
101
+ - lib/loxxy/ast/lox_seq_decl.rb
99
102
  - lib/loxxy/ast/lox_unary_expr.rb
100
103
  - lib/loxxy/ast/lox_var_stmt.rb
104
+ - lib/loxxy/ast/lox_variable_expr.rb
105
+ - lib/loxxy/ast/lox_while_stmt.rb
101
106
  - lib/loxxy/back_end/engine.rb
102
107
  - lib/loxxy/back_end/entry.rb
103
108
  - lib/loxxy/back_end/environment.rb