loxxy 0.0.15 → 0.0.16
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 +22 -0
- data/README.md +6 -3
- data/lib/loxxy/back_end/engine.rb +1 -1
- data/lib/loxxy/datatype/false.rb +16 -0
- data/lib/loxxy/datatype/lx_string.rb +17 -4
- data/lib/loxxy/datatype/nil.rb +16 -0
- data/lib/loxxy/datatype/number.rb +60 -15
- data/lib/loxxy/datatype/true.rb +16 -0
- data/lib/loxxy/version.rb +1 -1
- data/spec/interpreter_spec.rb +65 -9
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d7d30d3246aa8a8f06f3456d3996c680e9ddb4ed31bcf9fff99685702e50dd1
|
4
|
+
data.tar.gz: dc428ddd0fc03e153e70873bc2827b6e4aac813e5fdfba40ef2f28bfa7283fc2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d90f2494a324be036dae2f3d38636c571009b60f19d2b3d917b242ab98d231e03bb121f577e5598ac63514cc5817814972cabe927f05af2842a5a97c89eb69d9
|
7
|
+
data.tar.gz: e09a70a27baa1408904e1bfe512f4f523b8e4efd1aab00412b993c8f4a35b5498f1f6ddb5e67697108c80a91778301e41c15741451e73e1d869496d96441757a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## [0.0.16] - 2021-01-11
|
2
|
+
- The interpreter can evaluate product and division of two numbers.
|
3
|
+
- It also implements equality `==` and inequality `!=` operators
|
4
|
+
|
5
|
+
## Added
|
6
|
+
- Method `Datatype::False#==` for equality testing
|
7
|
+
- Method `Datatype::False#!=` for inequality testing
|
8
|
+
- Method `Datatype::LXString#==` for equality testing
|
9
|
+
- Method `Datatype::LXString#!=` for inequality testing
|
10
|
+
- Method `Datatype::Nil#==` for equality testing
|
11
|
+
- Method `Datatype::Nil#!=` for inequality testing
|
12
|
+
- Method `Datatype::Number#==` for equality testing
|
13
|
+
- Method `Datatype::Number#!=` for inequality testing
|
14
|
+
- Method `Datatype::Number#*` for multiply operator
|
15
|
+
- Method `Datatype::Number#/` for divide operator
|
16
|
+
- Method `Datatype::True#==` for equality testing
|
17
|
+
- Method `Datatype::True#!=` for inequality testing
|
18
|
+
|
19
|
+
## Changed
|
20
|
+
- Method `BackEnd::Engine#after_binary_expr` to allow `*`, `/`, `==`, `!=` operators
|
21
|
+
- File `README.md` updated for the newly implemented operators
|
22
|
+
|
1
23
|
## [0.0.15] - 2021-01-11
|
2
24
|
- The interpreter can evaluate substraction between two numbers.
|
3
25
|
|
data/README.md
CHANGED
@@ -166,6 +166,9 @@ The parser recognizes all the __Lox__ operators, delimiters and separators:
|
|
166
166
|
Of these, the interpreter implements:
|
167
167
|
`+` (addition of two numbers or string concatenation)
|
168
168
|
`-` (difference between two numbers)
|
169
|
+
`*` (product of two numbers)
|
170
|
+
`/` (division of two number)
|
171
|
+
`==` and `!=` (in)equality testing of two Lox values
|
169
172
|
|
170
173
|
#### Delimiters
|
171
174
|
The parser knows all the __Lox__ grouping delimiters:
|
@@ -193,9 +196,9 @@ loxxy supports all the standard __Lox__ datatypes:
|
|
193
196
|
### Implemented expressions
|
194
197
|
Loxxy implements expressions:
|
195
198
|
- Plain literals only; or,
|
196
|
-
- Addition of two numbers; or,
|
197
|
-
-
|
198
|
-
-
|
199
|
+
- Addition, subtraction, product and division of two numbers; or,
|
200
|
+
- Concatenation of two strings,
|
201
|
+
- (In)equality test of two Lox values
|
199
202
|
|
200
203
|
### Implemented statements
|
201
204
|
Loxxy implements the following statements:
|
@@ -44,7 +44,7 @@ module Loxxy
|
|
44
44
|
op = aBinaryExpr.operator
|
45
45
|
operand2 = stack.pop
|
46
46
|
operand1 = stack.pop
|
47
|
-
implemented = %i[+ -].include?(op)
|
47
|
+
implemented = %i[+ - * / == !=].include?(op)
|
48
48
|
if implemented && operand1.respond_to?(op)
|
49
49
|
stack.push operand1.send(op, operand2)
|
50
50
|
else
|
data/lib/loxxy/datatype/false.rb
CHANGED
@@ -19,6 +19,22 @@ module Loxxy
|
|
19
19
|
def false?
|
20
20
|
true
|
21
21
|
end
|
22
|
+
|
23
|
+
# Check for equality of a Lox False with another Lox object
|
24
|
+
# @param other [Datatype::BuiltinDatatype, FalseClass, Object]
|
25
|
+
# @return [Datatype::Boolean]
|
26
|
+
def ==(other)
|
27
|
+
falsey = other.kind_of?(False) || other.kind_of?(FalseClass)
|
28
|
+
falsey ? True.instance : False.instance
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check for inequality of a Lox False with another Lox object
|
32
|
+
# @param other [Datatype::BuiltinDatatype, FalseClass, Object]
|
33
|
+
# @return [Datatype::Boolean]
|
34
|
+
def !=(other)
|
35
|
+
falsey = other.kind_of?(False) || other.kind_of?(FalseClass)
|
36
|
+
falsey ? False.instance : True.instance
|
37
|
+
end
|
22
38
|
end # class
|
23
39
|
|
24
40
|
False.instance.freeze # Make the sole instance immutable
|
@@ -7,8 +7,8 @@ module Loxxy
|
|
7
7
|
module Datatype
|
8
8
|
# Class for representing a Lox string of characters value.
|
9
9
|
class LXString < BuiltinDatatype
|
10
|
-
#
|
11
|
-
# @param other [Datatype::LxString, String]
|
10
|
+
# Check the equality of a Lox String with another Lox object.
|
11
|
+
# @param other [Datatype::LxString, String, Object]
|
12
12
|
# @return [Datatype::Boolean]
|
13
13
|
def ==(other)
|
14
14
|
case other
|
@@ -17,8 +17,21 @@ module Loxxy
|
|
17
17
|
when String
|
18
18
|
(value == other) ? True.instance : False.instance
|
19
19
|
else
|
20
|
-
|
21
|
-
|
20
|
+
False.instance
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Check the inequality of a Lox String with another Lox object.
|
25
|
+
# @param other [Datatype::LxString, String, Object]
|
26
|
+
# @return [Datatype::Boolean]
|
27
|
+
def !=(other)
|
28
|
+
case other
|
29
|
+
when LXString
|
30
|
+
(value != other.value) ? True.instance : False.instance
|
31
|
+
when String
|
32
|
+
(value != other) ? True.instance : False.instance
|
33
|
+
else
|
34
|
+
True.instance
|
22
35
|
end
|
23
36
|
end
|
24
37
|
|
data/lib/loxxy/datatype/nil.rb
CHANGED
@@ -14,6 +14,22 @@ module Loxxy
|
|
14
14
|
super(nil)
|
15
15
|
end
|
16
16
|
|
17
|
+
# Check the equality with another object.
|
18
|
+
# @param other [Datatype::BuiltinDatatype, NilClass, Object]
|
19
|
+
# @return [Datatype::Boolean]
|
20
|
+
def ==(other)
|
21
|
+
is_nil = other.kind_of?(Nil) || other.kind_of?(NilClass)
|
22
|
+
is_nil ? True.instance : False.instance
|
23
|
+
end
|
24
|
+
|
25
|
+
# Check the inequality with another object.
|
26
|
+
# @param other [Datatype::BuiltinDatatype, NilClass, Object]
|
27
|
+
# @return [Datatype::Boolean]
|
28
|
+
def !=(other)
|
29
|
+
is_nil = other.kind_of?(Nil) || other.kind_of?(NilClass)
|
30
|
+
is_nil ? False.instance : True.instance
|
31
|
+
end
|
32
|
+
|
17
33
|
# Method called from Lox to obtain the text representation of nil.
|
18
34
|
# @return [String]
|
19
35
|
def to_str
|
@@ -7,21 +7,6 @@ module Loxxy
|
|
7
7
|
module Datatype
|
8
8
|
# Class for representing a Lox numeric value.
|
9
9
|
class Number < BuiltinDatatype
|
10
|
-
# Compare a Lox Number with another Lox (or genuine Ruby) Number
|
11
|
-
# @param other [Datatype::Number, Numeric]
|
12
|
-
# @return [Datatype::Boolean]
|
13
|
-
def ==(other)
|
14
|
-
case other
|
15
|
-
when Number
|
16
|
-
(value == other.value) ? True.instance : False.instance
|
17
|
-
when Numeric
|
18
|
-
(value == other) ? True.instance : False.instance
|
19
|
-
else
|
20
|
-
err_msg = "Cannot compare a #{self.class} with #{other.class}"
|
21
|
-
raise StandardError, err_msg
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
10
|
# Perform the addition of two Lox numbers or
|
26
11
|
# one Lox number and a Ruby Numeric
|
27
12
|
# @param other [Loxxy::Datatype::Number, Numeric]
|
@@ -54,6 +39,66 @@ module Loxxy
|
|
54
39
|
end
|
55
40
|
end
|
56
41
|
|
42
|
+
# Perform the multiplication of two Lox numbers or
|
43
|
+
# one Lox number and a Ruby Numeric
|
44
|
+
# @param other [Loxxy::Datatype::Number, Numeric]
|
45
|
+
# @return [Loxxy::Datatype::Number]
|
46
|
+
def *(other)
|
47
|
+
case other
|
48
|
+
when Number
|
49
|
+
self.class.new(value * other.value)
|
50
|
+
when Numeric
|
51
|
+
self.class.new(value * other)
|
52
|
+
else
|
53
|
+
err_msg = "'*': Operands must be numbers."
|
54
|
+
raise TypeError, err_msg
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Perform the division of two Lox numbers or
|
59
|
+
# one Lox number and a Ruby Numeric
|
60
|
+
# @param other [Loxxy::Datatype::Number, Numeric]
|
61
|
+
# @return [Loxxy::Datatype::Number]
|
62
|
+
def /(other)
|
63
|
+
case other
|
64
|
+
when Number
|
65
|
+
self.class.new(value / other.value)
|
66
|
+
when Numeric
|
67
|
+
self.class.new(value / other)
|
68
|
+
else
|
69
|
+
err_msg = "'/': Operands must be numbers."
|
70
|
+
raise TypeError, err_msg
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Check the equality of a Lox number object with another object
|
75
|
+
# @param other [Datatype::BuiltinDatatype, Numeric, Object]
|
76
|
+
# @return [Datatype::Boolean]
|
77
|
+
def ==(other)
|
78
|
+
case other
|
79
|
+
when Number
|
80
|
+
(value == other.value) ? True.instance : False.instance
|
81
|
+
when Numeric
|
82
|
+
(value == other) ? True.instance : False.instance
|
83
|
+
else
|
84
|
+
False.instance
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Check the inequality of a Lox number object with another object
|
89
|
+
# @param other [Datatype::BuiltinDatatype, Numeric, Object]
|
90
|
+
# @return [Datatype::Boolean]
|
91
|
+
def !=(other)
|
92
|
+
case other
|
93
|
+
when Number
|
94
|
+
(value != other.value) ? True.instance : False.instance
|
95
|
+
when Numeric
|
96
|
+
(value != other) ? True.instance : False.instance
|
97
|
+
else
|
98
|
+
True.instance
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
57
102
|
protected
|
58
103
|
|
59
104
|
def validated_value(aValue)
|
data/lib/loxxy/datatype/true.rb
CHANGED
@@ -19,6 +19,22 @@ module Loxxy
|
|
19
19
|
def true?
|
20
20
|
true
|
21
21
|
end
|
22
|
+
|
23
|
+
# Check for equality of a Lox True with another Lox object
|
24
|
+
# @param other [Datatype::True, TrueClass, Object]
|
25
|
+
# @return [Datatype::Boolean]
|
26
|
+
def ==(other)
|
27
|
+
thruthy = other.kind_of?(True) || other.kind_of?(TrueClass)
|
28
|
+
thruthy ? True.instance : False.instance
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check for inequality of a Lox True with another Lox object
|
32
|
+
# @param other [Datatype::BuiltinDatatype, TrueClass, Object]
|
33
|
+
# @return [Datatype::Boolean]
|
34
|
+
def !=(other)
|
35
|
+
thruthy = other.kind_of?(True) || other.kind_of?(TrueClass)
|
36
|
+
thruthy ? False.instance : True.instance
|
37
|
+
end
|
22
38
|
end # class
|
23
39
|
|
24
40
|
True.instance.freeze # Make the sole instance immutable
|
data/lib/loxxy/version.rb
CHANGED
data/spec/interpreter_spec.rb
CHANGED
@@ -25,32 +25,88 @@ module Loxxy
|
|
25
25
|
end
|
26
26
|
end # context
|
27
27
|
|
28
|
-
context 'Evaluating
|
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
|
-
|
28
|
+
context 'Evaluating arithmetic operations code:' do
|
36
29
|
it 'should evaluate an addition of two numbers' do
|
37
30
|
result = subject.evaluate('123 + 456; // => 579')
|
38
31
|
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
39
32
|
expect(result == 579).to be_true
|
40
33
|
end
|
41
34
|
|
42
|
-
it 'should evaluate a
|
35
|
+
it 'should evaluate a subtraction of two numbers' do
|
43
36
|
result = subject.evaluate('4 - 3; // => 1')
|
44
37
|
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
45
38
|
expect(result == 1).to be_true
|
46
39
|
end
|
47
40
|
|
41
|
+
it 'should evaluate a multiplication of two numbers' do
|
42
|
+
result = subject.evaluate('5 * 3; // => 15')
|
43
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
44
|
+
expect(result == 15).to be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should evaluate a division of two numbers' do
|
48
|
+
result = subject.evaluate('8 / 2; // => 4')
|
49
|
+
expect(result).to be_kind_of(Loxxy::Datatype::Number)
|
50
|
+
expect(result == 4).to be_true
|
51
|
+
end
|
52
|
+
end # context
|
53
|
+
|
54
|
+
context 'Evaluating Lox code:' do
|
55
|
+
let(:hello_world) { 'print "Hello, world!";' }
|
56
|
+
|
57
|
+
it 'should evaluate core data types' do
|
58
|
+
result = subject.evaluate('true; // Not false')
|
59
|
+
expect(result).to be_kind_of(Loxxy::Datatype::True)
|
60
|
+
end
|
61
|
+
|
48
62
|
it 'should evaluate string concatenation' do
|
49
63
|
result = subject.evaluate('"str" + "ing"; // => "string"')
|
50
64
|
expect(result).to be_kind_of(Loxxy::Datatype::LXString)
|
51
65
|
expect(result == 'string').to be_true
|
52
66
|
end
|
53
67
|
|
68
|
+
it 'should perform the equality tests of two values' do
|
69
|
+
[
|
70
|
+
['nil == nil;', true],
|
71
|
+
['true == true;', true],
|
72
|
+
['true == false;', false],
|
73
|
+
['1 == 1;', true],
|
74
|
+
['1 == 2;', false],
|
75
|
+
['0 == 0;', true],
|
76
|
+
['"str" == "str";', true],
|
77
|
+
['"str" == "ing";', false],
|
78
|
+
['"" == "";', true],
|
79
|
+
['nil == false;', false],
|
80
|
+
['false == 0;', false],
|
81
|
+
['0 == "0";', false]
|
82
|
+
].each do |(source, predicted)|
|
83
|
+
lox = Loxxy::Interpreter.new
|
84
|
+
result = lox.evaluate(source)
|
85
|
+
expect(result.value == predicted).to be_truthy
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should perform the inequality test of two values' do
|
90
|
+
[
|
91
|
+
['nil != nil;', false],
|
92
|
+
['true != true;', false],
|
93
|
+
['true != false;', true],
|
94
|
+
['1 != 1;', false],
|
95
|
+
['1 != 2;', true],
|
96
|
+
['0 != 0;', false],
|
97
|
+
['"str" != "str";', false],
|
98
|
+
['"str" != "ing";', true],
|
99
|
+
['"" != "";', false],
|
100
|
+
['nil != false;', true],
|
101
|
+
['false != 0;', true],
|
102
|
+
['0 != "0";', true]
|
103
|
+
].each do |(source, predicted)|
|
104
|
+
lox = Loxxy::Interpreter.new
|
105
|
+
result = lox.evaluate(source)
|
106
|
+
expect(result.value == predicted).to be_truthy
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
54
110
|
it 'should print the hello world message' do
|
55
111
|
expect { subject.evaluate(hello_world) }.not_to raise_error
|
56
112
|
expect(sample_cfg[:ostream].string).to eq('Hello, world!')
|