loxxy 0.0.28 → 0.1.04

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: 6b9202e7a755cffecb3226da5764a3cb6f75fd3179803eb25779ae42822bbf15
4
- data.tar.gz: 49767873134c5c124aab3e6b20a49c60f968df180dfd6e945f3da2808eee59c7
3
+ metadata.gz: 16614a276ddf1553d4373e5da9ab78d7f03f2fc8cadec6190c28bb27bdd95b99
4
+ data.tar.gz: 98903f6ec0c9e010fd429f6b1753b34f52b4cfc67c7eafd21b1103c6ac429bba
5
5
  SHA512:
6
- metadata.gz: 29c481015e414ea71eb55c0b4dcc4d793b011a8f16fa7f9218ec704b2baea820e47ba758ba9a2e30e5bdfe08bfd2ad8fa892e6d67e247938b8bcda7b005ff2a9
7
- data.tar.gz: cbf671e54aa98e799b6d565cac52fb19fb3f5d7b3ae84841f27067ae427e5a7c25a7d40a07d39645150f73176709fbcc6e3bbf36e9cada14d8b329f335c621d5
6
+ metadata.gz: 8278546ef246d8f4d5db72b18d5c91dfa3dc1d7f18f81b7491ca01df38a64495a3b5eb26df0fa18b652f59d56784efb8fe9348b5b65d091aa27a09e6b8f144a4
7
+ data.tar.gz: deaa7b43f225788b9366610572f5994eec8950a8e66c8159b83a18b874139d322270f274c4753dc28b6926b7c295d42a2f77600211dfbd0df0e24b82e1a155b5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,82 @@
1
+ ## [0.1.04] - 2021-02-28
2
+
3
+ ### Added
4
+ - Class `Ast::LoxReturnStmt` a node that represents a return statement
5
+ - Method `Ast::ASTBuilder#reduce_return_stmt`
6
+ - Method `Ast::ASTVisitor#visit_return_stmt` for visiting an `Ast::LoxReturnStmt` node
7
+ - Method `BackEnd::Engine#after_return_stmt` to handle return statement
8
+ - Method `BackEnd::Function#!` implementing the logical negation of a function (as value).
9
+ - Test suite for logical operators (in project repository)
10
+ - Test suite for block code
11
+ - Test suite for call and function declaration (initial)
12
+
13
+ ### Changed
14
+ - Method `BackEnd::Engine#after_call_expr` now generate a `catch` and `throw` events
15
+
16
+ ## [0.1.03] - 2021-02-26
17
+ - Runtime argument checking for arithmetic and comparison operators
18
+
19
+ ### Added
20
+ - Test suite for arithmetic and comparison operators (in project repository)
21
+ - Class `BackEnd::UnaryOperator`: runtime argument validation
22
+ - Class `BackEnd::BinaryOperator`: runtime argument validation
23
+
24
+ ### Changed
25
+ - File `console` renamed to `loxxy`. Very basic command-line interface.
26
+ - Custom exception classes
27
+ - File `README.md` updated list of supported `Lox` keywords.
28
+
29
+
30
+ ## [0.1.02] - 2021-02-21
31
+ - Function definition and call documented in `README.md`
32
+
33
+ ### Changed
34
+ - File `README.md` updated description of function definition and function call.
35
+
36
+ ### Fixed
37
+ - Method `BackEnd::Engine#after_print_stmt` now handles of empty stack or nil data.
38
+ - Method `BackEnd::Engine#after_call_expr` was pushing one spurious item onto data stack.
39
+
40
+ ## [0.1.01] - 2021-02-20
41
+ ### Fixed
42
+ - Fixed most offences for Rubocop.
43
+
44
+
45
+ ## [0.1.00] - 2021-02-20
46
+ - Version number bumped, `Loxxy` supports function definitions
47
+
48
+ ### Added
49
+ - Class `Ast::LoxFunStmt` a node that represents a function declaration
50
+ - Method `Ast::ASTBuilder#reduce_fun_decl`
51
+ - Method `Ast::ASTBuilder#reduce_function` creates a `LoxFunStmt` instance
52
+ - Method `Ast::ASTBuilder#reduce_parameters_plus_more` for dealing with function parameters
53
+ - Method `Ast::ASTBuilder#reduce_parameters_plus_end`
54
+ - Method `Ast::ASTVisitor#visit_fun_stmt` for visiting an `Ast::LoxFunStmt` node
55
+ - Method `Ast::LoxBlockStmt#empty?` returns true if the code block is empty
56
+ - Method `BackEnd::Engine#after_fun_stmt`
57
+ - Method `Backend::NativeFunction#call`
58
+ - Method `Backend::NativeFunction#to_str`
59
+ - Method `Backend::Function` implementation of a function object.
60
+
61
+ ### Changed
62
+ - Method `BackEnd::Engine#after_call_expr`
63
+
64
+ ### Fixed
65
+ - Fixed inconsistencies in documentation comments.
66
+
67
+ ## [0.0.28] - 2021-02-15
68
+ - The interpreter implements function calls (to a native function).
69
+
70
+ ### Added
71
+ - Class `Ast::LoxCallExpr` a node that represents a function call expression
72
+ - Method `Ast::ASTBuilder#reduce_call_expr`
73
+ - Method `Ast::ASTBuilder#reduce_refinement_plus_end`
74
+ - Method `Ast::ASTBuilder#reduce_call_arglist` creates a `LoxCallExpr` node
75
+ - Method `Ast::ASTBuilder#reduce_arguments_plus_more` builds the function argument array
76
+ - Method `Ast::ASTVisitor#visit_call_expr` for visiting an `Ast::LoxCallExpr` node
77
+ - Method `BackEnd::Engine#after_call_expr`implements the evaluation of a function call.
78
+ - Method `BackEnd::Engine#after_for_stmt` implements most of the `for` control flow
79
+
1
80
  ## [0.0.27] - 2021-01-24
2
81
  - The interpreter implements `while` loops.
3
82
 
@@ -157,11 +236,11 @@
157
236
  - The interpreter can evaluate substraction between two numbers.
158
237
 
159
238
  ### Added
