loxxy 0.0.28 → 0.1.0

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: 42a88690625576399255ae7fadd3ac6aee022fc8d56a8e10c1206b55eca207ab
4
+ data.tar.gz: 4042d268f199763405a264480765bbd5fe7aeaa998eb5e0a4353ae702c3bef2a
5
5
  SHA512:
6
- metadata.gz: 29c481015e414ea71eb55c0b4dcc4d793b011a8f16fa7f9218ec704b2baea820e47ba758ba9a2e30e5bdfe08bfd2ad8fa892e6d67e247938b8bcda7b005ff2a9
7
- data.tar.gz: cbf671e54aa98e799b6d565cac52fb19fb3f5d7b3ae84841f27067ae427e5a7c25a7d40a07d39645150f73176709fbcc6e3bbf36e9cada14d8b329f335c621d5
6
+ metadata.gz: 21a6a82509ead9c0d9f38c6798147dda38c436d87b8800a33ca7027553631866ce4215f2eb90c482f3c5a9b0bb42e99b7868fca888b78fcf7eca67afcd7db756
7
+ data.tar.gz: 71b53af0df630894c0d45639a84f427f34c7b92a5092e07cea16bc3786af666be13b0035a13c07b2910c374c76caa009c3acdbd675f430c8f6e4b7951c2b68a7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## [0.1.00] - 2021-02-20
2
+ - Version number bumped, `Loxxy` supports function definitions
3
+
4
+ ### Added
5
+ - Class `Ast::LoxFunStmt` a node that represents a function declaration
6
+ - Method `Ast::ASTBuilder#reduce_fun_decl`
7
+ - Method `Ast::ASTBuilder#reduce_function` creates a `LoxFunStmt` instance
8
+ - Method `Ast::ASTBuilder#reduce_parameters_plus_more` for dealing with function parameters
9
+ - Method `Ast::ASTBuilder#reduce_parameters_plus_end`
10
+ - Method `Ast::ASTVisitor#visit_fun_stmt` for visiting an `Ast::LoxFunStmt` node
11
+ - Method `Ast::LoxBlockStmt#empty?` returns true if the code block is empty
12
+ - Method `BackEnd::Engine#after_fun_stmt`
13
+ - Method `Backend::NativeFunction#call`
14
+ - Method `Backend::NativeFunction#to_str`
15
+ - Method `Backend::Function` implementation of a function object.
16
+
17
+ ### Changed
18
+ - Method `BackEnd::Engine#after_call_expr`
19
+
20
+ ### Fixed
21
+ - Fixed inconsistencies in documentation comments.
22
+
23
+ ## [0.0.28] - 2021-02-15
24
+ - The interpreter implements function calls (to a native function).
25
+
26
+ ### Added
27
+ - Class `Ast::LoxCallExpr` a node that represents a function call expression
28
+ - Method `Ast::ASTBuilder#reduce_call_expr`
29
+ - Method `Ast::ASTBuilder#reduce_refinement_plus_end`
30
+ - Method `Ast::ASTBuilder#reduce_call_arglist` creates a `LoxCallExpr` node
31
+ - Method `Ast::ASTBuilder#reduce_arguments_plus_more` builds the function argument array
32
+ - Method `Ast::ASTVisitor#visit_call_expr` for visiting an `Ast::LoxCallExpr` node
33
+ - Method `BackEnd::Engine#after_call_expr`implements the evaluation of a function call.
34
+ - Method `BackEnd::Engine#after_for_stmt` implements most of the `for` control flow
35
+
1
36
  ## [0.0.27] - 2021-01-24
2
37
  - The interpreter implements `while` loops.
3
38
 
@@ -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'
@@ -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
@@ -227,6 +232,11 @@ module Loxxy
227
232
  Ast::LoxBlockStmt.new(tokens[1].position, decls)
228
233
  end
229
234
 
235
+ # rule('block' => 'LEFT_BRACE RIGHT_BRACE').as 'block_empty'
236
+ def reduce_block_empty(_production, _range, tokens, theChildren)
237
+ Ast::LoxBlockStmt.new(tokens[0].position, nil)
238
+ end
239
+
230
240
  # rule('assignment' => 'owner_opt IDENTIFIER EQUAL assignment')
231
241
  def reduce_assign_expr(_production, _range, tokens, theChildren)
