loxxy 0.0.3 → 0.0.8
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/.rubocop.yml +13 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +56 -0
- data/README.md +60 -6
- data/lib/loxxy.rb +3 -1
- data/lib/loxxy/ast/ast_builder.rb +138 -0
- data/lib/loxxy/ast/ast_visitor.rb +125 -0
- data/lib/loxxy/ast/lox_binary_expr.rb +22 -0
- data/lib/loxxy/ast/lox_compound_expr.rb +25 -0
- data/lib/loxxy/ast/lox_literal_expr.rb +25 -0
- data/lib/loxxy/ast/lox_node.rb +22 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +3 -4
- data/lib/loxxy/datatype/false.rb +3 -3
- data/lib/loxxy/datatype/lx_string.rb +15 -6
- data/lib/loxxy/datatype/nil.rb +3 -3
- data/lib/loxxy/datatype/number.rb +2 -10
- data/lib/loxxy/datatype/true.rb +4 -4
- data/lib/loxxy/front_end/grammar.rb +45 -35
- data/lib/loxxy/front_end/literal.rb +1 -1
- data/lib/loxxy/front_end/parser.rb +18 -2
- data/lib/loxxy/front_end/raw_parser.rb +54 -0
- data/lib/loxxy/front_end/scanner.rb +4 -6
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +2 -2
- data/spec/datatype/lx_string_spec.rb +35 -0
- data/spec/front_end/parser_spec.rb +181 -10
- data/spec/front_end/raw_parser_spec.rb +98 -0
- data/spec/front_end/scanner_spec.rb +14 -2
- data/spec/loxxy_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -3
- metadata +14 -2
@@ -50,7 +50,7 @@ module Loxxy
|
|
50
50
|
'>' => 'GREATER',
|
51
51
|
'>=' => 'GREATER_EQUAL',
|
52
52
|
'<' => 'LESS',
|
53
|
-
'<=' => 'LESS_EQUAL'
|
53
|
+
'<=' => 'LESS_EQUAL'
|
54
54
|
}.freeze
|
55
55
|
|
56
56
|
# Here are all the implemented Lox keywords (in uppercase)
|
@@ -99,7 +99,7 @@ module Loxxy
|
|
99
99
|
|
100
100
|
token = nil
|
101
101
|
|
102
|
-
if
|
102
|
+
if '(){},.;/*'.include? curr_ch
|
103
103
|
# Single delimiter or separator character
|
104
104
|
token = build_token(@@lexeme2name[curr_ch], scanner.getch)
|
105
105
|
elsif (lexeme = scanner.scan(/[+\-](?!\d)/))
|
@@ -150,7 +150,7 @@ module Loxxy
|
|
150
150
|
when 'FALSE'
|
151
151
|
value = Datatype::False.instance
|
152
152
|
when 'NIL'
|
153
|
-
value = Datatype::Nil.instance
|
153
|
+
value = Datatype::Nil.instance
|
154
154
|
when 'NUMBER'
|
155
155
|
value = Datatype::Number.new(aLexeme)
|
156
156
|
when 'STRING'
|
@@ -167,8 +167,6 @@ module Loxxy
|
|
167
167
|
# Skip non-significant whitespaces and comments.
|
168
168
|
# Advance the scanner until something significant is found.
|
169
169
|
def skip_intertoken_spaces
|
170
|
-
pre_pos = scanner.pos
|
171
|
-
|
172
170
|
loop do
|
173
171
|
ws_found = scanner.skip(/[ \t\f]+/) ? true : false
|
174
172
|
nl_found = scanner.skip(/(?:\r\n)|\r|\n/)
|
@@ -191,7 +189,7 @@ module Loxxy
|
|
191
189
|
break unless ws_found || cmt_found
|
192
190
|
end
|
193
191
|
|
194
|
-
|
192
|
+
scanner.pos
|
195
193
|
end
|
196
194
|
|
197
195
|
def skip_block_comment
|
data/lib/loxxy/version.rb
CHANGED
data/loxxy.gemspec
CHANGED
@@ -40,8 +40,8 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.version = Loxxy::VERSION
|
41
41
|
spec.authors = ['Dimitri Geshef']
|
42
42
|
spec.email = ['famished.tiger@yahoo.com']
|
43
|
-
spec.summary =
|
44
|
-
spec.description =
|
43
|
+
spec.summary = 'An implementation of the Lox programming language. WIP'
|
44
|
+
spec.description = 'An implementation of the Lox programming language. WIP'
|
45
45
|
spec.homepage = 'https://github.com/famished-tiger/loxxy'
|
46
46
|
spec.license = 'MIT'
|
47
47
|
spec.required_ruby_version = '~> 2.4'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/datatype/lx_string'
|
7
|
+
|
8
|
+
module Loxxy
|
9
|
+
module Datatype
|
10
|
+
describe LXString do
|
11
|
+
let(:sample_text) { 'some_text' }
|
12
|
+
subject { LXString.new(sample_text) }
|
13
|
+
|
14
|
+
context 'Initialization:' do
|
15
|
+
it 'should accept a String value at initialization' do
|
16
|
+
expect { LXString.new(sample_text) }.not_to raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should know its value' do
|
20
|
+
expect(subject.value).to eq(sample_text)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'Provided services:' do
|
25
|
+
it 'compares with another string' do
|
26
|
+
expect(subject).to eq(sample_text)
|
27
|
+
expect(subject).to eq(LXString.new(sample_text.dup))
|
28
|
+
|
29
|
+
expect(subject).not_to eq('')
|
30
|
+
expect(subject).not_to eq('other-text')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end # describe
|
34
|
+
end # module
|
35
|
+
end # module
|
@@ -1,13 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
-
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/front_end/parser'
|
5
7
|
|
6
8
|
module Loxxy
|
7
9
|
module FrontEnd
|
8
10
|
describe Parser do
|
9
11
|
subject { Parser.new }
|
10
12
|
|
13
|
+
# Utility method to walk towards deeply nested node
|
14
|
+
# @param aNTNode [Rley::PTree::NonTerminalNode]
|
15
|
+
# @param subnodePath[Array<Integer>] An Array of subnode indices
|
16
|
+
def walk_subnodes(aNTNode, subnodePath)
|
17
|
+
curr_node = aNTNode
|
18
|
+
subnodePath.each do |index|
|
19
|
+
curr_node = curr_node.subnodes[index]
|
20
|
+
end
|
21
|
+
|
22
|
+
curr_node
|
23
|
+
end
|
24
|
+
|
11
25
|
context 'Initialization:' do
|
12
26
|
it 'should be initialized without argument' do
|
13
27
|
expect { Parser.new }.not_to raise_error
|
@@ -17,19 +31,13 @@ module Loxxy
|
|
17
31
|
expect(subject.engine).to be_kind_of(Rley::Engine)
|
18
32
|
end
|
19
33
|
end # context
|
20
|
-
|
34
|
+
|
21
35
|
context 'Parsing blank files:' do
|
22
36
|
def check_empty_input_result(aParseTree)
|
23
37
|
# Parse results MUST to comply to grammar rule:
|
24
38
|
# program => declaration_star EOF
|
25
39
|
# where the declaration_star MUST be empty
|
26
|
-
expect(aParseTree.root.symbol.name).to eq('
|
27
|
-
(decls, eof) = aParseTree.root.subnodes
|
28
|
-
expect(decls).to be_kind_of(Rley::PTree::NonTerminalNode)
|
29
|
-
expect(decls.symbol.name).to eq('declaration_star')
|
30
|
-
expect(decls.subnodes).to be_empty
|
31
|
-
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
32
|
-
expect(eof.symbol.name).to eq('EOF')
|
40
|
+
expect(aParseTree.root.symbol.name).to eq('EOF')
|
33
41
|
end
|
34
42
|
|
35
43
|
it 'should cope with an empty input' do
|
@@ -51,6 +59,169 @@ module Loxxy
|
|
51
59
|
check_empty_input_result(ptree)
|
52
60
|
end
|
53
61
|
end # context
|
62
|
+
|
63
|
+
context 'Parsing literals:' do
|
64
|
+
it 'should parse a false literal' do
|
65
|
+
input = 'false;'
|
66
|
+
ptree = subject.parse(input)
|
67
|
+
leaf = walk_subnodes(ptree.root, [0, 0])
|
68
|
+
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
69
|
+
expect(leaf.literal).to be_equal(Datatype::False.instance)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should parse a true literal' do
|
73
|
+
input = 'true;'
|
74
|
+
ptree = subject.parse(input)
|
75
|
+
leaf = walk_subnodes(ptree.root, [0, 0])
|
76
|
+
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
77
|
+
expect(leaf.literal).to be_equal(Datatype::True.instance)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should parse number literals' do
|
81
|
+
inputs = %w[1234; 12.34;]
|
82
|
+
inputs.each do |source|
|
83
|
+
ptree = subject.parse(source)
|
84
|
+
leaf = walk_subnodes(ptree.root, [0, 0])
|
85
|
+
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
86
|
+
expect(leaf.literal).to be_kind_of(Datatype::Number)
|
87
|
+
expect(leaf.literal.value).to eq(source.to_f)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should parse string literals' do
|
92
|
+
inputs = [
|
93
|
+
'"I am a string";',
|
94
|
+
'"";',
|
95
|
+
'"123";'
|
96
|
+
]
|
97
|
+
inputs.each do |source|
|
98
|
+
ptree = subject.parse(source)
|
99
|
+
leaf = walk_subnodes(ptree.root, [0, 0])
|
100
|
+
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
101
|
+
expect(leaf.literal).to be_kind_of(Datatype::LXString)
|
102
|
+
expect(leaf.literal.value).to eq(source.gsub(/(^")|(";$)/, ''))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should parse a nil literal' do
|
107
|
+
input = 'nil;'
|
108
|
+
ptree = subject.parse(input)
|
109
|
+
leaf = walk_subnodes(ptree.root, [0, 0])
|
110
|
+
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
111
|
+
expect(leaf.literal).to be_equal(Datatype::Nil.instance)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'Parsing expressions:' do
|
116
|
+
it 'should parse a hello world program' do
|
117
|
+
program = <<-LOX_END
|
118
|
+
// Your first Lox program!
|
119
|
+
print "Hello, world!";
|
120
|
+
LOX_END
|
121
|
+
ptree = subject.parse(program)
|
122
|
+
root = ptree.root
|
123
|
+
expect(root.symbol.name).to eq('program')
|
124
|
+
(prnt_stmt, eof) = root.subnodes
|
125
|
+
expect(prnt_stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
|
126
|
+
expect(prnt_stmt.symbol.name).to eq('printStmt')
|
127
|
+
expect(prnt_stmt.subnodes.size).to eq(3)
|
128
|
+
expect(prnt_stmt.subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
|
129
|
+
expect(prnt_stmt.subnodes[0].symbol.name).to eq('PRINT')
|
130
|
+
expect(prnt_stmt.subnodes[1]).to be_kind_of(Loxxy::Ast::LoxLiteralExpr)
|
131
|
+
expect(prnt_stmt.subnodes[1].literal).to be_kind_of(Loxxy::Datatype::LXString)
|
132
|
+
expect(prnt_stmt.subnodes[1].literal.value).to eq('Hello, world!')
|
133
|
+
expect(prnt_stmt.subnodes[2]).to be_kind_of(Rley::PTree::TerminalNode)
|
134
|
+
expect(prnt_stmt.subnodes[2].symbol.name).to eq('SEMICOLON')
|
135
|
+
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
136
|
+
expect(eof.symbol.name).to eq('EOF')
|
137
|
+
end
|
138
|
+
end # context
|
139
|
+
|
140
|
+
context 'Parsing arithmetic operations' do
|
141
|
+
it 'should parse the addition of two number literals' do
|
142
|
+
input = '123 + 456;'
|
143
|
+
ptree = subject.parse(input)
|
144
|
+
parent = ptree.root.subnodes[0]
|
145
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
146
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
147
|
+
expr = parent.subnodes[0]
|
148
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
149
|
+
expect(expr.operator).to eq(:+)
|
150
|
+
expect(expr.operands[0].literal.value).to eq(123)
|
151
|
+
expect(expr.operands[1].literal.value).to eq(456)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should parse the subtraction of two number literals' do
|
155
|
+
input = '4 - 3;'
|
156
|
+
ptree = subject.parse(input)
|
157
|
+
parent = ptree.root.subnodes[0]
|
158
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
159
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
160
|
+
expr = parent.subnodes[0]
|
161
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
162
|
+
expect(expr.operator).to eq(:-)
|
163
|
+
expect(expr.operands[0].literal.value).to eq(4)
|
164
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should parse multiple additive operations' do
|
168
|
+
input = '5 + 2 - 3;'
|
169
|
+
ptree = subject.parse(input)
|
170
|
+
parent = ptree.root.subnodes[0]
|
171
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
172
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
173
|
+
expr = parent.subnodes[0]
|
174
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
175
|
+
expect(expr.operator).to eq(:-)
|
176
|
+
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
177
|
+
expect(expr.operands[0].operator).to eq(:+)
|
178
|
+
expect(expr.operands[0].operands[0].literal.value).to eq(5)
|
179
|
+
expect(expr.operands[0].operands[1].literal.value).to eq(2)
|
180
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should parse the division of two number literals' do
|
184
|
+
input = '8 / 2;'
|
185
|
+
ptree = subject.parse(input)
|
186
|
+
parent = ptree.root.subnodes[0]
|
187
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
188
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
189
|
+
expr = parent.subnodes[0]
|
190
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
191
|
+
expect(expr.operator).to eq(:/)
|
192
|
+
expect(expr.operands[0].literal.value).to eq(8)
|
193
|
+
expect(expr.operands[1].literal.value).to eq(2)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should parse the product of two number literals' do
|
197
|
+
input = '12.34 * 0.3;'
|
198
|
+
ptree = subject.parse(input)
|
199
|
+
parent = ptree.root.subnodes[0]
|
200
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
201
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
202
|
+
expr = parent.subnodes[0]
|
203
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
204
|
+
expect(expr.operator).to eq(:*)
|
205
|
+
expect(expr.operands[0].literal.value).to eq(12.34)
|
206
|
+
expect(expr.operands[1].literal.value).to eq(0.3)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should parse multiple additive operations' do
|
210
|
+
input = '5 * 2 / 3;'
|
211
|
+
ptree = subject.parse(input)
|
212
|
+
parent = ptree.root.subnodes[0]
|
213
|
+
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
214
|
+
expect(parent.symbol.name).to eq('exprStmt')
|
215
|
+
expr = parent.subnodes[0]
|
216
|
+
expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
|
217
|
+
expect(expr.operator).to eq(:/)
|
218
|
+
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
219
|
+
expect(expr.operands[0].operator).to eq(:*)
|
220
|
+
expect(expr.operands[0].operands[0].literal.value).to eq(5)
|
221
|
+
expect(expr.operands[0].operands[1].literal.value).to eq(2)
|
222
|
+
expect(expr.operands[1].literal.value).to eq(3)
|
223
|
+
end
|
224
|
+
end # context
|
54
225
|
end # describe
|
55
226
|
end # module
|
56
|
-
end # module
|
227
|
+
end # module
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/front_end/raw_parser'
|
7
|
+
|
8
|
+
module Loxxy
|
9
|
+
module FrontEnd
|
10
|
+
describe RawParser do
|
11
|
+
subject { RawParser.new }
|
12
|
+
|
13
|
+
context 'Initialization:' do
|
14
|
+
it 'should be initialized without argument' do
|
15
|
+
expect { RawParser.new }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should have its parse engine initialized' do
|
19
|
+
expect(subject.engine).to be_kind_of(Rley::Engine)
|
20
|
+
end
|
21
|
+
end # context
|
22
|
+
|
23
|
+
context 'Parsing blank files:' do
|
24
|
+
def check_empty_input_result(aParseTree)
|
25
|
+
# Parse results MUST to comply to grammar rule:
|
26
|
+
# program => declaration_star EOF
|
27
|
+
# where the declaration_star MUST be empty
|
28
|
+
expect(aParseTree.root.symbol.name).to eq('program')
|
29
|
+
eof = aParseTree.root.subnodes.first
|
30
|
+
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
31
|
+
expect(eof.symbol.name).to eq('EOF')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should cope with an empty input' do
|
35
|
+
ptree = subject.parse('')
|
36
|
+
check_empty_input_result(ptree)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should cope with whitespaces only input' do
|
40
|
+
ptree = subject.parse(' ' * 80 + "\n" * 20)
|
41
|
+
check_empty_input_result(ptree)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should cope with comments only input' do
|
45
|
+
input = +''
|
46
|
+
%w[First Second Third].each do |ordinal|
|
47
|
+
input << "// #{ordinal} comment line\r\n"
|
48
|
+
end
|
49
|
+
ptree = subject.parse(input)
|
50
|
+
check_empty_input_result(ptree)
|
51
|
+
end
|
52
|
+
end # context
|
53
|
+
|
54
|
+
context 'Parsing expressions:' do
|
55
|
+
# Utility method to walk towards deeply nested node
|
56
|
+
# @param aNTNode [Rley::PTree::NonTerminalNode]
|
57
|
+
# @param subnodePath[Array<Integer>] An Array of subnode indices
|
58
|
+
def walk_subnodes(aNTNode, subnodePath)
|
59
|
+
curr_node = aNTNode
|
60
|
+
subnodePath.each do |index|
|
61
|
+
curr_node = curr_node.subnodes[index]
|
62
|
+
end
|
63
|
+
|
64
|
+
curr_node
|
65
|
+
end
|
66
|
+
it 'should parse a hello world program' do
|
67
|
+
program = <<-LOX_END
|
68
|
+
// Your first Lox program!
|
69
|
+
print "Hello, world!";
|
70
|
+
LOX_END
|
71
|
+
ptree = subject.parse(program)
|
72
|
+
root = ptree.root
|
73
|
+
expect(root.symbol.name).to eq('program')
|
74
|
+
(decls, eof) = root.subnodes
|
75
|
+
expect(decls).to be_kind_of(Rley::PTree::NonTerminalNode)
|
76
|
+
expect(decls.symbol.name).to eq('declaration_plus')
|
77
|
+
stmt = decls.subnodes[0].subnodes[0]
|
78
|
+
expect(stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
|
79
|
+
expect(stmt.symbol.name).to eq('statement')
|
80
|
+
prnt_stmt = stmt.subnodes[0]
|
81
|
+
expect(prnt_stmt).to be_kind_of(Rley::PTree::NonTerminalNode)
|
82
|
+
expect(prnt_stmt.subnodes.size).to eq(3)
|
83
|
+
expect(prnt_stmt.subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
|
84
|
+
expect(prnt_stmt.subnodes[0].symbol.name).to eq('PRINT')
|
85
|
+
expect(prnt_stmt.subnodes[1]).to be_kind_of(Rley::PTree::NonTerminalNode)
|
86
|
+
leaf_node = walk_subnodes(prnt_stmt, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
87
|
+
expect(leaf_node).to be_kind_of(Rley::PTree::TerminalNode)
|
88
|
+
expect(leaf_node.symbol.name).to eq('STRING')
|
89
|
+
expect(leaf_node.token.value).to eq('Hello, world!')
|
90
|
+
expect(prnt_stmt.subnodes[2]).to be_kind_of(Rley::PTree::TerminalNode)
|
91
|
+
expect(prnt_stmt.subnodes[2].symbol.name).to eq('SEMICOLON')
|
92
|
+
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
93
|
+
expect(eof.symbol.name).to eq('EOF')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end # describe
|
97
|
+
end # module
|
98
|
+
end # module
|
@@ -78,7 +78,7 @@ module Loxxy
|
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'should recognize non-datatype keywords' do
|
81
|
-
keywords
|
81
|
+
keywords = <<-LOX_END
|
82
82
|
and class else fun for if or
|
83
83
|
print return super this var while
|
84
84
|
LOX_END
|
@@ -167,7 +167,7 @@ LOX_END
|
|
167
167
|
end
|
168
168
|
|
169
169
|
it 'should recognize string values' do
|
170
|
-
input
|
170
|
+
input = <<-LOX_END
|
171
171
|
""
|
172
172
|
"string"
|
173
173
|
"123"
|
@@ -223,6 +223,18 @@ LOX_END
|
|
223
223
|
]
|
224
224
|
match_expectations(subject, expectations)
|
225
225
|
end
|
226
|
+
|
227
|
+
it 'should cope with single slash (divide) expression' do
|
228
|
+
subject.start_with('8 / 2')
|
229
|
+
|
230
|
+
expectations = [
|
231
|
+
# [token lexeme]
|
232
|
+
%w[NUMBER 8],
|
233
|
+
%w[SLASH /],
|
234
|
+
%w[NUMBER 2]
|
235
|
+
]
|
236
|
+
match_expectations(subject, expectations)
|
237
|
+
end
|
226
238
|
end # context
|
227
239
|
end # describe
|
228
240
|
end # module
|