loxxy 0.0.7 → 0.0.8
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 +9 -0
- data/README.md +11 -11
- data/lib/loxxy/ast/ast_builder.rb +50 -9
- data/lib/loxxy/front_end/grammar.rb +6 -6
- data/lib/loxxy/version.rb +1 -1
- data/spec/front_end/parser_spec.rb +82 -6
- data/spec/front_end/scanner_spec.rb +12 -0
- 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: ed8bad2906a9ffd76c81a1fe14d89088f913f84996f0a6d98e7f104e0eccfdc9
|
4
|
+
data.tar.gz: 40ee48dc0f4d7e0ce1028820b9c5cf56d0c78d9853916f3bf9e5f32a7106887a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69c3c6e6b2a60c3f27284be820ac8f2687de0073c28719bd9414578ab37ac59de267dc1e69897966fef33d4ba725597587fe991b8e20ce6d40ec1587f3aa53c4
|
7
|
+
data.tar.gz: c296dcedcf97fe7426a59cfb2df2144685f2809c64becb18483e62a5aea536c2ca3ae2ab697b865c0945456e191a0a011f01123d34160acfa554761b8a2f917e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.0.8] - 2021-01-07
|
2
|
+
- AST node generation for arithmetic operations of number literals.
|
3
|
+
|
4
|
+
## Changed
|
5
|
+
- Class `AST::ASTBuilder` added `reduce_` methods for arithmetic operations.
|
6
|
+
|
7
|
+
## Fixed
|
8
|
+
- File `grammar.rb`: second rule for `factor` had a missing member in rhs.
|
9
|
+
|
1
10
|
## [0.0.7] - 2021-01-06
|
2
11
|
- Lox grammar reworked, initial AST classes created.
|
3
12
|
|
data/README.md
CHANGED
@@ -9,6 +9,14 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
|
|
9
9
|
- The implementation should be mature enough to run (LoxLox)[https://github.com/benhoyt/loxlox],
|
10
10
|
a Lox interpreter written in Lox.
|
11
11
|
|
12
|
+
## Current status
|
13
|
+
The __loxxy__ gem hosts two distinct parsers classes (`RawParser` and `Parser`).
|
14
|
+
- A `RawParser` instance is able to recognize valid Lox input and to generate
|
15
|
+
a concrete parse tree from it.
|
16
|
+
- A `Parser` instance can also parse Lox source code but will generate an AST
|
17
|
+
(Abstract Syntax Tree) that will be used by the future tree-walking interpreter.
|
18
|
+
Currently it generates AST for arithmetic expressions with literal numbers only.
|
19
|
+
|
12
20
|
## Roadmap
|
13
21
|
- [DONE] Scanner (tokenizer)
|
14
22
|
- [DONE] Raw parser. It parses Lox programs and generates a parse tree.
|
@@ -17,14 +25,7 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
|
|
17
25
|
- [STARTED] Hierarchy classes for representing Lox expressions in AST
|
18
26
|
- [TODO] Interpreter or transpiler
|
19
27
|
|
20
|
-
## Example
|
21
|
-
The __loxxy__ hosts two distinct parsers classes (`RawParser` and `Parser`).
|
22
|
-
- A `RawParser` instance is able to recognize Lox input and to generate
|
23
|
-
a concrete parse tree from it.
|
24
|
-
- A `Parser` instance can also parse Lox source code but will generate an AST
|
25
|
-
(Abstract Syntax Tree) that will be used by the future tree-walking interpreter.
|
26
|
-
|
27
|
-
### Example using RawParser class
|
28
|
+
## Example using RawParser class
|
28
29
|
```ruby
|
29
30
|
require 'loxxy'
|
30
31
|
|
@@ -69,7 +70,6 @@ program
|
|
69
70
|
+-- EOF: ''
|
70
71
|
```
|
71
72
|
|
72
|
-
|
73
73
|
## Installation
|
74
74
|
|
75
75
|
Add this line to your application's Gemfile:
|
@@ -91,9 +91,9 @@ Or install it yourself as:
|
|
91
91
|
TODO: Write usage instructions here
|
92
92
|
|
93
93
|
## Other Lox implementations in Ruby
|
94
|
-
An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations
|
94
|
+
An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations)
|
95
95
|
|
96
|
-
For Ruby,
|
96
|
+
For Ruby, there is the [lox](https://github.com/rdodson41/ruby-lox) gem.
|
97
97
|
There are other Ruby-based projects as well:
|
98
98
|
- [SlowLox](https://github.com/ArminKleinert/SlowLox), described as a "1-to-1 conversion of JLox to Ruby"
|
99
99
|
- [rulox](https://github.com/LevitatingBusinessMan/rulox)
|
@@ -72,18 +72,59 @@ module Loxxy
|
|
72
72
|
node
|
73
73
|
end
|
74
74
|
|
75
|
+
# rule('term' => 'factor additive_plus')
|
76
|
+
def reduce_term_additive(_production, _range, tokens, theChildren)
|
77
|
+
operand1 = theChildren[0]
|
78
|
+
|
79
|
+
# Second child is anray with couples [operator, operand2]
|
80
|
+
theChildren[1].each do |(operator, operand2)|
|
81
|
+
operand1 = LoxBinaryExpr.new(tokens[0].position, operator, operand1, operand2)
|
82
|
+
end
|
83
|
+
|
84
|
+
operand1
|
85
|
+
end
|
86
|
+
|
75
87
|
# rule('additive_star' => 'additive_star additionOp factor').as 'additionOp_expr'
|
76
|
-
def
|
77
|
-
|
78
|
-
operator =
|
79
|
-
|
88
|
+
def reduce_additive_plus_more(_production, _range, _tokens, theChildren)
|
89
|
+
result = theChildren[0]
|
90
|
+
operator = theChildren[1].symbol.name == 'MINUS' ? :- : :+
|
91
|
+
operand2 = theChildren[2]
|
92
|
+
result << [operator, operand2]
|
93
|
+
end
|
94
|
+
|
95
|
+
# rule('additive_plus' => 'additionOp factor')
|
96
|
+
def reduce_additive_plus_end(_production, _range, _tokens, theChildren)
|
97
|
+
operator = theChildren[0].symbol.name == 'MINUS' ? :- : :+
|
98
|
+
operand2 = theChildren[1]
|
99
|
+
[[operator, operand2]]
|
80
100
|
end
|
81
101
|
|
82
|
-
# rule('
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
102
|
+
# rule('factor' => 'multiplicative_plus')
|
103
|
+
def reduce_factor_multiplicative(_production, _range, tokens, theChildren)
|
104
|
+
operand1 = theChildren[0]
|
105
|
+
|
106
|
+
# Second child is anray with couples [operator, operand2]
|
107
|
+
theChildren[1].each do |(operator, operand2)|
|
108
|
+
operand1 = LoxBinaryExpr.new(tokens[0].position, operator, operand1, operand2)
|
109
|
+
end
|
110
|
+
|
111
|
+
operand1
|
112
|
+
end
|
113
|
+
|
114
|
+
# rule('multiplicative_plus' => 'multiplicative_plus multOp unary')
|
115
|
+
def reduce_multiplicative_plus_more(_production, _range, _tokens, theChildren)
|
116
|
+
result = theChildren[0]
|
117
|
+
operator = theChildren[1].symbol.name == 'SLASH' ? :/ : :*
|
118
|
+
operand2 = theChildren[2]
|
119
|
+
result << [operator, operand2]
|
120
|
+
end
|
121
|
+
|
122
|
+
# rule('multiplicative_plus' => 'multOp unary')
|
123
|
+
def reduce_multiplicative_plus_end(_production, _range, _tokens, theChildren)
|
124
|
+
operator = theChildren[0].symbol.name == 'SLASH' ? :/ : :*
|
125
|
+
operand2 = theChildren[1]
|
126
|
+
[[operator, operand2]]
|
127
|
+
end
|
87
128
|
|
88
129
|
# rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
|
89
130
|
def reduce_literal_expr(_production, _range, _tokens, theChildren)
|
@@ -110,15 +110,15 @@ module Loxxy
|
|
110
110
|
rule('comparisonTest' => 'LESS')
|
111
111
|
rule('comparisonTest' => 'LESS_EQUAL')
|
112
112
|
rule('term' => 'factor')
|
113
|
-
rule('term' => 'factor additive_plus')
|
114
|
-
rule('additive_plus' => 'additive_plus additionOp factor').as '
|
115
|
-
rule('additive_plus' => 'additionOp factor')
|
113
|
+
rule('term' => 'factor additive_plus').as 'term_additive'
|
114
|
+
rule('additive_plus' => 'additive_plus additionOp factor').as 'additive_plus_more'
|
115
|
+
rule('additive_plus' => 'additionOp factor').as 'additive_plus_end'
|
116
116
|
rule('additionOp' => 'MINUS')
|
117
117
|
rule('additionOp' => 'PLUS')
|
118
118
|
rule('factor' => 'unary')
|
119
|
-
rule('factor' => 'multiplicative_plus')
|
120
|
-
rule('multiplicative_plus' => 'multiplicative_plus multOp unary')
|
121
|
-
rule('multiplicative_plus' => 'multOp unary')
|
119
|
+
rule('factor' => 'unary multiplicative_plus').as 'factor_multiplicative'
|
120
|
+
rule('multiplicative_plus' => 'multiplicative_plus multOp unary').as 'multiplicative_plus_more'
|
121
|
+
rule('multiplicative_plus' => 'multOp unary').as 'multiplicative_plus_end'
|
122
122
|
rule('multOp' => 'SLASH')
|
123
123
|
rule('multOp' => 'STAR')
|
124
124
|
rule('unary' => 'unaryOp unary')
|
data/lib/loxxy/version.rb
CHANGED
@@ -137,13 +137,89 @@ LOX_END
|
|
137
137
|
end
|
138
138
|
end # context
|
139
139
|
|
140
|
-
context 'Parsing
|
140
|
+
context 'Parsing arithmetic operations' do
|
141
141
|
it 'should parse the addition of two number literals' do
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
142
|
+
input = '123 + 456;'
|
143
|
+
ptree = subject.parse(input)
|
144
|
+
parent = ptree.root.subnodes[0]
|
145
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
146
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
147
|
+
expr = parent.subnodes[0]
|
148
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
149
|
+
expect(expr.operator).to eq(:+)
|
150
|
+
expect(expr.operands[0].literal.value).to eq(123)
|
151
|
+
expect(expr.operands[1].literal.value).to eq(456)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should parse the subtraction of two number literals' do
|
155
|
+
input = '4 - 3;'
|
156
|
+
ptree = subject.parse(input)
|
157
|
+
parent = ptree.root.subnodes[0]
|
158
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
159
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
160
|
+
expr = parent.subnodes[0]
|
161
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
162
|
+
expect(expr.operator).to eq(:-)
|
163
|
+
expect(expr.operands[0].literal.value).to eq(4)
|
164
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should parse multiple additive operations' do
|
168
|
+
input = '5 + 2 - 3;'
|
169
|
+
ptree = subject.parse(input)
|
170
|
+
parent = ptree.root.subnodes[0]
|
171
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
172
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
173
|
+
expr = parent.subnodes[0]
|
174
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
175
|
+
expect(expr.operator).to eq(:-)
|
176
|
+
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
177
|
+
expect(expr.operands[0].operator).to eq(:+)
|
178
|
+
expect(expr.operands[0].operands[0].literal.value).to eq(5)
|
179
|
+
expect(expr.operands[0].operands[1].literal.value).to eq(2)
|
180
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should parse the division of two number literals' do
|
184
|
+
input = '8 / 2;'
|
185
|
+
ptree = subject.parse(input)
|
186
|
+
parent = ptree.root.subnodes[0]
|
187
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
188
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
189
|
+
expr = parent.subnodes[0]
|
190
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
191
|
+
expect(expr.operator).to eq(:/)
|
192
|
+
expect(expr.operands[0].literal.value).to eq(8)
|
193
|
+
expect(expr.operands[1].literal.value).to eq(2)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should parse the product of two number literals' do
|
197
|
+
input = '12.34 * 0.3;'
|
198
|
+
ptree = subject.parse(input)
|
199
|
+
parent = ptree.root.subnodes[0]
|
200
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
201
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
202
|
+
expr = parent.subnodes[0]
|
203
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
204
|
+
expect(expr.operator).to eq(:*)
|
205
|
+
expect(expr.operands[0].literal.value).to eq(12.34)
|
206
|
+
expect(expr.operands[1].literal.value).to eq(0.3)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should parse multiple additive operations' do
|
210
|
+
input = '5 * 2 / 3;'
|
211
|
+
ptree = subject.parse(input)
|
212
|
+
parent = ptree.root.subnodes[0]
|
213
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
214
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
215
|
+
expr = parent.subnodes[0]
|
216
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
217
|
+
expect(expr.operator).to eq(:/)
|
218
|
+
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
219
|
+
expect(expr.operands[0].operator).to eq(:*)
|
220
|
+
expect(expr.operands[0].operands[0].literal.value).to eq(5)
|
221
|
+
expect(expr.operands[0].operands[1].literal.value).to eq(2)
|
222
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
147
223
|
end
|
148
224
|
end # context
|
149
225
|
end # describe
|
@@ -223,6 +223,18 @@ LOX_END
|
|
223
223
|
]
|
224
224
|
match_expectations(subject, expectations)
|
225
225
|
end
|
226
|
+
|
227
|
+
it 'should cope with single slash (divide) expression' do
|
228
|
+
subject.start_with('8 / 2')
|
229
|
+
|
230
|
+
expectations = [
|
231
|
+
# [token lexeme]
|
232
|
+
%w[NUMBER 8],
|
233
|
+
%w[SLASH /],
|
234
|
+
%w[NUMBER 2]
|
235
|
+
]
|
236
|
+
match_expectations(subject, expectations)
|
237
|
+
end
|
226
238
|
end # context
|
227
239
|
end # describe
|
228
240
|
end # module
|
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.8
|
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-01-
|
11
|
+
date: 2021-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|