loxxy 0.0.16 → 0.0.21

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: 7d7d30d3246aa8a8f06f3456d3996c680e9ddb4ed31bcf9fff99685702e50dd1
4
- data.tar.gz: dc428ddd0fc03e153e70873bc2827b6e4aac813e5fdfba40ef2f28bfa7283fc2
3
+ metadata.gz: fd4cbf32f4ee44a60c45630a76318425850dc35b4d9f6129274cefcbf4e91fcc
4
+ data.tar.gz: 711e0ae07d2a0b3a080c2fe408d9adf4f7b96bb070af686d66dd3f9dbae8391d
5
5
  SHA512:
6
- metadata.gz: d90f2494a324be036dae2f3d38636c571009b60f19d2b3d917b242ab98d231e03bb121f577e5598ac63514cc5817814972cabe927f05af2842a5a97c89eb69d9
7
- data.tar.gz: e09a70a27baa1408904e1bfe512f4f523b8e4efd1aab00412b993c8f4a35b5498f1f6ddb5e67697108c80a91778301e41c15741451e73e1d869496d96441757a
6
+ metadata.gz: 131f6fe3b23dc0a84b063efe70744b02ecc9edb68742540799964311298f35494a0d48db75bb18a240ddeed039286ab08ba2ef99e2ae4857d2b4d5dc4403d5ba
7
+ data.tar.gz: b46c18f54147fd01f9819e3ad06564ee78fe72de5c91d6ef8a5bef5945d9f1ad622cad848c4d521ae66f00c91b7825d01e57c831b2a097da830bec0d99f2cf06
@@ -250,7 +250,7 @@ Style/IfUnlessModifier:
250
250
  Enabled: false
251
251
 
252
252
  Style/InverseMethods:
253
- Enabled: true
253
+ Enabled: false
254
254
 
255
255
  Style/MissingRespondToMissing:
256
256
  Enabled: false
@@ -1,3 +1,62 @@
1
+ ## [0.0.21] - 2021-01-1x
2
+ - The interpreter supports the declaration global variables.
3
+
4
+ ## Added
5
+ - Class `BackEnd::Entry`, mixin module for objects put in the symbol table
6
+ - Class `BackEnd::Environment` that keeps track of variables in a given context.
7
+ - Class `BackEnd::SymbolTable` that keeps track of environments.
8
+ - Class `BackEnd::Variable` internal representation of a `Lox` variable
9
+ - Method `Ast::ASTBuilder#reduce_var_declaration` and `Ast::ASTBuilder#reduce_var_declaration`
10
+ - Method `Ast::ASTVisitor#visit_var_stmt` for visiting `LoxVarStmt` nodes
11
+ - Attribute `Engine::symbol_table`for keeping track of variables
12
+ - Method `Engine::after_var_stmt` for the implementation of variable declarations
13
+
14
+ ## [0.0.20] - 2021-01-15
15
+ - The interpreter supports the `if` ... `else` statement.
16
+
17
+ ## Added
18
+ - Class `Ast::LoxItStmt`, AST node specific for `if` `else` statements
19
+ - Method `Ast::ASTBuilder#reduce_if_stmt` as semantic action for if ... else
20
+ - Method `Ast::ASTVisitor#visit_if_stmt` for visiting `LoxIfStmt` nodes
21
+ - Method `Engine::after_if_stmt` implementation of the control flow
22
+
23
+ ## [0.0.19] - 2021-01-14
24
+ - The interpreter supports expressions between parentheses (grouping).
25
+
26
+ ## Added
27
+ - Class `Ast::LoxLogicalExpr`
28
+ - Method `Ast::ASTBuilder#reduce_grouping_expr` as semantic action for grouping expression
29
+ - Method `Ast::ASTVisitor#visit_grouping_expr` for visiting grouping expressions
30
+ - Method `Engine::after_grouping_expr`for the evaluation of grouping expressions
31
+
32
+ ## Changed
33
+ - File `grammar.rb` rules for if ... else were given names in order to activate semantic actions.
34
+ - File `README.md` updated with little `if ... else` documentation.
35
+
36
+ ## [0.0.18] - 2021-01-13
37
+ - The interpreter can evaluate `and`, `or`expressions.
38
+
39
+ ## Added
40
+ - Class `Ast::LoxLogicalExpr`
41
+ - Method `Ast::ASTBuilder#reduce_logical_expr` for the semantic action require for `and`, `or`
42
+ - Method `Ast::ASTVisitor#visit_logical_expr` for visiting logical expressions
43
+ - Method `Backend::Engine#after_logical_expr` implements the evaluation of the logical expressions
44
+
45
+ ## [0.0.17] - 2021-01-12
46
+ - The interpreter can evaluate all arithmetic and comparison operations.
47
+ - It implements `==`, `!=` and the unary operations `!`, `-`
48
+
49
+ ## Added
50
+ - Class `Ast::LoxUnaryExpr`
51
+ - Method `Ast::ASTBuilder#reduce_unary_expr` to support the evaluation of `!` and ``-@`
52
+ - Method `Ast::ASTVisitor#visit_unnary_expr` for visiting unary expressions
53
+ - Method `Backend::Engine#after_unary_expr` evaluating an unary expression
54
+ - In class `Datatype::BuiltinDatatype` the methods `falsey?`, `truthy?`, `!`, `!=`
55
+ - In class `Datatype::Number`the methods `<`, `<=`, ´>´, `>=` and `-@`
56
+
57
+ ## Changed
58
+ - File `README.md` updated.
59
+
1
60
  ## [0.0.16] - 2021-01-11
