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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47c5d65fa1f3c2d0025013577f46edf741572df743d8986e238f49a08ea32702
4
- data.tar.gz: 72a3beb6828362e6dc7c73072555ed6f87ed5bf57b4052ac55e06503b9582e29
3
+ metadata.gz: e321e9f44f39776e2684a1a2c2f2d032460847ff46cdea45791cf8724696d038
4
+ data.tar.gz: 1c455133b79cd26939998ebd791c5b39872de1ccf59fa6b8c8d4c7d819114021
5
5
  SHA512:
6
- metadata.gz: e83ee511c1ead4592153bb1e8ed8167439894bfefa2bb54060100eb9d221d77c453b4bad3d3e4a36209f3761812a5b9b0aa98b02a53556314c022d1f0b605bca
7
- data.tar.gz: 8d939d7ff60687dd64c4dc6e4beccffa512e3483f5b38042a83fffbc0a5cc83d218999f855b8765a47e24b8c0df7808ecd649e70cec11832a0591b5c141a659c
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 'null_program'
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
- LoxSeqDecl.new(tokens[0].position, theChildren[0])
154
- end
155
-
156
- # rule('declaration_plus' => 'declaration_plus declaration').as ''
157
- def reduce_declaration_plus_more(_production, _range, _tokens, theChildren)
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
- if theChildren[1].kind_of?(Array)
169
- name = theChildren[1].first
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 reduce_class_name(_production, _range, _tokens, theChildren)
180
- theChildren[0].token.lexeme
181
- end
182
-
183
- # rule('classNaming' => 'IDENTIFIER LESS IDENTIFIER')
184
- def reduce_class_subclassing(_production, _range, _tokens, theChildren)
185
- super_token = theChildren[2].token
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 methods_opt RIGHT_BRACE')
173
+ # rule('class_body' => 'LEFT_BRACE function* RIGHT_BRACE')
191
174
  def reduce_class_body(_production, _range, _tokens, theChildren)
192
- theChildren[1].nil? ? [] : 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
- Ast::LoxVarStmt.new(tokens[1].position, var_name, nil)
219
- end
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 forUpdate')
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' => 'expression_opt SEMICOLON')
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 expression_opt SEMICOLON')
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 declaration_plus RIGHT_BRACE')
273
+ # rule('block' => 'LEFT_BRACE declaration* RIGHT_BRACE')
306
274
  def reduce_block_stmt(_production, _range, tokens, theChildren)
307
- decls = LoxSeqDecl.new(tokens[1].position, theChildren[1])
308
- Ast::LoxBlockStmt.new(tokens[1].position, decls)
309
- end
310
-
311
- # rule('block' => 'LEFT_BRACE RIGHT_BRACE').as 'block_empty'
312
- def reduce_block_empty(_production, _range, tokens, _children)
313
- Ast::LoxBlockStmt.new(tokens[0].position, nil)
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' => 'owner_opt IDENTIFIER EQUAL 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].kind_of?(Ast::LoxSetExpr)
320
- theChildren[0].property = name_assignee
321
- theChildren[0].value = theChildren[3]
322
- theChildren[0]
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 arguments_opt RIGHT_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' => 'parameters COMMA IDENTIFIER')
426
- def reduce_parameters_plus_more(_production, _range, _tokens, theChildren)
427
- theChildren[0] << theChildren[2].token.lexeme
428
- end
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
- # rule('parameters' => 'IDENTIFIER')
431
- def reduce_parameters_plus_end(_production, _range, _tokens, theChildren)
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' => 'arguments COMMA expression')
436
- def reduce_arguments_plus_more(_production, _range, _tokens, theChildren)
437
- theChildren[0] << theChildren[2]
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
- # rule('arguments' => 'expression')
441
- def reduce_arguments_plus_end(_production, _range, _tokens, theChildren)
442
- theChildren
404
+ successors = theChildren[1].map(&:last)
405
+ successors.unshift(theChildren[0])
443
406
  end
444
407
  end # class
445
408
  end # module
@@ -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
- # Authoritave grammar at:
10
+ # Authoritative grammar at:
11
11
  # https://craftinginterpreters.com/appendix-i.html
12
- builder = Rley::Syntax::GrammarBuilder.new do
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 'null_program'
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' => 'stmt')
35
+ rule('declaration' => 'statement')
39
36
 
40
37
  rule('classDecl' => 'CLASS classNaming class_body').as 'class_decl'
41
- rule('classNaming' => 'IDENTIFIER LESS IDENTIFIER').as 'class_subclassing'
42
- rule('classNaming' => 'IDENTIFIER').as 'class_name'
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 forUpdate').as 'for_control'
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' => 'expression_opt SEMICOLON').as 'for_test'
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('unbalancedStmt' => 'IF ifCondition stmt').as 'if_stmt'
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 expression_opt SEMICOLON').as 'return_stmt'
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 declaration_plus RIGHT_BRACE').as 'block_stmt'
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' => 'owner_opt IDENTIFIER EQUAL assignment').as 'assign_expr'
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 refinement_plus').as 'call_expr'
134
- rule('refinement_plus' => 'refinement_plus refinement').as 'refinement_plus_more'
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 params_opt RIGHT_PAREN block').as 'function'
150
- rule('params_opt' => 'parameters')
151
- rule('params_opt' => [])
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.4.00'
4
+ VERSION = '0.4.04'
5
5
  end
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.4'
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.7.06'
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.first
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('declaration_plus')
77
- stmt = decls.subnodes[0].subnodes[0]
78
- expect(stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
79
- expect(stmt.symbol.name).to eq('stmt')
80
- statement = stmt.subnodes[0]
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rspec' # Use the RSpec framework
4
- require 'loxxy'
4
+ require_relative '../lib/loxxy'
5
5
 
6
6
  RSpec.configure do |config|
7
7
  # Enable flags like --only-failures and --next-failure
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.00
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-05-24 00:00:00.000000000 Z
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.7.06
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.7.06
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.4'
176
+ version: '2.5'
177
177
  required_rubygems_version: !ruby/object:Gem::Requirement
178
178
  requirements:
179
179
  - - ">="