loxxy 0.0.17 → 0.0.22

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: 6eed6a7de54b89c276b0f098cd7d824f26c0ce9ba957d4fb9e3a4d12e6dfbc4f
4
- data.tar.gz: ba7c00f11c5b69322aec0d447c2fef9cf6d6d74b2ea7bb16096581508a786427
3
+ metadata.gz: acd7b65477866aee4f022731a70f67cad63f482eae6ae5e3f5a35cd56c43f9b0
4
+ data.tar.gz: 4980c1dafbd83c1ed0a41cf5da09d0decba43e912722c5052fc3e4f63626d73a
5
5
  SHA512:
6
- metadata.gz: 1b2c3826f085ce3f723cdbc70c3bdc3563817270985a321db05f97ca1ff81971bf872db49631d3fa20580932f7a0e2910bf3c6c84daf7873cdcd1f04c3392a99
7
- data.tar.gz: 4e3d075facaf9c370d78f3f3ac89b7226e375eb32064535e3401c5ef52b8ca43c9d4c6cfb8f027b4037c7baa7c5945b0fd0dbe1e8b1e580fc732c4a38f7c57c6
6
+ metadata.gz: e8853388df750173e1a9e818e3aac92f33f98ff75cf5c575d0b583758c59938810a593823a73a6914a28413ba697d53147d7317b744484d43b4026c76a182bc4
7
+ data.tar.gz: 3426ce17792625f908f2a31c879b0a312cbefbe18c82848f769d78bcac550d3700349fc1408bbeddb7738b47735ed583fd89355636c8c377a7cde3baf2f5071f
@@ -1,10 +1,69 @@
1
+ ## [0.0.22] - 2021-01-17
2
+ - The interpreter can retrieve the value of a variable.
3
+
4
+ ## Added
5
+ - Method `Ast::ASTBuilder#declaration_plus_more` and `Ast::ASTBuilder#declaration_plus_end` to allow multiple expressions/statements
6
+ - Method `Ast::ASTBuilder#reduce_var_expression` creates an `Ast::LoxVariableExpr` node
7
+ - Method `Ast::ASTVisitor#visit_var_expr` for visiting `Ast::LoxVariableExpr` nodes
8
+ - Class `Ast::LoxSeqDecl` a node that represents a sequence of declarations/statements
9
+ - Class `Ast::LoxVarExpr` a node that represents a variable occurrence in an expression
10
+ - Method `Engine::after_variable_expr`: retrieve the value of variable with given name
11
+
12
+ ## Changed
13
+ - Method `Ast::ASTBuilder#reduce_lox_program` to support multiple statements/declarations
14
+ - File `README.md` updated.
15
+
16
+ ## [0.0.21] - 2021-01-16
17
+ - The interpreter supports the declaration global variables.
18
+
19
+ ## Added
20
+ - Class `BackEnd::Entry`, mixin module for objects put in the symbol table
21
+ - Class `BackEnd::Environment` that keeps track of variables in a given context.
22
+ - Class `BackEnd::SymbolTable` that keeps track of environments.
23
+ - Class `BackEnd::Variable` internal representation of a `Lox` variable
24
+ - Method `Ast::ASTBuilder#reduce_var_declaration` and `Ast::ASTBuilder#reduce_var_declaration`
25
+ - Method `Ast::ASTVisitor#visit_var_stmt` for visiting `LoxVarStmt` nodes
26
+ - Attribute `Engine::symbol_table`for keeping track of variables
27
+ - Method `Engine::after_var_stmt` for the implementation of variable declarations
28
+
29
+ ## [0.0.20] - 2021-01-15
30
+ - The interpreter supports the `if` ... `else` statement.
31
+
32
+ ## Added
33
+ - Class `Ast::LoxItStmt`, AST node specific for `if` `else` statements
34
+ - Method `Ast::ASTBuilder#reduce_if_stmt` as semantic action for if ... else
35
+ - Method `Ast::ASTVisitor#visit_if_stmt` for visiting `LoxIfStmt` nodes
36
+ - Method `Engine::after_if_stmt` implementation of the control flow
37
+
38
+ ## [0.0.19] - 2021-01-14
39
+ - The interpreter supports expressions between parentheses (grouping).
40
+
41
+ ## Added
42
+ - Class `Ast::LoxLogicalExpr`
43
+ - Method `Ast::ASTBuilder#reduce_grouping_expr` as semantic action for grouping expression
44
+ - Method `Ast::ASTVisitor#visit_grouping_expr` for visiting grouping expressions
45
+ - Method `Engine::after_grouping_expr`for the evaluation of grouping expressions
46
+
47
+ ## Changed
48
+ - File `grammar.rb` rules for if ... else were given names in order to activate semantic actions.
49
+ - File `README.md` updated with little `if ... else` documentation.
50
+
51
+ ## [0.0.18] - 2021-01-13
52
+ - The interpreter can evaluate `and`, `or`expressions.
53
+
54
+ ## Added
55
+ - Class `Ast::LoxLogicalExpr`
56
+ - Method `Ast::ASTBuilder#reduce_logical_expr` for the semantic action require for `and`, `or`
57
+ - Method `Ast::ASTVisitor#visit_logical_expr` for visiting logical expressions
58
+ - Method `Backend::Engine#after_logical_expr` implements the evaluation of the logical expressions
59
+
1
60
  ## [0.0.17] - 2021-01-12