2
61
  - The interpreter can evaluate product and division of two numbers.
3
62
  - It also implements equality `==` and inequality `!=` operators
@@ -36,7 +95,7 @@
36
95
  - The interpreter can evaluate addition of numbers and string concatenation
37
96
 
38
97
  ## Added
39
- - Method `Ast::ASTVisitor::visit_binary_expr` for visiting binary expressions
98
+ - Method `Ast::ASTVisitor#visit_binary_expr` for visiting binary expressions
40
99
  - Method `Ast::LoxBinaryExpr#accept` for visitor pattern
41
100
  - Method `BackEnd::Engine#after_binary_expr` to trigger execution of binary operator
42
101
  - `Boolean` class hierarchy: added methos `true?` and `false?` to ease spec test writing
data/README.md CHANGED
@@ -8,7 +8,7 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
8
8
 
9
9
  ### Purpose of this project:
10
10
  - To deliver an open source example of a programming language fully implemented in Ruby
11
- (from the scanner, parser, an interpreter).
11
+ (from the scanner and parser to an interpreter).
12
12
  - The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
13
13
  a Lox interpreter written in Lox.
14
14
 
@@ -128,16 +128,22 @@ program
128
128
  ```
129
129
 
130
130
  ## Suppported Lox language features
131
- Although the interpreter should parse almost any valid Lox program,
132
- it currently can evaluate a tiny set of AST node (AST = Abstract Syntax Tree).
131
+ On one hand, the parser covers the complete Lox grammar and should therefore, in principle,
132
+ parse any valid Lox program.
133
+
134
+ On the other hand, the interpreter is under development and currently it can evaluate only a tiny subset of __Lox__.
135
+ But the situation is changing almost daily, stay tuned...
133
136
 
134
137
  Here are the language features currently supported by the interpreter:
135
138
 
136
139
  - [Comments](#comments)
137
140
  - [Keywords](#keywords)
138
- - [Operators and Special Chars](#operators-and-special-chars)
139
141
  - [Datatypes](#datatypes)
140
- - [Statements](#statements)
142
+ - [Statements](#statements)
143
+ -[Expressions](#expressions)
144
+ - [Variable declarations](#var-statement)
145
+ - [If Statement](#if-statement)
146
+ - [Print Statement](#print-statement)
141
147
 
142
148
  ### Comments
143
149
 
@@ -148,41 +154,10 @@ Loxxy supports single line C-style comments.
148
154
  ```
149
155
 
150
156
  ### Keywords
151
-
152
- The parser knows all the __Lox__ reserved keywords:
157
+ Loxxy implements the following __Lox__ reserved keywords:
153
158
  ```lang-none
154
- and, class, else, false, fun, for, if, nil, or,
155
- print, return, super, this, true, var, while
159
+ and, false, nil, or, print, true
156
160
  ```
