loxxy 0.0.12 → 0.0.17
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +76 -0
- data/README.md +132 -13
- data/lib/loxxy.rb +5 -5
- data/lib/loxxy/ast/all_lox_nodes.rb +3 -1
- data/lib/loxxy/ast/ast_builder.rb +19 -3
- data/lib/loxxy/ast/ast_visitor.rb +17 -1
- data/lib/loxxy/ast/lox_binary_expr.rb +7 -1
- data/lib/loxxy/ast/lox_print_stmt.rb +0 -1
- data/lib/loxxy/ast/lox_unary_expr.rb +27 -0
- data/lib/loxxy/back_end/engine.rb +25 -1
- data/lib/loxxy/datatype/boolean.rb +11 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +28 -0
- data/lib/loxxy/datatype/false.rb +28 -0
- data/lib/loxxy/datatype/lx_string.rb +26 -10
- data/lib/loxxy/datatype/nil.rb +22 -0
- data/lib/loxxy/datatype/number.rb +132 -1
- data/lib/loxxy/datatype/true.rb +14 -0
- data/lib/loxxy/front_end/grammar.rb +2 -2
- data/lib/loxxy/interpreter.rb +3 -1
- data/lib/loxxy/version.rb +1 -1
- data/spec/datatype/lx_string_spec.rb +28 -5
- data/spec/datatype/number_spec.rb +26 -0
- data/spec/front_end/parser_spec.rb +18 -57
- data/spec/interpreter_spec.rb +136 -0
- metadata +3 -2
@@ -22,9 +22,35 @@ module Loxxy
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'Provided services:' do
|
25
|
+
it 'should compare with other Lox numbers' do
|
26
|
+
result = subject == Number.new(sample_value)
|
27
|
+
expect(result).to be_true
|
28
|
+
|
29
|
+
result = subject == Number.new(5)
|
30
|
+
expect(result).to be_false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should compare with Ruby numbers' do
|
34
|
+
result = subject == sample_value
|
35
|
+
expect(result).to be_true
|
36
|
+
|
37
|
+
result = subject == 5
|
38
|
+
expect(result).to be_false
|
39
|
+
end
|
40
|
+
|
25
41
|
it 'should give its display representation' do
|
26
42
|
expect(subject.to_str).to eq(sample_value.to_s)
|
27
43
|
end
|
44
|
+
|
45
|
+
it 'should compute the addition with another number' do
|
46
|
+
addition = subject + Number.new(10)
|
47
|
+
expect(addition == -2.34).to be_true
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should compute the subtraction with another number' do
|
51
|
+
subtraction = subject - Number.new(10)
|
52
|
+
expect(subtraction == -22.34).to be_true
|
53
|
+
end
|
28
54
|
end
|
29
55
|
end # describe
|
30
56
|
end # module
|
@@ -64,7 +64,7 @@ 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
|
+
leaf = ptree.root
|
68
68
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
69
69
|
expect(leaf.literal).to be_equal(Datatype::False.instance)
|
70
70
|
end
|
@@ -72,7 +72,7 @@ module Loxxy
|
|
72
72
|
it 'should parse a true literal' do
|
73
73
|
input = 'true;'
|
74
74
|
ptree = subject.parse(input)
|
75
|
-
leaf = ptree.root
|
75
|
+
leaf = ptree.root
|
76
76
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
77
77
|
expect(leaf.literal).to be_equal(Datatype::True.instance)
|
78
78
|
end
|
@@ -81,7 +81,7 @@ module Loxxy
|
|
81
81
|
inputs = %w[1234; 12.34;]
|
82
82
|
inputs.each do |source|
|
83
83
|
ptree = subject.parse(source)
|
84
|
-
leaf = ptree.root
|
84
|
+
leaf = ptree.root
|
85
85
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
86
86
|
expect(leaf.literal).to be_kind_of(Datatype::Number)
|
87
87
|
expect(leaf.literal.value).to eq(source.to_f)
|
@@ -96,7 +96,7 @@ module Loxxy
|
|
96
96
|
]
|
97
97
|
inputs.each do |source|
|
98
98
|
ptree = subject.parse(source)
|
99
|
-
leaf = ptree.root
|
99
|
+
leaf = ptree.root
|
100
100
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
101
101
|
expect(leaf.literal).to be_kind_of(Datatype::LXString)
|
102
102
|
expect(leaf.literal.value).to eq(source.gsub(/(^")|(";$)/, ''))
|
@@ -106,7 +106,7 @@ module Loxxy
|
|
106
106
|
it 'should parse a nil literal' do
|
107
107
|
input = 'nil;'
|
108
108
|
ptree = subject.parse(input)
|
109
|
-
leaf = ptree.root
|
109
|
+
leaf = ptree.root
|
110
110
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
111
111
|
expect(leaf.literal).to be_equal(Datatype::Nil.instance)
|
112
112
|
end
|
@@ -131,10 +131,7 @@ LOX_END
|
|
131
131
|
it 'should parse the addition of two number literals' do
|
132
132
|
input = '123 + 456;'
|
133
133
|
ptree = subject.parse(input)
|
134
|
-
|
135
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
136
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
137
|
-
expr = parent.subnodes[0]
|
134
|
+
expr = ptree.root
|
138
135
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
139
136
|
expect(expr.operator).to eq(:+)
|
140
137
|
expect(expr.operands[0].literal.value).to eq(123)
|
@@ -144,10 +141,7 @@ LOX_END
|
|
144
141
|
it 'should parse the subtraction of two number literals' do
|
145
142
|
input = '4 - 3;'
|
146
143
|
ptree = subject.parse(input)
|
147
|
-
|
148
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
149
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
150
|
-
expr = parent.subnodes[0]
|
144
|
+
expr = ptree.root
|
151
145
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
152
146
|
expect(expr.operator).to eq(:-)
|
153
147
|
expect(expr.operands[0].literal.value).to eq(4)
|
@@ -157,10 +151,7 @@ LOX_END
|
|
157
151
|
it 'should parse multiple additive operations' do
|
158
152
|
input = '5 + 2 - 3;'
|
159
153
|
ptree = subject.parse(input)
|
160
|
-
|
161
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
162
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
163
|
-
expr = parent.subnodes[0]
|
154
|
+
expr = ptree.root
|
164
155
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
165
156
|
expect(expr.operator).to eq(:-)
|
166
157
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
@@ -173,10 +164,7 @@ LOX_END
|
|
173
164
|
it 'should parse the division of two number literals' do
|
174
165
|
input = '8 / 2;'
|
175
166
|
ptree = subject.parse(input)
|
176
|
-
|
177
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
178
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
179
|
-
expr = parent.subnodes[0]
|
167
|
+
expr = ptree.root
|
180
168
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
181
169
|
expect(expr.operator).to eq(:/)
|
182
170
|
expect(expr.operands[0].literal.value).to eq(8)
|
@@ -186,10 +174,7 @@ LOX_END
|
|
186
174
|
it 'should parse the product of two number literals' do
|
187
175
|
input = '12.34 * 0.3;'
|
188
176
|
ptree = subject.parse(input)
|
189
|
-
|
190
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
191
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
192
|
-
expr = parent.subnodes[0]
|
177
|
+
expr = ptree.root
|
193
178
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
194
179
|
expect(expr.operator).to eq(:*)
|
195
180
|
expect(expr.operands[0].literal.value).to eq(12.34)
|
@@ -199,10 +184,7 @@ LOX_END
|
|
199
184
|
it 'should parse multiple multiplicative operations' do
|
200
185
|
input = '5 * 2 / 3;'
|
201
186
|
ptree = subject.parse(input)
|
202
|
-
|
203
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
204
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
205
|
-
expr = parent.subnodes[0]
|
187
|
+
expr = ptree.root
|
206
188
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
207
189
|
expect(expr.operator).to eq(:/)
|
208
190
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
@@ -215,10 +197,7 @@ LOX_END
|
|
215
197
|
it 'should parse combination of terms and factors' do
|
216
198
|
input = '5 + 2 / 3;'
|
217
199
|
ptree = subject.parse(input)
|
218
|
-
|
219
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
220
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
221
|
-
expr = parent.subnodes[0]
|
200
|
+
expr = ptree.root
|
222
201
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
223
202
|
expect(expr.operator).to eq(:+)
|
224
203
|
expect(expr.operands[0].literal.value).to eq(5)
|
@@ -233,10 +212,7 @@ LOX_END
|
|
233
212
|
it 'should parse the concatenation of two string literals' do
|
234
213
|
input = '"Lo" + "ve";'
|
235
214
|
ptree = subject.parse(input)
|
236
|
-
|
237
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
238
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
239
|
-
expr = parent.subnodes[0]
|
215
|
+
expr = ptree.root
|
240
216
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
241
217
|
expect(expr.operator).to eq(:+)
|
242
218
|
expect(expr.operands[0].literal.value).to eq('Lo')
|
@@ -249,10 +225,7 @@ LOX_END
|
|
249
225
|
%w[> >= < <=].each do |predicate|
|
250
226
|
input = "3 #{predicate} 2;"
|
251
227
|
ptree = subject.parse(input)
|
252
|
-
|
253
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
254
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
255
|
-
expr = parent.subnodes[0]
|
228
|
+
expr = ptree.root
|
256
229
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
257
230
|
expect(expr.operator).to eq(predicate.to_sym)
|
258
231
|
expect(expr.operands[0].literal.value).to eq(3)
|
@@ -266,10 +239,7 @@ LOX_END
|
|
266
239
|
%w[!= ==].each do |predicate|
|
267
240
|
input = "3 #{predicate} 2;"
|
268
241
|
ptree = subject.parse(input)
|
269
|
-
|
270
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
271
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
272
|
-
expr = parent.subnodes[0]
|
242
|
+
expr = ptree.root
|
273
243
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
274
244
|
expect(expr.operator).to eq(predicate.to_sym)
|
275
245
|
expect(expr.operands[0].literal.value).to eq(3)
|
@@ -280,10 +250,7 @@ LOX_END
|
|
280
250
|
it 'should parse combination of equality expressions' do
|
281
251
|
input = '5 != 2 == false; // A bit contrived example'
|
282
252
|
ptree = subject.parse(input)
|
283
|
-
|
284
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
285
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
286
|
-
expr = parent.subnodes[0]
|
253
|
+
expr = ptree.root
|
287
254
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
288
255
|
expect(expr.operator).to eq(:==)
|
289
256
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
@@ -299,10 +266,7 @@ LOX_END
|
|
299
266
|
%w[or and].each do |connector|
|
300
267
|
input = "5 > 2 #{connector} 3 <= 4;"
|
301
268
|
ptree = subject.parse(input)
|
302
|
-
|
303
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
304
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
305
|
-
expr = parent.subnodes[0]
|
269
|
+
expr = ptree.root
|
306
270
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
307
271
|
expect(expr.operator).to eq(connector.to_sym)
|
308
272
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
@@ -319,10 +283,7 @@ LOX_END
|
|
319
283
|
it 'should parse a combinations of logical expressions' do
|
320
284
|
input = '4 > 3 and 1 < 2 or 4 >= 5;'
|
321
285
|
ptree = subject.parse(input)
|
322
|
-
|
323
|
-
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
324
|
-
expect(parent.symbol.name).to eq('exprStmt')
|
325
|
-
expr = parent.subnodes[0]
|
286
|
+
expr = ptree.root
|
326
287
|
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
327
288
|
expect(expr.operator).to eq(:or) # or has lower precedence than and
|
328
289
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
data/spec/interpreter_spec.rb
CHANGED
@@ -25,9 +25,145 @@ module Loxxy
|
|
25
25
|
end
|
26
26
|
end # context
|
27
27
|
|
28
|
+
context 'Evaluating arithmetic operations code:' do
|
29
|
+
it 'should evaluate an addition of two numbers' do
|
30
|
+
result = subject.evaluate('123 + 456; // => 579')
|
31
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
32
|
+
expect(result == 579).to be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should evaluate a subtraction of two numbers' do
|
36
|
+
result = subject.evaluate('4 - 3; // => 1')
|
37
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
38
|
+
expect(result == 1).to be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should evaluate a multiplication of two numbers' do
|
42
|
+
result = subject.evaluate('5 * 3; // => 15')
|
43
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
44
|
+
expect(result == 15).to be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should evaluate a division of two numbers' do
|
48
|
+
result = subject.evaluate('8 / 2; // => 4')
|
49
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
50
|
+
expect(result == 4).to be_true
|
51
|
+
end
|
52
|
+
end # context
|
53
|
+
|
28
54
|
context 'Evaluating Lox code:' do
|
29
55
|
let(:hello_world) { 'print "Hello, world!";' }
|
30
56
|
|
57
|
+
it 'should evaluate core data types' do
|
58
|
+
result = subject.evaluate('true; // Not false')
|
59
|
+
expect(result).to be_kind_of(Loxxy::Datatype::True)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should evaluate string concatenation' do
|
63
|
+
result = subject.evaluate('"str" + "ing"; // => "string"')
|
64
|
+
expect(result).to be_kind_of(Loxxy::Datatype::LXString)
|
65
|
+
expect(result == 'string').to be_true
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should perform the equality tests of two values' do
|
69
|
+
[
|
70
|
+
['nil == nil;', true],
|
71
|
+
['true == true;', true],
|
72
|
+
['true == false;', false],
|
73
|
+
['1 == 1;', true],
|
74
|
+
['1 == 2;', false],
|
75
|
+
['0 == 0;', true],
|
76
|
+
['"str" == "str";', true],
|
77
|
+
['"str" == "ing";', false],
|
78
|
+
['"" == "";', true],
|
79
|
+
['nil == false;', false],
|
80
|
+
['false == 0;', false],
|
81
|
+
['0 == "0";', false]
|
82
|
+
].each do |(source, predicted)|
|
83
|
+
lox = Loxxy::Interpreter.new
|
84
|
+
result = lox.evaluate(source)
|
85
|
+
expect(result.value == predicted).to be_truthy
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should perform the inequality test of two values' do
|
90
|
+
[
|
91
|
+
['nil != nil;', false],
|
92
|
+
['true != true;', false],
|
93
|
+
['true != false;', true],
|
94
|
+
['1 != 1;', false],
|
95
|
+
['1 != 2;', true],
|
96
|
+
['0 != 0;', false],
|
97
|
+
['"str" != "str";', false],
|
98
|
+
['"str" != "ing";', true],
|
99
|
+
['"" != "";', false],
|
100
|
+
['nil != false;', true],
|
101
|
+
['false != 0;', true],
|
102
|
+
['0 != "0";', true]
|
103
|
+
].each do |(source, predicted)|
|
104
|
+
lox = Loxxy::Interpreter.new
|
105
|
+
result = lox.evaluate(source)
|
106
|
+
expect(result.value == predicted).to be_truthy
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should evaluate a comparison of two numbers' do
|
111
|
+
[
|
112
|
+
['1 < 2;', true],
|
113
|
+
['2 < 2;', false],
|
114
|
+
['2 < 1;', false],
|
115
|
+
['1 <= 2;', true],
|
116
|
+
['2 <= 2;', true],
|
117
|
+
['2 <= 1;', false],
|
118
|
+
['1 > 2;', false],
|
119
|
+
['2 > 2;', false],
|
120
|
+
['2 > 1;', true],
|
121
|
+
['1 >= 2;', false],
|
122
|
+
['2 >= 2;', true],
|
123
|
+
['2 >= 1;', true],
|
124
|
+
['0 < -0;', false],
|
125
|
+
['-0 < 0;', false],
|
126
|
+
['0 > -0;', false],
|
127
|
+
['-0 > 0;', false],
|
128
|
+
['0 <= -0;', true],
|
129
|
+
['-0 <= 0;', true],
|
130
|
+
['0 >= -0;', true],
|
131
|
+
['-0 >= 0;', true]
|
132
|
+
].each do |(source, predicted)|
|
133
|
+
lox = Loxxy::Interpreter.new
|
134
|
+
result = lox.evaluate(source)
|
135
|
+
expect(result.value == predicted).to be_truthy
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should evaluate the change sign of a number' do
|
140
|
+
[
|
141
|
+
['- 3;', -3],
|
142
|
+
['- - 3;', 3],
|
143
|
+
['- - - 3;', -3]
|
144
|
+
].each do |(source, predicted)|
|
145
|
+
lox = Loxxy::Interpreter.new
|
146
|
+
result = lox.evaluate(source)
|
147
|
+
expect(result.value == predicted).to be_truthy
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should evaluate the negation of an object' do
|
152
|
+
[
|
153
|
+
['!true;', false],
|
154
|
+
['!false;', true],
|
155
|
+
['!!true;', true],
|
156
|
+
['!123;', false],
|
157
|
+
['!0;', false],
|
158
|
+
['!nil;', true],
|
159
|
+
['!"";', false]
|
160
|
+
].each do |(source, predicted)|
|
161
|
+
lox = Loxxy::Interpreter.new
|
162
|
+
result = lox.evaluate(source)
|
163
|
+
expect(result.value == predicted).to be_truthy
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
31
167
|
it 'should print the hello world message' do
|
32
168
|
expect { subject.evaluate(hello_world) }.not_to raise_error
|
33
169
|
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.
|
4
|
+
version: 0.0.17
|
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-
|
11
|
+
date: 2021-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -93,6 +93,7 @@ files:
|
|
93
93
|
- lib/loxxy/ast/lox_node.rb
|
94
94
|
- lib/loxxy/ast/lox_noop_expr.rb
|
95
95
|
- lib/loxxy/ast/lox_print_stmt.rb
|
96
|
+
- lib/loxxy/ast/lox_unary_expr.rb
|
96
97
|
- lib/loxxy/back_end/engine.rb
|
97
98
|
- lib/loxxy/datatype/all_datatypes.rb
|
98
99
|
- lib/loxxy/datatype/boolean.rb
|