skeem 0.0.28 → 0.1.00
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|