loxxy 0.0.27 → 0.1.03
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 +64 -0
- data/README.md +56 -10
- data/bin/loxxy +11 -0
- data/lib/loxxy.rb +0 -2
- data/lib/loxxy/ast/all_lox_nodes.rb +2 -0
- data/lib/loxxy/ast/ast_builder.rb +56 -83
- data/lib/loxxy/ast/ast_visitor.rb +28 -10
- data/lib/loxxy/ast/lox_block_stmt.rb +5 -1
- data/lib/loxxy/ast/lox_call_expr.rb +25 -0
- data/lib/loxxy/ast/lox_for_stmt.rb +0 -1
- data/lib/loxxy/ast/lox_fun_stmt.rb +34 -0
- data/lib/loxxy/ast/lox_if_stmt.rb +3 -1
- data/lib/loxxy/back_end/binary_operator.rb +57 -0
- data/lib/loxxy/back_end/engine.rb +126 -5
- data/lib/loxxy/back_end/function.rb +44 -0
- data/lib/loxxy/back_end/unary_operator.rb +41 -0
- data/lib/loxxy/error.rb +9 -0
- data/lib/loxxy/front_end/grammar.rb +28 -28
- data/lib/loxxy/front_end/literal.rb +1 -1
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +2 -2
- data/spec/datatype/lx_string_spec.rb +2 -0
- data/spec/datatype/number_spec.rb +3 -1
- data/spec/front_end/scanner_spec.rb +2 -0
- data/spec/interpreter_spec.rb +45 -7
- metadata +12 -4
@@ -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')
|
@@ -88,37 +88,37 @@ module Loxxy
|
|
88
88
|
rule('owner_opt' => 'call DOT')
|
89
89
|
rule('owner_opt' => [])
|
90
90
|
rule('logic_or' => 'logic_and')
|
91
|
-
rule('logic_or' => 'logic_and disjunct_plus').as '
|
92
|
-
rule('disjunct_plus' => 'disjunct_plus OR logic_and').as '
|
93
|
-
rule('disjunct_plus' => 'OR logic_and').as '
|
91
|
+
rule('logic_or' => 'logic_and disjunct_plus').as 'logical_expr'
|
92
|
+
rule('disjunct_plus' => 'disjunct_plus OR logic_and').as 'binary_plus_more'
|
93
|
+
rule('disjunct_plus' => 'OR logic_and').as 'binary_plus_end'
|
94
94
|
rule('logic_and' => 'equality')
|
95
|
-
rule('logic_and' => 'equality conjunct_plus').as '
|
96
|
-
rule('conjunct_plus' => 'conjunct_plus AND equality').as '
|
97
|
-
rule('conjunct_plus' => 'AND equality').as '
|
95
|
+
rule('logic_and' => 'equality conjunct_plus').as 'logical_expr'
|
96
|
+
rule('conjunct_plus' => 'conjunct_plus AND equality').as 'binary_plus_more'
|
97
|
+
rule('conjunct_plus' => 'AND equality').as 'binary_plus_end'
|
98
98
|
rule('equality' => 'comparison')
|
99
|
-
rule('equality' => 'comparison equalityTest_plus').as '
|
100
|
-
rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison').as '
|
101
|
-
rule('equalityTest_plus' => 'equalityTest comparison').as '
|
99
|
+
rule('equality' => 'comparison equalityTest_plus').as 'binary_operator'
|
100
|
+
rule('equalityTest_plus' => 'equalityTest_plus equalityTest comparison').as 'binary_plus_more'
|
101
|
+
rule('equalityTest_plus' => 'equalityTest comparison').as 'binary_plus_end'
|
102
102
|
rule('equalityTest' => 'BANG_EQUAL')
|
103
103
|
rule('equalityTest' => 'EQUAL_EQUAL')
|
104
104
|
rule('comparison' => 'term')
|
105
|
-
rule('comparison' => 'term comparisonTest_plus').as '
|
105
|
+
rule('comparison' => 'term comparisonTest_plus').as 'binary_operator'
|
106
106
|
rule('comparisonTest_plus' => 'comparisonTest_plus comparisonTest term').as 'comparison_t_plus_more'
|
107
|
-
rule('comparisonTest_plus' => 'comparisonTest term').as '
|
107
|
+
rule('comparisonTest_plus' => 'comparisonTest term').as 'binary_plus_end'
|
108
108
|
rule('comparisonTest' => 'GREATER')
|
109
109
|
rule('comparisonTest' => 'GREATER_EQUAL')
|
110
110
|
rule('comparisonTest' => 'LESS')
|
111
111
|
rule('comparisonTest' => 'LESS_EQUAL')
|
112
112
|
rule('term' => 'factor')
|
113
|
-
rule('term' => 'factor additive_plus').as '
|
114
|
-
rule('additive_plus' => 'additive_plus additionOp factor').as '
|
115
|
-
rule('additive_plus' => 'additionOp factor').as '
|
113
|
+
rule('term' => 'factor additive_plus').as 'binary_operator'
|
114
|
+
rule('additive_plus' => 'additive_plus additionOp factor').as 'binary_plus_more'
|
115
|
+
rule('additive_plus' => 'additionOp factor').as 'binary_plus_end'
|
116
116
|
rule('additionOp' => 'MINUS')
|
117
117
|
rule('additionOp' => 'PLUS')
|
118
118
|
rule('factor' => 'unary')
|
119
|
-
rule('factor' => 'unary multiplicative_plus').as '
|
120
|
-
rule('multiplicative_plus' => 'multiplicative_plus multOp unary').as '
|
121
|
-
rule('multiplicative_plus' => 'multOp unary').as '
|
119
|
+
rule('factor' => 'unary multiplicative_plus').as 'binary_operator'
|
120
|
+
rule('multiplicative_plus' => 'multiplicative_plus multOp unary').as 'binary_plus_more'
|
121
|
+
rule('multiplicative_plus' => 'multOp unary').as 'binary_plus_end'
|
122
122
|
rule('multOp' => 'SLASH')
|
123
123
|
rule('multOp' => 'STAR')
|
124
124
|
rule('unary' => 'unaryOp unary').as 'unary_expr'
|
@@ -126,10 +126,10 @@ module Loxxy
|
|
126
126
|
rule('unaryOp' => 'BANG')
|
127
127
|
rule('unaryOp' => 'MINUS')
|
128
128
|
rule('call' => 'primary')
|
129
|
-
rule('call' => 'primary refinement_plus')
|
130
|
-
rule('refinement_plus' => 'refinement_plus refinement')
|
131
|
-
rule('refinement_plus' => 'refinement')
|
132
|
-
rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN')
|
129
|
+
rule('call' => 'primary refinement_plus').as 'call_expr'
|
130
|
+
rule('refinement_plus' => 'refinement_plus refinement') # .as 'refinement_plus_more'
|
131
|
+
rule('refinement_plus' => 'refinement').as 'refinement_plus_end'
|
132
|
+
rule('refinement' => 'LEFT_PAREN arguments_opt RIGHT_PAREN').as 'call_arglist'
|
133
133
|
rule('refinement' => 'DOT IDENTIFIER')
|
134
134
|
rule('primary' => 'TRUE').as 'literal_expr'
|
135
135
|
rule('primary' => 'FALSE').as 'literal_expr'
|
@@ -142,15 +142,15 @@ 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
|
-
rule('arguments' => 'arguments COMMA expression')
|
153
|
-
rule('arguments' => 'expression')
|
152
|
+
rule('arguments' => 'arguments COMMA expression').as 'arguments_plus_more'
|
153
|
+
rule('arguments' => 'expression').as 'arguments_plus_end'
|
154
154
|
end
|
155
155
|
|
156
156
|
unless defined?(Grammar)
|
@@ -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/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 = '
|
50
|
-
spec.executables =
|
49
|
+
spec.bindir = 'bin'
|
50
|
+
spec.executables = ['loxxy']
|
51
51
|
spec.require_paths = ['lib']
|
52
52
|
|
53
53
|
PkgExtending.pkg_files(spec)
|
@@ -26,6 +26,7 @@ module Loxxy
|
|
26
26
|
expect(subject.to_str).to eq(sample_text)
|
27
27
|
end
|
28
28
|
|
29
|
+
# rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
|
29
30
|
it 'compares with another Lox string' do
|
30
31
|
result = subject == LXString.new(sample_text.dup)
|
31
32
|
expect(result).to be_true
|
@@ -40,6 +41,7 @@ module Loxxy
|
|
40
41
|
result = LXString.new('') == LXString.new('')
|
41
42
|
expect(result).to be_true
|
42
43
|
end
|
44
|
+
# rubocop: enable Lint/BinaryOperatorWithIdenticalOperands
|
43
45
|
|
44
46
|
it 'compares with a Ruby string' do
|
45
47
|
result = subject == sample_text.dup
|
@@ -21,6 +21,7 @@ module Loxxy
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
# rubocop: disable Lint/FloatComparison
|
24
25
|
context 'Provided services:' do
|
25
26
|
it 'should compare with other Lox numbers' do
|
26
27
|
result = subject == Number.new(sample_value)
|
@@ -51,7 +52,8 @@ module Loxxy
|
|
51
52
|
subtraction = subject - Number.new(10)
|
52
53
|
expect(subtraction == -22.34).to be_true
|
53
54
|
end
|
54
|
-
end
|
55
|
+
end # context
|
56
|
+
# rubocop: enable Lint/FloatComparison
|
55
57
|
end # describe
|
56
58
|
end # module
|
57
59
|
end # module
|
@@ -208,6 +208,7 @@ LOX_END
|
|
208
208
|
expect(eof_token.terminal).to eq('EOF')
|
209
209
|
end
|
210
210
|
|
211
|
+
# rubocop: disable Lint/PercentStringArray
|
211
212
|
it 'should skip end of line comments' do
|
212
213
|
input = <<-LOX_END
|
213
214
|
// first comment
|
@@ -223,6 +224,7 @@ LOX_END
|
|
223
224
|
]
|
224
225
|
match_expectations(subject, expectations)
|
225
226
|
end
|
227
|
+
# rubocop: enable Lint/PercentStringArray
|
226
228
|
|
227
229
|
it 'should cope with single slash (divide) expression' do
|
228
230
|
subject.start_with('8 / 2')
|
data/spec/interpreter_spec.rb
CHANGED
@@ -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 }
|
@@ -384,16 +385,43 @@ LOX_END
|
|
384
385
|
expect(sample_cfg[:ostream].string).to eq('012')
|
385
386
|
end
|
386
387
|
|
387
|
-
it 'should implement
|
388
|
+
it 'should implement nullary function calls' do
|
388
389
|
program = <<-LOX_END
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
390
|
+
print clock(); // Lox expects the 'clock' predefined native function
|
391
|
+
LOX_END
|
392
|
+
expect { subject.evaluate(program) }.not_to raise_error
|
393
|
+
tick = sample_cfg[:ostream].string
|
394
|
+
expect(Time.now.to_f - tick.to_f).to be < 0.1
|
395
|
+
end
|
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();
|
394
412
|
LOX_END
|
395
413
|
expect { subject.evaluate(program) }.not_to raise_error
|
396
|
-
expect(sample_cfg[:ostream].string).to eq('
|
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>')
|
397
425
|
end
|
398
426
|
|
399
427
|
it 'should print the hello world message' do
|
@@ -401,5 +429,15 @@ LOX_END
|
|
401
429
|
expect(sample_cfg[:ostream].string).to eq('Hello, world!')
|
402
430
|
end
|
403
431
|
end # context
|
432
|
+
|
433
|
+
context 'Test suite:' do
|
434
|
+
it "should complain if one argument isn't a number" do
|
435
|
+
source = '1 + nil;'
|
436
|
+
err = Loxxy::RuntimeError
|
437
|
+
err_msg = 'Operands must be two numbers or two strings.'
|
438
|
+
expect { subject.evaluate(source) }.to raise_error(err, err_msg)
|
439
|
+
end
|
440
|
+
end # context
|
404
441
|
end # describe
|
442
|
+
# rubocop: enable Metrics/BlockLength
|
405
443
|
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.
|
4
|
+
version: 0.1.03
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-26 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
|
@@ -90,8 +92,10 @@ files:
|
|
90
92
|
- lib/loxxy/ast/lox_assign_expr.rb
|
91
93
|
- lib/loxxy/ast/lox_binary_expr.rb
|
92
94
|
- lib/loxxy/ast/lox_block_stmt.rb
|
95
|
+
- lib/loxxy/ast/lox_call_expr.rb
|
93
96
|
- lib/loxxy/ast/lox_compound_expr.rb
|
94
97
|
- lib/loxxy/ast/lox_for_stmt.rb
|
98
|
+
- lib/loxxy/ast/lox_fun_stmt.rb
|
95
99
|
- lib/loxxy/ast/lox_grouping_expr.rb
|
96
100
|
- lib/loxxy/ast/lox_if_stmt.rb
|
97
101
|
- lib/loxxy/ast/lox_literal_expr.rb
|
@@ -104,10 +108,13 @@ files:
|
|
104
108
|
- lib/loxxy/ast/lox_var_stmt.rb
|
105
109
|
- lib/loxxy/ast/lox_variable_expr.rb
|
106
110
|
- lib/loxxy/ast/lox_while_stmt.rb
|
111
|
+
- lib/loxxy/back_end/binary_operator.rb
|
107
112
|
- lib/loxxy/back_end/engine.rb
|
108
113
|
- lib/loxxy/back_end/entry.rb
|
109
114
|
- lib/loxxy/back_end/environment.rb
|
115
|
+
- lib/loxxy/back_end/function.rb
|
110
116
|
- lib/loxxy/back_end/symbol_table.rb
|
117
|
+
- lib/loxxy/back_end/unary_operator.rb
|
111
118
|
- lib/loxxy/back_end/variable.rb
|
112
119
|
- lib/loxxy/datatype/all_datatypes.rb
|
113
120
|
- lib/loxxy/datatype/boolean.rb
|
@@ -117,6 +124,7 @@ files:
|
|
117
124
|
- lib/loxxy/datatype/nil.rb
|
118
125
|
- lib/loxxy/datatype/number.rb
|
119
126
|
- lib/loxxy/datatype/true.rb
|
127
|
+
- lib/loxxy/error.rb
|
120
128
|
- lib/loxxy/front_end/grammar.rb
|
121
129
|
- lib/loxxy/front_end/literal.rb
|
122
130
|
- lib/loxxy/front_end/parser.rb
|