160
- - Method `Datatype::Number#-` implmenting the subtraction operation
239
+ - Method `Datatype::Number#-` implementing the subtraction operation
161
240
 
162
241
  ### Changed
163
242
  - File `README.md` minor editorial changes.
164
- - File `lx_string_spec.rb` Added test for string concatentation
243
+ - File `lx_string_spec.rb` Added test for string concatenation
165
244
  - File `number_spec.rb` Added tests for addition and subtraction operations
166
245
  - File `interpreter_spec.rb` Added tests for subtraction operation
167
246
 
data/README.md CHANGED
@@ -14,14 +14,13 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
14
14
 
15
15
  ### Current status
16
16
  The project is still in inception and the interpreter is being implemented...
17
- Currently it can execute all allowed __Lox__ expressions and statement except:
18
- - Functions and closures,
17
+ Currently it can execute all allowed __Lox__ expressions and statements except:
18
+ - Closures,
19
19
  - Classes and objects.
20
20
 
21
21
  These will be implemented soon.
22
22
 
23
23
 
24
-
25
24
  ## What's the fuss about Lox?
26
25
  ... Nothing...
27
26
  Bob Nystrom designed a language __simple__ enough so that he could present
@@ -36,11 +35,11 @@ Although __Lox__ is fairly simple, it is far from a toy language:
36
35
  - Functions and closures
37
36
  - Object-orientation (classes, methods, inheritance).
38
37
 
39
- In other words, __Lox__ contains interesting features expected from most general-purpose
38
+ In other words, __Lox__ contains interesting features found in most general-purpose
40
39
  languages.
41
40
 
42
41
  ### What's missing in Lox?
43
- __Lox__ was constrained by design and therefore was not aimed to be a language used in real-world applications.
42
+ __Lox__ was constrained by design and was therefore not aimed to be a language used in real-world applications.
44
43
  Here are some missing parts to make it a _practical_ language:
45
44
  - Collections (arrays, maps, ...)
46
45
  - Modules (importing stuff from other packages/files)
@@ -70,6 +69,23 @@ lox = Loxxy::Interpreter.new
70
69
  lox.evaluate(lox_program) # Output: Hello, world!
71
70
  ```
72
71
 
72
+ ## A function definition example
73
+ ```ruby
74
+ require 'loxxy'
75
+
76
+ lox_program = <<LOX_END
77
+ fun add4(n) {
78
+ n + 4;
79
+ }
80
+
81
+ print add4(6); // Output: 10
82
+ LOX_END
83
+
84
+ lox = Loxxy::Interpreter.new
85
+ lox.evaluate(lox_program) # Output 10
86
+ ```
87
+
88
+
73
89
  ## Retrieving the result from a Lox program
74
90
  The __Loxxy__ interpreter returns the value of the last evaluated expression.
75
91
 
@@ -151,6 +167,7 @@ Here are the language features currently supported by the interpreter:
151
167
  - [Print Statement](#print-statement)
152
168
  - [While Statement](#while-statement)
153
169
  - [Block Statement](#block-statement)
170
+ - [Function declaration](#func-statement)
154
171
 
155
172
  ### Comments
156
173
 
@@ -163,7 +180,8 @@ Loxxy supports single line C-style comments.
163
180
  ### Keywords
164
181
  Loxxy implements the following __Lox__ reserved keywords:
165
182
  ```lang-none
166
- and, false, nil, or, print, true
183
+ and, else, false, for, fun, if,
184
+ nil, or, print, true, var, while
167
185
  ```
168
186
 
169
187
  ### Datatypes
@@ -177,19 +195,21 @@ loxxy supports all the standard __Lox__ datatypes:
177
195
  ### Statements
178
196
 
179
197
  Loxxy supports the following statements:
180
- - [Expressions](#expressions)
198
+ - [Expressions](#expressions)
181
199
  -[Arithmetic expressions](#arithmetic-expressions)
182
200
  -[String concatenation](#string-concatenation)
183
201
  -[Comparison expressions](#comparison-expressions)
184
202
  -[Logical expressions](#logical-expressions)
185
203
  -[Grouping expressions](#grouping-expressions)
186
- -[Variable expressions and assignments](#variable-expressions)
187
-
204
+ -[Variable expressions and assignments](#variable-expressions)
205
+ -[Function call](#function-call)
206
+
188
207
  -[Variable declarations](#var-statement)
189
208
  -[If Statement](#if-statement)
190
209
  -[Print Statement](#print-statement)
191
- -[While Statement](#while-statement)
192
- -[Block Statement](#block-statement)
210
+ -[While Statement](#while-statement)
211
+ -[Block Statement](#block-statement)
212
+ -[Function Declaration](#function-declaration)
193
213
 
194
214
  #### Expressions
195
215
 
@@ -284,6 +304,15 @@ var iAmNil; // __Lox__ initializes variables to nil by default;
284
304
  print iAmNil; // output: nil
285
305
  ```
286
306
 
307
+ #### Function call
308
+ ``` javascript
309
+ // Calling a function without argument
310
+ print clock();
311
+
312
+ // Assumption: there exists a function `add` that takes two arguments
313
+ print add(2, 3);
314
+ ```
315
+
287
316
  #### For statement
288
317
 
289
318
  Similar to the `for` statement in `C` language
@@ -362,6 +391,19 @@ var a = "outer";
362
391
  print a; // output: outer
