loxxy 0.0.9 → 0.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74cd4aa3bd58cad64cad8ac452535052c761f166da883b06b593590310edd97d
4
- data.tar.gz: 15af4b4a4c86c7b8e6a14bda16433a9d1663ab581eae78331d29adeed02313d3
3
+ metadata.gz: e4f33203580d2b83ee7139e449787b439c0fb56c5a8c3dcc8035d114ffd957d3
4
+ data.tar.gz: 46c9fb2f55849c6aa9b9e4d58588746ddb3ac3353f7ed09922d9394a9fc512c6
5
5
  SHA512:
6
- metadata.gz: 0dbd9244c36913eed955b1ff92bdc63fd77cc6f7cda3d6b037f3ee87cdcc8d4450673f852426a7395d968711aaf9a3a539efeeaf5e2a0d46865f4f4fa7276c74
7
- data.tar.gz: c8c65b58fa53d0cce81a3e7508317dfbeb5d8e10f883a0a011d278ca33ee647967bfd34e79fc4703ad7a5b4a3a88aece8d17ca0d0db107f0ec0fcb9ac12e4280
6
+ metadata.gz: 30f554af6338b50297ce6befaa62c86c8406df681e25098cc95dc28da64bb6feabbb9e085846eb8032f51d8d3655332105eb1d7165903bbd0d6be24cb13c4d0b
7
+ data.tar.gz: d9d9a69a010d16807f6c4bf24b15e8135367bb62b6d2e052943e0d6030751f282c777f652dd3fced08093aee8abae228e63d365cae156fa6e87ac7f52fc7e2e6
@@ -1,3 +1,14 @@
1
+ ## [0.0.10] - 2021-01-08
2
+ - AST node generation for equality expression.
3
+
4
+ ## Changed
5
+ - Class `AST::ASTBuilder` refactoring and added `reduce_` methods for equality operations.
6
+ - File `grammar.rb`added name to equality rules
7
+ - File `README.md` added gem version and license badges, expanded roadmap section.
8
+
9
+ ## Fixed
10
+ - File `grammar.rb`: a rule had still the discarded non-terminal `equalityTest_star` in its lhs.
11
+
1
12
  ## [0.0.9] - 2021-01-07
2
13
  - AST node generation for comparison expression.
