loxxy 0.0.8 → 0.0.13

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.
@@ -22,6 +22,10 @@ module Loxxy
22
22
  end
23
23
 
24
24
  context 'Provided services:' do
25
+ it 'should give its display representation' do
26
+ expect(subject.to_str).to eq(sample_text)
27
+ end
28
+
25
29
  it 'compares with another string' do
26
30
  expect(subject).to eq(sample_text)
27
31
  expect(subject).to eq(LXString.new(sample_text.dup))
@@ -0,0 +1,26 @@
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/boolean'
7
+
8
+ module Loxxy
9
+ module Datatype
10
+ describe Nil do
11
+ subject { Nil.instance }
12
+
13
+ context 'Initialization:' do
14
+ it 'should know its value' do
15
+ expect(subject.value).to be_nil
16
+ end
17
+ end
18
+
19
+ context 'Provided services:' do
20
+ it 'should give its display representation' do
21
+ expect(subject.to_str).to eq('nil')
22
+ end
23
+ end
24
+ end # describe
25
+ end # module
26
+ end # module
@@ -0,0 +1,31 @@
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/number'
7
+
8
+ module Loxxy
9
+ module Datatype
10
+ describe Number do
11
+ let(:sample_value) { -12.34 }
12
+ subject { Number.new(sample_value) }
13
+
14
+ context 'Initialization:' do
15
+ it 'should accept a Numeric value at initialization' do
16
+ expect { Number.new(sample_value) }.not_to raise_error
17
+ end
18
+
19
+ it 'should know its value' do
20
+ expect(subject.value).to eq(sample_value)
21
+ end
22
+ end
23
+
24
+ context 'Provided services:' do
25
+ it 'should give its display representation' do
26
+ expect(subject.to_str).to eq(sample_value.to_s)
27
+ end
28
+ end
29
+ end # describe
30
+ end # module
31
+ end # module
@@ -37,7 +37,7 @@ module Loxxy
37
37
  # Parse results MUST to comply to grammar rule:
38
38
  # program => declaration_star EOF
39
39
  # where the declaration_star MUST be empty
40
- expect(aParseTree.root.symbol.name).to eq('EOF')
40
+ expect(aParseTree.root).to be_kind_of(Ast::LoxNoopExpr)
41
41
  end
42
42
 
43
43
  it 'should cope with an empty input' do
@@ -64,7 +64,7 @@ module Loxxy
64
64
  it 'should parse a false literal' do
65
65
  input = 'false;'
66
66
  ptree = subject.parse(input)
67
- leaf = walk_subnodes(ptree.root, [0, 0])
67
+ leaf = ptree.root
68
68
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
69
69
  expect(leaf.literal).to be_equal(Datatype::False.instance)
70
70
  end
@@ -72,7 +72,7 @@ module Loxxy
72
72
  it 'should parse a true literal' do
73
73
  input = 'true;'
74
74
  ptree = subject.parse(input)
75
- leaf = walk_subnodes(ptree.root, [0, 0])
75
+ leaf = ptree.root
76
76
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
77
77
  expect(leaf.literal).to be_equal(Datatype::True.instance)
78
78
  end
@@ -81,7 +81,7 @@ module Loxxy
81
81
  inputs = %w[1234; 12.34;]
82
82
  inputs.each do |source|
83
83
  ptree = subject.parse(source)
84
- leaf = walk_subnodes(ptree.root, [0, 0])
84
+ leaf = ptree.root
85
85
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
86
86
  expect(leaf.literal).to be_kind_of(Datatype::Number)
87
87
  expect(leaf.literal.value).to eq(source.to_f)
@@ -96,7 +96,7 @@ module Loxxy
96
96
  ]
97
97
  inputs.each do |source|
98
98
  ptree = subject.parse(source)
99
- leaf = walk_subnodes(ptree.root, [0, 0])
99
+ leaf = ptree.root
100
100
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
101
101
  expect(leaf.literal).to be_kind_of(Datatype::LXString)
102
102
  expect(leaf.literal.value).to eq(source.gsub(/(^")|(";$)/, ''))
@@ -106,7 +106,7 @@ module Loxxy
106
106
  it 'should parse a nil literal' do
107
107
  input = 'nil;'
108
108
  ptree = subject.parse(input)
109
- leaf = walk_subnodes(ptree.root, [0, 0])
109
+ leaf = ptree.root
110
110
  expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