363
392
  ```
364
393
 
394
+ #### Function Declaration
395
+ The keyword `fun` is used to begin a function declaration.
396
+ In __Lox__ a function has a name and a body (which may be empty).
397
+
398
+ ``` javascript
399
+ fun add4(n) // `add4` will be the name of the function
400
+ {
401
+ n + 4;
402
+ }
403
+
404
+ print add4(6); // output: 10
405
+ ```
406
+
365
407
  ## Installation
366
408
 
367
409
  Add this line to your application's Gemfile:
data/bin/loxxy ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'loxxy'
5
+
6
+ if ARGV[0]
7
+ lox = Loxxy::Interpreter.new
8
+ File.open(ARGV[0], 'r') do |f|
9
+ lox.evaluate(f.read)
10
+ end
11
+ end
data/lib/loxxy.rb CHANGED
@@ -6,8 +6,6 @@ require_relative 'loxxy/front_end/raw_parser'
6
6
 
7
7
  # Namespace for all classes and constants of __loxxy__ gem.
8
8
  module Loxxy
9
- class Error < StandardError; end
10
-
11
9
  # Shorthand method. Returns the sole object that represents
12
10
  # a Lox false literal.
13
11
  # @return [Loxxy::Datatype::False]
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'lox_fun_stmt'
3
4
  require_relative 'lox_variable_expr'
4
5
  require_relative 'lox_literal_expr'
5
6
  require_relative 'lox_noop_expr'
@@ -11,6 +12,7 @@ require_relative 'lox_logical_expr'
11
12
  require_relative 'lox_assign_expr'
12
13
  require_relative 'lox_block_stmt'
13
14
  require_relative 'lox_while_stmt'
15
+ require_relative 'lox_return_stmt'
14
16
  require_relative 'lox_print_stmt'
15
17
  require_relative 'lox_if_stmt'
16
18
  require_relative 'lox_for_stmt'
@@ -163,6 +163,11 @@ module Loxxy
163
163
  [theChildren[0]]
164
164
  end
165
165
 
166
+ # rule('funDecl' => 'FUN function')
167
+ def reduce_fun_decl(_production, _range, _tokens, theChildren)
168
+ theChildren[1]
169
+ end
170
+
166
171
  # rule('exprStmt' => 'expression SEMICOLON')
167
172
  def reduce_exprStmt(_production, range, tokens, theChildren)
168
173
  return_first_child(range, tokens, theChildren) # Discard the semicolon
@@ -216,6 +221,11 @@ module Loxxy
216
221
  Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
217
222
  end
218
223
 
224
+ # rule('returnStmt' => 'RETURN expression_opt SEMICOLON')
225
+ def reduce_return_stmt(_production, _range, tokens, theChildren)
226
+ Ast::LoxReturnStmt.new(tokens[1].position, theChildren[1])
227
+ end
228
+
219
229
  # rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement').as ''
220
230
  def reduce_while_stmt(_production, _range, tokens, theChildren)
221
231
  Ast::LoxWhileStmt.new(tokens[1].position, theChildren[2], theChildren[4])
@@ -227,6 +237,11 @@ module Loxxy
227
237
  Ast::LoxBlockStmt.new(tokens[1].position, decls)
228
238
  end
229
239
 
240
+ # rule('block' => 'LEFT_BRACE RIGHT_BRACE').as 'block_empty'
241
+ def reduce_block_empty(_production, _range, tokens, _children)
242
+ Ast::LoxBlockStmt.new(tokens[0].position, nil)
243
+ end
244
+
230
245
  # rule('assignment' => 'owner_opt IDENTIFIER EQUAL assignment')
231
246
  def reduce_assign_expr(_production, _range, tokens, theChildren)
232
247
  var_name = theChildren[1].token.lexeme.dup
@@ -284,6 +299,23 @@ module Loxxy
284
299
  LoxVariableExpr.new(tokens[0].position, var_name)
285
300
  end
286
301
 
302
+ # rule('function' => 'IDENTIFIER LEFT_PAREN params_opt RIGHT_PAREN block').as 'function'
303
+ def reduce_function(_production, _range, _tokens, theChildren)
304
+ first_child = theChildren.first
305
+ pos = first_child.token.position
306
+ LoxFunStmt.new(pos, first_child.token.lexeme, theChildren[2], theChildren[4])
307
+ end
308
+
309
+ # rule('parameters' => 'parameters COMMA IDENTIFIER')
310
+ def reduce_parameters_plus_more(_production, _range, _tokens, theChildren)
311
+ theChildren[0] << theChildren[2].token.lexeme
312
+ end
313
+
314
+ # rule('parameters' => 'IDENTIFIER')
315
+ def reduce_parameters_plus_end(_production, _range, _tokens, theChildren)
316
+ [theChildren[0].token.lexeme]
317
+ end
318
+
287
319
  # rule('arguments' => 'arguments COMMA expression')
288
320
  def reduce_arguments_plus_more(_production, _range, _tokens, theChildren)
289
321
  theChildren[0] << theChildren[2]
@@ -12,7 +12,7 @@ module Loxxy
12
12
  # attr_reader(:runtime)
13
13
 
14
14
  # Build a visitor for the given top.
15
- # @param aRoot [AST::LoxNode] the parse tree to visit.
15
+ # @param aTop [AST::LoxNode] the parse tree to visit.
16
16
  def initialize(aTop)
17
17
  raise StandardError if aTop.nil?
18
18
 
@@ -52,7 +52,7 @@ module Loxxy
52
52
  end
53
53
 
54
54
  # Visit event. The visitor is about to visit a variable declaration statement.
55
- # @param aPrintStmt [AST::LOXVarStmt] the variable declaration node to visit
55
+ # @param aSeqDecls [AST::LOXSeqDecl] the variable declaration node to visit
56
56
  def visit_seq_decl(aSeqDecls)
57
57
  broadcast(:before_seq_decl, aSeqDecls)
58
58
  traverse_subnodes(aSeqDecls)
@@ -60,7 +60,7 @@ module Loxxy
60
60
  end
61
61
 
62
62
  # Visit event. The visitor is about to visit a variable declaration statement.
63
- # @param aPrintStmt [AST::LOXVarStmt] the variable declaration node to visit
63
+ # @param aVarStmt [AST::LOXVarStmt] the variable declaration node to visit
64
64
  def visit_var_stmt(aVarStmt)
65
65
  broadcast(:before_var_stmt, aVarStmt)
66
66
  traverse_subnodes(aVarStmt)
@@ -91,6 +91,14 @@ module Loxxy
91
91
  broadcast(:after_print_stmt, aPrintStmt)
92
92
  end
93
93
 
94
+ # Visit event. The visitor is about to visit a return statement.
95
+ # @param aReturnStmt [AST::LOXReturnStmt] the return statement node to visit
96
+ def visit_return_stmt(aReturnStmt)
97
+ broadcast(:before_return_stmt, aReturnStmt)
98
+ traverse_subnodes(aReturnStmt)
99
+ broadcast(:after_return_stmt, aReturnStmt, self)
100
+ end
101
+
94
102
  # Visit event. The visitor is about to visit a while statement node.
95
103
  # @param aWhileStmt [AST::LOXWhileStmt] the while statement node to visit
96
104
  def visit_while_stmt(aWhileStmt)
@@ -103,12 +111,12 @@ module Loxxy
103
111
  # @param aBlockStmt [AST::LOXBlockStmt] the print statement node to visit
104
112
  def visit_block_stmt(aBlockStmt)
105
113
  broadcast(:before_block_stmt, aBlockStmt)
106
- traverse_subnodes(aBlockStmt)
114
+ traverse_subnodes(aBlockStmt) unless aBlockStmt.empty?
107
115
  broadcast(:after_block_stmt, aBlockStmt)
108
116
  end
109
117
 
110
118
  # Visit event. The visitor is visiting an assignment node
111
- # @param aLiteralExpr [AST::LoxAssignExpr] the variable assignment node to visit.
119
+ # @param anAssignExpr [AST::LoxAssignExpr] the variable assignment node to visit.
112
120
  def visit_assign_expr(anAssignExpr)
113
121
  broadcast(:before_assign_expr, anAssignExpr)
114
122
  traverse_subnodes(anAssignExpr)
@@ -118,7 +126,7 @@ module Loxxy
118
126
  # Visit event. The visitor is about to visit a logical expression.
119
127
  # Since logical expressions may take shorcuts by not evaluating all their
120
128
  # sub-expressiosns, they are responsible for visiting or not their children.
121
- # @param aBinaryExpr [AST::LOXBinaryExpr] the logical expression node to visit
129
+ # @param aLogicalExpr [AST::LOXLogicalExpr] the logical expression node to visit
122
130
  def visit_logical_expr(aLogicalExpr)
123
131
  broadcast(:before_logical_expr, aLogicalExpr)
124
132
 
@@ -170,25 +178,33 @@ module Loxxy
170
178
  end
171
179
 
172
180
  # Visit event. The visitor is visiting a variable usage node
173
- # @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
181
+ # @param aVariableExpr [AST::LoxVariableExpr] the variable reference node to visit.
174
182
  def visit_variable_expr(aVariableExpr)
175
183
  broadcast(:before_variable_expr, aVariableExpr)
176
184
  broadcast(:after_variable_expr, aVariableExpr, self)
177
185
  end
178
186
 
179
187
  # Visit event. The visitor is about to visit the given terminal datatype value.
180
- # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
188
+ # @param aValue [Ast::BuiltinDattype] the built-in datatype value
181
189
  def visit_builtin(aValue)
182
190
  broadcast(:before_visit_builtin, aValue)
183
191
  broadcast(:after_visit_builtin, aValue)
184
192
  end
185
193
 
194
+ # Visit event. The visitor is about to visit a function statement node.
195
+ # @param aFunStmt [AST::LoxFunStmt] function declaration to visit
196
+ def visit_fun_stmt(aFunStmt)
197
+ broadcast(:before_fun_stmt, aFunStmt)
198
+ traverse_subnodes(aFunStmt)
199
+ broadcast(:after_fun_stmt, aFunStmt, self)
200
+ end
201
+
186
202
  # Visit event. The visitor is about to visit the given non terminal node.
187
203
  # @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
188
- def visit_nonterminal(non_terminal_node)
204
+ def visit_nonterminal(aNonTerminalNode)
189
205
  # Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
190
206
  # that it cannot handle.
191
- symb = non_terminal_node.symbol.name
207
+ symb = aNonTerminalNode.symbol.name
192
208
  msg = "Loxxy cannot execute this code yet for non-terminal symbol '#{symb}'."
193
209
  raise NotImplementedError, msg
194
210
  end
@@ -6,11 +6,15 @@ module Loxxy
6
6
  module Ast
7
7
  class LoxBlockStmt < LoxCompoundExpr
8
8
  # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
9
- # @param operand [Loxxy::Ast::LoxSeqDecl]
9
+ # @param decls [Loxxy::Ast::LoxSeqDecl]
10
10
  def initialize(aPosition, decls)
11
11
  super(aPosition, [decls])
12
12
  end
13
13
 
14
+ def empty?
15
+ subnodes.size == 1 && subnodes[0].nil?
16
+ end
17
+
14
18
  # Part of the 'visitee' role in Visitor design pattern.
15
19
  # @param visitor [Ast::ASTVisitor] the visitor
16
20
  def accept(visitor)
@@ -18,7 +18,6 @@ module Loxxy
18
18
  # @param initialization [Loxxy::Ast::LoxNode]
19
19
  # @param testExpr [Loxxy::Ast::LoxNode]
20
20
  # @param updateExpr [Loxxy::Ast::LoxNode]
21
- # @param body [Loxxy::Ast::LoxNode]
22
21
  def initialize(aPosition, initialization, testExpr, updateExpr)
23
22
  child = initialization ? [initialization] : []
24
23
  super(aPosition, child)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_compound_expr'
4
+
5
+ module Loxxy
6
+ module Ast
7
+ # rubocop: disable Style/AccessorGrouping
8
+ class LoxFunStmt < LoxCompoundExpr
9
+ attr_reader :name
10
+ attr_reader :params
11
+ attr_reader :body
12
+
13
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
14
+ # @param aName [String]
15
+ # @param arguments [Array<String>]
16
+ # @param body [Ast::LoxBlockStmt]
17
+ def initialize(aPosition, aName, paramList, aBody)
18
+ super(aPosition, [])
19
+ @name = aName
20
+ @params = paramList
21
+ @body = aBody
22
+ end
23
+
24
+ # Part of the 'visitee' role in Visitor design pattern.
25
+ # @param visitor [Ast::ASTVisitor] the visitor
26
+ def accept(visitor)
27
+ visitor.visit_fun_stmt(self)
28
+ end
29
+
30
+ alias operands subnodes
31
+ end # class
32
+ # rubocop: enable Style/AccessorGrouping
33
+ end # module
34
+ end # module
@@ -12,7 +12,9 @@ module Loxxy
12
12
  attr_reader :else_stmt
13
13
 
14
14
  # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
15
- # @param subExpr [Loxxy::Ast::LoxNode]
15
+ # @param condExpr [Loxxy::Ast::LoxNode]
16
+ # @param thenStmt [Loxxy::Ast::LoxNode]
17
+ # @param elseStmt [Loxxy::Ast::LoxNode]
16
18
  def initialize(aPosition, condExpr, thenStmt, elseStmt)
17
19
  super(aPosition, [condExpr])
18
20
  @then_stmt = thenStmt
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_compound_expr'
4
+
5
+ module Loxxy
6
+ module Ast
7
+ class LoxReturnStmt < LoxCompoundExpr
8
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
9
+ # @param anExpression [Ast::LoxNode] expression to return
10
+ def initialize(aPosition, anExpression)
11
+ super(aPosition, [anExpression])
12
+ end
13
+
14
+ # Part of the 'visitee' role in Visitor design pattern.
15
+ # @param visitor [Ast::ASTVisitor] the visitor
16
+ def accept(visitor)
17
+ visitor.visit_return_stmt(self)
18
+ end
19
+ end # class
20
+ end # module
21
+ end # module
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../error'
4
+
5
+ module Loxxy
6
+ module BackEnd
7
+ Signature = Struct.new(:parameter_types)
8
+
9
+ # A Lox binary operator
10
+ class BinaryOperator
11
+ # @return [String] text representation of the operator
12
+ attr_reader :name
13
+
14
+ # @return [Array<Class>]
15
+ attr_reader :signatures
16
+
17
+ # @param aName [String] "name" of operator
18
+ # @param theSignatures [Array<Signature>] allowed signatures
19
+ def initialize(aName, theSignatures)
20
+ @name = aName
21
+ @signatures = theSignatures
22
+ end
23
+
24
+ # rubocop: disable Style/ClassEqualityComparison
25
+ def validate_operands(operand1, operand2)
26
+ compliant = signatures.find do |(type1, type2)|
27
+ next unless operand1.kind_of?(type1)
28
+
29
+ if type2 == :idem
30
+ (operand2.class == operand1.class)
31
+ else
32
+ operand2.kind_of?(type2)
33
+ end
34
+ end
35
+ # rubocop: enable Style/ClassEqualityComparison
36
+
37
+ unless compliant
38
+ err = Loxxy::RuntimeError
39
+ if signatures.size == 1 && signatures[0].last == :idem
40
+ raise err, "Operands must be #{datatype_name(signatures[0].first)}s."
41
+ elsif signatures.size == 2 && signatures.all? { |(_, second)| second == :idem }
42
+ type1 = datatype_name(signatures[0].first)
43
+ type2 = datatype_name(signatures[1].first)
44
+ raise err, "Operands must be two #{type1}s or two #{type2}s."
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def datatype_name(aClass)
52
+ # (?:(?:[^:](?!:|(?<=LX))))+$
53
+ aClass.name.sub(/^.+(?=::)::(?:LX)?/, '').downcase
54
+ end
55
+ end # class
56
+ end # module
57
+ end # module
@@ -2,7 +2,10 @@
2
2
 
3
3
  # Load all the classes implementing AST nodes
4
4
  require_relative '../ast/all_lox_nodes'
5
+ require_relative 'binary_operator'
6
+ require_relative 'function'
5
7
  require_relative 'symbol_table'
8
+ require_relative 'unary_operator'
6
9
 
7
10
  module Loxxy
8
11
  module BackEnd
@@ -16,16 +19,26 @@ module Loxxy
16
19
  # @return [BackEnd::SymbolTable]
17
20
  attr_reader :symbol_table
18
21
 
19
- # @return [Array<Datatype::BuiltinDatatyp>] Stack for the values of expr
22
+ # @return [Array<Datatype::BuiltinDatatype>] Data stack for the expression results
20
23
  attr_reader :stack
21
24
 
25
+ # @return [Hash { Symbol => UnaryOperator}]
26
+ attr_reader :unary_operators
27
+
28
+ # @return [Hash { Symbol => BinaryOperator}]
29
+ attr_reader :binary_operators
30
+
22
31
  # @param theOptions [Hash]
23
32
  def initialize(theOptions)
24
33
  @config = theOptions
25
34
  @ostream = config.include?(:ostream) ? config[:ostream] : $stdout
26
35
  @symbol_table = SymbolTable.new
27
36
  @stack = []
37
+ @unary_operators = {}
38
+ @binary_operators = {}
28
39
 
40
+ init_unary_operators
41
+ init_binary_operators
29
42
  init_globals
30
43
  end
31
44
 
@@ -82,7 +95,11 @@ module Loxxy
82
95
 
83
96
  def after_print_stmt(_printStmt)
84
97
  tos = stack.pop
85
- @ostream.print tos.to_str
98
+ @ostream.print tos ? tos.to_str : 'nil'
99
+ end
100
+
101
+ def after_return_stmt(_returnStmt, _aVisitor)
102
+ throw(:return)
86
103
  end
87
104
 
88
105
  def after_while_stmt(aWhileStmt, aVisitor)
@@ -147,9 +164,11 @@ module Loxxy
147
164
  end
148
165
 
149
166
  def after_binary_expr(aBinaryExpr)
150
- op = aBinaryExpr.operator
151
167
  operand2 = stack.pop
152
168
  operand1 = stack.pop
169
+ op = aBinaryExpr.operator
170
+ operator = binary_operators[op]
171
+ operator.validate_operands(operand1, operand2)
153
172
  if operand1.respond_to?(op)
154
173
  stack.push operand1.send(op, operand2)
155
174
  else
@@ -159,12 +178,14 @@ module Loxxy
159
178
  end
160
179
 
161
180
  def after_unary_expr(anUnaryExpr)
162
- op = anUnaryExpr.operator
163
181
  operand = stack.pop
182
+ op = anUnaryExpr.operator
183
+ operator = unary_operators[op]
184
+ operator.validate_operand(operand)
164
185
  if operand.respond_to?(op)
165
186
  stack.push operand.send(op)
166
187
  else
167
- msg1 = "`#{op}': Unimplemented operator for a #{operand1.class}."
188
+ msg1 = "`#{op}': Unimplemented operator for a #{operand.class}."
168
189
  raise StandardError, msg1