232
242
  var_name = theChildren[1].token.lexeme.dup
@@ -284,6 +294,23 @@ module Loxxy
284
294
  LoxVariableExpr.new(tokens[0].position, var_name)
285
295
  end
286
296
 
297
+ # rule('function' => 'IDENTIFIER LEFT_PAREN params_opt RIGHT_PAREN block').as 'function'
298
+ def reduce_function(_production, _range, _tokens, theChildren)
299
+ first_child = theChildren.first
300
+ pos = first_child.token.position
301
+ fun_stmt = LoxFunStmt.new(pos, first_child.token.lexeme, theChildren[2], theChildren[4])
302
+ end
303
+
304
+ # rule('parameters' => 'parameters COMMA IDENTIFIER')
305
+ def reduce_parameters_plus_more(_production, _range, _tokens, theChildren)
306
+ theChildren[0] << theChildren[2].token.lexeme
307
+ end
308
+
309
+ # rule('parameters' => 'IDENTIFIER')
310
+ def reduce_parameters_plus_end(_production, _range, _tokens, theChildren)
311
+ [theChildren[0].token.lexeme]
312
+ end
313
+
287
314
  # rule('arguments' => 'arguments COMMA expression')
288
315
  def reduce_arguments_plus_more(_production, _range, _tokens, theChildren)
289
316
  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)
@@ -103,12 +103,12 @@ module Loxxy
103
103
  # @param aBlockStmt [AST::LOXBlockStmt] the print statement node to visit
104
104
  def visit_block_stmt(aBlockStmt)
105
105
  broadcast(:before_block_stmt, aBlockStmt)
106
- traverse_subnodes(aBlockStmt)
106
+ traverse_subnodes(aBlockStmt) unless aBlockStmt.empty?
107
107
  broadcast(:after_block_stmt, aBlockStmt)
108
108
  end
109
109
 
110
110
  # Visit event. The visitor is visiting an assignment node
111
- # @param aLiteralExpr [AST::LoxAssignExpr] the variable assignment node to visit.
111
+ # @param anAssignExpr [AST::LoxAssignExpr] the variable assignment node to visit.
112
112
  def visit_assign_expr(anAssignExpr)
113
113
  broadcast(:before_assign_expr, anAssignExpr)
114
114
  traverse_subnodes(anAssignExpr)
@@ -118,7 +118,7 @@ module Loxxy
118
118
  # Visit event. The visitor is about to visit a logical expression.
119
119
  # Since logical expressions may take shorcuts by not evaluating all their
120
120
  # sub-expressiosns, they are responsible for visiting or not their children.
121
- # @param aBinaryExpr [AST::LOXBinaryExpr] the logical expression node to visit
121
+ # @param aLogicalExpr [AST::LOXLogicalExpr] the logical expression node to visit
122
122
  def visit_logical_expr(aLogicalExpr)
123
123
  broadcast(:before_logical_expr, aLogicalExpr)
124
124
 
@@ -170,25 +170,33 @@ module Loxxy
170
170
  end
171
171
 
172
172
  # Visit event. The visitor is visiting a variable usage node
173
- # @param aLiteralExpr [AST::LoxVariableExpr] the variable reference node to visit.
173
+ # @param aVariableExpr [AST::LoxVariableExpr] the variable reference node to visit.
174
174
  def visit_variable_expr(aVariableExpr)
175
175
  broadcast(:before_variable_expr, aVariableExpr)
176
176
  broadcast(:after_variable_expr, aVariableExpr, self)
177
177
  end
178
178
 
179
179
  # Visit event. The visitor is about to visit the given terminal datatype value.
180
- # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
180
+ # @param aValue [Ast::BuiltinDattype] the built-in datatype value
181
181
  def visit_builtin(aValue)
182
182
  broadcast(:before_visit_builtin, aValue)
183
183
  broadcast(:after_visit_builtin, aValue)
184
184
  end
185
185
 
186
+ # Visit event. The visitor is about to visit a function statement node.
187
+ # @param aFunStmt [AST::LoxFunStmt] function declaration to visit
188
+ def visit_fun_stmt(aFunStmt)
189
+ broadcast(:before_fun_stmt, aFunStmt)
190
+ traverse_subnodes(aFunStmt)
191
+ broadcast(:after_fun_stmt, aFunStmt, self)
192
+ end
193
+
186
194
  # Visit event. The visitor is about to visit the given non terminal node.