111
111
  expect(leaf.literal).to be_equal(Datatype::Nil.instance)
112
112
  end
@@ -119,21 +119,11 @@ module Loxxy
119
119
  print "Hello, world!";
120
120
  LOX_END
121
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')
122
+ prnt_stmt = ptree.root
123
+ expect(prnt_stmt).to be_kind_of(Ast::LoxPrintStmt)
124
+ expect(prnt_stmt.subnodes[0]).to be_kind_of(Ast::LoxLiteralExpr)
125
+ expect(prnt_stmt.subnodes[0].literal).to be_kind_of(Loxxy::Datatype::LXString)
126
+ expect(prnt_stmt.subnodes[0].literal.value).to eq('Hello, world!')
137
127
  end
138
128
  end # context
139
129
 
@@ -141,10 +131,7 @@ LOX_END
141
131
  it 'should parse the addition of two number literals' do
142
132
  input = '123 + 456;'
143
133
  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]
134
+ expr = ptree.root
148
135
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
149
136
  expect(expr.operator).to eq(:+)
150
137
  expect(expr.operands[0].literal.value).to eq(123)
@@ -154,10 +141,7 @@ LOX_END
154
141
  it 'should parse the subtraction of two number literals' do
155
142
  input = '4 - 3;'
156
143
  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]
144
+ expr = ptree.root
161
145
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
162
146
  expect(expr.operator).to eq(:-)
163
147
  expect(expr.operands[0].literal.value).to eq(4)
@@ -167,10 +151,7 @@ LOX_END
167
151
  it 'should parse multiple additive operations' do
168
152
  input = '5 + 2 - 3;'
169
153
  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]
154
+ expr = ptree.root
174
155
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
175
156
  expect(expr.operator).to eq(:-)
176
157
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -183,10 +164,7 @@ LOX_END
183
164
  it 'should parse the division of two number literals' do
184
165
  input = '8 / 2;'
185
166
  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]
167
+ expr = ptree.root
190
168
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
191
169
  expect(expr.operator).to eq(:/)
192
170
  expect(expr.operands[0].literal.value).to eq(8)
@@ -196,23 +174,17 @@ LOX_END
196
174
  it 'should parse the product of two number literals' do
197
175
  input = '12.34 * 0.3;'
198
176
  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]
177
+ expr = ptree.root
203
178
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
204
179
  expect(expr.operator).to eq(:*)
205
180
  expect(expr.operands[0].literal.value).to eq(12.34)
206
181
  expect(expr.operands[1].literal.value).to eq(0.3)
207
182
  end
208
183
 
209
- it 'should parse multiple additive operations' do
184
+ it 'should parse multiple multiplicative operations' do
210
185
  input = '5 * 2 / 3;'
211
186
  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]
187
+ expr = ptree.root
216
188
  expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
217
189
  expect(expr.operator).to eq(:/)
218
190
  expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
@@ -221,6 +193,115 @@ LOX_END
221
193
  expect(expr.operands[0].operands[1].literal.value).to eq(2)
222
194
  expect(expr.operands[1].literal.value).to eq(3)
223
195
  end