157
- Of these, the interpreter implements: `false`, `nil`, `true`
158
-
159
- ### Operators and Special Chars
160
- #### Operators
161
- The parser recognizes all the __Lox__ operators, delimiters and separators:
162
- - Arithmetic operators: `+`, `-`, `*`, `/`
163
- - Comparison operators: `>`, `>=`, `<`, `<=`
164
- - Equality operators: `==`, `!=`
165
-
166
- Of these, the interpreter implements:
167
- `+` (addition of two numbers or string concatenation)
168
- `-` (difference between two numbers)
169
- `*` (product of two numbers)
170
- `/` (division of two number)
171
- `==` and `!=` (in)equality testing of two Lox values
172
-
173
- #### Delimiters
174
- The parser knows all the __Lox__ grouping delimiters:
175
- (`, ), `{`, `}`
176
-
177
- These aren't yet implemented in the interpreter.
178
-
179
- The other characters that have a special meaning in __Lox__ are:
180
- - `,` Used in parameter list
181
- - `.` For the dot notation (i.e. calling a method)
182
- - `;` The semicolon is used to terminates expressions
183
- - `=` Assignment
184
-
185
- The parser recognizes them all but the interpreter accepts the semicolons only.
186
161
 
187
162
  ### Datatypes
188
163
 
@@ -192,22 +167,150 @@ loxxy supports all the standard __Lox__ datatypes:
192
167
  - `String`: Sequence of characters surrounded by `"`. For example: `"Hello!"`
193
168
  - `Nil`: Used to define a null value, denoted by the `nil` keyword
194
169
 
195
- ## Statements
196
- ### Implemented expressions
197
- Loxxy implements expressions:
198
- - Plain literals only; or,
199
- - Addition, subtraction, product and division of two numbers; or,
200
- - Concatenation of two strings,
201
- - (In)equality test of two Lox values
170
+ ### Statements
171
+
172
+ Loxxy supports the following statements:
173
+ - [Expressions](#expressions)
174
+ -[Arithmetic expressions](#arithmetic-expressions)
175
+ -[String concatenation](#string-concatenation)
176
+ -[Comparison expressions](#comparison-expressions)
177
+ -[Logical expressions](#logical-expressions)
178
+ -[Grouping expressions](#grouping-expressions)
179
+
180
+ -[Variable declarations](#var-statement)
181
+ -[If Statement](#if-statement)
182
+ -[Print Statement](#print-statement)
183
+
184
+ #### Expressions
185
+
186
+ ##### Arithmetic expressions
187
+ Loxxy supports the following operators for arithmetic expressions:
188
+
189
+ - `+`: Adds of two numbers. Both operands must be of the type Number
190
+ E.g. `37 + 5; // => 42`
191
+ `7 + -3; // => 4`
192
+ - `-`: (Binary) Subtracts right operand from left operand. Both operands must be numbers.
193
+ E.g. `47 - 5; // => 42`
194
+ - `-`: (Unary) Negates (= changes the sign) of the given number operand.
195
+ E.g. `- -3; // => 3`
196
+ - `*`: Multiplies two numbers
197
+ E.g. `2 * 3; // => 6`
198
+ - `/`: Divides two numbers
199
+ E.g. `8 / 2; // => 4`
200
+ `5 / 2; // => 2.5`
201
+
202
+ ##### String concatenation
203
+ - `+`: Concatenates two strings. Both operands must be of the String type.
204
+ E.g. `"Hello" + ", " + "world! // => "Hello, world!"`
205
+
206
+ ##### Comparison expressions
207
+
208
+ - `==`: Returns `true` if left operand is equal to right operand, otherwise `false`
209
+ E.g. `false == false; // => true`
210
+ `5 + 2 == 3 + 4; // => true`
211
+ `"" == ""; // => true`
212
+ - `!=`: Returns `true` if left operand is not equal to right operand, otherwise `false`
213
+ E.g. `false != "false"; // => true`
214
+ `5 + 2 != 4 + 3; // => false`
215
+ - `<`: Returns `true` if left operand is less than right operand, otherwise `false`. Both operands must be numbers
216
+ E.g. `1 < 3; // => true`
217
+ `1 < 0; // => false`
218
+ `2 < 2; // => false`
219
+ - `<=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
220
+ E.g. `1 <= 3; // => true`
221
+ `1 <= 0; // => false`
222
+ `2 <= 2; // => true`
223
+ - `>`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
224
+ E.g. `1 > 3; // => false`
225
+ `1 > 0; // => true`
226
+ `2 > 2; // => false`
227
+ - `>=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
228
+ E.g. `1 > 3; // => false`
229
+ `1 > 0; // => true`
230
+ `2 > 2; // => false`
231
+
232
+ ##### Logical expressions
233
+
234
+ REMINDER: In __Lox__, `false` and `nil` are considered falsey, everything else is truthy.
235
+
236
+ - `and`: When both operands are booleans, then returns `true` if both left and right operands are truthy, otherwise `false`.
237
+ If at least one operand isn't a boolean then returns first falsey operand else (both operands are truthy) returns the second operand.
238
+ truthy returns the second operand.
239
+ E.g. `false and true; // => false`
240
+ `true and nil; // => nil`
241
+ `0 and true and ""; // => ""`
242
+ - `or`: When both operands are booleans, then returns `true` if left or right operands are truthy, otherwise `false`.
243
+ If at least one operand isn't a boolean then returns first truthy operand else (both operands are truthy) returns the second operand.
244
+ E.g. `false or true; // => true`
245
+ `true or nil; // => nil`
246
+ `false or nil; // => nil`
247
+ `0 or true or ""; // => 0`
248
+ - `!`: Performs a logical negation on its operand
249
+ E.g. `!false; // => true`
250
+ `!!true; // => true`
251
+ `!0; // => false`
252
+
253
+ #### Grouping expressions
254
+ Use parentheses `(` `)` for a better control in expression/operator precedence.
255
+
256
+ ``` javascript
257
+ print 3 + 4 * 5; // => 23
258
+ print (3 + 4) * 5; // => 35
259
+ ```
260
+
261
+ #### Variable declarations
262
+ ``` javascript
263
+ var iAmAVariable = "my-initial-value";
264
+ var iAmNil; // __Lox__ initializes variables to nil by default;
265
+ ```
202
266
 
203
- ### Implemented statements
204
- Loxxy implements the following statements:
205
- - Expressions (see above sub-section)
206
- - Print statement
267
+ Warning: current version cannot retrieve the value of a variable.
268
+ Expect this capability to be implemented in the coming days.
269
+
270
+
271
+ #### If statement
272
+
273
+ Based on a given condition, an if statement executes one of two statements:
274
+ ``` javascript
275
+ if (condition) {
276
+ print "then-branch";
277
+ } else {
278
+ print "else-branch";
279
+ }
280
+ ```
281
+
282
+ As for other languages, the `else` part is optional.
283
+ ##### Warning: nested `if`...`else`
284
+ Call it a bug ... Nested `if` `else` control flow structure aren't yet supported by __Loxxy__.
285
+ The culprit has a name: [the dangling else](https://en.wikipedia.org/wiki/Dangling_else).
286
+
287
+ The problem in a nutshell: in a nested if ... else ... statement like this:
288
+ ``` javascript
289
+ 'if (true) if (false) print "bad"; else print "good";
290
+ ```
291
+ ... there is an ambiguity. Indeed, according to the __Lox__ grammar, the `else` could be bound
292
+ either to the first `if` or to the second one.
293
+ This ambiguity is usually lifted by applying an ad-hoc rule: an `else` is aways bound to the most
294
+ recent (rightmost) `if`.
295
+ Being a generic parsing library, `Rley` doesn't apply any of these supplemental rules.
296
+ As a consequence,it complains about the found ambiguity and stops the parsing...
297
+ Although `Rley` can cope with ambiguities, this requires the use of an advanced data structure
298
+ called `Shared Packed Parse Forest (SPPF)`.
299
+ SPPF are much more complex to handle than the `common` parse trees present in most compiler or interpreter books.
300
+ Therefore, a future version of `Rley` will incorporate the capability to define disambuiguation rules.
301
+
302
+ In the meantime, the `Loxxy` will progress on other __Lox__ features like:
303
+ - Variables,
304
+ - Block structures...
305
+
306
+
307
+ #### Print Statement
308
+
309
+ The statement print + expression + ; prints the result of the expression to stdout.
310
+
311
+ ``` javascript
312
+ print "Hello, world!"; // Output: Hello, world!
207
313
 
208
- ```javascript
209
- // Print statement with nested concatenation
210
- print "Hello" + ", " + "world!";
211
314
  ```
212
315
 
213
316
  ## Installation
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lox_print_stmt'
4
3
  require_relative 'lox_literal_expr'
5
4
  require_relative 'lox_noop_expr'
5
+ require_relative 'lox_grouping_expr'
6
+ require_relative 'lox_unary_expr'
7
+ require_relative 'lox_binary_expr'
8
+ require_relative 'lox_logical_expr'
9
+ require_relative 'lox_print_stmt'
10
+ require_relative 'lox_if_stmt'
11
+ require_relative 'lox_var_stmt'
@@ -15,7 +15,6 @@ module Loxxy
15
15
  # @return [Hash{String => String}]
16
16
  Name2special = {
17
17
  'AND' => 'and',
18
- 'BANG' => '!',
19
18
  'BANG_EQUAL' => '!=',
20
19
  'COMMA' => ',',
21
20
  'DOT' => '.',
@@ -36,6 +35,11 @@ module Loxxy
36
35
  'SLASH' => '/',
37
36
  'STAR' => '*'
38
37
  }.freeze
38
+
39
+ Name2unary = {
40
+ 'BANG' => '!',
41
+ 'MINUS' => '-@'
42
+ }.freeze
39
43
  end # defined
40
44
 
41
45
  attr_reader :strict
@@ -92,6 +96,17 @@ module Loxxy
92
96
  node
93
97
  end
94
98
 
99
+ def reduce_logical_expr(_production, _range, tokens, theChildren)
100
+ operand1 = theChildren[0]
101
+
102
+ # Second child is array with couples [operator, operand2]
103
+ theChildren[1].each do |(operator, operand2)|
104
+ operand1 = LoxLogicalExpr.new(tokens[0].position, operator, operand1, operand2)
105
+ end
106
+
107
+ operand1
108
+ end
109
+
95
110
  # rule('lhs' => 'nonterm_i nonterm_k_plus')
96
111
  def reduce_binary_operator(_production, _range, tokens, theChildren)
97
112
  operand1 = theChildren[0]
@@ -119,6 +134,11 @@ module Loxxy
119
134
  [[operator, operand2]]
120
135
  end
121
136
 
137
+ # Return the AST node corresponding to the second symbol in the rhs
138
+ def reduce_keep_symbol2(_production, _range, _tokens, theChildren)
139
+ theChildren[1]
140
+ end
141
+
122
142
  #####################################
123
143
  # SEMANTIC ACTIONS
124
144
  #####################################
@@ -138,6 +158,27 @@ module Loxxy
138
158
  return_first_child(range, tokens, theChildren) # Discard the semicolon
139
159
  end
140
160
 
161
+ # rule('varDecl' => 'VAR IDENTIFIER SEMICOLON')
162
+ def reduce_var_declaration(_production, _range, tokens, theChildren)
163
+ var_name = theChildren[1].token.lexeme.dup
164
+ Ast::LoxVarStmt.new(tokens[1].position, var_name, nil)
165
+ end
166
+
167
+ # rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON')
168
+ def reduce_var_initialization(_production, _range, tokens, theChildren)
169
+ var_name = theChildren[1].token.lexeme.dup
170
+ Ast::LoxVarStmt.new(tokens[1].position, var_name, theChildren[3])
171
+ end
172
+
173
+
174
+ # rule('ifStmt' => 'IF ifCondition statement elsePart_opt')
175
+ def reduce_if_stmt(_production, _range, tokens, theChildren)
176
+ condition = theChildren[1]
177
+ then_stmt = theChildren[2]
178
+ else_stmt = theChildren[3]
179
+ LoxIfStmt.new(tokens[0].position, condition, then_stmt, else_stmt)
180
+ end
181
+
141
182
  # rule('printStmt' => 'PRINT expression SEMICOLON')
142
183
  def reduce_print_stmt(_production, _range, tokens, theChildren)
143
184
  Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
@@ -145,7 +186,7 @@ module Loxxy
145
186
 
146
187
  # rule('logic_or' => 'logic_and disjunct_plus')
147
188
  def reduce_logic_or_plus(production, range, tokens, theChildren)
148
- reduce_binary_operator(production, range, tokens, theChildren)
189
+ reduce_logical_expr(production, range, tokens, theChildren)
149
190
  end
150
191
 
151
192
  # rule('disjunct_plus' => 'disjunct_plus OR logic_and')
@@ -160,7 +201,7 @@ module Loxxy
160
201
 
161
202
  # rule('logic_and' => 'equality conjunct_plus')
162
203
  def reduce_logic_and_plus(production, range, tokens, theChildren)
163
- reduce_binary_operator(production, range, tokens, theChildren)
204
+ reduce_logical_expr(production, range, tokens, theChildren)
164
205
  end
165
206
 
166
207
  # rule('conjunct_plus' => 'conjunct_plus AND equality')
@@ -231,6 +272,19 @@ module Loxxy
231
272
  reduce_binary_plus_end(production, range, tokens, theChildren)
232
273
  end
233
274
 
275
+ # rule('unary' => 'unaryOp unary')
276
+ def reduce_unary_expr(_production, _range, tokens, theChildren)
277
+ operator = Name2unary[theChildren[0].symbol.name].to_sym
278
+ operand = theChildren[1]
279
+ LoxUnaryExpr.new(tokens[0].position, operator, operand)
280
+ end
281
+
282
+ # rule('primary' => 'LEFT_PAREN expression RIGHT_PAREN')
283
+ def reduce_grouping_expr(_production, _range, tokens, theChildren)
284
+ subexpr = theChildren[1]
285
+ LoxGroupingExpr.new(tokens[0].position, subexpr)
286
+ end
287
+
234
288
  # rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
235
289
  def reduce_literal_expr(_production, _range, _tokens, theChildren)
236
290
  first_child = theChildren.first