skeem 0.0.28 → 0.1.00
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 +24 -1
- data/README.md +3 -3
- data/lib/skeem/datum_dsl.rb +11 -6
- data/lib/skeem/element_visitor.rb +26 -0
- data/lib/skeem/grammar.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +111 -33
- data/lib/skeem/primitive/primitive_procedure.rb +6 -5
- data/lib/skeem/runtime.rb +5 -5
- data/lib/skeem/s_expr_builder.rb +28 -12
- data/lib/skeem/s_expr_nodes.rb +39 -9
- data/lib/skeem/skm_compound_datum.rb +3 -2
- data/lib/skeem/skm_element.rb +4 -0
- data/lib/skeem/skm_empty_list.rb +60 -0
- data/lib/skeem/skm_pair.rb +126 -0
- data/lib/skeem/skm_simple_datum.rb +1 -2
- data/lib/skeem/standard/base.skm +24 -0
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/datum_dsl_spec.rb +45 -33
- data/spec/skeem/element_visitor_spec.rb +54 -53
- data/spec/skeem/interpreter_spec.rb +29 -25
- data/spec/skeem/parser_spec.rb +3 -3
- data/spec/skeem/primitive/primitive_builder_spec.rb +121 -12
- data/spec/skeem/s_expr_nodes_spec.rb +10 -10
- data/spec/skeem/skm_element_spec.rb +1 -0
- data/spec/skeem/skm_empty_list_spec.rb +44 -0
- data/spec/skeem/skm_pair_spec.rb +140 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c18e55326253e46eb6287437d7730b35a115ac6d
|
4
|
+
data.tar.gz: 5e868f0b8fb7fc6f0814a3dc25f7f09d1b4c542f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 192c9172702d53cbbe60475740a4cb6e95b7641a6d817287d3b446eb4d40ebc4662f3cfc2eec0e36d40717b076a08005e2e541bcd8639bdb5661e3f153a727da
|
7
|
+
data.tar.gz: c2ae96f49f854b63919966ecd1d9275f89da8a1487230c78509e1533a8748813b589f571dcca9065f3262fd51e167608e8759e0412dd1c69c43c4579af0e9305
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,32 @@
|
|
1
|
+
## [0.1.00] - 2018-12-28
|
2
|
+
- Version bumped because lists are re-implemented in a way to closer to historical Scheme/Lisp.
|
3
|
+
- A lot of internal refactoring after list re-implementation...
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- File `primitive_builder.rb` implementation of: `pair?`, `car`, `cdr`, `cons`, `list->vectors` list procedures.
|
7
|
+
- File `primitive_builder.rb` implementation of: `vector->list` vector procedures.
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- Class `SkmList` is now deprecated and being replaced by `SkmPair`nodes.
|
11
|
+
- Class `SkmElementVisitor` supports new visit events: `visit_empty_list` and `visit_pair`
|
12
|
+
|
13
|
+
|
14
|
+
## [0.0.28] - 2018-12-10
|
15
|
+
- Nasty bug fix: interpreter was'nt able to retrieve data argument deep in call stack.
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- Method `Environment#inspect`
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Method `SkmDefinition#call` now accepts variable references that refer to a lambda or a primitive procedure.
|
22
|
+
- Method `SkmLambda#evaluate_sequence` failed when argument value came from a caller deep in call stack?
|
23
|
+
- Added a specific test in `interpreter_spec.rb`
|
24
|
+
|
1
25
|
## [0.0.27] - 2018-11-25
|
2
26
|
### Fixed
|
3
27
|
- The interpreter failed with second-order lambdas (lambda expression that contains another lambda)
|
4
28
|
- Added a specific test in `interpreter_spec.rb`
|
5
29
|
|
6
|
-
|
7
30
|
## [0.0.26] - 2018-11-25
|
8
31
|
|
9
32
|
### Added
|
data/README.md
CHANGED
@@ -178,7 +178,7 @@ This section lists the implemented standard procedures
|
|
178
178
|
* Integer-level: `even?`, `odd?`
|
179
179
|
|
180
180
|
#### List procedures
|
181
|
-
* `list?`, `null?`, `
|
181
|
+
* `list?`, `null?`, `pair?`, `car`, `cdr`, `cons`, `length`, `list`, `list->vector`
|
182
182
|
|
183
183
|
#### String procedures
|
184
184
|
* `string?`, `string=?`, `string-append`, `string-length`, `string->symbol`,
|
@@ -187,7 +187,7 @@ This section lists the implemented standard procedures
|
|
187
187
|
* `symbol?`, `symbol=?`
|
188
188
|
|
189
189
|
#### Vector procedures
|
190
|
-
* `vector?`, `vector`, `vector-length`, `vector-set
|
190
|
+
* `vector?`, `vector`, `vector-length`, `vector-set!`, `vector->list`
|
191
191
|
|
192
192
|
#### Input/output procedures
|
193
193
|
* `newline`
|
@@ -204,7 +204,7 @@ Roadmap:
|
|
204
204
|
- Extend the language in order to support [Minikanren](https://github.com/TheReasonedSchemer2ndEd/CodeFromTheReasonedSchemer2ndEd)
|
205
205
|
- Make it pass all examples from the [Reasoned Schemer](https://mitpress.mit.edu/books/reasoned-schemer-second-edition) book.
|
206
206
|
|
207
|
-
## Other Scheme
|
207
|
+
## Other Scheme implementations in Ruby
|
208
208
|
__Skeem__ isn't the sole implementation of the Scheme language in Ruby.
|
209
209
|
Here are a few other ones:
|
210
210
|
- [Heist gem](https://rubygems.org/gems/heist) -- Probably one of best Scheme implementation in Ruby. Really worth a try. Alas, the [project](https://github.com/jcoglan/heist) seems to be dormant for several years.
|
data/lib/skeem/datum_dsl.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'skm_simple_datum'
|
2
2
|
require_relative 'skm_compound_datum'
|
3
|
+
require_relative 'skm_pair'
|
3
4
|
|
4
5
|
module Skeem
|
5
6
|
# Mixin module that provides factory methods that ease the conversion of
|
@@ -75,16 +76,16 @@ module Skeem
|
|
75
76
|
def list(aLiteral)
|
76
77
|
result = case aLiteral
|
77
78
|
when Array
|
78
|
-
|
79
|
-
when
|
80
|
-
|
79
|
+
SkmPair.create_from_a(to_datum(aLiteral))
|
80
|
+
when SkmPair
|
81
|
+
SkmPair.create_from_a(to_datum(aLiteral.to_a))
|
81
82
|
else
|
82
|
-
|
83
|
+
SkmPair.new(to_datum(aLiteral), SkmEmptyList.instance)
|
83
84
|
end
|
84
85
|
|
85
86
|
result
|
86
87
|
end
|
87
|
-
|
88
|
+
|
88
89
|
def vector(aLiteral)
|
89
90
|
result = case aLiteral
|
90
91
|
when Array
|
@@ -96,8 +97,9 @@ module Skeem
|
|
96
97
|
end
|
97
98
|
|
98
99
|
result
|
99
|
-
end
|
100
|
+
end
|
100
101
|
|
102
|
+
# Conversion from Ruby object value to Skeem datum
|
101
103
|
def to_datum(aLiteral)
|
102
104
|
return aLiteral if aLiteral.kind_of?(SkmSimpleDatum)
|
103
105
|
return list(aLiteral.members) if aLiteral.kind_of?(SkmList)
|
@@ -114,6 +116,9 @@ module Skeem
|
|
114
116
|
SkmBoolean.create(aLiteral)
|
115
117
|
when String
|
116
118
|
parse_literal(aLiteral)
|
119
|
+
when SkmPair # Special case: not a PORO literal
|
120
|
+
# One assumes that a Skeem list contains only Skeem datum objects
|
121
|
+
SkmPair.create_from_a(aLiteral.to_a)
|
117
122
|
else
|
118
123
|
raise StandardError, aLiteral.inspect
|
119
124
|
end
|
@@ -49,8 +49,21 @@ module Skeem
|
|
49
49
|
broadcast(:after_compound_datum, aCompoundDatum)
|
50
50
|
end
|
51
51
|
|
52
|
+
# Visit event. The visitor is visiting the
|
53
|
+
# given empty list object.
|
54
|
+
# @param anEmptyList [SkmEmptyList] the empty list object to visit.
|
55
|
+
def visit_empty_list(anEmptyList)
|
56
|
+
broadcast(:before_empty_list, anEmptyList)
|
57
|
+
broadcast(:after_empty_list, anEmptyList)
|
58
|
+
end
|
52
59
|
|
53
60
|
|
61
|
+
def visit_pair(aPair)
|
62
|
+
broadcast(:before_pair, aPair)
|
63
|
+
traverse_car_cdr(aPair)
|
64
|
+
broadcast(:after_pair, aPair)
|
65
|
+
end
|
66
|
+
|
54
67
|
=begin
|
55
68
|
# Visit event. The visitor is about to visit the given non terminal node.
|
56
69
|
# @param aNonTerminalNode [NonTerminalNode] the node to visit.
|
@@ -78,6 +91,19 @@ module Skeem
|
|
78
91
|
broadcast(:after_children, aParent, children)
|
79
92
|
end
|
80
93
|
|
94
|
+
def traverse_car_cdr(aPair)
|
95
|
+
if aPair.car
|
96
|
+
broadcast(:before_car, aPair, aPair.car)
|
97
|
+
aPair.car.accept(self)
|
98
|
+
broadcast(:after_car, aPair, aPair.car)
|
99
|
+
end
|
100
|
+
if aPair.cdr
|
101
|
+
broadcast(:before_cdr, aPair, aPair.cdr)
|
102
|
+
aPair.cdr.accept(self)
|
103
|
+
broadcast(:after_cdr, aPair, aPair.cdr)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
81
107
|
# Send a notification to all subscribers.
|
82
108
|
# @param msg [Symbol] event to notify
|
83
109
|
# @param args [Array] arguments of the notification.
|
data/lib/skeem/grammar.rb
CHANGED
@@ -54,7 +54,7 @@ module Skeem
|
|
54
54
|
rule 'compound_datum' => 'list'
|
55
55
|
rule 'compound_datum' => 'vector'
|
56
56
|
rule('list' => 'LPAREN datum_star RPAREN').as 'list'
|
57
|
-
rule
|
57
|
+
rule('list' => 'LPAREN datum_plus PERIOD datum RPAREN').as 'dotted_list'
|
58
58
|
rule('vector' => 'VECTOR_BEGIN datum_star RPAREN').as 'vector'
|
59
59
|
rule('datum_plus' => 'datum_plus datum').as 'multiple_datums'
|
60
60
|
rule('datum_plus' => 'datum').as 'last_datum'
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'primitive_procedure'
|
2
2
|
require_relative '../datum_dsl'
|
3
|
+
require_relative '../skm_pair'
|
3
4
|
# require_relative '../s_expr_nodes'
|
4
5
|
|
5
6
|
module Skeem
|
@@ -92,7 +93,12 @@ module Skeem
|
|
92
93
|
def add_list_procedures(aRuntime)
|
93
94
|
create_object_predicate(aRuntime, 'list?')
|
94
95
|
create_object_predicate(aRuntime, 'null?')
|
96
|
+
create_object_predicate(aRuntime, 'pair?')
|
97
|
+
create_cons(aRuntime)
|
98
|
+
create_car(aRuntime)
|
99
|
+
create_cdr(aRuntime)
|
95
100
|
create_length(aRuntime)
|
101
|
+
create_list2vector(aRuntime)
|
96
102
|
end
|
97
103
|
|
98
104
|
def add_vector_procedures(aRuntime)
|
@@ -100,6 +106,7 @@ module Skeem
|
|
100
106
|
create_vector(aRuntime)
|
101
107
|
create_vector_length(aRuntime)
|
102
108
|
create_vector_ref(aRuntime)
|
109
|
+
create_vector2list(aRuntime)
|
103
110
|
end
|
104
111
|
|
105
112
|
def add_io_procedures(aRuntime)(aRuntime)
|
@@ -132,7 +139,7 @@ module Skeem
|
|
132
139
|
else
|
133
140
|
first_one = arglist.first.evaluate(runtime)
|
134
141
|
raw_result = first_one.value
|
135
|
-
operands =
|
142
|
+
operands = remaining_args(arglist, runtime)
|
136
143
|
operands.each { |elem| raw_result += elem.value }
|
137
144
|
to_datum(raw_result)
|
138
145
|
end
|
@@ -147,7 +154,7 @@ module Skeem
|
|
147
154
|
if arglist.empty?
|
148
155
|
raw_result = -raw_result
|
149
156
|
else
|
150
|
-
operands =
|
157
|
+
operands = arglist.evaluate(runtime).to_a
|
151
158
|
operands.each { |elem| raw_result -= elem.value }
|
152
159
|
end
|
153
160
|
to_datum(raw_result)
|
@@ -163,15 +170,8 @@ module Skeem
|
|
163
170
|
else
|
164
171
|
first_one = arglist.first.evaluate(runtime)
|
165
172
|
raw_result = first_one.value
|
166
|
-
operands =
|
167
|
-
begin
|
173
|
+
operands = remaining_args(arglist, runtime)
|
168
174
|
operands.each { |elem| raw_result *= elem.value }
|
169
|
-
rescue NoMethodError => exc
|
170
|
-
# $stderr.puts aRuntime.environment.inspect
|
171
|
-
# $stderr.puts first_one.inspect
|
172
|
-
# $stderr.puts operands.inspect
|
173
|
-
raise exc
|
174
|
-
end
|
175
175
|
to_datum(raw_result)
|
176
176
|
end
|
177
177
|
end
|
@@ -186,7 +186,7 @@ module Skeem
|
|
186
186
|
if arglist.empty?
|
187
187
|
raw_result = 1 / raw_result.to_f
|
188
188
|
else
|
189
|
-
operands =
|
189
|
+
operands = arglist.evaluate(runtime).to_a
|
190
190
|
operands.each do |elem|
|
191
191
|
if raw_result > elem.value && raw_result.modulo(elem.value).zero?
|
192
192
|
raw_result /= elem.value
|
@@ -212,7 +212,7 @@ module Skeem
|
|
212
212
|
|
213
213
|
define_primitive_proc(aRuntime, 'floor-remainder', binary, primitive)
|
214
214
|
end
|
215
|
-
|
215
|
+
|
216
216
|
def create_eqv?(aRuntime)
|
217
217
|
primitive = ->(runtime, argument1, argument2) do
|
218
218
|
operand_1 = argument1.evaluate(runtime)
|
@@ -221,7 +221,7 @@ module Skeem
|
|
221
221
|
to_datum(raw_result)
|
222
222
|
end
|
223
223
|
|
224
|
-
define_primitive_proc(aRuntime, 'eqv?', binary, primitive)
|
224
|
+
define_primitive_proc(aRuntime, 'eqv?', binary, primitive)
|
225
225
|
end
|
226
226
|
|
227
227
|
def create_equal(aRuntime)
|
@@ -230,7 +230,7 @@ module Skeem
|
|
230
230
|
if arglist.empty?
|
231
231
|
boolean(true)
|
232
232
|
else
|
233
|
-
operands =
|
233
|
+
operands = arglist.evaluate(runtime).to_a
|
234
234
|
first_value = first_one.value
|
235
235
|
all_equal = operands.all? { |elem| first_value == elem.value }
|
236
236
|
boolean(all_equal)
|
@@ -246,7 +246,7 @@ module Skeem
|
|
246
246
|
boolean(false)
|
247
247
|
else
|
248
248
|
operands = [first_operand.evaluate(runtime)]
|
249
|
-
operands.concat(
|
249
|
+
operands.concat(arglist.evaluate(runtime).to_a)
|
250
250
|
result = true
|
251
251
|
operands.each_cons(2) do |(elem1, elem2)|
|
252
252
|
result &&= elem1.value < elem2.value
|
@@ -264,7 +264,7 @@ module Skeem
|
|
264
264
|
boolean(false)
|
265
265
|
else
|
266
266
|
operands = [first_operand.evaluate(runtime)]
|
267
|
-
operands.concat(
|
267
|
+
operands.concat(arglist.evaluate(runtime).to_a)
|
268
268
|
result = true
|
269
269
|
operands.each_cons(2) do |(elem1, elem2)|
|
270
270
|
result &&= elem1.value > elem2.value
|
@@ -282,7 +282,7 @@ module Skeem
|
|
282
282
|
boolean(true)
|
283
283
|
else
|
284
284
|
operands = [first_operand.evaluate(runtime)]
|
285
|
-
operands.concat(
|
285
|
+
operands.concat(arglist.evaluate(runtime).to_a)
|
286
286
|
result = true
|
287
287
|
operands.each_cons(2) do |(elem1, elem2)|
|
288
288
|
result &&= elem1.value <= elem2.value
|
@@ -300,11 +300,12 @@ module Skeem
|
|
300
300
|
boolean(true)
|
301
301
|
else
|
302
302
|
operands = [first_operand.evaluate(runtime)]
|
303
|
-
operands.concat(
|
303
|
+
operands.concat(arglist.evaluate(runtime).to_a)
|
304
304
|
result = true
|
305
305
|
operands.each_cons(2) do |(elem1, elem2)|
|
306
306
|
result &&= elem1.value >= elem2.value
|
307
307
|
end
|
308
|
+
|
308
309
|
boolean(result)
|
309
310
|
end
|
310
311
|
end
|
@@ -331,6 +332,7 @@ module Skeem
|
|
331
332
|
else
|
332
333
|
raw_result = true
|
333
334
|
last_result = nil
|
335
|
+
# $stderr.puts arglist.inspect
|
334
336
|
arglist.each do |raw_arg|
|
335
337
|
argument = raw_arg.evaluate(aRuntime)
|
336
338
|
last_result = argument
|
@@ -338,6 +340,9 @@ module Skeem
|
|
338
340
|
break unless raw_result
|
339
341
|
end
|
340
342
|
raw_result = last_result if raw_result
|
343
|
+
# $stderr.puts raw_result.inspect
|
344
|
+
# $stderr.puts raw_result.cdr.inspect if raw_result.kind_of?(SkmPair)
|
345
|
+
# $stderr.puts to_datum(raw_result).inspect
|
341
346
|
to_datum(raw_result)
|
342
347
|
end
|
343
348
|
end
|
@@ -371,7 +376,7 @@ module Skeem
|
|
371
376
|
if arglist.empty?
|
372
377
|
boolean(true)
|
373
378
|
else
|
374
|
-
operands =
|
379
|
+
operands = evaluate_arguments(arglist, runtime)
|
375
380
|
first_value = first_one.value
|
376
381
|
all_equal = operands.all? { |elem| first_value == elem.value }
|
377
382
|
boolean(all_equal)
|
@@ -386,7 +391,7 @@ module Skeem
|
|
386
391
|
if arglist.empty?
|
387
392
|
value = ''
|
388
393
|
else
|
389
|
-
parts =
|
394
|
+
parts = evaluate_arguments(arglist, aRuntime)
|
390
395
|
value = parts.reduce('') { |interim, substr| interim << substr.value }
|
391
396
|
end
|
392
397
|
|
@@ -416,22 +421,60 @@ module Skeem
|
|
416
421
|
define_primitive_proc(aRuntime, 'string->symbol', unary, primitive)
|
417
422
|
end
|
418
423
|
|
424
|
+
def create_cons(aRuntime)
|
425
|
+
primitive = ->(runtime, obj1, obj2) do
|
426
|
+
SkmPair.new(obj1.evaluate(aRuntime), obj2.evaluate(aRuntime))
|
427
|
+
end
|
428
|
+
|
429
|
+
define_primitive_proc(aRuntime, 'cons', binary, primitive)
|
430
|
+
end
|
431
|
+
|
432
|
+
def create_car(aRuntime)
|
433
|
+
primitive = ->(runtime, arg) do
|
434
|
+
arg_evaluated = arg.evaluate(runtime)
|
435
|
+
check_argtype(arg_evaluated, SkmPair, 'pair', 'car')
|
436
|
+
arg_evaluated.car
|
437
|
+
end
|
438
|
+
|
439
|
+
define_primitive_proc(aRuntime, 'car', unary, primitive)
|
440
|
+
end
|
441
|
+
|
442
|
+
def create_cdr(aRuntime)
|
443
|
+
primitive = ->(runtime, arg) do
|
444
|
+
arg_evaluated = arg.evaluate(runtime)
|
445
|
+
check_argtype(arg_evaluated, SkmPair, 'pair', 'cdr')
|
446
|
+
arg_evaluated.cdr
|
447
|
+
end
|
448
|
+
|
449
|
+
define_primitive_proc(aRuntime, 'cdr', unary, primitive)
|
450
|
+
end
|
451
|
+
|
419
452
|
def create_length(aRuntime)
|
420
453
|
primitive = ->(runtime, arg) do
|
421
454
|
arg_evaluated = arg.evaluate(runtime)
|
422
|
-
check_argtype(arg_evaluated,
|
455
|
+
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'length')
|
423
456
|
integer(arg_evaluated.length)
|
424
457
|
end
|
425
458
|
|
426
459
|
define_primitive_proc(aRuntime, 'length', unary, primitive)
|
427
460
|
end
|
428
461
|
|
462
|
+
def create_list2vector(aRuntime)
|
463
|
+
primitive = ->(runtime, arg) do
|
464
|
+
arg_evaluated = arg.evaluate(runtime)
|
465
|
+
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list->vector')
|
466
|
+
vector(arg_evaluated.to_a)
|
467
|
+
end
|
468
|
+
|
469
|
+
define_primitive_proc(aRuntime, 'list->vector', unary, primitive)
|
470
|
+
end
|
471
|
+
|
429
472
|
def create_vector(aRuntime)
|
430
473
|
primitive = ->(runtime, arglist) do
|
431
474
|
if arglist.empty?
|
432
475
|
elements = []
|
433
476
|
else
|
434
|
-
elements =
|
477
|
+
elements = evaluate_arguments(arglist, aRuntime)
|
435
478
|
end
|
436
479
|
|
437
480
|
vector(elements)
|
@@ -465,6 +508,16 @@ module Skeem
|
|
465
508
|
define_primitive_proc(aRuntime, 'vector-ref', binary, primitive)
|
466
509
|
end
|
467
510
|
|
511
|
+
def create_vector2list(aRuntime)
|
512
|
+
primitive = ->(runtime, arg) do
|
513
|
+
arg_evaluated = arg.evaluate(runtime)
|
514
|
+
check_argtype(arg_evaluated, SkmVector, 'vector', 'vector->list')
|
515
|
+
SkmPair.create_from_a(arg_evaluated.members)
|
516
|
+
end
|
517
|
+
|
518
|
+
define_primitive_proc(aRuntime, 'vector->list', unary, primitive)
|
519
|
+
end
|
520
|
+
|
468
521
|
def create_newline(aRuntime)
|
469
522
|
primitive = ->(runtime) do
|
470
523
|
# @TODO: make output stream configurable
|
@@ -473,13 +526,13 @@ module Skeem
|
|
473
526
|
|
474
527
|
define_primitive_proc(aRuntime, 'newline', nullary, primitive)
|
475
528
|
end
|
476
|
-
|
529
|
+
|
477
530
|
def create_assert(aRuntime)
|
478
531
|
primitive = ->(runtime, arg) do
|
479
532
|
arg_evaluated = arg.evaluate(runtime)
|
480
533
|
if arg_evaluated.boolean? && arg_evaluated.value == false
|
481
534
|
assert_call = aRuntime.caller
|
482
|
-
pos = assert_call.call_site
|
535
|
+
pos = assert_call.call_site
|
483
536
|
# Error: assertion failed: (> 1 2)
|
484
537
|
msg = "assertion failed on line #{pos.line}, column #{pos.column}"
|
485
538
|
raise StandardError, 'Error: ' + msg
|
@@ -525,20 +578,45 @@ module Skeem
|
|
525
578
|
aRuntime.define(aKey, anEntry)
|
526
579
|
end
|
527
580
|
|
528
|
-
def
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
581
|
+
def evaluate_arguments(arglist, aRuntime)
|
582
|
+
case arglist
|
583
|
+
when Array
|
584
|
+
arglist.map { |elem| elem.evaluate(aRuntime) }
|
585
|
+
when SkmPair
|
586
|
+
arglist.evaluate(aRuntime).to_a
|
587
|
+
end
|
534
588
|
end
|
535
589
|
|
536
590
|
def check_argtype(argument, requiredRubyClass, requiredSkmType, aProcName)
|
591
|
+
if requiredRubyClass.kind_of?(Array)
|
592
|
+
unless requiredRubyClass.include?(argument.class)
|
593
|
+
type_error(argument, requiredSkmType, aProcName)
|
594
|
+
end
|
595
|
+
else
|
537
596
|
unless argument.kind_of?(requiredRubyClass)
|
538
|
-
|
539
|
-
msg2 = "but got #{argument.value}"
|
540
|
-
raise StandardError, msg1 + ' ' + msg2
|
597
|
+
type_error(argument, requiredSkmType, aProcName)
|
541
598
|
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def type_error(argument, requiredSkmType, aProcName)
|
603
|
+
msg1 = "Procedure '#{aProcName}': #{requiredSkmType} argument required,"
|
604
|
+
if argument.respond_to?(:value)
|
605
|
+
msg2 = "but got #{argument.value}"
|
606
|
+
else
|
607
|
+
msg2 = "but got #{argument.class}"
|
608
|
+
end
|
609
|
+
raise StandardError, msg1 + ' ' + msg2
|
610
|
+
end
|
611
|
+
|
612
|
+
def remaining_args(arglist, aRuntime)
|
613
|
+
case arglist
|
614
|
+
when Array
|
615
|
+
raw_arg = arglist[1..-1]
|
616
|
+
when SkmPair
|
617
|
+
raw_arg = arglist.cdr.to_a
|
618
|
+
end
|
619
|
+
raw_arg.map { |arg| arg.evaluate(aRuntime) }
|
542
620
|
end
|
543
621
|
end # module
|
544
622
|
end # module
|
@@ -16,9 +16,10 @@ module Skeem
|
|
16
16
|
|
17
17
|
# Arguments are positional in a primitive procedure.
|
18
18
|
def call(aRuntime, aProcedureCall)
|
19
|
-
|
19
|
+
actuals = aProcedureCall.operands.to_a
|
20
|
+
check_actual_count(actuals)
|
20
21
|
aProcedureCall.operands_consumed = true
|
21
|
-
do_call(aRuntime,
|
22
|
+
do_call(aRuntime, actuals)
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
@@ -50,8 +51,8 @@ module Skeem
|
|
50
51
|
anArity
|
51
52
|
end
|
52
53
|
|
53
|
-
def check_actual_count(
|
54
|
-
count_actuals =
|
54
|
+
def check_actual_count(actuals)
|
55
|
+
count_actuals = actuals.size
|
55
56
|
if arity.nullary?
|
56
57
|
unless count_actuals.zero?
|
57
58
|
wrong_number_arguments(arity.high, count_actuals)
|
@@ -77,7 +78,7 @@ module Skeem
|
|
77
78
|
arguments = []
|
78
79
|
arguments << operands.take(arity.low).flatten
|
79
80
|
count_delta = operands.size - arity.low
|
80
|
-
arguments <<
|
81
|
+
arguments << SkmPair.create_from_a(operands.slice(-count_delta, count_delta))
|
81
82
|
#p operands.size
|
82
83
|
#p count_delta
|
83
84
|
#p arguments.inspect
|
data/lib/skeem/runtime.rb
CHANGED
@@ -57,11 +57,11 @@ module Skeem
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
# @param aList[
|
60
|
+
# @param aList[SkmPair] first member is an identifier.
|
61
61
|
def evaluate_form(aList)
|
62
62
|
# TODO: manage the cases where first_member is a keyword
|
63
|
-
first_member = aList.
|
64
|
-
invokation = ProcedureCall.new(nil, first_member, aList.
|
63
|
+
first_member = aList.car
|
64
|
+
invokation = ProcedureCall.new(nil, first_member, aList.cdr.to_a)
|
65
65
|
invokation.evaluate(self)
|
66
66
|
end
|
67
67
|
|
@@ -98,9 +98,9 @@ module Skeem
|
|
98
98
|
raise StandardError, "Invalid call object #{aProcCall.inspect}"
|
99
99
|
end
|
100
100
|
# $stderr.puts 'CALL STACK vvvv'
|
101
|
-
call_stack.each do |proc_call|
|
101
|
+
# call_stack.each do |proc_call|
|
102
102
|
# $stderr.puts proc_call.inspect
|
103
|
-
end
|
103
|
+
# end
|
104
104
|
# $stderr.puts 'CALL STACK ^^^^'
|
105
105
|
end
|
106
106
|
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'stringio'
|
2
|
+
require_relative 'skm_pair'
|
2
3
|
require_relative 's_expr_nodes'
|
3
4
|
|
4
5
|
module Skeem
|
@@ -38,8 +39,9 @@ module Skeem
|
|
38
39
|
# rule('program' => 'cmd_or_def_plus').as 'main'
|
39
40
|
def reduce_main(_production, _range, _tokens, theChildren)
|
40
41
|
last_child = theChildren.last
|
41
|
-
|
42
|
-
|
42
|
+
# $stderr.puts last_child.inspect
|
43
|
+
result = if last_child.length == 1
|
44
|
+
last_child.car
|
43
45
|
else
|
44
46
|
last_child
|
45
47
|
end
|
@@ -47,13 +49,13 @@ module Skeem
|
|
47
49
|
|
48
50
|
# rule('cmd_or_def_plus' => 'cmd_or_def_plus cmd_or_def').as 'multiple_cmd_def'
|
49
51
|
def reduce_multiple_cmd_def(_production, _range, _tokens, theChildren)
|
50
|
-
theChildren[0].
|
52
|
+
theChildren[0].append(theChildren[1])
|
51
53
|
theChildren[0]
|
52
54
|
end
|
53
55
|
|
54
56
|
# rule('cmd_or_def_plus' => 'cmd_or_def').as 'last_cmd_def'
|
55
57
|
def reduce_last_cmd_def(_production, _range, _tokens, theChildren)
|
56
|
-
|
58
|
+
SkmPair.create_from_a([theChildren.last])
|
57
59
|
end
|
58
60
|
|
59
61
|
# rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN')
|
@@ -86,9 +88,24 @@ module Skeem
|
|
86
88
|
end
|
87
89
|
|
88
90
|
# rule('list' => 'LPAREN datum_star RPAREN').as 'list'
|
89
|
-
def reduce_list(_production,
|
90
|
-
|
91
|
+
def reduce_list(_production, _range, _tokens, theChildren)
|
92
|
+
SkmPair.create_from_a(theChildren[1])
|
91
93
|
end
|
94
|
+
|
95
|
+
# rule('list' => 'LPAREN datum_plus PERIOD datum RPAREN').as 'dotted_list'
|
96
|
+
def reduce_dotted_list(_production, _range, _tokens, theChildren)
|
97
|
+
# if theChildren[1].kind_of?(Array)
|
98
|
+
# if theChildren[1].size == 1
|
99
|
+
# car_arg = theChildren[1].first
|
100
|
+
# else
|
101
|
+
# car_arg = SkmPair.create_from_a(theChildren[1])
|
102
|
+
# end
|
103
|
+
# else
|
104
|
+
# car_arg = theChildren[1]
|
105
|
+
# end
|
106
|
+
|
107
|
+
SkmPair.new(theChildren[1], theChildren[3])
|
108
|
+
end
|
92
109
|
|
93
110
|
# rule('vector' => 'VECTOR_BEGIN datum_star RPAREN').as 'vector'
|
94
111
|
def reduce_vector(_production, aRange, _tokens, theChildren)
|
@@ -197,7 +214,7 @@ module Skeem
|
|
197
214
|
|
198
215
|
# rule('sequence' => 'command_star expression').as 'sequence'
|
199
216
|
def reduce_sequence(_production, _range, _tokens, theChildren)
|
200
|
-
|
217
|
+
SkmPair.create_from_a(theChildren[0] << theChildren[1])
|
201
218
|
end
|
202
219
|
|
203
220
|
# rule('command_star' => 'command_star command').as 'multiple_commands'
|
@@ -225,22 +242,21 @@ module Skeem
|
|
225
242
|
# $stderr.puts theChildren[1].inspect
|
226
243
|
SkmQuasiquotation.new(theChildren[1])
|
227
244
|
end
|
228
|
-
|
245
|
+
|
229
246
|
# rule('list_qq_template' => 'LPAREN qq_template_or_splice_star RPAREN').as 'list_qq'
|
230
247
|
def reduce_list_qq(_production, _range, _tokens, theChildren)
|
231
|
-
|
232
|
-
end
|
248
|
+
SkmPair.create_from_a(theChildren[1])
|
249
|
+
end
|
233
250
|
|
234
251
|
# rule('vector_qq_template' => 'VECTOR_BEGIN qq_template_or_splice_star RPAREN').as 'vector_qq'
|
235
252
|
def reduce_vector_qq(_production, _range, _tokens, theChildren)
|
236
253
|
SkmVector.new(theChildren[1])
|
237
254
|
end
|
238
|
-
|
255
|
+
|
239
256
|
# rule('unquotation' => 'COMMA qq_template').as 'unquotation_short'
|
240
257
|
def reduce_unquotation_short(_production, aRange, _tokens, theChildren)
|
241
258
|
SkmUnquotation.new(theChildren[1])
|
242
259
|
end
|
243
|
-
|
244
260
|
|
245
261
|
# rule('qq_template_or_splice_star' => 'qq_template_or_splice_star qq_template_or_splice').as 'multiple_template_splice'
|
246
262
|
def reduce_multiple_template_splice(_production, _range, _tokens, theChildren)
|