loxxy 0.4.00 → 0.4.04
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +42 -12
- data/lib/loxxy/ast/ast_builder.rb +52 -89
- data/lib/loxxy/ast/lox_node.rb +1 -1
- data/lib/loxxy/front_end/grammar.rb +19 -45
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +2 -2
- data/spec/front_end/raw_parser_spec.rb +10 -6
- data/spec/spec_helper.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e321e9f44f39776e2684a1a2c2f2d032460847ff46cdea45791cf8724696d038
|
4
|
+
data.tar.gz: 1c455133b79cd26939998ebd791c5b39872de1ccf59fa6b8c8d4c7d819114021
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '031899513309e2950fd9dcf9fc782a14299bed0337e6ca2383351b277c69e1e5afc865d82a9bfce030d4780b9c738de18f18db970d862b344ac98ad00f22a2a7'
|
7
|
+
data.tar.gz: 60938437329c31b76307ea181e5596191b5261d55aeca369365fd8076f08879e2adfb112ec8cbaf1fd9d365e9e13816b644e1b897dd4f7840e37d9d20cc89ac8
|
data/.rubocop.yml
CHANGED
@@ -50,6 +50,9 @@ Layout/IndentationConsistency:
|
|
50
50
|
Layout/HeredocIndentation:
|
51
51
|
Enabled: false
|
52
52
|
|
53
|
+
Layout/LineEndStringConcatenationIndentation:
|
54
|
+
Enabled: true
|
55
|
+
|
53
56
|
Layout/MultilineHashBraceLayout:
|
54
57
|
Enabled: true
|
55
58
|
|
@@ -81,6 +84,9 @@ Layout/TrailingWhitespace:
|
|
81
84
|
Lint/AmbiguousAssignment:
|
82
85
|
Enabled: true
|
83
86
|
|
87
|
+
Lint/AmbiguousRange:
|
88
|
+
Enabled: true
|
89
|
+
|
84
90
|
Lint/DeprecatedConstants:
|
85
91
|
Enabled: true
|
86
92
|
|
@@ -96,6 +102,9 @@ Lint/EmptyBlock:
|
|
96
102
|
Lint/EmptyClass:
|
97
103
|
Enabled: false
|
98
104
|
|
105
|
+
Lint/EmptyInPattern:
|
106
|
+
Enabled: true
|
107
|
+
|
99
108
|
Lint/LambdaWithoutLiteralBlock:
|
100
109
|
Enabled: true
|
101
110
|
|
@@ -192,6 +201,9 @@ Naming/ClassAndModuleCamelCase:
|
|
192
201
|
Naming/BlockParameterName:
|
193
202
|
Enabled: true
|
194
203
|
|
204
|
+
Naming/InclusiveLanguage:
|
205
|
+
Enabled: true
|
206
|
+
|
195
207
|
Naming/MethodParameterName:
|
196
208
|
Enabled: false
|
197
209
|
|
@@ -273,11 +285,17 @@ Style/HashTransformValues:
|
|
273
285
|
Style/IfUnlessModifier:
|
274
286
|
Enabled: false
|
275
287
|
|
288
|
+
Style/InPatternThen:
|
289
|
+
Enabled: true
|
290
|
+
|
276
291
|
Style/InverseMethods:
|
277
292
|
Enabled: false
|
278
293
|
|
279
294
|
Style/MissingRespondToMissing:
|
280
295
|
Enabled: false
|
296
|
+
|
297
|
+
Style/MultilineInPatternThen:
|
298
|
+
Enabled: true
|
281
299
|
|
282
300
|
Style/NegatedIfElseCondition:
|
283
301
|
Enabled: true
|
@@ -290,6 +308,9 @@ Style/NilLambda:
|
|
290
308
|
|
291
309
|
Style/NumericLiterals:
|
292
310
|
Enabled: false
|
311
|
+
|
312
|
+
Style/QuotedSymbols:
|
313
|
+
Enabled: true
|
293
314
|
|
294
315
|
Style/RaiseArgs:
|
295
316
|
Enabled: true
|
@@ -302,6 +323,9 @@ Style/RedundantReturn:
|
|
302
323
|
|
303
324
|
Style/RedundantSelf:
|
304
325
|
Enabled: true
|
326
|
+
|
327
|
+
Style/RedundantSelfAssignmentBranch:
|
328
|
+
Enabled: true
|
305
329
|
|
306
330
|
Style/RegexpLiteral:
|
307
331
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
## [0.4.04] - 2021-09-11
|
2
|
+
- Grammar optimization (3 rules less, use of match_closest feature from `Rley`)
|
3
|
+
|
4
|
+
### Changed
|
5
|
+
- Method `Ast::AstBuilder#reduce_arguments` code re-styling: use shorthand &:
|
6
|
+
- File `grammar.rb` use `match_closest` constraint from Rley to cope with dangling else statement
|
7
|
+
|
8
|
+
## [0.4.02] - 2021-09-10
|
9
|
+
- Fixes in`AST::AstBuilder` class to cope with changes in Rley 0.8.03
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- File `loxxy.gemspec` forced dependency to Rley 0.8.03
|
13
|
+
|
14
|
+
### Fixed
|
15
|
+
- Method `Ast::AstBuilder#reduce_class_naming` fixed access to `IDENTIFER` in (LESS IDENTIFER)?
|
16
|
+
- Method `Ast::AstBuilder#reduce_var_declaration` fixed access to `expression` in (EQUAL expression)?
|
17
|
+
- Method `Ast::AstBuilder#reduce_assign_expr`fixed access to `call` in (call DOT)?
|
18
|
+
- Method `Ast::AstBuilder#reduce_parameters`fixed access to `IDENTIFIER` in (COMMA IDENTIFIER)*
|
19
|
+
- Method `Ast::AstBuilder#reduce_arguments`fixed access to `expression` in (COMMA expression)*
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
## [0.4.01] - 2021-08-22
|
24
|
+
- Grammar and AST::AstBuilder adapted to take profit of extended grammar notiation in Rley 0.8.01
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
- Class `Ast::ASTBuilder` removal of methods made redundant with new Rley version
|
28
|
+
- File `.rubocop.yml` added config for new cops
|
29
|
+
- File `grammar.rb` changed rules to use new extended rule syntax in Rley
|
30
|
+
|
1
31
|
## [0.4.00] - 2021-05-24
|
2
32
|
- Version bump. `Loxxy` is capable to run the LoxLox interpreter, an interpreter written in `Lox`.
|
3
33
|
|
@@ -45,14 +75,14 @@
|
|
45
75
|
- Milestone: `Loxxy` passes all reference test suite.
|
46
76
|
|
47
77
|
### Fixed
|
48
|
-
- Method `BackEnd::Resolver#before_variable_expr`: Standard `Lox` allows re-declaration of a variable at top-level scope
|
78
|
+
- Method `BackEnd::Resolver#before_variable_expr`: Standard `Lox` allows re-declaration of a variable at top-level scope
|
79
|
+
|
49
80
|
|
50
|
-
|
51
81
|
## [0.2.06] - 2021-05-04
|
52
82
|
- Nearly passing the 'official' test suite, fixing non-compliant behavior, specialized exceptions for errors
|
53
83
|
|
54
84
|
### New
|
55
|
-
- Module `LoxFileTester` module that hosts methods that simplify the tests of `Lox` source file.
|
85
|
+
- Module `LoxFileTester` module that hosts methods that simplify the tests of `Lox` source file.
|
56
86
|
|
57
87
|
### Changed
|
58
88
|
- Folder `test_suite` vastly reorganized. Sub-folder `baseline` contains spec files testing the `Lox` files from official implementation
|
@@ -62,7 +92,7 @@
|
|
62
92
|
|
63
93
|
### Fixed
|
64
94
|
- `0/0` expression results in a ZeroDivisionError exception, in Lox this result to a NaN (Not a Number). Now, `Loxxy` is aligned to standard `Lox`
|
65
|
-
- `FrontEnd::Scanner` now always treats expression like `-123` as the unary or binary minus operator applied to a positive number.
|
95
|
+
- `FrontEnd::Scanner` now always treats expression like `-123` as the unary or binary minus operator applied to a positive number.
|
66
96
|
|
67
97
|
## [0.2.05] - 2021-04-26
|
68
98
|
- `Loxxy` now transforms for loops into while loops (desugaring), fix in Scanner class
|
@@ -89,7 +119,7 @@
|
|
89
119
|
- Method `BackEnd::Resolver#after_for_stmt now accepts nil test expression
|
90
120
|
|
91
121
|
## [0.2.03] - 2021-04-24
|
92
|
-
- Fixes for the set (field) expressions, `accept` methods for AST nodes are meta-programmed
|
122
|
+
- Fixes for the set (field) expressions, `accept` methods for AST nodes are meta-programmed
|
93
123
|
|
94
124
|
### New
|
95
125
|
- Module `Ast::Visitee` provides the `define_accept` method that generate `accept` method with meta-programming
|
@@ -264,7 +294,7 @@
|
|
264
294
|
- Fix and test suite for return statements
|
265
295
|
|
266
296
|
### CHANGED
|
267
|
-
- `Loxxy` reports an error when a return statement occurs in top-level scope
|
297
|
+
- `Loxxy` reports an error when a return statement occurs in top-level scope
|
268
298
|
|
269
299
|
### Fixed
|
270
300
|
- A return without explicit value genrated an exception in some cases.
|
@@ -288,7 +318,7 @@
|
|
288
318
|
- Class `BackEnd::Environment`: added the attributes `predecessor` and `embedding` to support closures.
|
289
319
|
- Class `BackeEnd::LoxFunction`: added the attribute `closure` that is equal to the environment where the function is declared.
|
290
320
|
- Constructor `BackEnd::LoxFunction#new` now takes a `BackEnd::Engine`as its fourth parameter
|
291
|
-
- Methods `BackEnd::SymbolTable#enter_environment`, `BackEnd::SymbolTable#leave_environment` take into account closures.
|
321
|
+
- Methods `BackEnd::SymbolTable#enter_environment`, `BackEnd::SymbolTable#leave_environment` take into account closures.
|
292
322
|
|
293
323
|
### Fixed
|
294
324
|
- Method `Ast::AstBuilder#after_var_stmt` now takes into account the value from the top of stack
|
@@ -334,7 +364,7 @@
|
|
334
364
|
|
335
365
|
### Changed
|
336
366
|
- File `console` renamed to `loxxy`. Very basic command-line interface.
|
337
|
-
- Custom exception classes
|
367
|
+
- Custom exception classes
|
338
368
|
- File `README.md` updated list of supported `Lox` keywords.
|
339
369
|
|
340
370
|
|
@@ -365,8 +395,8 @@
|
|
365
395
|
- Method `Ast::ASTVisitor#visit_fun_stmt` for visiting an `Ast::LoxFunStmt` node
|
366
396
|
- Method `Ast::LoxBlockStmt#empty?` returns true if the code block is empty
|
367
397
|
- Method `BackEnd::Engine#after_fun_stmt`
|
368
|
-
- Method `BackEnd::NativeFunction#call`
|
369
|
-
- Method `BackEnd::NativeFunction#to_str`
|
398
|
+
- Method `BackEnd::NativeFunction#call`
|
399
|
+
- Method `BackEnd::NativeFunction#to_str`
|
370
400
|
- Method `BackEnd::LoxFunction` runtime representation of a Lox function.
|
371
401
|
|
372
402
|
### Changed
|
@@ -435,7 +465,7 @@
|
|
435
465
|
- Method `Ast::ASTBuilder#reduce_assign_expr` creates an `Ast::LoxAssignExpr` node
|
436
466
|
- Method `Ast::ASTVisitor#visit_assign_expr` for visiting an `Ast::LoxAssignExpr` node
|
437
467
|
- Method `BackEnd::Engine#after_assign_expr` implementation of the assignment
|
438
|
-
- Method `BackEnd::Variable#assign` to assign a value to a variable
|
468
|
+
- Method `BackEnd::Variable#assign` to assign a value to a variable
|
439
469
|
|
440
470
|
## [0.0.23] - 2021-01-20
|
441
471
|
- Fix for variables without explicit initialization.
|
@@ -705,4 +735,4 @@
|
|
705
735
|
|
706
736
|
## [0.0.1] - 2020-12-27
|
707
737
|
### Added
|
708
|
-
- Initial Github commit
|
738
|
+
- Initial Github commit
|
@@ -143,63 +143,36 @@ module Loxxy
|
|
143
143
|
# SEMANTIC ACTIONS
|
144
144
|
#####################################
|
145
145
|
|
146
|
-
# rule('program' => 'EOF').as '
|
147
|
-
def reduce_null_program(_production, _range, _tokens, _theChildren)
|
148
|
-
Ast::LoxNoopExpr.new(tokens[0].position)
|
149
|
-
end
|
150
|
-
|
151
|
-
# rule('program' => 'declaration_plus EOF').as ''
|
146
|
+
# rule('program' => 'declaration+ EOF').as ''
|
152
147
|
def reduce_lox_program(_production, _range, tokens, theChildren)
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
theChildren[0] << theChildren[1]
|
159
|
-
end
|
160
|
-
|
161
|
-
# rule('declaration_plus' => 'declaration')
|
162
|
-
def reduce_declaration_plus_end(_production, _range, _tokens, theChildren)
|
163
|
-
[theChildren[0]]
|
148
|
+
if theChildren[0].empty?
|
149
|
+
Ast::LoxNoopExpr.new(tokens[0].position)
|
150
|
+
else
|
151
|
+
LoxSeqDecl.new(tokens[0].position, theChildren[0])
|
152
|
+
end
|
164
153
|
end
|
165
154
|
|
166
155
|
# rule('classDecl' => 'CLASS classNaming class_body')
|
167
156
|
def reduce_class_decl(_production, _range, _tokens, theChildren)
|
168
|
-
|
169
|
-
|
170
|
-
parent = theChildren[1].last
|
171
|
-
else
|
172
|
-
name = theChildren[1]
|
173
|
-
parent = nil
|
174
|
-
end
|
157
|
+
name = theChildren[1].first
|
158
|
+
parent = theChildren[1].last
|
175
159
|
Ast::LoxClassStmt.new(tokens[1].position, name, parent, theChildren[2])
|
176
160
|
end
|
177
161
|
|
178
|
-
# rule('classNaming' => 'IDENTIFIER')
|
179
|
-
def
|
180
|
-
theChildren[
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
super_var = LoxVariableExpr.new(super_token.position, super_token.lexeme)
|
162
|
+
# rule('classNaming' => 'IDENTIFIER (LESS IDENTIFIER)?')
|
163
|
+
def reduce_class_naming(_production, _range, _tokens, theChildren)
|
164
|
+
if theChildren[1].nil?
|
165
|
+
super_var = nil
|
166
|
+
else
|
167
|
+
super_token = theChildren[1].last.token
|
168
|
+
super_var = LoxVariableExpr.new(super_token.position, super_token.lexeme)
|
169
|
+
end
|
187
170
|
[theChildren[0].token.lexeme, super_var]
|
188
171
|
end
|
189
172
|
|
190
|
-
# rule('class_body' => 'LEFT_BRACE
|
173
|
+
# rule('class_body' => 'LEFT_BRACE function* RIGHT_BRACE')
|
191
174
|
def reduce_class_body(_production, _range, _tokens, theChildren)
|
192
|
-
theChildren[1]
|
193
|
-
end
|
194
|
-
|
195
|
-
# rule('method_plus' => 'method_plus function')
|
196
|
-
def reduce_method_plus_more(_production, _range, _tokens, theChildren)
|
197
|
-
theChildren[0] << theChildren[1]
|
198
|
-
end
|
199
|
-
|
200
|
-
# rule('method_plus' => 'function')
|
201
|
-
def reduce_method_plus_end(_production, _range, _tokens, theChildren)
|
202
|
-
theChildren
|
175
|
+
theChildren[1]
|
203
176
|
end
|
204
177
|
|
205
178
|
# rule('funDecl' => 'FUN function')
|
@@ -212,16 +185,11 @@ module Loxxy
|
|
212
185
|
return_first_child(range, tokens, theChildren) # Discard the semicolon
|
213
186
|
end
|
214
187
|
|
215
|
-
# rule('varDecl' => 'VAR IDENTIFIER SEMICOLON')
|
188
|
+
# rule('varDecl' => 'VAR IDENTIFIER (EQUAL expression)? SEMICOLON')
|
216
189
|
def reduce_var_declaration(_production, _range, tokens, theChildren)
|
217
190
|
var_name = theChildren[1].token.lexeme.dup
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
# rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON')
|
222
|
-
def reduce_var_initialization(_production, _range, tokens, theChildren)
|
223
|
-
var_name = theChildren[1].token.lexeme.dup
|
224
|
-
Ast::LoxVarStmt.new(tokens[1].position, var_name, theChildren[3])
|
191
|
+
init_val = theChildren[2] ? theChildren[2].last : nil
|
192
|
+
Ast::LoxVarStmt.new(tokens[1].position, var_name, init_val)
|
225
193
|
end
|
226
194
|
|
227
195
|
# rule('forStmt' => 'FOR LEFT_PAREN forControl RIGHT_PAREN statement')
|
@@ -248,7 +216,7 @@ module Loxxy
|
|
248
216
|
for_stmt
|
249
217
|
end
|
250
218
|
|
251
|
-
# rule('forControl' => 'forInitialization forTest
|
219
|
+
# rule('forControl' => 'forInitialization forTest expression?')
|
252
220
|
def reduce_for_control(_production, _range, tokens, theChildren)
|
253
221
|
(init, test, update) = theChildren
|
254
222
|
if test.nil? && update
|
@@ -265,7 +233,7 @@ module Loxxy
|
|
265
233
|
nil
|
266
234
|
end
|
267
235
|
|
268
|
-
# rule('forTest' => '
|
236
|
+
# rule('forTest' => 'expression? SEMICOLON')
|
269
237
|
def reduce_for_test(_production, range, tokens, theChildren)
|
270
238
|
return_first_child(range, tokens, theChildren)
|
271
239
|
end
|
@@ -292,7 +260,7 @@ module Loxxy
|
|
292
260
|
Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
|
293
261
|
end
|
294
262
|
|
295
|
-
# rule('returnStmt' => 'RETURN
|
263
|
+
# rule('returnStmt' => 'RETURN expression? SEMICOLON')
|
296
264
|
def reduce_return_stmt(_production, _range, tokens, theChildren)
|
297
265
|
Ast::LoxReturnStmt.new(tokens[1].position, theChildren[1])
|
298
266
|
end
|
@@ -302,34 +270,31 @@ module Loxxy
|
|
302
270
|
Ast::LoxWhileStmt.new(tokens[1].position, theChildren[2], theChildren[4])
|
303
271
|
end
|
304
272
|
|
305
|
-
# rule('block' => 'LEFT_BRACE
|
273
|
+
# rule('block' => 'LEFT_BRACE declaration* RIGHT_BRACE')
|
306
274
|
def reduce_block_stmt(_production, _range, tokens, theChildren)
|
307
|
-
decls =
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
275
|
+
decls = nil
|
276
|
+
if theChildren[1]
|
277
|
+
pos = tokens[1].position
|
278
|
+
decls = LoxSeqDecl.new(tokens[1].position, theChildren[1])
|
279
|
+
else
|
280
|
+
pos = tokens[0].position
|
281
|
+
end
|
282
|
+
Ast::LoxBlockStmt.new(pos, decls)
|
314
283
|
end
|
315
284
|
|
316
|
-
# rule('assignment' => '
|
285
|
+
# rule('assignment' => '(call DOT)? IDENTIFIER EQUAL assignment')
|
317
286
|
def reduce_assign_expr(_production, _range, tokens, theChildren)
|
318
287
|
name_assignee = theChildren[1].token.lexeme.dup
|
319
|
-
if theChildren[0]
|
320
|
-
theChildren[0].
|
321
|
-
|
322
|
-
theChildren[
|
288
|
+
if theChildren[0]
|
289
|
+
set_expr = Ast::LoxSetExpr.new(tokens[1].position, theChildren[0].first)
|
290
|
+
set_expr.property = name_assignee
|
291
|
+
set_expr.value = theChildren[3]
|
292
|
+
set_expr
|
323
293
|
else
|
324
294
|
Ast::LoxAssignExpr.new(tokens[1].position, name_assignee, theChildren[3])
|
325
295
|
end
|
326
296
|
end
|
327
297
|
|
328
|
-
# rule('owner_opt' => 'call DOT')
|
329
|
-
def reduce_set_expr(_production, _range, tokens, theChildren)
|
330
|
-
Ast::LoxSetExpr.new(tokens[1].position, theChildren[0])
|
331
|
-
end
|
332
|
-
|
333
298
|
|
334
299
|
# rule('comparisonTest_plus' => 'comparisonTest_plus comparisonTest term').as 'comparison_t_plus_more'
|
335
300
|
# TODO: is it meaningful to implement this rule?
|
@@ -343,6 +308,7 @@ module Loxxy
|
|
343
308
|
|
344
309
|
# rule('call' => 'primary refinement_plus').as 'call_expr'
|
345
310
|
def reduce_call_expr(_production, _range, _tokens, theChildren)
|
311
|
+
# return theChildren[0] unless theChildren[1]
|
346
312
|
members = theChildren.flatten
|
347
313
|
call_expr = nil
|
348
314
|
loop do
|
@@ -365,7 +331,7 @@ module Loxxy
|
|
365
331
|
theChildren
|
366
332
|
end
|
367
333
|
|
368
|
-
# rule('refinement' => 'LEFT_PAREN
|
334
|
+
# rule('refinement' => 'LEFT_PAREN arguments? RIGHT_PAREN')
|
369
335
|
def reduce_call_arglist(_production, _range, tokens, theChildren)
|
370
336
|
args = theChildren[1] || []
|
371
337
|
if args.size > 255
|
@@ -422,24 +388,21 @@ module Loxxy
|
|
422
388
|
LoxFunStmt.new(pos, first_child.token.lexeme, theChildren[2], theChildren[4])
|
423
389
|
end
|
424
390
|
|
425
|
-
# rule('parameters' => '
|
426
|
-
def
|
427
|
-
|
428
|
-
|
391
|
+
# rule('parameters' => 'IDENTIFIER (COMMA IDENTIFIER)*').as 'parameters'
|
392
|
+
def reduce_parameters(_production, _range, _tokens, theChildren)
|
393
|
+
first_lexeme = theChildren[0].token.lexeme
|
394
|
+
return [first_lexeme] unless theChildren[1]
|
429
395
|
|
430
|
-
|
431
|
-
|
432
|
-
[theChildren[0].token.lexeme]
|
396
|
+
successors = theChildren[1].map { |seq_node| seq_node.last.token.lexeme }
|
397
|
+
successors.unshift(first_lexeme)
|
433
398
|
end
|
434
399
|
|
435
|
-
# rule('arguments' => '
|
436
|
-
def
|
437
|
-
theChildren[0]
|
438
|
-
end
|
400
|
+
# rule('arguments' => 'expression (COMMA expression)*')
|
401
|
+
def reduce_arguments(_production, _range, _tokens, theChildren)
|
402
|
+
return [theChildren[0]] unless theChildren[1]
|
439
403
|
|
440
|
-
|
441
|
-
|
442
|
-
theChildren
|
404
|
+
successors = theChildren[1].map(&:last)
|
405
|
+
successors.unshift(theChildren[0])
|
443
406
|
end
|
444
407
|
end # class
|
445
408
|
end # module
|
data/lib/loxxy/ast/lox_node.rb
CHANGED
@@ -11,7 +11,7 @@ module Loxxy
|
|
11
11
|
# Let nodes take `visitee` role as defined in the Visitor design pattern
|
12
12
|
extend ASTVisitee
|
13
13
|
|
14
|
-
# return [Rley::Lexical::Position] Position of the entry in the input stream.
|
14
|
+
# @return [Rley::Lexical::Position] Position of the entry in the input stream.
|
15
15
|
attr_reader :position
|
16
16
|
|
17
17
|
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
@@ -7,9 +7,9 @@ module Loxxy
|
|
7
7
|
module FrontEnd
|
8
8
|
########################################
|
9
9
|
# Grammar for Lox language
|
10
|
-
#
|
10
|
+
# Authoritative grammar at:
|
11
11
|
# https://craftinginterpreters.com/appendix-i.html
|
12
|
-
builder = Rley::
|
12
|
+
builder = Rley::grammar_builder do
|
13
13
|
# Punctuators, separators...
|
14
14
|
add_terminals('LEFT_PAREN', 'RIGHT_PAREN', 'LEFT_BRACE', 'RIGHT_BRACE')
|
15
15
|
add_terminals('COMMA', 'DOT', 'MINUS', 'PLUS')
|
@@ -26,34 +26,23 @@ module Loxxy
|
|
26
26
|
add_terminals('EOF')
|
27
27
|
|
28
28
|
# Top-level rule that matches an entire Lox program
|
29
|
-
rule('program' => 'EOF').as '
|
30
|
-
rule('program' => 'declaration_plus EOF').as 'lox_program'
|
29
|
+
rule('program' => 'declaration* EOF').as 'lox_program'
|
31
30
|
|
32
31
|
# Declarations: bind an identifier to something
|
33
|
-
rule('declaration_plus' => 'declaration_plus declaration').as 'declaration_plus_more'
|
34
|
-
rule('declaration_plus' => 'declaration').as 'declaration_plus_end'
|
35
32
|
rule('declaration' => 'classDecl')
|
36
33
|
rule('declaration' => 'funDecl')
|
37
34
|
rule('declaration' => 'varDecl')
|
38
|
-
rule('declaration' => '
|
35
|
+
rule('declaration' => 'statement')
|
39
36
|
|
40
37
|
rule('classDecl' => 'CLASS classNaming class_body').as 'class_decl'
|
41
|
-
rule('classNaming' => 'IDENTIFIER LESS IDENTIFIER').as '
|
42
|
-
rule('
|
43
|
-
rule('class_body' => 'LEFT_BRACE methods_opt RIGHT_BRACE').as 'class_body'
|
44
|
-
rule('methods_opt' => 'method_plus')
|
45
|
-
rule('methods_opt' => [])
|
46
|
-
rule('method_plus' => 'method_plus function').as 'method_plus_more'
|
47
|
-
rule('method_plus' => 'function').as 'method_plus_end'
|
38
|
+
rule('classNaming' => 'IDENTIFIER (LESS IDENTIFIER)?').as 'class_naming'
|
39
|
+
rule('class_body' => 'LEFT_BRACE function* RIGHT_BRACE').as 'class_body'
|
48
40
|
|
49
41
|
rule('funDecl' => 'FUN function').as 'fun_decl'
|
50
42
|
|
51
|
-
rule('varDecl' => 'VAR IDENTIFIER SEMICOLON').as 'var_declaration'
|
52
|
-
rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON').as 'var_initialization'
|
43
|
+
rule('varDecl' => 'VAR IDENTIFIER (EQUAL expression)? SEMICOLON').as 'var_declaration'
|
53
44
|
|
54
45
|
# Statements: produce side effects, but don't introduce bindings
|
55
|
-
rule('stmt' => 'statement')
|
56
|
-
rule('stmt' => 'unbalancedStmt') # Tweak to cope with "dangling else" problem
|
57
46
|
rule('statement' => 'exprStmt')
|
58
47
|
rule('statement' => 'forStmt')
|
59
48
|
rule('statement' => 'ifStmt')
|
@@ -65,32 +54,25 @@ module Loxxy
|
|
65
54
|
rule('exprStmt' => 'expression SEMICOLON').as 'exprStmt'
|
66
55
|
|
67
56
|
rule('forStmt' => 'FOR LEFT_PAREN forControl RIGHT_PAREN statement').as 'for_stmt'
|
68
|
-
rule('forControl' => 'forInitialization forTest
|
57
|
+
rule('forControl' => 'forInitialization forTest expression?').as 'for_control'
|
69
58
|
rule('forInitialization' => 'varDecl')
|
70
59
|
rule('forInitialization' => 'exprStmt')
|
71
60
|
rule('forInitialization' => 'SEMICOLON').as 'empty_for_initialization'
|
72
|
-
rule('forTest' => '
|
73
|
-
rule('forUpdate' => 'expression_opt')
|
61
|
+
rule('forTest' => 'expression? SEMICOLON').as 'for_test'
|
74
62
|
|
75
|
-
rule('ifStmt' => 'IF ifCondition statement ELSE statement').as 'if_else_stmt'
|
76
|
-
rule('
|
77
|
-
rule('unbalancedStmt' => 'IF ifCondition statement ELSE unbalancedStmt').as 'if_else_stmt'
|
63
|
+
rule('ifStmt' => 'IF ifCondition statement ELSE {match_closest: "IF"} statement').as 'if_else_stmt'
|
64
|
+
rule('ifStmt' => 'IF ifCondition statement').as 'if_stmt'
|
78
65
|
rule('ifCondition' => 'LEFT_PAREN expression RIGHT_PAREN').as 'keep_symbol2'
|
79
66
|
|
80
67
|
rule('printStmt' => 'PRINT expression SEMICOLON').as 'print_stmt'
|
81
|
-
rule('returnStmt' => 'RETURN
|
68
|
+
rule('returnStmt' => 'RETURN expression? SEMICOLON').as 'return_stmt'
|
82
69
|
rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement').as 'while_stmt'
|
83
|
-
rule('block' => 'LEFT_BRACE
|
84
|
-
rule('block' => 'LEFT_BRACE RIGHT_BRACE').as 'block_empty'
|
70
|
+
rule('block' => 'LEFT_BRACE declaration* RIGHT_BRACE').as 'block_stmt'
|
85
71
|
|
86
72
|
# Expressions: produce values
|
87
|
-
rule('expression_opt' => 'expression')
|
88
|
-
rule('expression_opt' => [])
|
89
73
|
rule('expression' => 'assignment')
|
90
|
-
rule('assignment' => '
|
74
|
+
rule('assignment' => '(call DOT)? IDENTIFIER EQUAL assignment').as 'assign_expr'
|
91
75
|
rule('assignment' => 'logic_or')
|
92
|
-
rule('owner_opt' => 'call DOT').as 'set_expr'
|
93
|
-
rule('owner_opt' => [])
|
94
76
|
rule('logic_or' => 'logic_and')
|
95
77
|
rule('logic_or' => 'logic_and disjunct_plus').as 'logical_expr'
|
96
78
|
rule('disjunct_plus' => 'disjunct_plus OR logic_and').as 'binary_plus_more'
|
@@ -130,10 +112,8 @@ module Loxxy
|
|
130
112
|
rule('unaryOp' => 'BANG')
|
131
113
|
rule('unaryOp' => 'MINUS')
|
132
114
|
rule('call' => 'primary')
|
133
|
-
rule('call' => 'primary
|
134
|
-
rule('
|
135
|
-
rule('refinement_plus' => 'refinement').as 'refinement_plus_end'
|
136
|
-
rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN').as 'call_arglist'
|
115
|
+
rule('call' => 'primary refinement+').as 'call_expr'
|
116
|
+
rule('refinement' => 'LEFT_PAREN arguments? RIGHT_PAREN').as 'call_arglist'
|
137
117
|
rule('refinement' => 'DOT IDENTIFIER').as 'get_expr'
|
138
118
|
rule('primary' => 'TRUE').as 'literal_expr'
|
139
119
|
rule('primary' => 'FALSE').as 'literal_expr'
|
@@ -146,15 +126,9 @@ module Loxxy
|
|
146
126
|
rule('primary' => 'SUPER DOT IDENTIFIER').as 'super_expr'
|
147
127
|
|
148
128
|
# Utility rules
|
149
|
-
rule('function' => 'IDENTIFIER LEFT_PAREN
|
150
|
-
rule('
|
151
|
-
rule('
|
152
|
-
rule('parameters' => 'parameters COMMA IDENTIFIER').as 'parameters_plus_more'
|
153
|
-
rule('parameters' => 'IDENTIFIER').as 'parameters_plus_end'
|
154
|
-
rule('arguments_opt' => 'arguments')
|
155
|
-
rule('arguments_opt' => [])
|
156
|
-
rule('arguments' => 'arguments COMMA expression').as 'arguments_plus_more'
|
157
|
-
rule('arguments' => 'expression').as 'arguments_plus_end'
|
129
|
+
rule('function' => 'IDENTIFIER LEFT_PAREN parameters? RIGHT_PAREN block').as 'function'
|
130
|
+
rule('parameters' => 'IDENTIFIER (COMMA IDENTIFIER)*').as 'parameters'
|
131
|
+
rule('arguments' => 'expression (COMMA expression)*').as 'arguments'
|
158
132
|
end
|
159
133
|
|
160
134
|
unless defined?(Grammar)
|
data/lib/loxxy/version.rb
CHANGED
data/loxxy.gemspec
CHANGED
@@ -48,7 +48,7 @@ Gem::Specification.new do |spec|
|
|
48
48
|
DESCR_END
|
49
49
|
spec.homepage = 'https://github.com/famished-tiger/loxxy'
|
50
50
|
spec.license = 'MIT'
|
51
|
-
spec.required_ruby_version = '~> 2.
|
51
|
+
spec.required_ruby_version = '~> 2.5'
|
52
52
|
|
53
53
|
spec.bindir = 'bin'
|
54
54
|
spec.executables = ['loxxy']
|
@@ -58,7 +58,7 @@ Gem::Specification.new do |spec|
|
|
58
58
|
PkgExtending.pkg_documentation(spec)
|
59
59
|
|
60
60
|
# Runtime dependencies
|
61
|
-
spec.add_dependency 'rley', '~> 0.
|
61
|
+
spec.add_dependency 'rley', '~> 0.8.03'
|
62
62
|
|
63
63
|
# Development dependencies
|
64
64
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
@@ -26,7 +26,10 @@ module Loxxy
|
|
26
26
|
# program => declaration_star EOF
|
27
27
|
# where the declaration_star MUST be empty
|
28
28
|
expect(aParseTree.root.symbol.name).to eq('program')
|
29
|
-
eof = aParseTree.root.subnodes
|
29
|
+
(decls, eof) = aParseTree.root.subnodes
|
30
|
+
expect(decls).to be_kind_of(Rley::PTree::NonTerminalNode)
|
31
|
+
expect(decls.symbol.name).to eq('declaration_star')
|
32
|
+
expect(decls.subnodes).to be_empty
|
30
33
|
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
31
34
|
expect(eof.symbol.name).to eq('EOF')
|
32
35
|
end
|
@@ -73,11 +76,12 @@ LOX_END
|
|
73
76
|
expect(root.symbol.name).to eq('program')
|
74
77
|
(decls, eof) = root.subnodes
|
75
78
|
expect(decls).to be_kind_of(Rley::PTree::NonTerminalNode)
|
76
|
-
expect(decls.symbol.name).to eq('
|
77
|
-
|
78
|
-
expect(
|
79
|
-
expect(
|
80
|
-
|
79
|
+
expect(decls.symbol.name).to eq('declaration_star')
|
80
|
+
expect(decls.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
|
81
|
+
expect(decls.subnodes[0].symbol.name).to eq('declaration_star')
|
82
|
+
expect(decls.subnodes[1]).to be_kind_of(Rley::PTree::NonTerminalNode)
|
83
|
+
expect(decls.subnodes[1].symbol.name).to eq('declaration')
|
84
|
+
statement = decls.subnodes[1].subnodes[0]
|
81
85
|
expect(statement).to be_kind_of(Rley::PTree::NonTerminalNode)
|
82
86
|
expect(statement.symbol.name).to eq('statement')
|
83
87
|
prnt_stmt = statement.subnodes[0]
|
data/spec/spec_helper.rb
CHANGED
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.4.
|
4
|
+
version: 0.4.04
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.8.03
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.8.03
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -173,7 +173,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
173
|
requirements:
|
174
174
|
- - "~>"
|
175
175
|
- !ruby/object:Gem::Version
|
176
|
-
version: '2.
|
176
|
+
version: '2.5'
|
177
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
178
|
requirements:
|
179
179
|
- - ">="
|