skeem 0.2.14 → 0.2.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/.rubocop.yml +451 -195
- data/.travis.yml +27 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +2 -0
- data/README.md +125 -56
- data/Rakefile +2 -0
- data/appveyor.yml +3 -4
- data/bin/cubic.skm +4 -0
- data/bin/hello-world.skm +1 -0
- data/bin/skeem +72 -0
- data/lib/skeem/datum_dsl.rb +40 -30
- data/lib/skeem/element_visitor.rb +5 -2
- data/lib/skeem/grammar.rb +88 -26
- data/lib/skeem/interpreter.rb +9 -7
- data/lib/skeem/parser.rb +6 -4
- data/lib/skeem/primitive/primitive_builder.rb +148 -122
- data/lib/skeem/primitive/primitive_procedure.rb +23 -25
- data/lib/skeem/runtime.rb +17 -15
- data/lib/skeem/s_expr_builder.rb +49 -117
- data/lib/skeem/s_expr_nodes.rb +147 -132
- data/lib/skeem/skeem_exception.rb +1 -0
- data/lib/skeem/skm_binding.rb +9 -11
- data/lib/skeem/skm_compound_datum.rb +9 -6
- data/lib/skeem/skm_element.rb +15 -13
- data/lib/skeem/skm_empty_list.rb +6 -4
- data/lib/skeem/skm_exception.rb +9 -0
- data/lib/skeem/skm_expression.rb +3 -1
- data/lib/skeem/skm_frame.rb +3 -2
- data/lib/skeem/skm_pair.rb +26 -18
- data/lib/skeem/skm_procedure_exec.rb +11 -6
- data/lib/skeem/skm_simple_datum.rb +23 -20
- data/lib/skeem/skm_unary_expression.rb +34 -37
- data/lib/skeem/standard/base.skm +4 -0
- data/lib/skeem/tokenizer.rb +38 -28
- data/lib/skeem/version.rb +3 -1
- data/lib/skeem.rb +2 -0
- data/skeem.gemspec +9 -6
- data/spec/skeem/add4.skm +4 -0
- data/spec/skeem/datum_dsl_spec.rb +13 -12
- data/spec/skeem/element_visitor_spec.rb +14 -10
- data/spec/skeem/interpreter_spec.rb +84 -44
- data/spec/skeem/lambda_spec.rb +13 -11
- data/spec/skeem/parser_spec.rb +23 -19
- data/spec/skeem/primitive/primitive_builder_spec.rb +65 -48
- data/spec/skeem/primitive/primitive_procedure_spec.rb +14 -12
- data/spec/skeem/runtime_spec.rb +20 -18
- data/spec/skeem/s_expr_nodes_spec.rb +8 -6
- data/spec/skeem/skm_compound_datum_spec.rb +12 -10
- data/spec/skeem/skm_element_spec.rb +7 -5
- data/spec/skeem/skm_empty_list_spec.rb +7 -5
- data/spec/skeem/skm_frame_spec.rb +5 -4
- data/spec/skeem/skm_pair_spec.rb +9 -8
- data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
- data/spec/skeem/skm_simple_datum_spec.rb +24 -22
- data/spec/skeem/skm_unary_expression_spec.rb +11 -9
- data/spec/skeem/tokenizer_spec.rb +54 -43
- data/spec/skeem_spec.rb +2 -0
- data/spec/spec_helper.rb +15 -10
- metadata +18 -10
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
data/lib/skeem/skm_binding.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'skm_element'
|
2
4
|
|
3
5
|
module Skeem
|
4
|
-
|
5
6
|
# An identifier that is not a syntactic keyword can be used as a variable.
|
6
7
|
# A variable may give a name to value that is bound (i.e. associated)
|
7
8
|
# to that variable.
|
@@ -16,10 +17,13 @@ module Skeem
|
|
16
17
|
# @param anIdentifier [SkmIdentifier] The variable name
|
17
18
|
# @param aValue [SkmElement] The value to bind to the variable.
|
18
19
|
def initialize(anIdentifier, aValue)
|
20
|
+
super(nil)
|
19
21
|
@variable = anIdentifier
|
20
22
|
@value = aValue
|
21
23
|
end
|
22
24
|
|
25
|
+
# rubocop: disable Style/NegatedIfElseCondition
|
26
|
+
|
23
27
|
def evaluate(aRuntime)
|
24
28
|
name = variable.evaluate(aRuntime)
|
25
29
|
|
@@ -41,6 +45,7 @@ module Skeem
|
|
41
45
|
binding_action(aRuntime, name, result)
|
42
46
|
result
|
43
47
|
end
|
48
|
+
# rubocop: enable Style/NegatedIfElseCondition
|
44
49
|
|
45
50
|
protected
|
46
51
|
|
@@ -56,26 +61,19 @@ module Skeem
|
|
56
61
|
|
57
62
|
result
|
58
63
|
end
|
59
|
-
|
60
64
|
end # class
|
61
65
|
|
62
|
-
|
63
66
|
class SkmUpdateBinding < SkmBinding
|
64
|
-
|
65
67
|
protected
|
66
68
|
|
67
69
|
def binding_action(aRuntime, anIdentifier, anExpression)
|
68
70
|
aRuntime.update_binding(anIdentifier, anExpression)
|
69
71
|
end
|
70
72
|
end # class
|
71
|
-
|
73
|
+
|
72
74
|
class SkmDelayedUpdateBinding < SkmBinding
|
73
75
|
attr_reader :new_val
|
74
|
-
|
75
|
-
def initialize(anIdentifier, aValue)
|
76
|
-
super(anIdentifier, aValue)
|
77
|
-
end
|
78
|
-
|
76
|
+
|
79
77
|
def do_it!(aRuntime)
|
80
78
|
aRuntime.update_binding(variable, new_val)
|
81
79
|
end
|
@@ -85,5 +83,5 @@ module Skeem
|
|
85
83
|
def binding_action(_runtime, _identifier, anExpression)
|
86
84
|
@new_val = anExpression
|
87
85
|
end
|
88
|
-
end # class
|
86
|
+
end # class
|
89
87
|
end # module
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
require_relative 'skm_element'
|
3
5
|
|
@@ -18,10 +20,11 @@ module Skeem
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def ==(other)
|
21
|
-
return true if
|
22
|
-
|
23
|
+
return true if equal?(other)
|
24
|
+
|
25
|
+
case other
|
23
26
|
when SkmCompoundDatum
|
24
|
-
self.class == other.class &&
|
27
|
+
self.class == other.class && members == other.members
|
25
28
|
when Array
|
26
29
|
members == other
|
27
30
|
end
|
@@ -65,8 +68,8 @@ module Skeem
|
|
65
68
|
protected
|
66
69
|
|
67
70
|
def inspect_specific
|
68
|
-
result = ''
|
69
|
-
members.each { |elem| result << elem.inspect
|
71
|
+
result = +''
|
72
|
+
members.each { |elem| result << "#{elem.inspect}, " }
|
70
73
|
result.sub!(/, $/, '')
|
71
74
|
result
|
72
75
|
end
|
@@ -77,4 +80,4 @@ module Skeem
|
|
77
80
|
true
|
78
81
|
end
|
79
82
|
end # class
|
80
|
-
end # module
|
83
|
+
end # module
|
data/lib/skeem/skm_element.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Skeem
|
2
4
|
# Abstract class. Generalization of any S-expr element.
|
3
5
|
SkmElement = Struct.new(:position) do
|
4
6
|
def initialize(aPosition)
|
5
7
|
self.position = aPosition
|
6
8
|
end
|
7
|
-
|
9
|
+
|
8
10
|
def callable?
|
9
11
|
false
|
10
12
|
end
|
@@ -12,15 +14,15 @@ module Skeem
|
|
12
14
|
def number?
|
13
15
|
false
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
def complex?
|
17
19
|
false
|
18
|
-
end
|
20
|
+
end
|
19
21
|
|
20
22
|
def real?
|
21
23
|
false
|
22
24
|
end
|
23
|
-
|
25
|
+
|
24
26
|
def rational?
|
25
27
|
false
|
26
28
|
end
|
@@ -32,7 +34,7 @@ module Skeem
|
|
32
34
|
def boolean?
|
33
35
|
false
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
def char?
|
37
39
|
false
|
38
40
|
end
|
@@ -56,7 +58,7 @@ module Skeem
|
|
56
58
|
def pair?
|
57
59
|
false
|
58
60
|
end
|
59
|
-
|
61
|
+
|
60
62
|
def procedure?
|
61
63
|
false
|
62
64
|
end
|
@@ -73,11 +75,11 @@ module Skeem
|
|
73
75
|
msg = "Missing implementation of method #{self.class.name}##{__method__}"
|
74
76
|
raise NotImplementedError, msg
|
75
77
|
end
|
76
|
-
|
78
|
+
|
77
79
|
def skm_eq?(other)
|
78
80
|
# Default implementation, to override when necessary
|
79
|
-
|
80
|
-
end
|
81
|
+
eqv?(other)
|
82
|
+
end
|
81
83
|
|
82
84
|
# @return [TrueClass, FalseClass] true if quoted element is identical to itself
|
83
85
|
def verbatim?
|
@@ -117,8 +119,8 @@ module Skeem
|
|
117
119
|
# Do nothing
|
118
120
|
end
|
119
121
|
|
120
|
-
|
121
|
-
result = inspect_prefix
|
122
|
+
def inspect
|
123
|
+
result = inspect_prefix.dup
|
122
124
|
result << inspect_specific
|
123
125
|
result << inspect_suffix
|
124
126
|
|
@@ -136,7 +138,7 @@ module Skeem
|
|
136
138
|
end
|
137
139
|
|
138
140
|
def inspect_specific
|
139
|
-
raise NotImplementedError, "Missing #{self.class
|
141
|
+
raise NotImplementedError, "Missing #{self.class}#inspect_specific"
|
140
142
|
end
|
141
143
|
end # struct
|
142
|
-
end # module
|
144
|
+
end # module
|
data/lib/skeem/skm_empty_list.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'singleton'
|
2
4
|
require_relative 'skm_element'
|
3
5
|
|
@@ -42,7 +44,7 @@ module Skeem
|
|
42
44
|
def klone
|
43
45
|
self
|
44
46
|
end
|
45
|
-
|
47
|
+
|
46
48
|
def append_list(aList)
|
47
49
|
aList
|
48
50
|
end
|
@@ -64,14 +66,14 @@ module Skeem
|
|
64
66
|
protected
|
65
67
|
|
66
68
|
def inspect_specific
|
67
|
-
'()'
|
69
|
+
+'()'
|
68
70
|
end
|
69
71
|
|
70
72
|
private
|
71
73
|
|
72
|
-
def initialize
|
74
|
+
def initialize
|
73
75
|
super(0)
|
74
|
-
|
76
|
+
freeze
|
75
77
|
end
|
76
78
|
end # class
|
77
79
|
end # module
|
data/lib/skeem/skm_expression.rb
CHANGED
data/lib/skeem/skm_frame.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'skm_simple_datum'
|
2
4
|
|
3
5
|
module Skeem
|
@@ -139,6 +141,5 @@ module Skeem
|
|
139
141
|
# Notify the value that it is bound to a variable from this frame.
|
140
142
|
anExpression.bound!(self)
|
141
143
|
end
|
142
|
-
|
143
144
|
end # class
|
144
|
-
end # module
|
145
|
+
end # module
|
data/lib/skeem/skm_pair.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'skm_empty_list'
|
2
4
|
|
3
5
|
module Skeem
|
4
6
|
class SkmPair < SkmElement
|
7
|
+
# @return [SkmElement]
|
5
8
|
attr_accessor :car
|
9
|
+
|
10
|
+
# @return [SkmElement]
|
6
11
|
attr_accessor :cdr
|
7
12
|
|
8
13
|
alias first car
|
@@ -41,11 +46,12 @@ module Skeem
|
|
41
46
|
def self.create_from_a(anArray)
|
42
47
|
current = nil
|
43
48
|
return SkmEmptyList.instance if anArray.empty?
|
49
|
+
|
44
50
|
anArray.reverse_each do |elem|
|
45
51
|
if current.nil?
|
46
|
-
current =
|
52
|
+
current = new(elem, SkmEmptyList.instance)
|
47
53
|
else
|
48
|
-
current =
|
54
|
+
current = new(elem, current)
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
@@ -54,6 +60,7 @@ module Skeem
|
|
54
60
|
|
55
61
|
def empty?
|
56
62
|
return false if car
|
63
|
+
|
57
64
|
if [SkmPair, SkmEmptyList].include? cdr.class
|
58
65
|
cdr.empty?
|
59
66
|
else
|
@@ -92,20 +99,20 @@ module Skeem
|
|
92
99
|
end
|
93
100
|
|
94
101
|
def last_pair
|
95
|
-
if cdr.nil? || (cdr == SkmEmptyList.instance) ||
|
102
|
+
if cdr.nil? || (cdr == SkmEmptyList.instance) || !cdr.kind_of?(SkmPair)
|
96
103
|
self
|
97
104
|
else
|
98
105
|
cdr.last_pair
|
99
106
|
end
|
100
107
|
end
|
101
|
-
|
108
|
+
|
102
109
|
def proper?
|
103
|
-
last_node =
|
110
|
+
last_node = last_pair
|
104
111
|
last_node.cdr.nil? || (last_node.cdr == SkmEmptyList.instance)
|
105
112
|
end
|
106
113
|
|
107
114
|
def last
|
108
|
-
|
115
|
+
to_a.last
|
109
116
|
end
|
110
117
|
|
111
118
|
def eqv?(_other)
|
@@ -138,7 +145,7 @@ module Skeem
|
|
138
145
|
end
|
139
146
|
|
140
147
|
def append(anElement)
|
141
|
-
last_one =
|
148
|
+
last_one = last_pair
|
142
149
|
if last_one.cdr.nil? || last_one.cdr.kind_of?(SkmEmptyList)
|
143
150
|
last_one.cdr = SkmPair.new(anElement, SkmEmptyList.instance)
|
144
151
|
else
|
@@ -147,7 +154,7 @@ module Skeem
|
|
147
154
|
end
|
148
155
|
|
149
156
|
def append_list(aList)
|
150
|
-
last_one =
|
157
|
+
last_one = last_pair
|
151
158
|
if last_one.cdr.nil? || last_one.cdr.kind_of?(SkmEmptyList)
|
152
159
|
last_one.cdr = aList
|
153
160
|
else
|
@@ -157,22 +164,23 @@ module Skeem
|
|
157
164
|
|
158
165
|
def evaluate(aRuntime)
|
159
166
|
return SkmEmptyList.instance if empty?
|
167
|
+
|
160
168
|
if car.kind_of?(SkmIdentifier) && car.is_var_name
|
161
169
|
result = aRuntime.evaluate_form(self)
|
162
170
|
else
|
163
171
|
begin
|
164
172
|
result = clone_evaluate(aRuntime)
|
165
|
-
rescue NoMethodError =>
|
166
|
-
$stderr.puts
|
167
|
-
$stderr.puts
|
168
|
-
raise
|
173
|
+
rescue NoMethodError => e
|
174
|
+
$stderr.puts "SkmPair#evaluate: #{inspect}"
|
175
|
+
$stderr.puts "SkmPair as Array: #{to_a.inspect}"
|
176
|
+
raise e
|
169
177
|
end
|
170
178
|
end
|
171
179
|
result
|
172
180
|
end
|
173
181
|
|
174
182
|
def quasiquote(aRuntime)
|
175
|
-
members_eval =
|
183
|
+
members_eval = to_a.map { |elem| elem.quasiquote(aRuntime) }
|
176
184
|
self.class.create_from_a(members_eval)
|
177
185
|
end
|
178
186
|
|
@@ -184,16 +192,17 @@ module Skeem
|
|
184
192
|
|
185
193
|
def quoted!
|
186
194
|
car.quoted!
|
187
|
-
cdr
|
195
|
+
cdr&.quoted!
|
188
196
|
end
|
189
197
|
|
190
198
|
def unquoted!
|
191
199
|
car.unquoted!
|
192
|
-
cdr
|
200
|
+
cdr&.unquoted!
|
193
201
|
end
|
194
202
|
|
195
|
-
def verbatim?
|
203
|
+
def verbatim?
|
196
204
|
return false unless car.verbatim?
|
205
|
+
|
197
206
|
if cdr.nil?
|
198
207
|
true
|
199
208
|
else
|
@@ -211,6 +220,5 @@ module Skeem
|
|
211
220
|
|
212
221
|
result
|
213
222
|
end
|
214
|
-
|
215
223
|
end # class
|
216
|
-
end # module
|
224
|
+
end # module
|
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'runtime'
|
2
4
|
|
3
5
|
module Skeem
|
4
6
|
class SkmProcedureExec
|
7
|
+
# @return [SkmFrame]
|
5
8
|
attr_reader :frame
|
9
|
+
|
10
|
+
# @return [SkmLambda]
|
6
11
|
attr_reader :definition
|
7
12
|
|
8
13
|
def initialize(aLambda)
|
@@ -27,18 +32,18 @@ module Skeem
|
|
27
32
|
result = definition.evaluate_sequence(runtime)
|
28
33
|
runtime.pop
|
29
34
|
# $stderr.puts "Lambda result: #{result.object_id.to_s(16)}" if result.kind_of?(SkmLambda)
|
30
|
-
|
35
|
+
|
31
36
|
result
|
32
37
|
end
|
33
|
-
|
38
|
+
|
34
39
|
private
|
35
|
-
|
40
|
+
|
36
41
|
def evaluate_defs(aRuntime)
|
37
42
|
definition.definitions.each do |bndng|
|
38
|
-
val = bndng.value.evaluate(aRuntime)
|
43
|
+
val = bndng.value.evaluate(aRuntime)
|
39
44
|
var = bndng.variable.evaluate(aRuntime)
|
40
45
|
frame.add_binding(var, val)
|
41
|
-
end
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end # class
|
44
|
-
end # module
|
49
|
+
end # module
|
@@ -1,10 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'skm_element'
|
2
4
|
|
3
5
|
module Skeem
|
4
6
|
# Abstract class. Root of class hierarchy needed for Interpreter
|
5
7
|
# design pattern
|
6
8
|
class SkmSimpleDatum < SkmElement
|
9
|
+
# @return [Rley::Syntax::Token] token object corresponding to Skeem element
|
7
10
|
attr_reader :token
|
11
|
+
|
12
|
+
# @return [Object]
|
8
13
|
attr_reader :value
|
9
14
|
|
10
15
|
def initialize(aToken, aPosition)
|
@@ -14,7 +19,7 @@ module Skeem
|
|
14
19
|
end
|
15
20
|
|
16
21
|
def self.create(aValue)
|
17
|
-
lightweight =
|
22
|
+
lightweight = allocate
|
18
23
|
lightweight.init_value(aValue)
|
19
24
|
return lightweight
|
20
25
|
end
|
@@ -33,15 +38,13 @@ module Skeem
|
|
33
38
|
# @param other [SkmSimpleDatum, Object] object to compare with.
|
34
39
|
# @return [TrueClass, FalseClass]
|
35
40
|
def ==(other)
|
36
|
-
return true if
|
37
|
-
|
38
|
-
result = if other.kind_of?(SkmSimpleDatum)
|
39
|
-
self.value == other.value
|
40
|
-
else
|
41
|
-
self.value == other
|
42
|
-
end
|
41
|
+
return true if equal?(other)
|
43
42
|
|
44
|
-
|
43
|
+
if other.kind_of?(SkmSimpleDatum)
|
44
|
+
value == other.value
|
45
|
+
else
|
46
|
+
value == other
|
47
|
+
end
|
45
48
|
end
|
46
49
|
|
47
50
|
alias eqv? ==
|
@@ -51,7 +54,7 @@ module Skeem
|
|
51
54
|
true
|
52
55
|
end
|
53
56
|
|
54
|
-
def done!
|
57
|
+
def done!
|
55
58
|
# Do nothing
|
56
59
|
end
|
57
60
|
|
@@ -102,21 +105,22 @@ module Skeem
|
|
102
105
|
false
|
103
106
|
end
|
104
107
|
|
108
|
+
# rubocop: disable Style/NegatedIfElseCondition
|
109
|
+
|
105
110
|
def eqv?(other)
|
106
|
-
return true if
|
111
|
+
return true if equal?(other)
|
107
112
|
|
108
|
-
|
109
|
-
if
|
113
|
+
if other.kind_of?(SkmNumber)
|
114
|
+
if exact? != other.exact?
|
110
115
|
false
|
111
116
|
else
|
112
|
-
|
117
|
+
value == other.value
|
113
118
|
end
|
114
119
|
else
|
115
|
-
|
120
|
+
value == other
|
116
121
|
end
|
117
|
-
|
118
|
-
result
|
119
122
|
end
|
123
|
+
# rubocop: enable Style/NegatedIfElseCondition
|
120
124
|
end # class
|
121
125
|
|
122
126
|
class SkmReal < SkmNumber
|
@@ -159,7 +163,6 @@ module Skeem
|
|
159
163
|
char_value = int_value < 0xff ? int_value.chr : [int_value].pack('U')
|
160
164
|
create(char_value)
|
161
165
|
end
|
162
|
-
|
163
166
|
end # class
|
164
167
|
|
165
168
|
class SkmString < SkmSimpleDatum
|
@@ -199,7 +202,7 @@ module Skeem
|
|
199
202
|
end
|
200
203
|
|
201
204
|
def verbatim?
|
202
|
-
|
205
|
+
!is_var_name
|
203
206
|
end
|
204
207
|
|
205
208
|
def quoted!
|
@@ -213,4 +216,4 @@ module Skeem
|
|
213
216
|
|
214
217
|
class SkmReserved < SkmIdentifier
|
215
218
|
end # class
|
216
|
-
end # module
|
219
|
+
end # module
|