196
+
197
+ it 'should parse combination of terms and factors' do
198
+ input = '5 + 2 / 3;'
199
+ ptree = subject.parse(input)
200
+ expr = ptree.root
201
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
202
+ expect(expr.operator).to eq(:+)
203
+ expect(expr.operands[0].literal.value).to eq(5)
204
+ expect(expr.operands[1]).to be_kind_of(Ast::LoxBinaryExpr)
205
+ expect(expr.operands[1].operator).to eq(:/)
206
+ expect(expr.operands[1].operands[0].literal.value).to eq(2)
207
+ expect(expr.operands[1].operands[1].literal.value).to eq(3)
208
+ end
209
+ end # context
210
+
211
+ context 'Parsing string concatenation' do
212
+ it 'should parse the concatenation of two string literals' do
213
+ input = '"Lo" + "ve";'
214
+ ptree = subject.parse(input)
215
+ expr = ptree.root
216
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
217
+ expect(expr.operator).to eq(:+)
218
+ expect(expr.operands[0].literal.value).to eq('Lo')
219
+ expect(expr.operands[1].literal.value).to eq('ve')
220
+ end
221
+ end # context
222
+
223
+ context 'Parsing comparison expressions' do
224
+ it 'should parse the comparison of two number literals' do
225
+ %w[> >= < <=].each do |predicate|
226
+ input = "3 #{predicate} 2;"
227
+ ptree = subject.parse(input)
228
+ expr = ptree.root
229
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
230
+ expect(expr.operator).to eq(predicate.to_sym)
231
+ expect(expr.operands[0].literal.value).to eq(3)
232
+ expect(expr.operands[1].literal.value).to eq(2)
233
+ end
234
+ end
235
+ end # context
236
+
237
+ context 'Parsing equality expressions' do
238
+ it 'should parse the equality of two number literals' do
239
+ %w[!= ==].each do |predicate|
240
+ input = "3 #{predicate} 2;"
241
+ ptree = subject.parse(input)
242
+ expr = ptree.root
243
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
244
+ expect(expr.operator).to eq(predicate.to_sym)
245
+ expect(expr.operands[0].literal.value).to eq(3)
246
+ expect(expr.operands[1].literal.value).to eq(2)
247
+ end
248
+ end
249
+
250
+ it 'should parse combination of equality expressions' do
251
+ input = '5 != 2 == false; // A bit contrived example'
252
+ ptree = subject.parse(input)
253
+ expr = ptree.root
254
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
255
+ expect(expr.operator).to eq(:==)
256
+ expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
257
+ expect(expr.operands[0].operator).to eq(:!=)
258
+ expect(expr.operands[0].operands[0].literal.value).to eq(5)
259
+ expect(expr.operands[0].operands[1].literal.value).to eq(2)
260
+ expect(expr.operands[1].literal.value).to be_falsey
261
+ end
262
+ end # context
263
+
264
+ context 'Parsing logical expressions' do
265
+ it 'should parse the logical operations betweentwo sub-expression' do
266
+ %w[or and].each do |connector|
267
+ input = "5 > 2 #{connector} 3 <= 4;"
268
+ ptree = subject.parse(input)
269
+ expr = ptree.root
270
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
271
+ expect(expr.operator).to eq(connector.to_sym)
272
+ expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
273
+ expect(expr.operands[0].operator).to eq(:>)
274
+ expect(expr.operands[0].operands[0].literal.value).to eq(5)
275
+ expect(expr.operands[0].operands[1].literal.value).to eq(2)
276
+ expect(expr.operands[1]).to be_kind_of(Ast::LoxBinaryExpr)
277
+ expect(expr.operands[1].operator).to eq(:<=)
278
+ expect(expr.operands[1].operands[0].literal.value).to eq(3)
279
+ expect(expr.operands[1].operands[1].literal.value).to eq(4)
280
+ end
281
+ end
282
+
283
+ it 'should parse a combinations of logical expressions' do
284
+ input = '4 > 3 and 1 < 2 or 4 >= 5;'
285
+ ptree = subject.parse(input)
286
+ expr = ptree.root
287
+ expect(expr).to be_kind_of(Ast::LoxBinaryExpr)
288
+ expect(expr.operator).to eq(:or) # or has lower precedence than and
289
+ expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
290
+ expect(expr.operands[0].operator).to eq(:and)
291
+ conjuncts = expr.operands[0].operands
292
+ expect(conjuncts[0]).to be_kind_of(Ast::LoxBinaryExpr)
293
+ expect(conjuncts[0].operator).to eq(:>)
294
+ expect(conjuncts[0].operands[0].literal.value).to eq(4)
295
+ expect(conjuncts[0].operands[1].literal.value).to eq(3)
296
+ expect(conjuncts[1]).to be_kind_of(Ast::LoxBinaryExpr)
297
+ expect(conjuncts[1].operator).to eq(:<)
298
+ expect(conjuncts[1].operands[0].literal.value).to eq(1)
299
+ expect(conjuncts[1].operands[1].literal.value).to eq(2)
300
+ expect(expr.operands[1]).to be_kind_of(Ast::LoxBinaryExpr)
301
+ expect(expr.operands[1].operator).to eq(:>=)
302
+ expect(expr.operands[1].operands[0].literal.value).to eq(4)
303
+ expect(expr.operands[1].operands[1].literal.value).to eq(5)
304
+ end
224
305
  end # context
225
306
  end # describe