169
190
  end
170
191
  end
@@ -173,11 +194,32 @@ module Loxxy
173
194
  # Evaluate callee part
174
195
  aCallExpr.callee.accept(aVisitor)
175
196
  callee = stack.pop
176
- # TODO: reverse order?
177
- aCallExpr.arguments.each do |arg|
178
- arg.evaluate(aVisitor)
197
+ aCallExpr.arguments.reverse_each { |arg| arg.accept(aVisitor) }
198
+
199
+ case callee
200
+ when NativeFunction
201
+ stack.push callee.call # Pass arguments
202
+ when Function
203
+ new_env = Environment.new(symbol_table.current_env)
204
+ symbol_table.enter_environment(new_env)
205
+ callee.parameters&.each do |param_name|
206
+ local = Variable.new(param_name, stack.pop)
207
+ symbol_table.insert(local)
208
+ end
209
+ catch(:return) do
210
+ callee.call(aVisitor)
211
+ throw(:return)
212
+ end
213
+
214
+ symbol_table.leave_environment
215
+ else
216
+ raise Loxxy::RuntimeError, 'Can only call functions and classes.'
179
217
  end
180
- stack.push callee.call # Pass arguments
218
+ end
219
+
220
+ def complete_call
221
+ callee = ret_stack.pop
222
+ symbol_table.leave_environment if callee.kind_of?(Function)
181
223
  end