187
195
  # @param aNonTerminalNode [Rley::PTree::NonTerminalNode] the node to visit.
188
- def visit_nonterminal(non_terminal_node)
196
+ def visit_nonterminal(aNonTerminalNode)
189
197
  # Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
190
198
  # that it cannot handle.
191
- symb = non_terminal_node.symbol.name
199
+ symb = aNonTerminalNode.symbol.name
192
200
  msg = "Loxxy cannot execute this code yet for non-terminal symbol '#{symb}'."
193
201
  raise NotImplementedError, msg
194
202
  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,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_compound_expr'
4
+
5
+ module Loxxy
6
+ module Ast
7
+ class LoxFunStmt < LoxCompoundExpr
8
+ attr_reader :name
9
+ attr_reader :params
10
+ attr_reader :body
11
+
12
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
13
+ # @param aName [String]
14
+ # @param arguments [Array<String>]
15
+ # @param body [Ast::LoxBlockStmt]
16
+ def initialize(aPosition, aName, paramList, aBody)
17
+ super(aPosition, [])
18
+ @name = aName
19
+ @params = paramList
20
+ @body = aBody
21
+ end
22
+
23
+ # Part of the 'visitee' role in Visitor design pattern.
24
+ # @param visitor [Ast::ASTVisitor] the visitor
25
+ def accept(visitor)
26
+ visitor.visit_fun_stmt(self)
27
+ end
28
+
29
+ alias operands subnodes
30
+ end # class
31
+ end # module
32
+ 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
@@ -2,6 +2,7 @@
2
2
 
3
3
  # Load all the classes implementing AST nodes
4
4
  require_relative '../ast/all_lox_nodes'
5
+ require_relative 'function'
5
6
  require_relative 'symbol_table'
6
7
 
7
8
  module Loxxy
@@ -173,11 +174,21 @@ module Loxxy
173
174
  # Evaluate callee part
174
175
  aCallExpr.callee.accept(aVisitor)
175
176
  callee = stack.pop
176
- # TODO: reverse order?
177
- aCallExpr.arguments.each do |arg|
178
- arg.evaluate(aVisitor)
177
+ aCallExpr.arguments.reverse_each { |arg| arg.accept(aVisitor) }
178
+
179
+ if callee.kind_of?(NativeFunction)
180
+ stack.push callee.call # Pass arguments
181
+ else
182
+ new_env = Environment.new(symbol_table.current_env)
183
+ symbol_table.enter_environment(new_env)
184
+ callee.parameters&.each do |param_name|
185
+ local = Variable.new(param_name, stack.pop)
186
+ symbol_table.insert(local)
187
+ end
188
+ stack.push callee.call(aVisitor)
189
+
190
+ symbol_table.leave_environment
179
191
  end
180
- stack.push callee.call # Pass arguments
181
192
  end
182
193
 
183
194
  def after_grouping_expr(_groupingExpr)
@@ -197,16 +208,30 @@ module Loxxy
197
208
  stack.push(literalExpr.literal)
198
209
  end
199
210
 
200
- # @param aNonTerminalNode [Ast::BuiltinDattype] the built-in datatype value
211
+ # @param aValue [Ast::BuiltinDattype] the built-in datatype value
201
212
  def before_visit_builtin(aValue)
202
213
  stack.push(aValue)
203
214
  end
204
215
 
216
+ def after_fun_stmt(aFunStmt, aVisitor)
217
+ function = Function.new(aFunStmt.name, aFunStmt.params, aFunStmt.body, stack)
218
+ new_var = Variable.new(aFunStmt.name, function)
219
+ symbol_table.insert(new_var)
220
+ end
221
+
205
222
  private
206
223
 
207
224
  NativeFunction = Struct.new(:callable, :interp) do
208
225
  def accept(_visitor)
209
- interp.stack.push callable
226
+ interp.stack.push self
227
+ end
228
+
229
+ def call
230
+ callable.call
231
+ end
232
+
233
+ def to_str
234
+ '<native fn>'
210
235
  end
211
236
  end