2
61
  - The interpreter can evaluate all arithmetic and comparison operations.
3
62
  - It implements `==`, `!=` and the unary operations `!`, `-`
4
63
 
5
64
  ## Added
6
- - Class `AST::LoxUnaryExpr`
7
- - Method `AST::ASTBuilder#reduce_unary_expr` to support the evaluation of `!` and ``-@`
65
+ - Class `Ast::LoxUnaryExpr`
66
+ - Method `Ast::ASTBuilder#reduce_unary_expr` to support the evaluation of `!` and ``-@`
8
67
  - Method `Ast::ASTVisitor#visit_unnary_expr` for visiting unary expressions
9
68
  - Method `Backend::Engine#after_unary_expr` evaluating an unary expression
10
69
  - In class `Datatype::BuiltinDatatype` the methods `falsey?`, `truthy?`, `!`, `!=`
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,36 +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`, `print`, `true`
158
-
159
- ### Operators and Special Chars
160
- #### Operators
161
- The __loxxy__ interpreter supports all the __Lox__ unary and binary operators:
162
- - Arithmetic operators: `+`, `-`, `*`, `/`
163
- - Comparison operators: `>`, `>=`, `<`, `<=`
164
- - Equality operators: `==`, `!=`
165
- - Unary negate (change sign): `-`
166
- - Unary not: `!`
167
-
168
- #### Delimiters
169
- The parser knows all the __Lox__ grouping delimiters:
170
- (`, ), `{`, `}`
171
-
172
- These aren't yet implemented in the interpreter.
173
-
174
- The other characters that have a special meaning in __Lox__ are:
175
- - `,` Used in parameter list
176
- - `.` For the dot notation (i.e. calling a method)
177
- - `;` The semicolon is used to terminates expressions
178
- - `=` Assignment
179
-
180
- The parser recognizes them all but the interpreter accepts the semicolons only.
181
161
 
182
162
  ### Datatypes
183
163
 
@@ -187,24 +167,158 @@ loxxy supports all the standard __Lox__ datatypes:
187
167
  - `String`: Sequence of characters surrounded by `"`. For example: `"Hello!"`
188
168
  - `Nil`: Used to define a null value, denoted by the `nil` keyword
189
169
 
