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 +4 -4
- data/CHANGELOG.md +35 -0
- data/lib/loxxy/ast/all_lox_nodes.rb +1 -0
- data/lib/loxxy/ast/ast_builder.rb +27 -0
- data/lib/loxxy/ast/ast_visitor.rb +18 -10
- data/lib/loxxy/ast/lox_block_stmt.rb +5 -1
- data/lib/loxxy/ast/lox_for_stmt.rb +0 -1
- data/lib/loxxy/ast/lox_fun_stmt.rb +32 -0
- data/lib/loxxy/ast/lox_if_stmt.rb +3 -1
- data/lib/loxxy/back_end/engine.rb +31 -6
- data/lib/loxxy/back_end/function.rb +45 -0
- data/lib/loxxy/front_end/grammar.rb +5 -5
- data/lib/loxxy/front_end/literal.rb +1 -1
- data/lib/loxxy/version.rb +1 -1
- data/spec/interpreter_spec.rb +30 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42a88690625576399255ae7fadd3ac6aee022fc8d56a8e10c1206b55eca207ab
|
4
|
+
data.tar.gz: 4042d268f199763405a264480765bbd5fe7aeaa998eb5e0a4353ae702c3bef2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
|
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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
|
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(
|
196
|
+
def visit_nonterminal(aNonTerminalNode)
|
189
197
|
# Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
|
190
198
|
# that it cannot handle.
|
191
|
-
symb =
|
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
|
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
|
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
|
-
|
177
|
-
|
178
|
-
|
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
|
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
|
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
|
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
data/spec/interpreter_spec.rb
CHANGED
@@ -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
|
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
|
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-
|
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
|