loxxy 0.0.17 → 0.0.18
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 +5 -0
- data/README.md +96 -49
- data/lib/loxxy/ast/all_lox_nodes.rb +2 -1
- data/lib/loxxy/ast/ast_builder.rb +13 -2
- data/lib/loxxy/ast/ast_visitor.rb +28 -0
- data/lib/loxxy/ast/lox_logical_expr.rb +28 -0
- data/lib/loxxy/back_end/engine.rb +32 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +32 -5
- data/lib/loxxy/version.rb +1 -1
- data/spec/front_end/parser_spec.rb +4 -4
- data/spec/interpreter_spec.rb +47 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43f600b63e6a264cf14a760e82537693068118152aa41e2b6d87f99d993280ea
|
4
|
+
data.tar.gz: 5ea73cae221b5039ec8257ef29c49bd63d22bb2477cde37b60f4f3799fe06534
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d4944a0b164730ddf0839abc325fc0389d895abecb1cd37f22909dc5a17243c29965eb194c351044fb3087bebc1d3dfd319aa6188f05e7a31df09bb41326e18
|
7
|
+
data.tar.gz: e7f857a51b74337724fa4cfd16816d79f9a0dec2b51dcdc8c297a52773048ea2dd2349a110fbf9b0d5eea6f2c57c6397f8196d14520cff59edab1e99444d7a60
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -128,16 +128,20 @@ program
|
|
128
128
|
```
|
129
129
|
|
130
130
|
## Suppported Lox language features
|
131
|
-
|
132
|
-
|
131
|
+
On one hand, the parser covers the complete Lox grammar and should therefore, in principle,
|
132
|
+
parse any valid Lox program.
|
133
|
+
|
134
|
+
On the other hand, the interpreter is under development and currently it can evaluate only a tiny subset of __Lox__.
|
135
|
+
But the situation is changing almost daily, stay tuned...
|
133
136
|
|
134
137
|
Here are the language features currently supported by the interpreter:
|
135
138
|
|
136
139
|
- [Comments](#comments)
|
137
140
|
- [Keywords](#keywords)
|
138
|
-
- [Operators and Special Chars](#operators-and-special-chars)
|
139
141
|
- [Datatypes](#datatypes)
|
140
|
-
- [Statements](#statements)
|
142
|
+
- [Statements](#statements)
|
143
|
+
-[Expressions](#expressions)
|
144
|
+
-[Print Statement](#print-statement)
|
141
145
|
|
142
146
|
### Comments
|
143
147
|
|
@@ -148,36 +152,10 @@ Loxxy supports single line C-style comments.
|
|
148
152
|
```
|
149
153
|
|
150
154
|
### Keywords
|
151
|
-
|
152
|
-
The parser knows all the __Lox__ reserved keywords:
|
155
|
+
Loxxy implements the following __Lox__ reserved keywords:
|
153
156
|
```lang-none
|
154
|
-
and,
|
155
|
-
print, return, super, this, true, var, while
|
157
|
+
and, false, nil, or, print, true
|
156
158
|
```
|
157
|
-
Of these, the interpreter implements: `false`, `nil`, `print`, `true`
|
158
|
-
|
159
|
-
### Operators and Special Chars
|
160
|
-
#### Operators
|
161
|
-
The __loxxy__ interpreter supports all the __Lox__ unary and binary operators:
|
162
|
-
- Arithmetic operators: `+`, `-`, `*`, `/`
|
163
|
-
- Comparison operators: `>`, `>=`, `<`, `<=`
|
164
|
-
- Equality operators: `==`, `!=`
|
165
|
-
- Unary negate (change sign): `-`
|
166
|
-
- Unary not: `!`
|
167
|
-
|
168
|
-
#### Delimiters
|
169
|
-
The parser knows all the __Lox__ grouping delimiters:
|
170
|
-
(`, ), `{`, `}`
|
171
|
-
|
172
|
-
These aren't yet implemented in the interpreter.
|
173
|
-
|
174
|
-
The other characters that have a special meaning in __Lox__ are:
|
175
|
-
- `,` Used in parameter list
|
176
|
-
- `.` For the dot notation (i.e. calling a method)
|
177
|
-
- `;` The semicolon is used to terminates expressions
|
178
|
-
- `=` Assignment
|
179
|
-
|
180
|
-
The parser recognizes them all but the interpreter accepts the semicolons only.
|
181
159
|
|
182
160
|
### Datatypes
|
183
161
|
|
@@ -187,24 +165,93 @@ loxxy supports all the standard __Lox__ datatypes:
|
|
187
165
|
- `String`: Sequence of characters surrounded by `"`. For example: `"Hello!"`
|
188
166
|
- `Nil`: Used to define a null value, denoted by the `nil` keyword
|
189
167
|
|
190
|
-
|
191
|
-
|
192
|
-
Loxxy
|
193
|
-
-
|
194
|
-
- (
|
195
|
-
-
|
196
|
-
-
|
197
|
-
-
|
198
|
-
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
168
|
+
### Statements
|
169
|
+
|
170
|
+
Loxxy supports the following statements:
|
171
|
+
-[Expressions](#expressions)
|
172
|
+
-[Arithmetic expressions](#arithmetic-expressions)
|
173
|
+
-[String concatenation](#string-concatenation)
|
174
|
+
-[Comparison expressions](#comparison-expressions)
|
175
|
+
-[Logical expressions](#logical-expressions)
|
176
|
+
-[Grouping expressions](#grouping-expressions)
|
177
|
+
-[Print Statement](#print-statement)
|
178
|
+
|
179
|
+
#### Expressions
|
180
|
+
|
181
|
+
##### Arithmetic expressions
|
182
|
+
Loxxy supports the following operators for arithmetic expressions:
|
183
|
+
|
184
|
+
- `+`: Adds of two numbers. Both operands must be of the type Number
|
185
|
+
E.g. `37 + 5; // => 42`
|
186
|
+
`7 + -3; // => 4`
|
187
|
+
- `-`: (Binary) Subtracts right operand from left operand. Both operands must be numbers.
|
188
|
+
E.g. `47 - 5; // => 42`
|
189
|
+
- `-`: (Unary) Negates (= changes the sign) of the given number operand.
|
190
|
+
E.g. `- -3; // => 3`
|
191
|
+
- `*`: Multiplies two numbers
|
192
|
+
E.g. `2 * 3; // => 6`
|
193
|
+
- `/`: Divides two numbers
|
194
|
+
E.g. `8 / 2; // => 4`
|
195
|
+
`5 / 2; // => 2.5`
|
196
|
+
|
197
|
+
##### String concatenation
|
198
|
+
- `+`: Concatenates two strings. Both operands must be of the String type.
|
199
|
+
E.g. `"Hello" + ", " + "world! // => "Hello, world!"`
|
200
|
+
|
201
|
+
##### Comparison expressions
|
202
|
+
|
203
|
+
- `==`: Returns `true` if left operand is equal to right operand, otherwise `false`
|
204
|
+
E.g. `false == false; // => true`
|
205
|
+
`5 + 2 == 3 + 4; // => true`
|
206
|
+
`"" == ""; // => true`
|
207
|
+
- `!=`: Returns `true` if left operand is not equal to right operand, otherwise `false`
|
208
|
+
E.g. `false != "false"; // => true`
|
209
|
+
`5 + 2 != 4 + 3; // => false`
|
210
|
+
- `<`: Returns `true` if left operand is less than right operand, otherwise `false`. Both operands must be numbers
|
211
|
+
E.g. `1 < 3; // => true`
|
212
|
+
`1 < 0; // => false`
|
213
|
+
`2 < 2; // => false`
|
214
|
+
- `<=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
|
215
|
+
E.g. `1 <= 3; // => true`
|
216
|
+
`1 <= 0; // => false`
|
217
|
+
`2 <= 2; // => true`
|
218
|
+
- `>`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
|
219
|
+
E.g. `1 > 3; // => false`
|
220
|
+
`1 > 0; // => true`
|
221
|
+
`2 > 2; // => false`
|
222
|
+
- `>=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers
|
223
|
+
E.g. `1 > 3; // => false`
|
224
|
+
`1 > 0; // => true`
|
225
|
+
`2 > 2; // => false`
|
226
|
+
|
227
|
+
##### Logical expressions
|
228
|
+
|
229
|
+
REMINDER: In __Lox__, `false` and `nil` are considered falsey, everything else is truthy.
|
230
|
+
|
231
|
+
- `and`: When both operands are booleans, then returns `true` if both left and right operands are truthy, otherwise `false`.
|
232
|
+
If at least one operand isn't a boolean then returns first falsey operand else (both operands are truthy) returns the second operand.
|
233
|
+
truthy returns the second operand.
|
234
|
+
E.g. `false and true; // => false`
|
235
|
+
`true and nil; // => nil`
|
236
|
+
`0 and true and ""; // => ""`
|
237
|
+
- `or`: When both operands are booleans, then returns `true` if left or right operands are truthy, otherwise `false`.
|
238
|
+
If at least one operand isn't a boolean then returns first truthy operand else (both operands are truthy) returns the second operand.
|
239
|
+
E.g. `false or true; // => true`
|
240
|
+
`true or nil; // => nil`
|
241
|
+
`false or nil; // => nil`
|
242
|
+
`0 or true or ""; // => 0`
|
243
|
+
- `!`: Performs a logical negation on its operand
|
244
|
+
E.g. `!false; // => true`
|
245
|
+
`!!true; // => true`
|
246
|
+
`!0; // => false`
|
247
|
+
|
248
|
+
##### Print Statement
|
249
|
+
|
250
|
+
The statement print + expression + ; prints the result of the expression to stdout.
|
251
|
+
|
252
|
+
``` javascript
|
253
|
+
print "Hello, world!"; // Output: Hello, world!
|
204
254
|
|
205
|
-
```javascript
|
206
|
-
// Print statement with nested string concatenation
|
207
|
-
print "Hello" + ", " + "world!";
|
208
255
|
```
|
209
256
|
|
210
257
|
## Installation
|
@@ -96,6 +96,17 @@ module Loxxy
|
|
96
96
|
node
|
97
97
|
end
|
98
98
|
|
99
|
+
def reduce_logical_expr(_production, _range, tokens, theChildren)
|
100
|
+
operand1 = theChildren[0]
|
101
|
+
|
102
|
+
# Second child is array with couples [operator, operand2]
|
103
|
+
theChildren[1].each do |(operator, operand2)|
|
104
|
+
operand1 = LoxLogicalExpr.new(tokens[0].position, operator, operand1, operand2)
|
105
|
+
end
|
106
|
+
|
107
|
+
operand1
|
108
|
+
end
|
109
|
+
|
99
110
|
# rule('lhs' => 'nonterm_i nonterm_k_plus')
|
100
111
|
def reduce_binary_operator(_production, _range, tokens, theChildren)
|
101
112
|
operand1 = theChildren[0]
|
@@ -149,7 +160,7 @@ module Loxxy
|
|
149
160
|
|
150
161
|
# rule('logic_or' => 'logic_and disjunct_plus')
|
151
162
|
def reduce_logic_or_plus(production, range, tokens, theChildren)
|
152
|
-
|
163
|
+
reduce_logical_expr(production, range, tokens, theChildren)
|
153
164
|
end
|
154
165
|
|
155
166
|
# rule('disjunct_plus' => 'disjunct_plus OR logic_and')
|
@@ -164,7 +175,7 @@ module Loxxy
|
|
164
175
|
|
165
176
|
# rule('logic_and' => 'equality conjunct_plus')
|
166
177
|
def reduce_logic_and_plus(production, range, tokens, theChildren)
|
167
|
-
|
178
|
+
reduce_logical_expr(production, range, tokens, theChildren)
|
168
179
|
end
|
169
180
|
|
170
181
|
# rule('conjunct_plus' => 'conjunct_plus AND equality')
|
@@ -59,6 +59,20 @@ module Loxxy
|
|
59
59
|
broadcast(:after_print_stmt, aPrintStmt)
|
60
60
|
end
|
61
61
|
|
62
|
+
# Visit event. The visitor is about to visit a logical expression.
|
63
|
+
# Since logical expressions may take shorcuts by not evaluating all their
|
64
|
+
# sub-expressiosns, they are responsible for visiting or not their children.
|
65
|
+
# @param aBinaryExpr [AST::LOXBinaryExpr] the logical expression node to visit
|
66
|
+
def visit_logical_expr(aLogicalExpr)
|
67
|
+
broadcast(:before_logical_expr, aLogicalExpr)
|
68
|
+
|
69
|
+
# As logical connectors may take a shortcut only the first argument is visited
|
70
|
+
traverse_given_subnode(aLogicalExpr, 0)
|
71
|
+
|
72
|
+
# The second child could be visited: this action is deferred in handler
|
73
|
+
broadcast(:after_logical_expr, aLogicalExpr, self)
|
74
|
+
end
|
75
|
+
|
62
76
|
# Visit event. The visitor is about to visit a binary expression.
|
63
77
|
# @param aBinaryExpr [AST::LOXBinaryExpr] the binary expression node to visit
|
64
78
|
def visit_binary_expr(aBinaryExpr)
|
@@ -106,6 +120,20 @@ module Loxxy
|
|
106
120
|
broadcast(:after_subnodes, aParentNode, subnodes)
|
107
121
|
end
|
108
122
|
|
123
|
+
# Visit event. The visitor is about to visit one given subnode of a non
|
124
|
+
# terminal node.
|
125
|
+
# @param aParentNode [Ast::LocCompoundExpr] the parent node.
|
126
|
+
# @param index [integer] index of child subnode
|
127
|
+
def traverse_given_subnode(aParentNode, index)
|
128
|
+
subnode = aParentNode.subnodes[index]
|
129
|
+
broadcast(:before_given_subnode, aParentNode, subnode)
|
130
|
+
|
131
|
+
# Now, let's proceed with the visit of that subnode
|
132
|
+
subnode.accept(self)
|
133
|
+
|
134
|
+
broadcast(:after_given_subnode, aParentNode, subnode)
|
135
|
+
end
|
136
|
+
|
109
137
|
# Send a notification to all subscribers.
|
110
138
|
# @param msg [Symbol] event to notify
|
111
139
|
# @param args [Array] arguments of the notification.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxLogicalExpr < LoxCompoundExpr
|
8
|
+
# @return [Symbol] message name to be sent to receiver
|
9
|
+
attr_reader :operator
|
10
|
+
|
11
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
12
|
+
# @param operand1 [Loxxy::Ast::LoxNode]
|
13
|
+
# @param operand2 [Loxxy::Ast::LoxNode]
|
14
|
+
def initialize(aPosition, anOperator, operand1, operand2)
|
15
|
+
super(aPosition, [operand1, operand2])
|
16
|
+
@operator = anOperator
|
17
|
+
end
|
18
|
+
|
19
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
20
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
21
|
+
def accept(visitor)
|
22
|
+
visitor.visit_logical_expr(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias operands subnodes
|
26
|
+
end # class
|
27
|
+
end # module
|
28
|
+
end # module
|
@@ -40,6 +40,38 @@ module Loxxy
|
|
40
40
|
@ostream.print tos.to_str
|
41
41
|
end
|
42
42
|
|
43
|
+
def after_logical_expr(aLogicalExpr, visitor)
|
44
|
+
op = aLogicalExpr.operator
|
45
|
+
operand1 = stack.pop # only first operand was evaluated
|
46
|
+
result = nil
|
47
|
+
if ((op == :and) && operand1.falsey?) || ((op == :or) && operand1.truthy?)
|
48
|
+
result = operand1
|
49
|
+
else
|
50
|
+
raw_operand2 = aLogicalExpr.subnodes[1]
|
51
|
+
raw_operand2.accept(visitor) # Visit means operand2 is evaluated
|
52
|
+
operand2 = stack.pop
|
53
|
+
result = logical_2nd_arg(operand2)
|
54
|
+
end
|
55
|
+
|
56
|
+
stack.push result
|
57
|
+
end
|
58
|
+
|
59
|
+
def logical_2nd_arg(operand2)
|
60
|
+
case operand2
|
61
|
+
when false
|
62
|
+
False.instance # Convert to Lox equivalent
|
63
|
+
when nil
|
64
|
+
Nil.instance # Convert to Lox equivalent
|
65
|
+
when true
|
66
|
+
True.instance # Convert to Lox equivalent
|
67
|
+
when Proc
|
68
|
+
# Second operand wasn't yet evaluated...
|
69
|
+
operand2.call
|
70
|
+
else
|
71
|
+
operand2
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
43
75
|
def after_binary_expr(aBinaryExpr)
|
44
76
|
op = aBinaryExpr.operator
|
45
77
|
operand2 = stack.pop
|
@@ -28,6 +28,13 @@ module Loxxy
|
|
28
28
|
true # Default implementation
|
29
29
|
end
|
30
30
|
|
31
|
+
# Check for inequality of this object with another Lox object
|
32
|
+
# @param other [Datatype::BuiltinDatatype, Object]
|
33
|
+
# @return [Datatype::Boolean]
|
34
|
+
def !=(other)
|
35
|
+
!(self == other)
|
36
|
+
end
|
37
|
+
|
31
38
|
# Negation ('not')
|
32
39
|
# Returns a boolean with opposite truthiness value.
|
33
40
|
# @return [Datatype::Boolean]
|
@@ -35,11 +42,18 @@ module Loxxy
|
|
35
42
|
falsey? ? True.instance : False.instance
|
36
43
|
end
|
37
44
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# @
|
41
|
-
def
|
42
|
-
|
45
|
+
# Returns the first falsey argument (if any),
|
46
|
+
# otherwise returns the last truthy argument.
|
47
|
+
# @param operand2 [Loxxy::Datatype::BuiltinDatatype, Proc]
|
48
|
+
def and(operand2)
|
49
|
+
falsey? ? self : logical_2nd_arg(operand2)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the first truthy argument (if any),
|
53
|
+
# otherwise returns the last falsey argument.
|
54
|
+
# @param operand2 [Loxxy::Datatype::BuiltinDatatype, Proc]
|
55
|
+
def or(operand2)
|
56
|
+
truthy? ? self : logical_2nd_arg(operand2)
|
43
57
|
end
|
44
58
|
|
45
59
|
# Method called from Lox to obtain the text representation of the boolean.
|
@@ -53,6 +67,19 @@ module Loxxy
|
|
53
67
|
def validated_value(aValue)
|
54
68
|
aValue
|
55
69
|
end
|
70
|
+
|
71
|
+
def logical_2nd_arg(operand2)
|
72
|
+
case operand2
|
73
|
+
when false
|
74
|
+
False.instance # Convert to Lox equivalent
|
75
|
+
when nil
|
76
|
+
Nil.instance # Convert to Lox equivalent
|
77
|
+
when true
|
78
|
+
True.instance # Convert to Lox equivalent
|
79
|
+
else
|
80
|
+
operand2
|
81
|
+
end
|
82
|
+
end
|
56
83
|
end # class
|
57
84
|
end # module
|
58
85
|
end # module
|
data/lib/loxxy/version.rb
CHANGED
@@ -262,12 +262,12 @@ LOX_END
|
|
262
262
|
end # context
|
263
263
|
|
264
264
|
context 'Parsing logical expressions' do
|
265
|
-
it 'should parse the logical operations
|
265
|
+
it 'should parse the logical operations between two sub-expression' do
|
266
266
|
%w[or and].each do |connector|
|
267
267
|
input = "5 > 2 #{connector} 3 <= 4;"
|
268
268
|
ptree = subject.parse(input)
|
269
269
|
expr = ptree.root
|
270
|
-
expect(expr).to be_kind_of(Ast::
|
270
|
+
expect(expr).to be_kind_of(Ast::LoxLogicalExpr)
|
271
271
|
expect(expr.operator).to eq(connector.to_sym)
|
272
272
|
expect(expr.operands[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
273
273
|
expect(expr.operands[0].operator).to eq(:>)
|
@@ -284,9 +284,9 @@ LOX_END
|
|
284
284
|
input = '4 > 3 and 1 < 2 or 4 >= 5;'
|
285
285
|
ptree = subject.parse(input)
|
286
286
|
expr = ptree.root
|
287
|
-
expect(expr).to be_kind_of(Ast::
|
287
|
+
expect(expr).to be_kind_of(Ast::LoxLogicalExpr)
|
288
288
|
expect(expr.operator).to eq(:or) # or has lower precedence than and
|
289
|
-
expect(expr.operands[0]).to be_kind_of(Ast::
|
289
|
+
expect(expr.operands[0]).to be_kind_of(Ast::LoxLogicalExpr)
|
290
290
|
expect(expr.operands[0].operator).to eq(:and)
|
291
291
|
conjuncts = expr.operands[0].operands
|
292
292
|
expect(conjuncts[0]).to be_kind_of(Ast::LoxBinaryExpr)
|
data/spec/interpreter_spec.rb
CHANGED
@@ -164,6 +164,53 @@ module Loxxy
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
+
it 'should evaluate the "conjunction" of two values' do
|
168
|
+
[
|
169
|
+
# Return the first falsey argument
|
170
|
+
['false and 1;', false],
|
171
|
+
['nil and 1;', nil],
|
172
|
+
['true and 1;', 1],
|
173
|
+
['1 and 2 and false;', false],
|
174
|
+
['1 and 2 and nil;', nil],
|
175
|
+
|
176
|
+
# Return the last argument if all are truthy
|
177
|
+
['1 and true;', true],
|
178
|
+
['0 and true;', true],
|
179
|
+
['"false" and 0;', 0],
|
180
|
+
['1 and 2 and 3;', 3]
|
181
|
+
|
182
|
+
# TODO test short-circuit at first false argument
|
183
|
+
].each do |(source, predicted)|
|
184
|
+
lox = Loxxy::Interpreter.new
|
185
|
+
result = lox.evaluate(source)
|
186
|
+
expect(result.value == predicted).to be_truthy
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should evaluate the "disjunction" of two values' do
|
191
|
+
[
|
192
|
+
# Return the first truthy argument
|
193
|
+
['1 or true;', 1],
|
194
|
+
['false or 1;', 1],
|
195
|
+
['nil or 1;', 1],
|
196
|
+
['false or false or true;', true],
|
197
|
+
['1 and 2 and nil;', nil],
|
198
|
+
|
199
|
+
# Return the last argument if all are falsey
|
200
|
+
['false or false;', false],
|
201
|
+
['nil or false;', false],
|
202
|
+
['false or nil;', nil],
|
203
|
+
['false or false or false;', false],
|
204
|
+
['false or false or nil;', nil]
|
205
|
+
|
206
|
+
# TODO test short-circuit at first false argument
|
207
|
+
].each do |(source, predicted)|
|
208
|
+
lox = Loxxy::Interpreter.new
|
209
|
+
result = lox.evaluate(source)
|
210
|
+
expect(result.value == predicted).to be_truthy
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
167
214
|
it 'should print the hello world message' do
|
168
215
|
expect { subject.evaluate(hello_world) }.not_to raise_error
|
169
216
|
expect(sample_cfg[:ostream].string).to eq('Hello, world!')
|
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.0.18
|
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-
|
11
|
+
date: 2021-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/loxxy/ast/lox_binary_expr.rb
|
91
91
|
- lib/loxxy/ast/lox_compound_expr.rb
|
92
92
|
- lib/loxxy/ast/lox_literal_expr.rb
|
93
|
+
- lib/loxxy/ast/lox_logical_expr.rb
|
93
94
|
- lib/loxxy/ast/lox_node.rb
|
94
95
|
- lib/loxxy/ast/lox_noop_expr.rb
|
95
96
|
- lib/loxxy/ast/lox_print_stmt.rb
|