182
224
 
183
225
  def after_grouping_expr(_groupingExpr)
@@ -197,17 +239,73 @@ module Loxxy
197
239
  stack.push(literalExpr.literal)
198
240
  end
199
241
 
200
- # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
242
+ # @param aValue [Ast::BuiltinDattype] the built-in datatype value
201
243
  def before_visit_builtin(aValue)
202
244
  stack.push(aValue)
203
245
  end
204
246
 
247
+ def after_fun_stmt(aFunStmt, _visitor)
248
+ function = Function.new(aFunStmt.name, aFunStmt.params, aFunStmt.body, stack)
249
+ new_var = Variable.new(aFunStmt.name, function)
250
+ symbol_table.insert(new_var)
251
+ end
252
+
205
253
  private
206
254
 
207
255
  NativeFunction = Struct.new(:callable, :interp) do
208
256
  def accept(_visitor)
209
- interp.stack.push callable
257
+ interp.stack.push self
258
+ end
259
+
260
+ def call
261
+ callable.call
210
262
  end
263
+
264
+ def to_str
265
+ '<native fn>'
266
+ end
267
+ end
268
+
269
+ def init_unary_operators
270
+ negate_op = UnaryOperator.new('-', [Datatype::Number])
271
+ unary_operators[:-@] = negate_op
272
+
273
+ negation_op = UnaryOperator.new('!', [Datatype::BuiltinDatatype,
274
+ BackEnd::Function])
275
+ unary_operators[:!] = negation_op
276
+ end
277
+
278
+ def init_binary_operators
279
+ plus_op = BinaryOperator.new('+', [[Datatype::Number, :idem],
280
+ [Datatype::LXString, :idem]])
281
+ binary_operators[:+] = plus_op
282
+
283
+ minus_op = BinaryOperator.new('-', [[Datatype::Number, :idem]])
284
+ binary_operators[:-] = minus_op
285
+
286
+ star_op = BinaryOperator.new('*', [[Datatype::Number, :idem]])
287
+ binary_operators[:*] = star_op
288
+
289
+ slash_op = BinaryOperator.new('/', [[Datatype::Number, :idem]])
290
+ binary_operators[:/] = slash_op
291
+
292
+ equal_equal_op = BinaryOperator.new('==', [[Datatype::BuiltinDatatype, Datatype::BuiltinDatatype]])
293
+ binary_operators[:==] = equal_equal_op
294
+
295
+ not_equal_op = BinaryOperator.new('!=', [[Datatype::BuiltinDatatype, Datatype::BuiltinDatatype]])
296
+ binary_operators[:!=] = not_equal_op
297
+
298
+ less_op = BinaryOperator.new('<', [[Datatype::Number, :idem]])
299
+ binary_operators[:<] = less_op
300
+
301
+ less_equal_op = BinaryOperator.new('<=', [[Datatype::Number, :idem]])
302
+ binary_operators[:<=] = less_equal_op
303
+
304
+ greater_op = BinaryOperator.new('>', [[Datatype::Number, :idem]])
305
+ binary_operators[:>] = greater_op
306
+
307
+ greater_equal_op = BinaryOperator.new('>=', [[Datatype::Number, :idem]])
308
+ binary_operators[:>=] = greater_equal_op
211
309
  end