226
307
  end # module
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'spec_helper' # Use the RSpec framework
4
+ require 'stringio'
5
+
6
+ # Load the class under test
7
+ require_relative '../lib/loxxy/interpreter'
8
+
9
+ module Loxxy
10
+ # This spec contains the bare bones test for the Interpreter class.
11
+ # The execution of Lox code is tested elsewhere.
12
+ describe Interpreter do
13
+ let(:sample_cfg) do
14
+ { ostream: StringIO.new }
15
+ end
16
+ subject { Interpreter.new(sample_cfg) }
17
+
18
+ context 'Initialization:' do
19
+ it 'should accept a option Hash at initialization' do
20
+ expect { Interpreter.new(sample_cfg) }.not_to raise_error
21
+ end
22
+
23
+ it 'should know its config options' do
24
+ expect(subject.config).to eq(sample_cfg)
25
+ end
26
+ end # context
27
+
28
+ context 'Evaluating Lox code:' do
29
+ let(:hello_world) { 'print "Hello, world!";' }
30
+
31
+ it 'should evaluate core data types' do
32
+ result = subject.evaluate('true; // Not false')
33
+ expect(result).to be_kind_of(Loxxy::Datatype::True)
34
+ end
35
+
36
+ it 'should print the hello world message' do
37
+ expect { subject.evaluate(hello_world) }.not_to raise_error
38
+ expect(sample_cfg[:ostream].string).to eq('Hello, world!')
39
+ end
40
+ end # context
41
+ end # describe
42
+ 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.8
4
+ version: 0.0.13
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-01-07 00:00:00.000000000 Z
11
+ date: 2021-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -84,12 +84,16 @@ files:
84
84
  - README.md
85
85
  - Rakefile
86
86
  - lib/loxxy.rb
87
+ - lib/loxxy/ast/all_lox_nodes.rb
87
88
  - lib/loxxy/ast/ast_builder.rb
88
89
  - lib/loxxy/ast/ast_visitor.rb
89
90
  - lib/loxxy/ast/lox_binary_expr.rb
90
91
  - lib/loxxy/ast/lox_compound_expr.rb
91
92
  - lib/loxxy/ast/lox_literal_expr.rb
92
93
  - lib/loxxy/ast/lox_node.rb
94
+ - lib/loxxy/ast/lox_noop_expr.rb
95
+ - lib/loxxy/ast/lox_print_stmt.rb
96
+ - lib/loxxy/back_end/engine.rb
93
97
  - lib/loxxy/datatype/all_datatypes.rb
94
98
  - lib/loxxy/datatype/boolean.rb
95
99
  - lib/loxxy/datatype/builtin_datatype.rb
@@ -103,12 +107,18 @@ files:
103
107
  - lib/loxxy/front_end/parser.rb
104
108
  - lib/loxxy/front_end/raw_parser.rb
105
109
  - lib/loxxy/front_end/scanner.rb
110
+ - lib/loxxy/interpreter.rb
106
111
  - lib/loxxy/version.rb
107
112
  - loxxy.gemspec
113
+ - spec/back_end/engine_spec.rb
114
+ - spec/datatype/boolean_spec.rb
108
115
  - spec/datatype/lx_string_spec.rb
116
+ - spec/datatype/nil_spec.rb
117
+ - spec/datatype/number_spec.rb
109
118
  - spec/front_end/parser_spec.rb
110
119
  - spec/front_end/raw_parser_spec.rb
111
120
  - spec/front_end/scanner_spec.rb
121
+ - spec/interpreter_spec.rb
112
122
  - spec/loxxy_spec.rb
113
123
  - spec/spec_helper.rb
114
124
  homepage: https://github.com/famished-tiger/loxxy
@@ -136,8 +146,13 @@ signing_key:
136
146
  specification_version: 4
137
147
  summary: An implementation of the Lox programming language. WIP
138
148
  test_files:
149
+ - spec/back_end/engine_spec.rb
150
+ - spec/datatype/boolean_spec.rb
139
151
  - spec/datatype/lx_string_spec.rb
152
+ - spec/datatype/nil_spec.rb
153
+ - spec/datatype/number_spec.rb
140
154
  - spec/front_end/parser_spec.rb
141
155
  - spec/front_end/raw_parser_spec.rb
142
156
  - spec/front_end/scanner_spec.rb
157
+ - spec/interpreter_spec.rb
143
158
  - spec/loxxy_spec.rb