190
- ## Statements
191
- ### Implemented expressions
192
- Loxxy implements expressions:
193
- - Plain literals only; or,
194
- - (In)equality testing between two values; or,
195
- - Basic arithmetic operations (`+`, `-`, `*`, `/`, `unary -`); or,
196
- - Comparison between two numbers; or,
197
- - Concatenation of two strings,
198
- - Negation `!`
199
-
200
- ### Implemented statements
201
- Loxxy implements the following statements:
202
- - Expressions (see above sub-section)
203
- - Print statement
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
+ -[Variable expressions](#variable-expressions)
180
+
181
+ -[Variable declarations](#var-statement)
182
+ -[If Statement](#if-statement)
183
+ -[Print Statement](#print-statement)
184
+
185
+ #### Expressions
186
+
187
+ ##### Arithmetic expressions
188
+ Loxxy supports the following operators for arithmetic expressions:
189
+
190
+ - `+`: Adds of two numbers. Both operands must be of the type Number
191
+ E.g. `37 + 5; // => 42`
192
+ `7 + -3; // => 4`
193
+ - `-`: (Binary) Subtracts right operand from left operand. Both operands must be numbers.
194
+ E.g. `47 - 5; // => 42`
195
+ - `-`: (Unary) Negates (= changes the sign) of the given number operand.
196
+ E.g. `- -3; // => 3`
197
+ - `*`: Multiplies two numbers
198
+ E.g. `2 * 3; // => 6`
199
+ - `/`: Divides two numbers
200
+ E.g. `8 / 2; // => 4`
201
+ `5 / 2; // => 2.5`
202
+
203
+ ##### String concatenation
204
+ - `+`: Concatenates two strings. Both operands must be of the String type.
205
+ E.g. `"Hello" + ", " + "world! // => "Hello, world!"`
206
+
207
+ ##### Comparison expressions
208
+
209
+ - `==`: Returns `true` if left operand is equal to right operand, otherwise `false`
210
+ E.g. `false == false; // => true`
211
+ `5 + 2 == 3 + 4; // => true`
212
+ `"" == ""; // => true`
213
+ - `!=`: Returns `true` if left operand is not equal to right operand, otherwise `false`
214
+ E.g. `false != "false"; // => true`
215
+ `5 + 2 != 4 + 3; // => false`
216
+ - `<`: Returns `true` if left operand is less than right operand, otherwise `false`. Both operands must be numbers
217
+ E.g. `1 < 3; // => true`
218
+ `1 < 0; // => false`
219
+ `2 < 2; // => false`
220
+ - `<=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
221
+ E.g. `1 <= 3; // => true`
222
+ `1 <= 0; // => false`
223
+ `2 <= 2; // => true`
224
+ - `>`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
225
+ E.g. `1 > 3; // => false`
226
+ `1 > 0; // => true`
227
+ `2 > 2; // => false`
228
+ - `>=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
229
+ E.g. `1 > 3; // => false`
230
+ `1 > 0; // => true`
231
+ `2 > 2; // => false`
232
+
233
+ ##### Logical expressions
234
+
235
+ REMINDER: In __Lox__, `false` and `nil` are considered falsey, everything else is truthy.
236
+
237
+ - `and`: When both operands are booleans, then returns `true` if both left and right operands are truthy, otherwise `false`.
238
+ If at least one operand isn't a boolean then returns first falsey operand else (both operands are truthy) returns the second operand.
239
+ truthy returns the second operand.
240
+ E.g. `false and true; // => false`
241
+ `true and nil; // => nil`
242
+ `0 and true and ""; // => ""`
243
+ - `or`: When both operands are booleans, then returns `true` if left or right operands are truthy, otherwise `false`.
244
+ If at least one operand isn't a boolean then returns first truthy operand else (both operands are truthy) returns the second operand.
245
+ E.g. `false or true; // => true`
246
+ `true or nil; // => nil`
247
+ `false or nil; // => nil`
248
+ `0 or true or ""; // => 0`
249
+ - `!`: Performs a logical negation on its operand
250
+ E.g. `!false; // => true`
251
+ `!!true; // => true`
252
+ `!0; // => false`
253
+
254
+ #### Grouping expressions
255
+ Use parentheses `(` `)` for a better control in expression/operator precedence.
256
+
257
+ ``` javascript
258
+ print 3 + 4 * 5; // => 23
259
+ print (3 + 4) * 5; // => 35
260
+ ```
261
+
262
+ #### Variable expressions
263
+ In __Lox__, a variable expression is nothing than retrieving the value of a variable.
264
+ ``` javascript
265
+ var foo = "bar;" // Variable declaration
266
+ foo; // Varible expression (= retrieving its value)
267
+ ```
268
+
269
+ #### Variable declarations
270
+ ``` javascript
271
+ var iAmAVariable = "my-initial-value";
272
+ var iAmNil; // __Lox__ initializes variables to nil by default;
273
+ ```
274
+
275
+ Warning: current version cannot assign a value to an existing variable.
276
+ Expect this capability to be implemented in the coming days.
277
+
278
+
279
+ #### If statement
280
+
281
+ Based on a given condition, an if statement executes one of two statements:
282
+ ``` javascript
283
+ if (condition) {
284
+ print "then-branch";
285
+ } else {
286
+ print "else-branch";
287
+ }
288
+ ```
289
+
290
+ As for other languages, the `else` part is optional.
291
+ ##### Warning: nested `if`...`else`
292
+ Call it a bug ... Nested `if` `else` control flow structure aren't yet supported by __Loxxy__.
293
+ The culprit has a name: [the dangling else](https://en.wikipedia.org/wiki/Dangling_else).
294
+
295
+ The problem in a nutshell: in a nested if ... else ... statement like this:
296
+ ``` javascript
297
+ 'if (true) if (false) print "bad"; else print "good";
298
+ ```
299
+ ... there is an ambiguity. Indeed, according to the __Lox__ grammar, the `else` could be bound
300
+ either to the first `if` or to the second one.
301
+ This ambiguity is usually lifted by applying an ad-hoc rule: an `else` is aways bound to the most
302
+ recent (rightmost) `if`.
303
+ Being a generic parsing library, `Rley` doesn't apply any of these supplemental rules.
304
+ As a consequence,it complains about the found ambiguity and stops the parsing...
305
+ Although `Rley` can cope with ambiguities, this requires the use of an advanced data structure
306
+ called `Shared Packed Parse Forest (SPPF)`.
307
+ SPPF are much more complex to handle than the `common` parse trees present in most compiler or interpreter books.
308
+ Therefore, a future version of `Rley` will incorporate the capability to define disambuiguation rules.
309
+
310
+ In the meantime, the `Loxxy` will progress on other __Lox__ features like:
311
+ - Variables,
312
+ - Block structures...
313
+
314
+
315
+ #### Print Statement
316
+
317
+ The statement print + expression + ; prints the result of the expression to stdout.
318
+
319
+ ``` javascript
320
+ print "Hello, world!"; // Output: Hello, world!
204
321
 
205
- ```javascript
206
- // Print statement with nested string concatenation
207
- print "Hello" + ", " + "world!";
208
322
  ```
209
323
 
210
324
  ## Installation
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'lox_variable_expr'
3
4
  require_relative 'lox_literal_expr'
4
5
  require_relative 'lox_noop_expr'
5
- require_relative 'lox_binary_expr'
6
+ require_relative 'lox_grouping_expr'
6
7
  require_relative 'lox_unary_expr'
8
+ require_relative 'lox_binary_expr'
9
+ require_relative 'lox_logical_expr'
7
10
  require_relative 'lox_print_stmt'
11
+ require_relative 'lox_if_stmt'
12
+ require_relative 'lox_var_stmt'
13
+ require_relative 'lox_seq_decl'
@@ -96,6 +96,17 @@ module Loxxy
96
96
  node
97
97
  end
98
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
+
99
110
  # rule('lhs' => 'nonterm_i nonterm_k_plus')
100
111
  def reduce_binary_operator(_production, _range, tokens, theChildren)
101
112
  operand1 = theChildren[0]
@@ -123,6 +134,11 @@ module Loxxy
123
134
  [[operator, operand2]]
124
135
  end
125
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
+
126
142
  #####################################
127
143
  # SEMANTIC ACTIONS
128
144
  #####################################
@@ -134,7 +150,17 @@ module Loxxy
134
150
 
135
151
  # rule('program' => 'declaration_plus EOF').as ''
136
152
  def reduce_lox_program(_production, range, tokens, theChildren)
137
- return_first_child(range, tokens, theChildren) # Discard the semicolon
153
+ LoxSeqDecl.new(tokens[0].position, theChildren[0])
154
+ end
155
+
156
+ # rule('declaration_plus' => 'declaration_plus declaration').as ''
157
+ def reduce_declaration_plus_more(_production, range, tokens, theChildren)
158
+ theChildren[0] << theChildren[1]
159
+ end
160
+
161
+ # rule('declaration_plus' => 'declaration')
162
+ def reduce_declaration_plus_end(_production, range, tokens, theChildren)
163
+ [ theChildren[0] ]
138
164
  end
139
165
 
140
166
  # rule('exprStmt' => 'expression SEMICOLON')
@@ -142,6 +168,27 @@ module Loxxy
142
168
  return_first_child(range, tokens, theChildren) # Discard the semicolon
143
169
  end
144
170
 
171
+ # rule('varDecl' => 'VAR IDENTIFIER SEMICOLON')
172
+ def reduce_var_declaration(_production, _range, tokens, theChildren)
173
+ var_name = theChildren[1].token.lexeme.dup
174
+ Ast::LoxVarStmt.new(tokens[1].position, var_name, nil)
175
+ end
176
+
177
+ # rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON')
178
+ def reduce_var_initialization(_production, _range, tokens, theChildren)
179
+ var_name = theChildren[1].token.lexeme.dup
180
+ Ast::LoxVarStmt.new(tokens[1].position, var_name, theChildren[3])
181
+ end
182
+
183
+
184
+ # rule('ifStmt' => 'IF ifCondition statement elsePart_opt')
185
+ def reduce_if_stmt(_production, _range, tokens, theChildren)
186
+ condition = theChildren[1]
187
+ then_stmt = theChildren[2]
188
+ else_stmt = theChildren[3]
189
+ LoxIfStmt.new(tokens[0].position, condition, then_stmt, else_stmt)
190
+ end
191
+
145
192
  # rule('printStmt' => 'PRINT expression SEMICOLON')
146
193
  def reduce_print_stmt(_production, _range, tokens, theChildren)
147
194
  Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
@@ -149,7 +196,7 @@ module Loxxy
149
196
 
150
197
  # rule('logic_or' => 'logic_and disjunct_plus')
151
198
  def reduce_logic_or_plus(production, range, tokens, theChildren)
152
- reduce_binary_operator(production, range, tokens, theChildren)
199
+ reduce_logical_expr(production, range, tokens, theChildren)
153
200
  end
154
201
 
155
202
  # rule('disjunct_plus' => 'disjunct_plus OR logic_and')
@@ -164,7 +211,7 @@ module Loxxy
164
211
 
165
212
  # rule('logic_and' => 'equality conjunct_plus')
166
213
  def reduce_logic_and_plus(production, range, tokens, theChildren)
167
- reduce_binary_operator(production, range, tokens, theChildren)
214
+ reduce_logical_expr(production, range, tokens, theChildren)
168
215
  end
169
216
 
170
217
  # rule('conjunct_plus' => 'conjunct_plus AND equality')
@@ -242,6 +289,12 @@ module Loxxy
242
289
  LoxUnaryExpr.new(tokens[0].position, operator, operand)
243
290
  end
244
291
 
292
+ # rule('primary' => 'LEFT_PAREN expression RIGHT_PAREN')
293
+ def reduce_grouping_expr(_production, _range, tokens, theChildren)
294
+ subexpr = theChildren[1]
295
+ LoxGroupingExpr.new(tokens[0].position, subexpr)
296
+ end
297
+
245
298
  # rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
246
299
  def reduce_literal_expr(_production, _range, _tokens, theChildren)
247
300
  first_child = theChildren.first
@@ -249,6 +302,13 @@ module Loxxy
249
302
  literal = first_child.token.value
250
303
  LoxLiteralExpr.new(pos, literal)
251
304
  end
305
+
306
+ # rule('primary' => 'IDENTIFIER')
307
+ def reduce_variable_expr(_production, _range, tokens, theChildren)
308
+ var_name = theChildren[0].token.lexeme
309
+ LoxVariableExpr.new(tokens[0].position, var_name)
310
+ end#
311
+
252
312
  end # class
253
313
  end # module
254
314
  end # module