212
310
 
213
311
  def init_globals
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../datatype/all_datatypes'
4
+
5
+ module Loxxy
6
+ module BackEnd
7
+ # rubocop: disable Style/AccessorGrouping
8
+ # Representation of a Lox function.
9
+ # It is a named slot that can be associated with a value at the time.
10
+ class Function
11
+ # @return [String]
12
+ attr_reader :name
13
+
14
+ # @return [Array<>] the parameters
15
+ attr_reader :parameters
16
+ attr_reader :body
17
+ attr_reader :stack
18
+
19
+ # Create a variable with given name and initial value
20
+ # @param aName [String] The name of the variable
21
+ # @param aValue [Datatype::BuiltinDatatype] the initial assigned value
22
+ def initialize(aName, parameterList, aBody, aStack)
23
+ @name = aName.dup
24
+ @parameters = parameterList
25
+ @body = aBody
26
+ @stack = aStack
27
+ end
28
+
29
+ def accept(_visitor)
30
+ stack.push self
31
+ end
32
+
33
+ def call(aVisitor)
34
+ body.empty? ? Datatype::Nil.instance : body.accept(aVisitor)
35
+ end
36
+
37
+ # Logical negation.
38
+ # As a function is a truthy thing, its negation is thus false.
39
+ # @return [Datatype::False]
40
+ def !
41
+ Datatype::False.instance
42
+ end
43
+
44
+ # Text representation of a Lox function
45
+ def to_str
46
+ "<fn #{name}>"
47
+ end
48
+ end # class
49
+ # rubocop: enable Style/AccessorGrouping
50
+ end # module
51
+ end # module
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../error'
4
+
5
+ module Loxxy
6
+ module BackEnd
7
+ # A Lox unary operator
8
+ class UnaryOperator
9
+ # @return [String] text representation of the operator
10
+ attr_reader :name
11
+
12
+ # @return [Array<Class>]
13
+ attr_reader :signatures
14
+
15
+ # @param aName [String] "name" of operator
16
+ # @param theSignatures [Array<Class>] allowed signatures
17
+ def initialize(aName, theSignatures)
18
+ @name = aName
19
+ @signatures = theSignatures
20
+ end
21
+
22
+ def validate_operand(operand1)
23
+ compliant = signatures.find { |some_type| operand1.kind_of?(some_type) }
24
+
25
+ unless compliant
26
+ err = Loxxy::RuntimeError
27
+ # if signatures.size == 1
28
+ raise err, "Operand must be a #{datatype_name(signatures[0])}."
29
+ # end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def datatype_name(aClass)
36
+ # (?:(?:[^:](?!:|(?<=LX))))+$
37
+ aClass.name.sub(/^.+(?=::)::(?:LX)?/, '').downcase
38
+ end
39
+ end # class
40
+ end # module
41
+ end # module
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Loxxy
4
+ # Abstract class. Generalization of Loxxy error classes.
5
+ class Error < StandardError; end
6
+
7
+ # Error occurring while Loxxy executes some invalid Lox code.
8
+ class RuntimeError < Error; end
9
+ end
@@ -44,7 +44,7 @@ module Loxxy
44
44
  rule('function_star' => 'function_star function')
