skeem 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/skeem/parser.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +57 -27
- data/lib/skeem/{primitive_func.rb → primitive_procedure.rb} +2 -2
- data/lib/skeem/s_expr_builder.rb +6 -6
- data/lib/skeem/s_expr_nodes.rb +47 -16
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +62 -22
- data/spec/skeem/parser_spec.rb +5 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6261d01a57850b9accad9ba2136b59625c37ea58
|
4
|
+
data.tar.gz: 7918e865cadb393e285bfdea1e722970b918549b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a4efb9e1b96a298448c908e11c1df6a03b810586f7008e10eab9c7336705d3df8e4648155f42737f4fd4453e62ad258af031efc3a884019e42f81babc63b722
|
7
|
+
data.tar.gz: abd048ab5117289e788090947e142805183283b49f05bdd5f16ac491888c8a5f1c6857bc631d51b6db7dc5c9229ccd5b6f65962e7950cdd24bb30c2f761ebb98
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## [0.0.9] - 2018-09-15
|
2
|
+
Added primitive procedures: 'number?', 'real?', 'integer?'.
|
3
|
+
|
4
|
+
### Added
|
5
|
+
- Class `PrimitiveBuilder`. Added methods to implement the predicates number?, real?, integer?
|
6
|
+
### Changed
|
7
|
+
- Class hierarchy `SExprElement`. Prefix `SExpr` in class names changed into 'Skm'
|
8
|
+
|
1
9
|
## [0.0.8] - 2018-09-13
|
2
10
|
Added primitive operators: '-', '*', '/' operators.
|
3
11
|
|
data/lib/skeem/parser.rb
CHANGED
@@ -1,19 +1,26 @@
|
|
1
|
-
require_relative '../
|
1
|
+
require_relative '../primitive_procedure'
|
2
2
|
|
3
3
|
module Skeem
|
4
4
|
module Primitive
|
5
5
|
module PrimitiveBuilder
|
6
6
|
def add_primitives(aRuntime)
|
7
7
|
add_arithmetic(aRuntime)
|
8
|
+
add_number_predicates(aRuntime)
|
8
9
|
end
|
9
10
|
|
10
11
|
private
|
11
12
|
|
12
13
|
def add_arithmetic(aRuntime)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def_procedure(aRuntime, create_plus)
|
15
|
+
def_procedure(aRuntime, create_minus)
|
16
|
+
def_procedure(aRuntime, create_multiply)
|
17
|
+
def_procedure(aRuntime, create_divide)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_number_predicates(aRuntime)
|
21
|
+
def_procedure(aRuntime, create_number?)
|
22
|
+
def_procedure(aRuntime, create_real?)
|
23
|
+
def_procedure(aRuntime, create_integer?)
|
17
24
|
end
|
18
25
|
|
19
26
|
def create_plus()
|
@@ -22,11 +29,7 @@ module Skeem
|
|
22
29
|
operands = arglist.tail.to_eval_enum(runtime)
|
23
30
|
raw_result = first_one.value
|
24
31
|
operands.each { |elem| raw_result += elem.value }
|
25
|
-
|
26
|
-
SExprReal.create(raw_result)
|
27
|
-
else
|
28
|
-
SExprInteger.create(raw_result)
|
29
|
-
end
|
32
|
+
to_skm(raw_result)
|
30
33
|
end
|
31
34
|
|
32
35
|
['+', plus_code]
|
@@ -38,11 +41,7 @@ module Skeem
|
|
38
41
|
operands = arglist.tail.to_eval_enum(runtime)
|
39
42
|
raw_result = first_one.value
|
40
43
|
operands.each { |elem| raw_result -= elem.value }
|
41
|
-
|
42
|
-
SExprReal.create(raw_result)
|
43
|
-
else
|
44
|
-
SExprInteger.create(raw_result)
|
45
|
-
end
|
44
|
+
to_skm(raw_result)
|
46
45
|
end
|
47
46
|
|
48
47
|
['-', minus_code]
|
@@ -54,11 +53,7 @@ module Skeem
|
|
54
53
|
operands = arglist.tail.to_eval_enum(runtime)
|
55
54
|
raw_result = first_one.value
|
56
55
|
operands.each { |elem| raw_result *= elem.value }
|
57
|
-
|
58
|
-
SExprReal.create(raw_result)
|
59
|
-
else
|
60
|
-
SExprInteger.create(raw_result)
|
61
|
-
end
|
56
|
+
to_skm(raw_result)
|
62
57
|
end
|
63
58
|
|
64
59
|
['*', multiply_code]
|
@@ -70,24 +65,59 @@ module Skeem
|
|
70
65
|
operands = arglist.tail.to_eval_enum(runtime)
|
71
66
|
raw_result = first_one.value
|
72
67
|
operands.each { |elem| raw_result /= elem.value }
|
73
|
-
|
74
|
-
SExprReal.create(raw_result)
|
75
|
-
else
|
76
|
-
SExprInteger.create(raw_result)
|
77
|
-
end
|
68
|
+
to_skm(raw_result)
|
78
69
|
end
|
79
70
|
|
80
71
|
['/', divide_code]
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_number?()
|
75
|
+
pred_code = ->(runtime, arg) do
|
76
|
+
arg_evaluated = arg.evaluate(runtime)
|
77
|
+
to_skm(arg_evaluated.number?)
|
78
|
+
end
|
79
|
+
|
80
|
+
['number?', pred_code]
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_real?()
|
84
|
+
pred_code = ->(runtime, arg) do
|
85
|
+
arg_evaluated = arg.evaluate(runtime)
|
86
|
+
to_skm(arg_evaluated.real?)
|
87
|
+
end
|
88
|
+
|
89
|
+
['real?', pred_code]
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_integer?()
|
93
|
+
pred_code = ->(runtime, arg) do
|
94
|
+
arg_evaluated = arg.evaluate(runtime)
|
95
|
+
to_skm(arg_evaluated.integer?)
|
96
|
+
end
|
97
|
+
|
98
|
+
['integer?', pred_code]
|
81
99
|
end
|
82
100
|
|
83
|
-
def
|
84
|
-
func =
|
101
|
+
def def_procedure(aRuntime, aPair)
|
102
|
+
func = PrimitiveProcedure.new(aPair.first, aPair.last)
|
85
103
|
define(aRuntime, func.identifier, func)
|
86
104
|
end
|
87
105
|
|
88
106
|
def define(aRuntime, aKey, anEntry)
|
89
107
|
aRuntime.define(aKey, anEntry)
|
90
108
|
end
|
109
|
+
|
110
|
+
# Convert Ruby object into its Skeem counterpart
|
111
|
+
def to_skm(native_obj)
|
112
|
+
case native_obj
|
113
|
+
when TrueClass, FalseClass
|
114
|
+
SkmBoolean.create(native_obj)
|
115
|
+
when Float
|
116
|
+
SkmReal.create(native_obj)
|
117
|
+
when Integer
|
118
|
+
SkmInteger.create(native_obj)
|
119
|
+
end
|
120
|
+
end
|
91
121
|
end # module
|
92
122
|
end # module
|
93
123
|
end # module
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require_relative 's_expr_nodes'
|
2
2
|
|
3
3
|
module Skeem
|
4
|
-
class
|
4
|
+
class PrimitiveProcedure
|
5
5
|
attr_reader(:identifier)
|
6
6
|
attr_reader(:code)
|
7
7
|
|
8
8
|
def initialize(anId, aLambda)
|
9
|
-
@identifier = anId.kind_of?(String) ?
|
9
|
+
@identifier = anId.kind_of?(String) ? SkmIdentifier.create(anId) : anId
|
10
10
|
@code = aLambda
|
11
11
|
end
|
12
12
|
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -9,13 +9,13 @@ module Skeem
|
|
9
9
|
# The Builder pattern creates a complex object
|
10
10
|
# (say, a parse tree) from simpler objects (terminal and non-terminal
|
11
11
|
# nodes) and using a step by step approach.
|
12
|
-
class
|
12
|
+
class SkmBuilder < Rley::ParseRep::ASTBaseBuilder
|
13
13
|
Terminal2NodeClass = {
|
14
|
-
'BOOLEAN' =>
|
15
|
-
'IDENTIFIER' =>
|
16
|
-
'INTEGER' =>
|
17
|
-
'REAL' =>
|
18
|
-
'STRING_LIT' =>
|
14
|
+
'BOOLEAN' => SkmBoolean,
|
15
|
+
'IDENTIFIER' => SkmIdentifier,
|
16
|
+
'INTEGER' => SkmInteger,
|
17
|
+
'REAL' => SkmReal,
|
18
|
+
'STRING_LIT' => SkmString
|
19
19
|
}.freeze
|
20
20
|
|
21
21
|
# Create a new AST builder instance.
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -5,19 +5,31 @@ require 'forwardable'
|
|
5
5
|
|
6
6
|
module Skeem
|
7
7
|
# Abstract class. Generalization of any S-expr element.
|
8
|
-
|
8
|
+
SkmElement = Struct.new(:position) do
|
9
9
|
def initialize(aPosition)
|
10
10
|
self.position = aPosition
|
11
11
|
end
|
12
12
|
|
13
13
|
def evaluate(_runtime)
|
14
|
-
raise NotImplementedError
|
14
|
+
raise NotImplementedError, "Missing implementation of #{self.class.name}"
|
15
15
|
end
|
16
16
|
|
17
17
|
def done!()
|
18
18
|
# Do nothing
|
19
19
|
end
|
20
20
|
|
21
|
+
def number?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def real?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def integer?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
21
33
|
# Abstract method.
|
22
34
|
# Part of the 'visitee' role in Visitor design pattern.
|
23
35
|
# @param _visitor[ParseTreeVisitor] the visitor
|
@@ -28,7 +40,7 @@ module Skeem
|
|
28
40
|
|
29
41
|
# Abstract class. Root of class hierarchy needed for Interpreter
|
30
42
|
# design pattern
|
31
|
-
class
|
43
|
+
class SkmTerminal < SkmElement
|
32
44
|
attr_reader :token
|
33
45
|
attr_reader :value
|
34
46
|
|
@@ -68,37 +80,46 @@ module Skeem
|
|
68
80
|
end
|
69
81
|
end # class
|
70
82
|
|
71
|
-
class
|
83
|
+
class SkmBoolean < SkmTerminal
|
72
84
|
end # class
|
73
85
|
|
74
|
-
class
|
86
|
+
class SkmNumber < SkmTerminal
|
87
|
+
def number?
|
88
|
+
true
|
89
|
+
end
|
75
90
|
end # class
|
76
91
|
|
77
|
-
class
|
92
|
+
class SkmReal < SkmNumber
|
93
|
+
def real?
|
94
|
+
true
|
95
|
+
end
|
78
96
|
end # class
|
79
97
|
|
80
|
-
class
|
98
|
+
class SkmInteger < SkmReal
|
99
|
+
def integer?
|
100
|
+
true
|
101
|
+
end
|
81
102
|
end # class
|
82
103
|
|
83
|
-
class
|
104
|
+
class SkmString < SkmTerminal
|
84
105
|
# Override
|
85
106
|
def init_value(aValue)
|
86
107
|
super(aValue.dup)
|
87
108
|
end
|
88
109
|
end # class
|
89
110
|
|
90
|
-
class
|
111
|
+
class SkmIdentifier < SkmTerminal
|
91
112
|
# Override
|
92
113
|
def init_value(aValue)
|
93
114
|
super(aValue.dup)
|
94
115
|
end
|
95
116
|
end # class
|
96
117
|
|
97
|
-
class
|
118
|
+
class SkmReserved < SkmIdentifier
|
98
119
|
end # class
|
99
120
|
|
100
121
|
|
101
|
-
class
|
122
|
+
class SkmList < SkmElement
|
102
123
|
attr_accessor(:members)
|
103
124
|
extend Forwardable
|
104
125
|
|
@@ -112,9 +133,19 @@ module Skeem
|
|
112
133
|
def head()
|
113
134
|
return members.first
|
114
135
|
end
|
115
|
-
|
136
|
+
|
116
137
|
def tail()
|
117
|
-
|
138
|
+
SkmList.new(members.slice(1..-1))
|
139
|
+
end
|
140
|
+
|
141
|
+
def evaluate(aRuntime)
|
142
|
+
result = nil
|
143
|
+
|
144
|
+
members.each do |elem|
|
145
|
+
result = elem.evaluate(aRuntime)
|
146
|
+
end
|
147
|
+
|
148
|
+
result
|
118
149
|
end
|
119
150
|
|
120
151
|
# Factory method.
|
@@ -145,21 +176,21 @@ module Skeem
|
|
145
176
|
alias subnodes members
|
146
177
|
end # class
|
147
178
|
|
148
|
-
class ProcedureCall <
|
179
|
+
class ProcedureCall < SkmElement
|
149
180
|
attr_reader :operator
|
150
181
|
attr_reader :operands
|
151
182
|
|
152
183
|
def initialize(aPosition, anOperator, theOperands)
|
153
184
|
super(aPosition)
|
154
185
|
@operator = anOperator
|
155
|
-
@operands =
|
186
|
+
@operands = SkmList.new(theOperands)
|
156
187
|
end
|
157
188
|
|
158
189
|
def evaluate(aRuntime)
|
159
190
|
proc_key = operator.evaluate(aRuntime)
|
160
191
|
unless aRuntime.include?(proc_key.value)
|
161
192
|
err = StandardError
|
162
|
-
key = proc_key.kind_of?(
|
193
|
+
key = proc_key.kind_of?(SkmIdentifier) ? proc_key.value : proc_key
|
163
194
|
err_msg = "Unknown function '#{key}'"
|
164
195
|
raise err, err_msg
|
165
196
|
end
|
data/lib/skeem/version.rb
CHANGED
@@ -31,7 +31,7 @@ module Skeem
|
|
31
31
|
]
|
32
32
|
samples.each do |source, predicted|
|
33
33
|
result = subject.run(source)
|
34
|
-
expect(result).to be_kind_of(
|
34
|
+
expect(result).to be_kind_of(SkmBoolean)
|
35
35
|
expect(result.value).to eq(predicted)
|
36
36
|
end
|
37
37
|
end
|
@@ -46,7 +46,7 @@ module Skeem
|
|
46
46
|
]
|
47
47
|
samples.each do |source, predicted|
|
48
48
|
result = subject.run(source)
|
49
|
-
expect(result).to be_kind_of(
|
49
|
+
expect(result).to be_kind_of(SkmInteger)
|
50
50
|
expect(result.value).to eq(predicted)
|
51
51
|
end
|
52
52
|
end
|
@@ -61,7 +61,7 @@ module Skeem
|
|
61
61
|
]
|
62
62
|
samples.each do |source, predicted|
|
63
63
|
result = subject.run(source)
|
64
|
-
expect(result).to be_kind_of(
|
64
|
+
expect(result).to be_kind_of(SkmReal)
|
65
65
|
expect(result.value).to eq(predicted)
|
66
66
|
end
|
67
67
|
end
|
@@ -72,7 +72,7 @@ module Skeem
|
|
72
72
|
]
|
73
73
|
samples.each do |source, predicted|
|
74
74
|
result = subject.run(source)
|
75
|
-
expect(result).to be_kind_of(
|
75
|
+
expect(result).to be_kind_of(SkmString)
|
76
76
|
expect(result.value).to eq(predicted)
|
77
77
|
end
|
78
78
|
end
|
@@ -84,41 +84,81 @@ module Skeem
|
|
84
84
|
]
|
85
85
|
samples.each do |source, predicted|
|
86
86
|
result = subject.run(source)
|
87
|
-
expect(result).to be_kind_of(
|
87
|
+
expect(result).to be_kind_of(SkmIdentifier)
|
88
88
|
expect(result.value).to eq(predicted)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end # context
|
92
92
|
|
93
|
-
context 'Built-in primitive
|
94
|
-
it 'should
|
93
|
+
context 'Built-in primitive procedures' do
|
94
|
+
it 'should implement the addition of integers' do
|
95
95
|
result = subject.run('(+ 2 2)')
|
96
|
-
expect(result).to be_kind_of(
|
96
|
+
expect(result).to be_kind_of(SkmInteger)
|
97
97
|
expect(result.value).to eq(4)
|
98
98
|
end
|
99
99
|
|
100
|
-
it 'should
|
100
|
+
it 'should implement the addition of real numbers' do
|
101
101
|
result = subject.run('(+ 2 2.34)')
|
102
|
-
expect(result).to be_kind_of(
|
102
|
+
expect(result).to be_kind_of(SkmReal)
|
103
103
|
expect(result.value).to eq(4.34)
|
104
104
|
end
|
105
|
-
|
106
|
-
it 'should
|
105
|
+
|
106
|
+
it 'should implement the product of numbers' do
|
107
107
|
result = subject.run('(* 2 3 4)')
|
108
|
-
expect(result).to be_kind_of(
|
109
|
-
expect(result.value).to eq(24)
|
110
|
-
end
|
108
|
+
expect(result).to be_kind_of(SkmInteger)
|
109
|
+
expect(result.value).to eq(24)
|
110
|
+
end
|
111
111
|
|
112
|
-
it 'should
|
112
|
+
it 'should implement the division of numbers' do
|
113
113
|
result = subject.run('(/ 24 3)')
|
114
|
-
expect(result).to be_kind_of(
|
115
|
-
expect(result.value).to eq(8)
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'should
|
114
|
+
expect(result).to be_kind_of(SkmInteger)
|
115
|
+
expect(result.value).to eq(8)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should implement the arithmetic expressions' do
|
119
119
|
result = subject.run('(+ (* 2 100) (* 1 10))')
|
120
|
-
expect(result).to be_kind_of(
|
120
|
+
expect(result).to be_kind_of(SkmInteger)
|
121
121
|
expect(result.value).to eq(210)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should implement the number? predicate' do
|
125
|
+
checks = [
|
126
|
+
['(number? 3.1)', true],
|
127
|
+
['(number? 3)', true],
|
128
|
+
['(number? "3")', false],
|
129
|
+
['(number? #t)', false]
|
130
|
+
]
|
131
|
+
checks.each do |(skeem_expr, expectation)|
|
132
|
+
result = subject.run(skeem_expr)
|
133
|
+
expect(result.value).to eq(expectation)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should implement the real? predicate' do
|
138
|
+
checks = [
|
139
|
+
['(real? 3.1)', true],
|
140
|
+
['(real? 3)', true],
|
141
|
+
['(real? "3")', false],
|
142
|
+
['(real? #t)', false]
|
143
|
+
]
|
144
|
+
checks.each do |(skeem_expr, expectation)|
|
145
|
+
result = subject.run(skeem_expr)
|
146
|
+
expect(result.value).to eq(expectation)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should implement the integer? predicate' do
|
151
|
+
checks = [
|
152
|
+
['(integer? 3.1)', false],
|
153
|
+
# ['(integer? 3.0)', true], TODO: should pass when exact? will be implemented
|
154
|
+
['(integer? 3)', true],
|
155
|
+
['(integer? "3")', false],
|
156
|
+
['(integer? #t)', false]
|
157
|
+
]
|
158
|
+
checks.each do |(skeem_expr, expectation)|
|
159
|
+
result = subject.run(skeem_expr)
|
160
|
+
expect(result.value).to eq(expectation)
|
161
|
+
end
|
122
162
|
end
|
123
163
|
end # context
|
124
164
|
end # describe
|
data/spec/skeem/parser_spec.rb
CHANGED
@@ -23,7 +23,7 @@ module Skeem
|
|
23
23
|
]
|
24
24
|
samples.each do |source, predicted|
|
25
25
|
ptree = subject.parse(source)
|
26
|
-
expect(ptree.root).to be_kind_of(
|
26
|
+
expect(ptree.root).to be_kind_of(SkmBoolean)
|
27
27
|
expect(ptree.root.value).to eq(predicted)
|
28
28
|
end
|
29
29
|
end
|
@@ -38,7 +38,7 @@ module Skeem
|
|
38
38
|
]
|
39
39
|
samples.each do |source, predicted|
|
40
40
|
ptree = subject.parse(source)
|
41
|
-
expect(ptree.root).to be_kind_of(
|
41
|
+
expect(ptree.root).to be_kind_of(SkmInteger)
|
42
42
|
expect(ptree.root.value).to eq(predicted)
|
43
43
|
end
|
44
44
|
end
|
@@ -53,7 +53,7 @@ module Skeem
|
|
53
53
|
]
|
54
54
|
samples.each do |source, predicted|
|
55
55
|
ptree = subject.parse(source)
|
56
|
-
expect(ptree.root).to be_kind_of(
|
56
|
+
expect(ptree.root).to be_kind_of(SkmReal)
|
57
57
|
expect(ptree.root.value).to eq(predicted)
|
58
58
|
end
|
59
59
|
end
|
@@ -64,7 +64,7 @@ module Skeem
|
|
64
64
|
]
|
65
65
|
samples.each do |source, predicted|
|
66
66
|
ptree = subject.parse(source)
|
67
|
-
expect(ptree.root).to be_kind_of(
|
67
|
+
expect(ptree.root).to be_kind_of(SkmString)
|
68
68
|
expect(ptree.root.value).to eq(predicted)
|
69
69
|
end
|
70
70
|
end
|
@@ -75,7 +75,7 @@ module Skeem
|
|
75
75
|
]
|
76
76
|
samples.each do |source, predicted|
|
77
77
|
ptree = subject.parse(source)
|
78
|
-
expect(ptree.root).to be_kind_of(
|
78
|
+
expect(ptree.root).to be_kind_of(SkmIdentifier)
|
79
79
|
expect(ptree.root.value).to eq(predicted)
|
80
80
|
end
|
81
81
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skeem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -90,7 +90,7 @@ files:
|
|
90
90
|
- lib/skeem/interpreter.rb
|
91
91
|
- lib/skeem/parser.rb
|
92
92
|
- lib/skeem/primitive/primitive_builder.rb
|
93
|
-
- lib/skeem/
|
93
|
+
- lib/skeem/primitive_procedure.rb
|
94
94
|
- lib/skeem/runtime.rb
|
95
95
|
- lib/skeem/s_expr_builder.rb
|
96
96
|
- lib/skeem/s_expr_nodes.rb
|