loxxy 0.1.14 → 0.1.15
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/CHANGELOG.md +14 -0
- data/README.md +0 -24
- data/lib/loxxy/ast/ast_builder.rb +11 -2
- data/lib/loxxy/front_end/grammar.rb +6 -4
- data/lib/loxxy/version.rb +1 -1
- data/spec/front_end/raw_parser_spec.rb +5 -2
- data/spec/interpreter_spec.rb +8 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3994a3225b7dbc4a39d24cc646c20e4a7a19b074e85fe2dd9bc87d9ca1d61cb
|
4
|
+
data.tar.gz: 965c328057f51fb7d13886255955e782e51b1f030f3053a6f5f6f4534962855b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9db05948e45f7903ca71d7d0e3722f3c9b1fd3f50931e17b6bb1666c34cf03e1dc7f6cf32abee461dd6e6ec6824cd89b8ef5b2b56ae41fcd40068228d8cbaba2
|
7
|
+
data.tar.gz: eaa762982bd89f2b4cb85e8d6831017e702b87501b7c29132f25f79fa592bf804ec95736f518d304f43caf814aa55eeadd5041ffcba1afa3aaaed631d23027af
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.1.15] - 2021-04-08
|
2
|
+
- Fixed the `dangling else`by tweaking the grammar rules
|
3
|
+
|
4
|
+
### Changed
|
5
|
+
- Method `Ast::ASTBuilder#reduce_if__else_stmt` parse action specific for if with else branch
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
- File `grammar.rb` changed rules to cope with `dangling else` issue
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
- Method `Ast::ASTBuilder#reduce_if_stmt` parse action for if without else branch
|
12
|
+
- File `README.md` removed the section about the `dangling else` issue.
|
13
|
+
|
14
|
+
|
1
15
|
## [0.1.14] - 2021-04-05
|
2
16
|
- `Loxxy` now implements the 'this' keyword
|
3
17
|
|
data/README.md
CHANGED
@@ -331,30 +331,6 @@ print "else-branch";
|
|
331
331
|
```
|
332
332
|
|
333
333
|
As for other languages, the `else` part is optional.
|
334
|
-
##### Warning: nested `if`...`else`
|
335
|
-
Call it a bug ... Nested `if` `else` control flow structure aren't yet supported by __Loxxy__.
|
336
|
-
The culprit has a name: [the dangling else](https://en.wikipedia.org/wiki/Dangling_else).
|
337
|
-
|
338
|
-
The problem in a nutshell: in a nested if ... else ... statement like this:
|
339
|
-
``` javascript
|
340
|
-
'if (true) if (false) print "bad"; else print "good";
|
341
|
-
```
|
342
|
-
... there is an ambiguity.
|
343
|
-
Indeed, according to the __Lox__ grammar, the `else` could be bound
|
344
|
-
either to the first `if` or to the second one.
|
345
|
-
This ambiguity is usually lifted by applying an ad-hoc rule: an `else` is aways bound to the most
|
346
|
-
recent (rightmost) `if`.
|
347
|
-
Being a generic parsing library, `Rley` doesn't apply any of these supplemental rules.
|
348
|
-
As a consequence,it complains about the found ambiguity and stops the parsing...
|
349
|
-
Although `Rley` can cope with ambiguities, this requires the use of an advanced data structure
|
350
|
-
called `Shared Packed Parse Forest (SPPF)`.
|
351
|
-
SPPF are much more complex to handle than the "common" parse trees present in most compiler or interpreter books.
|
352
|
-
Therefore, a future version of `Rley` will incorporate the capability to define disambuiguation rules.
|
353
|
-
|
354
|
-
In the meantime, the `Loxxy` will progress on other __Lox__ features like:
|
355
|
-
- Block structures...
|
356
|
-
- Iteration structures (`for` and `while` loops)
|
357
|
-
|
358
334
|
|
359
335
|
#### Print Statement
|
360
336
|
|
@@ -233,11 +233,20 @@ module Loxxy
|
|
233
233
|
return_first_child(range, tokens, theChildren)
|
234
234
|
end
|
235
235
|
|
236
|
-
# rule('ifStmt' => 'IF ifCondition statement
|
236
|
+
# rule('ifStmt' => 'IF ifCondition statement ELSE statement')
|
237
|
+
# rule('unbalancedStmt' => 'IF ifCondition statement ELSE unbalancedStmt')
|
238
|
+
def reduce_if_else_stmt(_production, _range, tokens, theChildren)
|
239
|
+
condition = theChildren[1]
|
240
|
+
then_stmt = theChildren[2]
|
241
|
+
else_stmt = theChildren[4]
|
242
|
+
LoxIfStmt.new(tokens[0].position, condition, then_stmt, else_stmt)
|
243
|
+
end
|
244
|
+
|
245
|
+
# rule('unbalancedStmt' => 'IF ifCondition stmt').as ''
|
237
246
|
def reduce_if_stmt(_production, _range, tokens, theChildren)
|
238
247
|
condition = theChildren[1]
|
239
248
|
then_stmt = theChildren[2]
|
240
|
-
else_stmt =
|
249
|
+
else_stmt = nil
|
241
250
|
LoxIfStmt.new(tokens[0].position, condition, then_stmt, else_stmt)
|
242
251
|
end
|
243
252
|
|
@@ -35,7 +35,7 @@ module Loxxy
|
|
35
35
|
rule('declaration' => 'classDecl')
|
36
36
|
rule('declaration' => 'funDecl')
|
37
37
|
rule('declaration' => 'varDecl')
|
38
|
-
rule('declaration' => '
|
38
|
+
rule('declaration' => 'stmt')
|
39
39
|
|
40
40
|
rule('classDecl' => 'CLASS classNaming class_body').as 'class_decl'
|
41
41
|
rule('classNaming' => 'IDENTIFIER LESS IDENTIFIER')
|
@@ -52,6 +52,8 @@ module Loxxy
|
|
52
52
|
rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON').as 'var_initialization'
|
53
53
|
|
54
54
|
# Statements: produce side effects, but don't introduce bindings
|
55
|
+
rule('stmt' => 'statement')
|
56
|
+
rule('stmt' => 'unbalancedStmt') # Tweak to cope with "dangling else" problem
|
55
57
|
rule('statement' => 'exprStmt')
|
56
58
|
rule('statement' => 'forStmt')
|
57
59
|
rule('statement' => 'ifStmt')
|
@@ -70,10 +72,10 @@ module Loxxy
|
|
70
72
|
rule('forTest' => 'expression_opt SEMICOLON').as 'for_test'
|
71
73
|
rule('forUpdate' => 'expression_opt')
|
72
74
|
|
73
|
-
rule('ifStmt' => 'IF ifCondition statement
|
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'
|
74
78
|
rule('ifCondition' => 'LEFT_PAREN expression RIGHT_PAREN').as 'keep_symbol2'
|
75
|
-
rule('elsePart_opt' => 'ELSE statement').as 'keep_symbol2'
|
76
|
-
rule('elsePart_opt' => [])
|
77
79
|
|
78
80
|
rule('printStmt' => 'PRINT expression SEMICOLON').as 'print_stmt'
|
79
81
|
rule('returnStmt' => 'RETURN expression_opt SEMICOLON').as 'return_stmt'
|
data/lib/loxxy/version.rb
CHANGED
@@ -76,8 +76,11 @@ LOX_END
|
|
76
76
|
expect(decls.symbol.name).to eq('declaration_plus')
|
77
77
|
stmt = decls.subnodes[0].subnodes[0]
|
78
78
|
expect(stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
|
79
|
-
expect(stmt.symbol.name).to eq('
|
80
|
-
|
79
|
+
expect(stmt.symbol.name).to eq('stmt')
|
80
|
+
statement = stmt.subnodes[0]
|
81
|
+
expect(statement).to be_kind_of(Rley::PTree::NonTerminalNode)
|
82
|
+
expect(statement.symbol.name).to eq('statement')
|
83
|
+
prnt_stmt = statement.subnodes[0]
|
81
84
|
expect(prnt_stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
|
82
85
|
expect(prnt_stmt.subnodes.size).to eq(3)
|
83
86
|
expect(prnt_stmt.subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
|
data/spec/interpreter_spec.rb
CHANGED
@@ -227,19 +227,20 @@ module Loxxy
|
|
227
227
|
# Evaluate the 'then' expression if the condition is true.
|
228
228
|
['if (true) print "then-branch";', 'then-branch'],
|
229
229
|
['if (false) print "ignored";', ''],
|
230
|
-
|
231
|
-
|
230
|
+
['if (nil) print "ignored";', ''],
|
231
|
+
['if (true) { print "block"; }', 'block'],
|
232
|
+
['var a = false; if (a = true) print a;', 'true'],
|
232
233
|
|
233
234
|
# Evaluate the 'else' expression if the condition is false.
|
234
235
|
['if (true) print "then-branch"; else print "else-branch";', 'then-branch'],
|
235
236
|
['if (false) print "then-branch"; else print "else-branch";', 'else-branch'],
|
236
237
|
['if (0) print "then-branch"; else print "else-branch";', 'then-branch'],
|
237
|
-
['if (nil) print "then-branch"; else print "else-branch";', 'else-branch']
|
238
|
-
|
238
|
+
['if (nil) print "then-branch"; else print "else-branch";', 'else-branch'],
|
239
|
+
['if (false) nil; else { print "else-branch"; }', 'else-branch'],
|
239
240
|
|
240
|
-
#
|
241
|
-
|
242
|
-
|
241
|
+
# A dangling else binds to the right-most if.
|
242
|
+
['if (true) if (false) print "bad"; else print "good";', 'good'],
|
243
|
+
['if (false) if (true) print "bad"; else print "worse";', '']
|
243
244
|
].each do |(source, predicted)|
|
244
245
|
io = StringIO.new
|
245
246
|
cfg = { ostream: io }
|
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.1.
|
4
|
+
version: 0.1.15
|
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-04-
|
11
|
+
date: 2021-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|