45
45
  rule('function_star' => [])
46
46
 
47
- rule('funDecl' => 'FUN function')
47
+ rule('funDecl' => 'FUN function').as 'fun_decl'
48
48
 
49
49
  rule('varDecl' => 'VAR IDENTIFIER SEMICOLON').as 'var_declaration'
50
50
  rule('varDecl' => 'VAR IDENTIFIER EQUAL expression SEMICOLON').as 'var_initialization'
@@ -74,10 +74,10 @@ module Loxxy
74
74
  rule('elsePart_opt' => [])
75
75
 
76
76
  rule('printStmt' => 'PRINT expression SEMICOLON').as 'print_stmt'
77
- rule('returnStmt' => 'RETURN expression_opt SEMICOLON')
77
+ rule('returnStmt' => 'RETURN expression_opt SEMICOLON').as 'return_stmt'
78
78
  rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement').as 'while_stmt'
79
79
  rule('block' => 'LEFT_BRACE declaration_plus RIGHT_BRACE').as 'block_stmt'
80
- rule('block' => 'LEFT_BRACE RIGHT_BRACE')
80
+ rule('block' => 'LEFT_BRACE RIGHT_BRACE').as 'block_empty'
81
81
 
82
82
  # Expressions: produce values
83
83
  rule('expression_opt' => 'expression')
@@ -142,11 +142,11 @@ module Loxxy
142
142
  rule('primary' => 'SUPER DOT IDENTIFIER')
143
143
 
144
144
  # Utility rules
145
- rule('function' => 'IDENTIFIER LEFT_PAREN params_opt RIGHT_PAREN block')
145
+ rule('function' => 'IDENTIFIER LEFT_PAREN params_opt RIGHT_PAREN block').as 'function'
146
146
  rule('params_opt' => 'parameters')
147
147
  rule('params_opt' => [])
148
- rule('parameters' => 'parameters COMMA IDENTIFIER')
149
- rule('parameters' => 'IDENTIFIER')
148
+ rule('parameters' => 'parameters COMMA IDENTIFIER').as 'parameters_plus_more'
149
+ rule('parameters' => 'IDENTIFIER').as 'parameters_plus_end'
150
150
  rule('arguments_opt' => 'arguments')
151
151
  rule('arguments_opt' => [])
152
152
  rule('arguments' => 'arguments COMMA expression').as 'arguments_plus_more'
@@ -11,7 +11,7 @@ module Loxxy
11
11
 
12
12
  # Constructor.
13
13
  # @param aValue [Datatype::BuiltinDatatype] the Lox data value
14
- # @param theLexeme [String] the lexeme (= piece of text from input)
14
+ # @param aLexeme [String] the lexeme (= piece of text from input)
15
15
  # @param aTerminal [Rley::Syntax::Terminal, String]
16
16
  # The terminal symbol corresponding to the lexeme.
17
17
  # @param aPosition [Rley::Lexical::Position] The position of lexeme
@@ -92,6 +92,7 @@ module Loxxy
92
92
 
93
93
  private
94
94
 
95
+ # rubocop: disable Lint/DuplicateBranch
95
96
  def _next_token
96
97
  skip_intertoken_spaces
97
98
  curr_ch = scanner.peek(1)
@@ -125,6 +126,7 @@ module Loxxy
125
126
 
126
127
  return token
127
128
  end
129
+ # rubocop: enable Lint/DuplicateBranch
128
130
 
129
131
  def build_token(aSymbolName, aLexeme)
130
132
  begin
data/lib/loxxy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.0.28'
4
+ VERSION = '0.1.04'
5
5
  end
data/loxxy.gemspec CHANGED
@@ -46,8 +46,8 @@ Gem::Specification.new do |spec|
46
46
  spec.license = 'MIT'
47
47
  spec.required_ruby_version = '~> 2.4'
48
48
 
49
- spec.bindir = 'exe'
50
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
49
+ spec.bindir = 'bin'
50
+ spec.executables = ['loxxy']
51
51
  spec.require_paths = ['lib']
52
52
 
53
53
  PkgExtending.pkg_files(spec)
@@ -9,6 +9,7 @@ require_relative '../lib/loxxy/interpreter'
9
9
  module Loxxy