212
237
 
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../datatype/all_datatypes'
4
+
5
+ module Loxxy
6
+ module BackEnd
7
+ # Representation of a Lox function.
8
+ # It is a named slot that can be associated with a value at the time.
9
+ class Function
10
+
11
+ # @return [String]
12
+ attr_reader :name
13
+
14
+ # @return [Array<>] the parameters
15
+ attr_reader :parameters
16
+
17
+ attr_reader :body
18
+
19
+ attr_reader :stack
20
+
21
+ # Create a variable with given name and initial value
22
+ # @param aName [String] The name of the variable
23
+ # @param aValue [Datatype::BuiltinDatatype] the initial assigned value
24
+ def initialize(aName, parameterList, aBody, aStack)
25
+ @name = aName.dup
26
+ @parameters = parameterList
27
+ @body = aBody
28
+ @stack = aStack
29
+ end
30
+
31
+ def accept(_visitor)
32
+ stack.push self
33
+ end
34
+
35
+ def call(aVisitor)
36
+ body.empty? ? Datatype::Nil.instance : body.accept(aVisitor)
37
+ end
38
+
39
+ # Text representation of a Lox function
40
+ def to_str
41
+ "<fn #{name}>"
42
+ end
43
+ end # class
44
+ end # module
45
+ end # module
@@ -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'
@@ -77,7 +77,7 @@ module Loxxy
77
77
  rule('returnStmt' => 'RETURN expression_opt SEMICOLON')
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
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.0'
5
5
  end
@@ -386,13 +386,42 @@ LOX_END
386
386
 
387
387
  it 'should implement nullary function calls' do
388
388
  program = <<-LOX_END
389
- print clock(); // Lox expect the 'clock' predefined native function
389
+ print clock(); // Lox expects the 'clock' predefined native function
390
390
  LOX_END
391
391
  expect { subject.evaluate(program) }.not_to raise_error
392
392
  tick = sample_cfg[:ostream].string
393
393
  expect(Time.now.to_f - tick.to_f).to be < 0.1
394
394
  end
395
395
 
396
+ it 'should implement function definition' do
397
+ program = <<-LOX_END
398
+ fun printSum(a, b) {
399
+ print a + b;
400
+ }
401
+ printSum(1, 2);
402
+ LOX_END
403
+ expect { subject.evaluate(program) }.not_to raise_error
404
+ expect(sample_cfg[:ostream].string).to eq('3')
405
+ end
406
+
407
+ it 'should support functions with empty body' do
408
+ program = <<-LOX_END
409
+ fun f() {}
410
+ print f();
411
+ LOX_END
412
+ expect { subject.evaluate(program) }.not_to raise_error
413
+ expect(sample_cfg[:ostream].string).to eq('nil')
414
+ end
415
+
416
+ it 'should provide print representation of functions' do
417
+ program = <<-LOX_END
418
+ fun foo() {}
419
+ print foo; // output: <fn foo>
420
+ print clock; // output: <native fn>
421
+ LOX_END
422
+ expect { subject.evaluate(program) }.not_to raise_error
423
+ expect(sample_cfg[:ostream].string).to eq('<fn foo><native fn>')
424
+ end
396
425
 
397
426
  it 'should print the hello world message' do
398
427
  expect { subject.evaluate(hello_world) }.not_to raise_error
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.0
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-02-15 00:00:00.000000000 Z
11
+ date: 2021-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -93,6 +93,7 @@ files:
93
93
  - lib/loxxy/ast/lox_call_expr.rb
94
94
  - lib/loxxy/ast/lox_compound_expr.rb
95
95
  - lib/loxxy/ast/lox_for_stmt.rb
96
+ - lib/loxxy/ast/lox_fun_stmt.rb
96
97
  - lib/loxxy/ast/lox_grouping_expr.rb
97
98
  - lib/loxxy/ast/lox_if_stmt.rb
98
99
  - lib/loxxy/ast/lox_literal_expr.rb
@@ -108,6 +109,7 @@ files:
108
109
  - lib/loxxy/back_end/engine.rb
109
110
  - lib/loxxy/back_end/entry.rb
110
111
  - lib/loxxy/back_end/environment.rb
112
+ - lib/loxxy/back_end/function.rb
111
113
  - lib/loxxy/back_end/symbol_table.rb
112
114
  - lib/loxxy/back_end/variable.rb
113
115
  - lib/loxxy/datatype/all_datatypes.rb