loxxy 0.0.27 → 0.0.28
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/README.md +6 -2
- data/lib/loxxy/ast/all_lox_nodes.rb +1 -0
- data/lib/loxxy/ast/ast_builder.rb +29 -83
- data/lib/loxxy/ast/ast_visitor.rb +12 -2
- data/lib/loxxy/ast/lox_call_expr.rb +25 -0
- data/lib/loxxy/back_end/engine.rb +39 -0
- data/lib/loxxy/front_end/grammar.rb +23 -23
- data/lib/loxxy/version.rb +1 -1
- data/spec/datatype/lx_string_spec.rb +2 -0
- data/spec/datatype/number_spec.rb +3 -1
- data/spec/front_end/scanner_spec.rb +2 -0
- data/spec/interpreter_spec.rb +5 -7
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b9202e7a755cffecb3226da5764a3cb6f75fd3179803eb25779ae42822bbf15
|
4
|
+
data.tar.gz: 49767873134c5c124aab3e6b20a49c60f968df180dfd6e945f3da2808eee59c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29c481015e414ea71eb55c0b4dcc4d793b011a8f16fa7f9218ec704b2baea820e47ba758ba9a2e30e5bdfe08bfd2ad8fa892e6d67e247938b8bcda7b005ff2a9
|
7
|
+
data.tar.gz: cbf671e54aa98e799b6d565cac52fb19fb3f5d7b3ae84841f27067ae427e5a7c25a7d40a07d39645150f73176709fbcc6e3bbf36e9cada14d8b329f335c621d5
|
data/README.md
CHANGED
@@ -14,9 +14,13 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
|
|
14
14
|
|
15
15
|
### Current status
|
16
16
|
The project is still in inception and the interpreter is being implemented...
|
17
|
-
Currently it can execute
|
17
|
+
Currently it can execute all allowed __Lox__ expressions and statement except:
|
18
|
+
- Functions and closures,
|
19
|
+
- Classes and objects.
|
20
|
+
|
21
|
+
These will be implemented soon.
|
22
|
+
|
18
23
|
|
19
|
-
But the __loxxy__ gem hosts also a parser class `RawPaser` that can parse, in principle, any valid Lox input.
|
20
24
|
|
21
25
|
## What's the fuss about Lox?
|
22
26
|
... Nothing...
|
@@ -233,99 +233,35 @@ module Loxxy
|
|
233
233
|
Ast::LoxAssignExpr.new(tokens[1].position, var_name, theChildren[3])
|
234
234
|
end
|
235
235
|
|
236
|
-
# rule('logic_or' => 'logic_and disjunct_plus')
|
237
|
-
def reduce_logic_or_plus(production, range, tokens, theChildren)
|
238
|
-
reduce_logical_expr(production, range, tokens, theChildren)
|
239
|
-
end
|
240
|
-
|
241
|
-
# rule('disjunct_plus' => 'disjunct_plus OR logic_and')
|
242
|
-
def reduce_logic_or_plus_more(production, range, tokens, theChildren)
|
243
|
-
reduce_binary_plus_more(production, range, tokens, theChildren)
|
244
|
-
end
|
245
|
-
|
246
|
-
# rule('disjunct_plus' => 'OR logic_and')
|
247
|
-
def reduce_logic_or_plus_end(production, range, tokens, theChildren)
|
248
|
-
reduce_binary_plus_end(production, range, tokens, theChildren)
|
249
|
-
end
|
250
|
-
|
251
|
-
# rule('logic_and' => 'equality conjunct_plus')
|
252
|
-
def reduce_logic_and_plus(production, range, tokens, theChildren)
|
253
|
-
reduce_logical_expr(production, range, tokens, theChildren)
|
254
|
-
end
|
255
|
-
|
256
|
-
# rule('conjunct_plus' => 'conjunct_plus AND equality')
|
257
|
-
def reduce_logic_and_plus_more(production, range, tokens, theChildren)
|
258
|
-
reduce_binary_plus_more(production, range, tokens, theChildren)
|
259
|
-
end
|
260
|
-
|
261
|
-
# rule('conjunct_plus' => 'AND equality')
|
262
|
-
def reduce_logic_and_plus_end(production, range, tokens, theChildren)
|
263
|
-
reduce_binary_plus_end(production, range, tokens, theChildren)
|
264
|
-
end
|
265
|
-
|
266
|
-
# rule('equality' => 'comparison equalityTest_plus')
|
267
|
-
def reduce_equality_plus(production, range, tokens, theChildren)
|
268
|
-
reduce_binary_operator(production, range, tokens, theChildren)
|
269
|
-
end
|
270
|
-
|
271
|
-
# rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison')
|
272
|
-
def reduce_equality_t_plus_more(production, range, tokens, theChildren)
|
273
|
-
reduce_binary_plus_more(production, range, tokens, theChildren)
|
274
|
-
end
|
275
|
-
|
276
|
-
# rule('equalityTest_star' => 'equalityTest comparison')
|
277
|
-
def reduce_equality_t_plus_end(production, range, tokens, theChildren)
|
278
|
-
reduce_binary_plus_end(production, range, tokens, theChildren)
|
279
|
-
end
|
280
|
-
|
281
|
-
# rule('comparison' => 'term comparisonTest_plus')
|
282
|
-
def reduce_comparison_plus(production, range, tokens, theChildren)
|
283
|
-
reduce_binary_operator(production, range, tokens, theChildren)
|
284
|
-
end
|
285
|
-
|
286
236
|
# rule('comparisonTest_plus' => 'comparisonTest_plus comparisonTest term').as 'comparison_t_plus_more'
|
287
237
|
# TODO: is it meaningful to implement this rule?
|
288
238
|
|
289
|
-
# rule('
|
290
|
-
def
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
# rule('term' => 'factor additive_plus')
|
295
|
-
def reduce_term_additive(production, range, tokens, theChildren)
|
296
|
-
reduce_binary_operator(production, range, tokens, theChildren)
|
297
|
-
end
|
298
|
-
|
299
|
-
# rule('additive_star' => 'additive_star additionOp factor').as 'additionOp_expr'
|
300
|
-
def reduce_additive_plus_more(production, range, tokens, theChildren)
|
301
|
-
reduce_binary_plus_more(production, range, tokens, theChildren)
|
302
|
-
end
|
303
|
-
|
304
|
-
# rule('additive_plus' => 'additionOp factor')
|
305
|
-
def reduce_additive_plus_end(production, range, tokens, theChildren)
|
306
|
-
reduce_binary_plus_end(production, range, tokens, theChildren)
|
239
|
+
# rule('unary' => 'unaryOp unary')
|
240
|
+
def reduce_unary_expr(_production, _range, tokens, theChildren)
|
241
|
+
operator = Name2unary[theChildren[0].symbol.name].to_sym
|
242
|
+
operand = theChildren[1]
|
243
|
+
LoxUnaryExpr.new(tokens[0].position, operator, operand)
|
307
244
|
end
|
308
245
|
|
309
|
-
# rule('
|
310
|
-
def
|
311
|
-
|
246
|
+
# rule('call' => 'primary refinement_plus').as 'call_expr'
|
247
|
+
def reduce_call_expr(_production, _range, _tokens, theChildren)
|
248
|
+
theChildren[1].callee = theChildren[0]
|
249
|
+
theChildren[1]
|
312
250
|
end
|
313
251
|
|
314
|
-
# rule('
|
315
|
-
def
|
316
|
-
|
252
|
+
# rule('refinement_plus' => 'refinement').
|
253
|
+
def reduce_refinement_plus_end(_production, _range, _tokens, theChildren)
|
254
|
+
theChildren[0]
|
317
255
|
end
|
318
256
|
|
319
|
-
# rule('
|
320
|
-
def
|
321
|
-
|
322
|
-
|
257
|
+
# rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN')
|
258
|
+
def reduce_call_arglist(_production, _range, tokens, theChildren)
|
259
|
+
args = theChildren[1] || []
|
260
|
+
if args.size > 255
|
261
|
+
raise StandardError, "Can't have more than 255 arguments."
|
262
|
+
end
|
323
263
|
|
324
|
-
|
325
|
-
def reduce_unary_expr(_production, _range, tokens, theChildren)
|
326
|
-
operator = Name2unary[theChildren[0].symbol.name].to_sym
|
327
|
-
operand = theChildren[1]
|
328
|
-
LoxUnaryExpr.new(tokens[0].position, operator, operand)
|
264
|
+
LoxCallExpr.new(tokens[0].position, args)
|
329
265
|
end
|
330
266
|
|
331
267
|
# rule('primary' => 'LEFT_PAREN expression RIGHT_PAREN')
|
@@ -347,6 +283,16 @@ module Loxxy
|
|
347
283
|
var_name = theChildren[0].token.lexeme
|
348
284
|
LoxVariableExpr.new(tokens[0].position, var_name)
|
349
285
|
end
|
286
|
+
|
287
|
+
# rule('arguments' => 'arguments COMMA expression')
|
288
|
+
def reduce_arguments_plus_more(_production, _range, _tokens, theChildren)
|
289
|
+
theChildren[0] << theChildren[2]
|
290
|
+
end
|
291
|
+
|
292
|
+
# rule('arguments' => 'expression')
|
293
|
+
def reduce_arguments_plus_end(_production, _range, _tokens, theChildren)
|
294
|
+
theChildren
|
295
|
+
end
|
350
296
|
end # class
|
351
297
|
end # module
|
352
298
|
end # module
|
@@ -145,6 +145,14 @@ module Loxxy
|
|
145
145
|
broadcast(:after_unary_expr, anUnaryExpr)
|
146
146
|
end
|
147
147
|
|
148
|
+
# Visit event. The visitor is about to visit a call expression.
|
149
|
+
# @param aCallExpr [AST::LoxCallExpr] call expression to visit
|
150
|
+
def visit_call_expr(aCallExpr)
|
151
|
+
broadcast(:before_call_expr, aCallExpr)
|
152
|
+
traverse_subnodes(aCallExpr)
|
153
|
+
broadcast(:after_call_expr, aCallExpr, self)
|
154
|
+
end
|
155
|
+
|
148
156
|
# Visit event. The visitor is about to visit a grouping expression.
|
149
157
|
# @param aGroupingExpr [AST::LoxGroupingExpr] grouping expression to visit
|
150
158
|
def visit_grouping_expr(aGroupingExpr)
|
@@ -177,10 +185,12 @@ module Loxxy
|
|
177
185
|
|
178
186
|
# Visit event. The visitor is about to visit the given non terminal node.
|
179
187
|
# @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
|
180
|
-
def visit_nonterminal(
|
188
|
+
def visit_nonterminal(non_terminal_node)
|
181
189
|
# Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
|
182
190
|
# that it cannot handle.
|
183
|
-
|
191
|
+
symb = non_terminal_node.symbol.name
|
192
|
+
msg = "Loxxy cannot execute this code yet for non-terminal symbol '#{symb}'."
|
193
|
+
raise NotImplementedError, msg
|
184
194
|
end
|
185
195
|
|
186
196
|
private
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxCallExpr < LoxCompoundExpr
|
8
|
+
attr_accessor :callee
|
9
|
+
attr_reader :arguments
|
10
|
+
|
11
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
12
|
+
# @param argList [Array<Loxxy::Ast::LoxNode>]
|
13
|
+
def initialize(aPosition, argList)
|
14
|
+
super(aPosition, [])
|
15
|
+
@arguments = argList
|
16
|
+
end
|
17
|
+
|
18
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
19
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
20
|
+
def accept(visitor)
|
21
|
+
visitor.visit_call_expr(self)
|
22
|
+
end
|
23
|
+
end # class
|
24
|
+
end # module
|
25
|
+
end # module
|
@@ -25,6 +25,8 @@ module Loxxy
|
|
25
25
|
@ostream = config.include?(:ostream) ? config[:ostream] : $stdout
|
26
26
|
@symbol_table = SymbolTable.new
|
27
27
|
@stack = []
|
28
|
+
|
29
|
+
init_globals
|
28
30
|
end
|
29
31
|
|
30
32
|
# Given an abstract syntax parse tree visitor, launch the visit
|
@@ -167,6 +169,17 @@ module Loxxy
|
|
167
169
|
end
|
168
170
|
end
|
169
171
|
|
172
|
+
def after_call_expr(aCallExpr, aVisitor)
|
173
|
+
# Evaluate callee part
|
174
|
+
aCallExpr.callee.accept(aVisitor)
|
175
|
+
callee = stack.pop
|
176
|
+
# TODO: reverse order?
|
177
|
+
aCallExpr.arguments.each do |arg|
|
178
|
+
arg.evaluate(aVisitor)
|
179
|
+
end
|
180
|
+
stack.push callee.call # Pass arguments
|
181
|
+
end
|
182
|
+
|
170
183
|
def after_grouping_expr(_groupingExpr)
|
171
184
|
# Do nothing: work was already done by visiting /evaluating the subexpression
|
172
185
|
end
|
@@ -188,6 +201,32 @@ module Loxxy
|
|
188
201
|
def before_visit_builtin(aValue)
|
189
202
|
stack.push(aValue)
|
190
203
|
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
NativeFunction = Struct.new(:callable, :interp) do
|
208
|
+
def accept(_visitor)
|
209
|
+
interp.stack.push callable
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def init_globals
|
214
|
+
add_native_fun('clock', native_clock)
|
215
|
+
end
|
216
|
+
|
217
|
+
def add_native_fun(aName, aProc)
|
218
|
+
native_fun = Variable.new(aName, NativeFunction.new(aProc, self))
|
219
|
+
symbol_table.insert(native_fun)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Ruby-native function that returns (as float) the number of seconds since
|
223
|
+
# a given time reference.
|
224
|
+
def native_clock
|
225
|
+
proc do
|
226
|
+
now = Time.now.to_f
|
227
|
+
Datatype::Number.new(now)
|
228
|
+
end
|
229
|
+
end
|
191
230
|
end # class
|
192
231
|
end # module
|
193
232
|
end # module
|
@@ -88,37 +88,37 @@ module Loxxy
|
|
88
88
|
rule('owner_opt' => 'call DOT')
|
89
89
|
rule('owner_opt' => [])
|
90
90
|
rule('logic_or' => 'logic_and')
|
91
|
-
rule('logic_or' => 'logic_and disjunct_plus').as '
|
92
|
-
rule('disjunct_plus' => 'disjunct_plus OR logic_and').as '
|
93
|
-
rule('disjunct_plus' => 'OR logic_and').as '
|
91
|
+
rule('logic_or' => 'logic_and disjunct_plus').as 'logical_expr'
|
92
|
+
rule('disjunct_plus' => 'disjunct_plus OR logic_and').as 'binary_plus_more'
|
93
|
+
rule('disjunct_plus' => 'OR logic_and').as 'binary_plus_end'
|
94
94
|
rule('logic_and' => 'equality')
|
95
|
-
rule('logic_and' => 'equality conjunct_plus').as '
|
96
|
-
rule('conjunct_plus' => 'conjunct_plus AND equality').as '
|
97
|
-
rule('conjunct_plus' => 'AND equality').as '
|
95
|
+
rule('logic_and' => 'equality conjunct_plus').as 'logical_expr'
|
96
|
+
rule('conjunct_plus' => 'conjunct_plus AND equality').as 'binary_plus_more'
|
97
|
+
rule('conjunct_plus' => 'AND equality').as 'binary_plus_end'
|
98
98
|
rule('equality' => 'comparison')
|
99
|
-
rule('equality' => 'comparison equalityTest_plus').as '
|
100
|
-
rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison').as '
|
101
|
-
rule('equalityTest_plus' => 'equalityTest comparison').as '
|
99
|
+
rule('equality' => 'comparison equalityTest_plus').as 'binary_operator'
|
100
|
+
rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison').as 'binary_plus_more'
|
101
|
+
rule('equalityTest_plus' => 'equalityTest comparison').as 'binary_plus_end'
|
102
102
|
rule('equalityTest' => 'BANG_EQUAL')
|
103
103
|
rule('equalityTest' => 'EQUAL_EQUAL')
|
104
104
|
rule('comparison' => 'term')
|
105
|
-
rule('comparison' => 'term comparisonTest_plus').as '
|
105
|
+
rule('comparison' => 'term comparisonTest_plus').as 'binary_operator'
|
106
106
|
rule('comparisonTest_plus' => 'comparisonTest_plus comparisonTest term').as 'comparison_t_plus_more'
|
107
|
-
rule('comparisonTest_plus' => 'comparisonTest term').as '
|
107
|
+
rule('comparisonTest_plus' => 'comparisonTest term').as 'binary_plus_end'
|
108
108
|
rule('comparisonTest' => 'GREATER')
|
109
109
|
rule('comparisonTest' => 'GREATER_EQUAL')
|
110
110
|
rule('comparisonTest' => 'LESS')
|
111
111
|
rule('comparisonTest' => 'LESS_EQUAL')
|
112
112
|
rule('term' => 'factor')
|
113
|
-
rule('term' => 'factor additive_plus').as '
|
114
|
-
rule('additive_plus' => 'additive_plus additionOp factor').as '
|
115
|
-
rule('additive_plus' => 'additionOp factor').as '
|
113
|
+
rule('term' => 'factor additive_plus').as 'binary_operator'
|
114
|
+
rule('additive_plus' => 'additive_plus additionOp factor').as 'binary_plus_more'
|
115
|
+
rule('additive_plus' => 'additionOp factor').as 'binary_plus_end'
|
116
116
|
rule('additionOp' => 'MINUS')
|
117
117
|
rule('additionOp' => 'PLUS')
|
118
118
|
rule('factor' => 'unary')
|
119
|
-
rule('factor' => 'unary multiplicative_plus').as '
|
120
|
-
rule('multiplicative_plus' => 'multiplicative_plus multOp unary').as '
|
121
|
-
rule('multiplicative_plus' => 'multOp unary').as '
|
119
|
+
rule('factor' => 'unary multiplicative_plus').as 'binary_operator'
|
120
|
+
rule('multiplicative_plus' => 'multiplicative_plus multOp unary').as 'binary_plus_more'
|
121
|
+
rule('multiplicative_plus' => 'multOp unary').as 'binary_plus_end'
|
122
122
|
rule('multOp' => 'SLASH')
|
123
123
|
rule('multOp' => 'STAR')
|
124
124
|
rule('unary' => 'unaryOp unary').as 'unary_expr'
|
@@ -126,10 +126,10 @@ module Loxxy
|
|
126
126
|
rule('unaryOp' => 'BANG')
|
127
127
|
rule('unaryOp' => 'MINUS')
|
128
128
|
rule('call' => 'primary')
|
129
|
-
rule('call' => 'primary refinement_plus')
|
130
|
-
rule('refinement_plus' => 'refinement_plus refinement')
|
131
|
-
rule('refinement_plus' => 'refinement')
|
132
|
-
rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN')
|
129
|
+
rule('call' => 'primary refinement_plus').as 'call_expr'
|
130
|
+
rule('refinement_plus' => 'refinement_plus refinement') # .as 'refinement_plus_more'
|
131
|
+
rule('refinement_plus' => 'refinement').as 'refinement_plus_end'
|
132
|
+
rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN').as 'call_arglist'
|
133
133
|
rule('refinement' => 'DOT IDENTIFIER')
|
134
134
|
rule('primary' => 'TRUE').as 'literal_expr'
|
135
135
|
rule('primary' => 'FALSE').as 'literal_expr'
|
@@ -149,8 +149,8 @@ module Loxxy
|
|
149
149
|
rule('parameters' => 'IDENTIFIER')
|
150
150
|
rule('arguments_opt' => 'arguments')
|
151
151
|
rule('arguments_opt' => [])
|
152
|
-
rule('arguments' => 'arguments COMMA expression')
|
153
|
-
rule('arguments' => 'expression')
|
152
|
+
rule('arguments' => 'arguments COMMA expression').as 'arguments_plus_more'
|
153
|
+
rule('arguments' => 'expression').as 'arguments_plus_end'
|
154
154
|
end
|
155
155
|
|
156
156
|
unless defined?(Grammar)
|
data/lib/loxxy/version.rb
CHANGED
@@ -26,6 +26,7 @@ module Loxxy
|
|
26
26
|
expect(subject.to_str).to eq(sample_text)
|
27
27
|
end
|
28
28
|
|
29
|
+
# rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
|
29
30
|
it 'compares with another Lox string' do
|
30
31
|
result = subject == LXString.new(sample_text.dup)
|
31
32
|
expect(result).to be_true
|
@@ -40,6 +41,7 @@ module Loxxy
|
|
40
41
|
result = LXString.new('') == LXString.new('')
|
41
42
|
expect(result).to be_true
|
42
43
|
end
|
44
|
+
# rubocop: enable Lint/BinaryOperatorWithIdenticalOperands
|
43
45
|
|
44
46
|
it 'compares with a Ruby string' do
|
45
47
|
result = subject == sample_text.dup
|
@@ -21,6 +21,7 @@ module Loxxy
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
# rubocop: disable Lint/FloatComparison
|
24
25
|
context 'Provided services:' do
|
25
26
|
it 'should compare with other Lox numbers' do
|
26
27
|
result = subject == Number.new(sample_value)
|
@@ -51,7 +52,8 @@ module Loxxy
|
|
51
52
|
subtraction = subject - Number.new(10)
|
52
53
|
expect(subtraction == -22.34).to be_true
|
53
54
|
end
|
54
|
-
end
|
55
|
+
end # context
|
56
|
+
# rubocop: enable Lint/FloatComparison
|
55
57
|
end # describe
|
56
58
|
end # module
|
57
59
|
end # module
|
@@ -208,6 +208,7 @@ LOX_END
|
|
208
208
|
expect(eof_token.terminal).to eq('EOF')
|
209
209
|
end
|
210
210
|
|
211
|
+
# rubocop: disable Lint/PercentStringArray
|
211
212
|
it 'should skip end of line comments' do
|
212
213
|
input = <<-LOX_END
|
213
214
|
// first comment
|
@@ -223,6 +224,7 @@ LOX_END
|
|
223
224
|
]
|
224
225
|
match_expectations(subject, expectations)
|
225
226
|
end
|
227
|
+
# rubocop: enable Lint/PercentStringArray
|
226
228
|
|
227
229
|
it 'should cope with single slash (divide) expression' do
|
228
230
|
subject.start_with('8 / 2')
|
data/spec/interpreter_spec.rb
CHANGED
@@ -384,18 +384,16 @@ LOX_END
|
|
384
384
|
expect(sample_cfg[:ostream].string).to eq('012')
|
385
385
|
end
|
386
386
|
|
387
|
-
it 'should implement
|
387
|
+
it 'should implement nullary function calls' do
|
388
388
|
program = <<-LOX_END
|
389
|
-
|
390
|
-
// No variable in initialization.
|
391
|
-
for (; i < 2; i = i + 1) print i;
|
392
|
-
// output: 0
|
393
|
-
// output: 1
|
389
|
+
print clock(); // Lox expect the 'clock' predefined native function
|
394
390
|
LOX_END
|
395
391
|
expect { subject.evaluate(program) }.not_to raise_error
|
396
|
-
|
392
|
+
tick = sample_cfg[:ostream].string
|
393
|
+
expect(Time.now.to_f - tick.to_f).to be < 0.1
|
397
394
|
end
|
398
395
|
|
396
|
+
|
399
397
|
it 'should print the hello world message' do
|
400
398
|
expect { subject.evaluate(hello_world) }.not_to raise_error
|
401
399
|
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.28
|
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-
|
11
|
+
date: 2021-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/loxxy/ast/lox_assign_expr.rb
|
91
91
|
- lib/loxxy/ast/lox_binary_expr.rb
|
92
92
|
- lib/loxxy/ast/lox_block_stmt.rb
|
93
|
+
- lib/loxxy/ast/lox_call_expr.rb
|
93
94
|
- lib/loxxy/ast/lox_compound_expr.rb
|
94
95
|
- lib/loxxy/ast/lox_for_stmt.rb
|
95
96
|
- lib/loxxy/ast/lox_grouping_expr.rb
|