10
10
  # This spec contains the bare bones test for the Interpreter class.
11
11
  # The execution of Lox code is tested elsewhere.
12
+ # rubocop: disable Metrics/BlockLength
12
13
  describe Interpreter do
13
14
  let(:sample_cfg) do
14
15
  { ostream: StringIO.new }
@@ -386,18 +387,71 @@ LOX_END
386
387
 
387
388
  it 'should implement nullary function calls' do
388
389
  program = <<-LOX_END
389
- print clock(); // Lox expect the 'clock' predefined native function
390
+ print clock(); // Lox expects the 'clock' predefined native function
390
391
  LOX_END
391
392
  expect { subject.evaluate(program) }.not_to raise_error
392
393
  tick = sample_cfg[:ostream].string
393
394
  expect(Time.now.to_f - tick.to_f).to be < 0.1
394
395
  end
395
396
 
397
+ it 'should implement function definition' do
398
+ program = <<-LOX_END
399
+ fun printSum(a, b) {
400
+ print a + b;
401
+ }
402
+ printSum(1, 2);
403
+ LOX_END
404
+ expect { subject.evaluate(program) }.not_to raise_error
405
+ expect(sample_cfg[:ostream].string).to eq('3')
406
+ end
407
+
408
+ it 'should support functions with empty body' do
409
+ program = <<-LOX_END
410
+ fun f() {}
411
+ print f();
412
+ LOX_END
413
+ expect { subject.evaluate(program) }.not_to raise_error
414
+ expect(sample_cfg[:ostream].string).to eq('nil')
415
+ end
416
+
417
+ it 'should provide print representation of functions' do
418
+ program = <<-LOX_END
419
+ fun foo() {}
420
+ print foo; // output: <fn foo>
421
+ print clock; // output: <native fn>
422
+ LOX_END
423
+ expect { subject.evaluate(program) }.not_to raise_error
424
+ expect(sample_cfg[:ostream].string).to eq('<fn foo><native fn>')
425
+ end
426
+
427
+ it 'should support return statements' do
428
+ program = <<-LOX_END
429
+ fun max(a, b) {
430
+ if (a > b) return a;
431
+
432
+ return b;
433
+ }
434
+
435
+ max(3, 2);
436
+ LOX_END
437
+ result = subject.evaluate(program)
438
+ expect(result).to eq(3)
439
+ end
396
440
 
397
441
  it 'should print the hello world message' do
398
442
  expect { subject.evaluate(hello_world) }.not_to raise_error
399
443
  expect(sample_cfg[:ostream].string).to eq('Hello, world!')
400
444
  end
401
445
  end # context
446
+
447
+ context 'Test suite:' do
448
+ it "should complain if one argument isn't a number" do
449
+ source = '1 + nil;'
450
+ err = Loxxy::RuntimeError
451
+ err_msg = 'Operands must be two numbers or two strings.'
452
+ expect { subject.evaluate(source) }.to raise_error(err, err_msg)
453
+ end
454
+ end # context
402
455
  end # describe
456
+ # rubocop: enable Metrics/BlockLength
403
457
  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.28
4
+ version: 0.1.04
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2021-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -69,7 +69,8 @@ dependencies:
69
69
  description: An implementation of the Lox programming language. WIP
70
70
  email:
71
71
  - famished.tiger@yahoo.com
72
- executables: []
72
+ executables:
73
+ - loxxy
73
74
  extensions: []
74
75
  extra_rdoc_files:
75
76
  - README.md
@@ -83,6 +84,7 @@ files:
83
84
  - LICENSE.txt
84
85
  - README.md
85
86
  - Rakefile
87
+ - bin/loxxy
86
88
  - lib/loxxy.rb
87
89
  - lib/loxxy/ast/all_lox_nodes.rb
88
90
  - lib/loxxy/ast/ast_builder.rb
@@ -93,6 +95,7 @@ files:
93
95
  - lib/loxxy/ast/lox_call_expr.rb
94
96
  - lib/loxxy/ast/lox_compound_expr.rb
95
97
  - lib/loxxy/ast/lox_for_stmt.rb
98
+ - lib/loxxy/ast/lox_fun_stmt.rb
96
99
  - lib/loxxy/ast/lox_grouping_expr.rb
97
100
  - lib/loxxy/ast/lox_if_stmt.rb
98
101
  - lib/loxxy/ast/lox_literal_expr.rb
@@ -100,15 +103,19 @@ files:
100
103
  - lib/loxxy/ast/lox_node.rb
101
104
  - lib/loxxy/ast/lox_noop_expr.rb
102
105
  - lib/loxxy/ast/lox_print_stmt.rb
106
+ - lib/loxxy/ast/lox_return_stmt.rb
103
107
  - lib/loxxy/ast/lox_seq_decl.rb
104
108
  - lib/loxxy/ast/lox_unary_expr.rb
105
109
  - lib/loxxy/ast/lox_var_stmt.rb
106
110
  - lib/loxxy/ast/lox_variable_expr.rb
107
111
  - lib/loxxy/ast/lox_while_stmt.rb
112
+ - lib/loxxy/back_end/binary_operator.rb
108
113
  - lib/loxxy/back_end/engine.rb
109
114
  - lib/loxxy/back_end/entry.rb
110
115
  - lib/loxxy/back_end/environment.rb
116
+ - lib/loxxy/back_end/function.rb
111
117
  - lib/loxxy/back_end/symbol_table.rb
118
+ - lib/loxxy/back_end/unary_operator.rb
112
119
  - lib/loxxy/back_end/variable.rb
113
120
  - lib/loxxy/datatype/all_datatypes.rb
114
121
  - lib/loxxy/datatype/boolean.rb
@@ -118,6 +125,7 @@ files:
118
125
  - lib/loxxy/datatype/nil.rb
119
126
  - lib/loxxy/datatype/number.rb
120
127
  - lib/loxxy/datatype/true.rb
128
+ - lib/loxxy/error.rb
121
129
  - lib/loxxy/front_end/grammar.rb
122
130
  - lib/loxxy/front_end/literal.rb
123
131
  - lib/loxxy/front_end/parser.rb