loxxy 0.1.14 → 0.1.15
Sign up to get free protection for your applications and to get access to all the features.
- 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
|