3
14
 
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # Loxxy
1
+ # loxxy
2
+ [![Gem Version](https://badge.fury.io/rb/loxxy.svg)](https://badge.fury.io/rb/loxxy)
3
+ [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/famished-tiger/loxxy/blob/main/LICENSE.txt)
4
+
2
5
 
3
6
  A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html ),
4
7
  a simple language used in Bob Nystrom's online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
@@ -6,7 +9,7 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
6
9
  ## Purpose of this project:
7
10
  - To deliver an open source example of a programming language fully implemented in Ruby
8
11
  (from the scanner, parser, code generation).
9
- - The implementation should be mature enough to run (LoxLox)[https://github.com/benhoyt/loxlox],
12
+ - The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
10
13
  a Lox interpreter written in Lox.
11
14
 
12
15
  ## Current status
@@ -18,12 +21,48 @@ The __loxxy__ gem hosts two distinct parsers classes (`RawParser` and `Parser`).
18
21
  Currently it generates AST for arithmetic expressions with literal numbers only.
19
22
 
20
23
  ## Roadmap
21
- - [DONE] Scanner (tokenizer)
22
- - [DONE] Raw parser. It parses Lox programs and generates a parse tree.
23
- - [DONE] Tailored parser for generating AST (Abstract Syntax Tree)
24
- - [STARTED] Custom AST builder class
25
- - [STARTED] Hierarchy classes for representing Lox expressions in AST
26
- - [TODO] Interpreter or transpiler
24
+ ### Done
25
+ - Scanner (tokenizer)
26
+ - Lox grammar (in format required by Rley gem)
27
+ - Raw parser. It parses Lox programs and generates a raw parse tree.
28
+ - Tailored parser for generating AST (Abstract Syntax Tree)
29
+
30
+ ### Started
31
+ - Custom AST builder class
32
+ - Classes for representing Lox expressions in AST
33
+
34
+ ### TODO
35
+ AST Node generation
36
+ Goal: parser should generate AST for any input Lox program
37
+ - [X] Equality operator
38
+ - [] Logical operator (and, or)
39
+ - [] Unary expressions (negate, not)
40
+ - [] Grouping expressions
41
+ - [] Print statement
42
+ - [] Simple assignment expressions
43
+ - [] Variable declaration
44
+ - [] Dot notation
45
+ - [] Block statement
46
+ - [] If statement
47
+ - [] For statement
48
+ - [] While statement
49
+ - [] Function declaration
50
+ - [] Call expression
51
+ - [] Return statement
52
+ - [] Class declaration
53
+ - [] AST generation covers complete grammar
54
+
55
+ Tree-walking:
56
+ - [] Tree visitor recognizes all AST node types
57
+
58
+ Interpreter:
59
+ - Keywords: symbol table, scope, activation record, class & object model, Lox test suite
60
+ - [] Milestone: Interpreter handles expressions but function calls
61
+ - [] Milestone: Interpreter handles `for`, `if`, `print`, `while` and block statements
62
+ - [] Milestone: Interpreter handles variable declarations (global, block)
63
+ - [] Milestone: Interpreter handles function declarations and calls
64
+ - [] Milestone: Interpreter supports class and object definition
65
+ - [] Milestone: Lox interpreter complete
27
66
 
28
67
  ## Example using RawParser class
29
68
  ```ruby
@@ -10,13 +10,31 @@ module Loxxy
10
10
  # (Abstract Syntax Tree) from a sequence of input tokens and
11
11
  # visit events produced by walking over a GFGParsing object.
12
12
  class ASTBuilder < Rley::ParseRep::ASTBaseBuilder
13
- # Terminal2NodeClass = {
14
- # 'FALSE' => Datatype::False,
15
- # 'NIL' => Datatype::Nil,
16
- # 'NUMBER' => Datatype::Number,
17
- # 'STRING' => Datatype::LXString,
18
- # 'TRUE' => Datatype::True
19
- # }.freeze
13
+ # Mapping Token name => operator | separator | delimiter characters
14
+ # @return [Hash{String => String}]
15
+ Name2special = {
16
+ 'AND' => 'and',
17
+ 'BANG' => '!',
18
+ 'BANG_EQUAL' => '!=',
19
+ 'COMMA' => ',',
20
+ 'DOT' => '.',
21
+ 'EQUAL' => '=',
22
+ 'EQUAL_EQUAL' => '==',
23
+ 'GREATER' => '>',
24
+ 'GREATER_EQUAL' => '>=',
25
+ 'LEFT_BRACE' => '{',
26
+ 'LEFT_PAREN' => '(',
27
+ 'LESS' => '<',
28
+ 'LESS_EQUAL' => '<=',
29
+ 'MINUS' => '-',
30
+ 'OR' => 'or',
31
+ 'PLUS' => '+',
32
+ 'RIGHT_BRACE' => '}',
33
+ 'RIGHT_PAREN' => ')',
34
+ 'SEMICOLON' => ';',
35
+ 'SLASH' => '/',
36
+ 'STAR' => '*'
37
+ }.freeze
20
38
 
21
39
  attr_reader :strict
22
40
 
@@ -76,7 +94,7 @@ module Loxxy
76
94
  def reduce_binary_operator(_production, _range, tokens, theChildren)
77
95
  operand1 = theChildren[0]
78
96
 
79
- # Second child is anray with couples [operator, operand2]
97
+ # Second child is array with couples [operator, operand2]
80
98
  theChildren[1].each do |(operator, operand2)|
81
99
  operand1 = LoxBinaryExpr.new(tokens[0].position, operator, operand1, operand2)
82
100
  end
@@ -84,6 +102,36 @@ module Loxxy
84
102
  operand1
85
103
  end
86
104
 
105
+ # rule('something_plus' => 'something_plus operator symbol')
106
+ def reduce_binary_plus_more(_production, _range, _tokens, theChildren)
107
+ result = theChildren[0]
108
+ operator = Name2special[theChildren[1].symbol.name].to_sym
109
+ operand2 = theChildren[2]
110
+ result << [operator, operand2]
111
+ end
112
+
113
+ # rule('something_plus' => 'something_plus symbol')
114
+ def reduce_binary_plus_end(_production, _range, _tokens, theChildren)
115
+ operator = Name2special[theChildren[0].symbol.name].to_sym
116
+ operand2 = theChildren[1]
117
+ [[operator, operand2]]
118
+ end
119
+
120
+ # rule('equality' => 'comparison equalityTest_plus')
121
+ def reduce_equality_plus(production, range, tokens, theChildren)
122
+ reduce_binary_operator(production, range, tokens, theChildren)
123
+ end
124
+
125
+ # rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison')
126
+ def reduce_equality_t_plus_more(production, range, tokens, theChildren)
127
+ reduce_binary_plus_more(production, range, tokens, theChildren)
128
+ end
129
+
130
+ # rule('equalityTest_star' => 'equalityTest comparison')
131
+ def reduce_equality_t_plus_end(production, range, tokens, theChildren)
132
+ reduce_binary_plus_end(production, range, tokens, theChildren)
133
+ end
134
+
87
135
  # rule('comparison' => 'term comparisonTest_plus')
88
136
  def reduce_comparison_plus(production, range, tokens, theChildren)
89
137
  reduce_binary_operator(production, range, tokens, theChildren)
@@ -93,16 +141,8 @@ module Loxxy
93
141
  # TODO: is it meaningful to implement this rule?
94
142
 
95
143
  # rule('comparisonTest_plus' => 'comparisonTest term')
96
- def reduce_comparison_t_plus_end(_production, _range, _tokens, theChildren)
97
- name2operators = {
98
- 'GREATER' => '>',
99
- 'GREATER_EQUAL' => '>=',
100
- 'LESS' => '<',
101
- 'LESS_EQUAL' => '<='
102
- }
103
- operator = name2operators[theChildren[0].symbol.name].to_sym
104
- operand2 = theChildren[1]
105
- [[operator, operand2]]
144
+ def reduce_comparison_t_plus_end(production, range, tokens, theChildren)
145
+ reduce_binary_plus_end(production, range, tokens, theChildren)
106
146
  end
107
147
 
108
148
  # rule('term' => 'factor additive_plus')
@@ -111,18 +151,13 @@ module Loxxy
111
151
  end
112
152
 
113
153
  # rule('additive_star' => 'additive_star additionOp factor').as 'additionOp_expr'
114
- def reduce_additive_plus_more(_production, _range, _tokens, theChildren)
115
- result = theChildren[0]
116
- operator = theChildren[1].symbol.name == 'MINUS' ? :- : :+
117
- operand2 = theChildren[2]
118
- result << [operator, operand2]
154
+ def reduce_additive_plus_more(production, range, tokens, theChildren)
155
+ reduce_binary_plus_more(production, range, tokens, theChildren)
119
156
  end
120
157
 
121
158
  # rule('additive_plus' => 'additionOp factor')
122
- def reduce_additive_plus_end(_production, _range, _tokens, theChildren)
123
- operator = theChildren[0].symbol.name == 'MINUS' ? :- : :+
124
- operand2 = theChildren[1]
125
- [[operator, operand2]]
159
+ def reduce_additive_plus_end(production, range, tokens, theChildren)
160
+ reduce_binary_plus_end(production, range, tokens, theChildren)
126
161
  end
127
162
 
128
163
  # rule('factor' => 'multiplicative_plus')
@@ -131,18 +166,13 @@ module Loxxy
131
166
  end
132
167
 
133
168
  # rule('multiplicative_plus' => 'multiplicative_plus multOp unary')
134
- def reduce_multiplicative_plus_more(_production, _range, _tokens, theChildren)
135
- result = theChildren[0]
136
- operator = theChildren[1].symbol.name == 'SLASH' ? :/ : :*
137
- operand2 = theChildren[2]
138
- result << [operator, operand2]
169
+ def reduce_multiplicative_plus_more(production, range, tokens, theChildren)
170
+ reduce_binary_plus_more(production, range, tokens, theChildren)
139
171
  end
140
172
 
141
173
  # rule('multiplicative_plus' => 'multOp unary')
142
- def reduce_multiplicative_plus_end(_production, _range, _tokens, theChildren)
143
- operator = theChildren[0].symbol.name == 'SLASH' ? :/ : :*
144
- operand2 = theChildren[1]
145
- [[operator, operand2]]
174
+ def reduce_multiplicative_plus_end(production, range, tokens, theChildren)
175
+ reduce_binary_plus_end(production, range, tokens, theChildren)
146
176
  end
147
177
 
148
178
  # rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
@@ -96,9 +96,9 @@ module Loxxy
96
96
  rule('conjunct_plus' => 'conjunct_plus AND equality')
97
97
  rule('conjunct_' => 'AND equality')
98
98
  rule('equality' => 'comparison')
99
- rule('equality' => 'comparison equalityTest_plus')
100
- rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison')
101
- rule('equalityTest_star' => 'equalityTest comparison')
99
+ rule('equality' => 'comparison equalityTest_plus').as 'equality_plus'
100
+ rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison').as 'equality_t_plus_more'
101
+ rule('equalityTest_plus' => 'equalityTest comparison').as 'equality_t_plus_end'
102
102
  rule('equalityTest' => 'BANG_EQUAL')
103
103
  rule('equalityTest' => 'EQUAL_EQUAL')
104
104
  rule('comparison' => 'term')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.0.9'
4
+ VERSION = '0.0.10'
5
5
  end
@@ -255,8 +255,25 @@ LOX_END
255
255
  end # context
256
256
 
257
257
  context 'Parsing comparison expressions' do
258
- it 'should parse the comparison of two number literals' do
259
- %w[> >= < <=].each do |predicate|
258
+ it 'should parse the comparison of two number literals' do
259
+ %w[> >= < <=].each do |predicate|
260
+ input = "3 #{predicate} 2;"
261
+ ptree = subject.parse(input)
262
+ parent = ptree.root.subnodes[0]
263
+ expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
264
+ expect(parent.symbol.name).to eq('exprStmt')
265
+ expr = parent.subnodes[0]
266
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
267
+ expect(expr.operator).to eq(predicate.to_sym)
268
+ expect(expr.operands[0].literal.value).to eq(3)
269
+ expect(expr.operands[1].literal.value).to eq(2)
270
+ end
271
+ end
272
+ end # context
273
+
274
+ context 'Parsing equality expressions' do
275
+ it 'should parse the equality of two number literals' do
276
+ %w[!= ==].each do |predicate|
260
277
  input = "3 #{predicate} 2;"
261
278
  ptree = subject.parse(input)
262
279
  parent = ptree.root.subnodes[0]
@@ -269,6 +286,22 @@ LOX_END
269
286
  expect(expr.operands[1].literal.value).to eq(2)
270
287
  end
271
288
  end
289
+
290
+ it 'should parse combination of equality expressions' do
291
+ input = '5 != 2 == false; // A bit contrived example'
292
+ ptree = subject.parse(input)
293
+ parent = ptree.root.subnodes[0]
294
+ expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
295
+ expect(parent.symbol.name).to eq('exprStmt')
296
+ expr = parent.subnodes[0]
297
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
298
+ expect(expr.operator).to eq(:==)
299
+ expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
300
+ expect(expr.operands[0].operator).to eq(:!=)
301
+ expect(expr.operands[0].operands[0].literal.value).to eq(5)
302
+ expect(expr.operands[0].operands[1].literal.value).to eq(2)
303
+ expect(expr.operands[1].literal.value).to be_falsey
304
+ end
272
305
  end # context
273
306
  end # describe
274
307
  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.9
4
+ version: 0.0.10
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-07 00:00:00.000000000 Z
11
+ date: 2021-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley