skeem 0.0.27 → 0.0.28
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/lib/skeem/environment.rb +19 -4
- data/lib/skeem/primitive/primitive_builder.rb +7 -0
- data/lib/skeem/runtime.rb +32 -14
- data/lib/skeem/s_expr_nodes.rb +46 -21
- data/lib/skeem/skm_unary_expression.rb +2 -1
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +18 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c6cb859a4082620c599599f02f5948ee5608d79
|
4
|
+
data.tar.gz: 742acc6b351efce05a6d40f7c9b558368c734fd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc51a07506b30450c78fd538a9127926378d6fdc3d165a1a3e075424295876a2727734bc4b969895f6f6bc76ea3f7c6a5e5ea6cdaec9495556a34b3d8e7c8c80
|
7
|
+
data.tar.gz: 076b28ff2fc211ed0ae3e2bf3cdfa08f4d220f5682c72f8f59e98dfe84f2555aa9ebbb529e08d94c24349e3845aad836c64eb541c5c2f414f917678fc36f096b
|
data/lib/skeem/environment.rb
CHANGED
@@ -47,19 +47,34 @@ module Skeem
|
|
47
47
|
|
48
48
|
my_result
|
49
49
|
end
|
50
|
-
|
51
|
-
# The number of outer parents the current environment has.
|
50
|
+
|
51
|
+
# The number of outer parents the current environment has.
|
52
52
|
# @return [Integer] The nesting levels
|
53
53
|
def depth
|
54
54
|
count = 0
|
55
|
-
|
55
|
+
|
56
56
|
curr_env = self
|
57
57
|
while curr_env.outer
|
58
58
|
count += 1
|
59
59
|
curr_env = curr_env.outer
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
count
|
63
63
|
end
|
64
|
+
|
65
|
+
def inspect
|
66
|
+
result = ''
|
67
|
+
if outer
|
68
|
+
result << outer.inspect
|
69
|
+
else
|
70
|
+
return "\n"
|
71
|
+
end
|
72
|
+
result << "\n----\n"
|
73
|
+
bindings.each_pair do |key, expr|
|
74
|
+
result << "#{key.inspect} => #{expr.inspect}\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
result
|
78
|
+
end
|
64
79
|
end # class
|
65
80
|
end # module
|
@@ -164,7 +164,14 @@ module Skeem
|
|
164
164
|
first_one = arglist.first.evaluate(runtime)
|
165
165
|
raw_result = first_one.value
|
166
166
|
operands = evaluate_tail(arglist, runtime)
|
167
|
+
begin
|
167
168
|
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
|
168
175
|
to_datum(raw_result)
|
169
176
|
end
|
170
177
|
end
|
data/lib/skeem/runtime.rb
CHANGED
@@ -3,7 +3,10 @@ require_relative 'environment'
|
|
3
3
|
|
4
4
|
module Skeem
|
5
5
|
class Runtime
|
6
|
+
# @return [Environment]
|
6
7
|
attr_reader(:environment)
|
8
|
+
|
9
|
+
# @return [Array<ProcedureCall>] The call stack
|
7
10
|
attr_reader(:call_stack)
|
8
11
|
|
9
12
|
def initialize(anEnvironment)
|
@@ -14,7 +17,7 @@ module Skeem
|
|
14
17
|
def include?(anIdentifier)
|
15
18
|
environment.include?(normalize_key(anIdentifier))
|
16
19
|
end
|
17
|
-
|
20
|
+
|
18
21
|
def fetch(aKey)
|
19
22
|
key_value = normalize_key(aKey)
|
20
23
|
include?(key_value) ? environment.fetch(key_value) : nil
|
@@ -28,14 +31,24 @@ module Skeem
|
|
28
31
|
key_value = normalize_key(aKey)
|
29
32
|
if include?(key_value)
|
30
33
|
entry = environment.fetch(key_value)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
result = nil
|
35
|
+
begin
|
36
|
+
case entry
|
37
|
+
when Primitive::PrimitiveProcedure
|
38
|
+
result = entry
|
39
|
+
when SkmDefinition
|
40
|
+
result = entry.expression.evaluate(self)
|
41
|
+
else
|
42
|
+
raise StandardError, entry.inspect
|
43
|
+
end
|
44
|
+
rescue NoMethodError => exc
|
45
|
+
# $stderr.puts 'In rescue block'
|
46
|
+
# $stderr.puts key_value.inspect
|
47
|
+
# $stderr.puts entry.inspect
|
48
|
+
# $stderr.puts entry.expression.inspect
|
49
|
+
raise exc
|
38
50
|
end
|
51
|
+
result
|
39
52
|
else
|
40
53
|
err = StandardError
|
41
54
|
key = aKey.kind_of?(SkmIdentifier) ? aKey.value : key_value
|
@@ -43,7 +56,7 @@ module Skeem
|
|
43
56
|
raise err, err_msg
|
44
57
|
end
|
45
58
|
end
|
46
|
-
|
59
|
+
|
47
60
|
# @param aList[SkmList] first member is an identifier.
|
48
61
|
def evaluate_form(aList)
|
49
62
|
# TODO: manage the cases where first_member is a keyword
|
@@ -69,30 +82,35 @@ module Skeem
|
|
69
82
|
|
70
83
|
def push(anEnvironment)
|
71
84
|
@environment = anEnvironment
|
72
|
-
end
|
73
|
-
|
85
|
+
end
|
86
|
+
|
74
87
|
# Make the outer enviromnent thecurrent one inside the provided block
|
75
88
|
def pop
|
76
89
|
env = environment
|
77
90
|
@environment = environment.outer
|
78
91
|
env
|
79
92
|
end
|
80
|
-
|
93
|
+
|
81
94
|
def push_call(aProcCall)
|
82
95
|
if aProcCall.kind_of?(ProcedureCall)
|
83
96
|
call_stack.push(aProcCall)
|
84
97
|
else
|
85
98
|
raise StandardError, "Invalid call object #{aProcCall.inspect}"
|
86
99
|
end
|
100
|
+
# $stderr.puts 'CALL STACK vvvv'
|
101
|
+
call_stack.each do |proc_call|
|
102
|
+
# $stderr.puts proc_call.inspect
|
103
|
+
end
|
104
|
+
# $stderr.puts 'CALL STACK ^^^^'
|
87
105
|
end
|
88
|
-
|
106
|
+
|
89
107
|
def pop_call()
|
90
108
|
if call_stack.empty?
|
91
109
|
raise StandardError, 'Skeem call stack empty!'
|
92
110
|
end
|
93
111
|
call_stack.pop
|
94
112
|
end
|
95
|
-
|
113
|
+
|
96
114
|
def caller(index = -1)
|
97
115
|
call_stack[index]
|
98
116
|
end
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -68,7 +68,7 @@ module Skeem
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
else
|
71
|
-
# INFINITE LOOP DANGER: definition of 'x'
|
71
|
+
# INFINITE LOOP DANGER: definition of 'x' has a reference to 'x'!
|
72
72
|
# Way out: the lookup for the reference should start from outer
|
73
73
|
# environment.
|
74
74
|
env = aRuntime.pop
|
@@ -96,11 +96,14 @@ module Skeem
|
|
96
96
|
|
97
97
|
# call method should only invoked when the expression is a SkmLambda
|
98
98
|
def call(aRuntime, aProcedureCall)
|
99
|
-
|
100
|
-
|
99
|
+
expr = expression
|
100
|
+
expr = expr.evaluate(aRuntime) if expr.kind_of?(SkmVariableReference)
|
101
|
+
unless [SkmLambda, Primitive::PrimitiveProcedure].include?(expr.class)
|
102
|
+
err_msg = "Expected a SkmLambda instead of #{expr.class}"
|
101
103
|
raise StandardError, err_msg
|
102
104
|
end
|
103
|
-
|
105
|
+
# $stderr.puts "SkmDefinition#call #{aProcedureCall.inspect}"
|
106
|
+
expr.call(aRuntime, aProcedureCall)
|
104
107
|
end
|
105
108
|
|
106
109
|
def inspect
|
@@ -146,13 +149,14 @@ module Skeem
|
|
146
149
|
end
|
147
150
|
begin
|
148
151
|
aRuntime.include?(var_key.value)
|
149
|
-
rescue NoMethodError
|
150
|
-
$stderr.puts "VVVVVVVVVVVVVVV"
|
151
|
-
$stderr.puts 'var_key: ' + var_key.inspect
|
152
|
-
$stderr.puts 'operator: ' + operator.inspect
|
153
|
-
$stderr.puts 'operands: ' + operands.inspect
|
154
|
-
$stderr.puts 'operands_consumed: ' + operands_consumed.inspect
|
155
|
-
$stderr.puts "^^^^^^^^^^^^^^^"
|
152
|
+
rescue NoMethodError => exc
|
153
|
+
# $stderr.puts "VVVVVVVVVVVVVVV"
|
154
|
+
# $stderr.puts 'var_key: ' + var_key.inspect
|
155
|
+
# $stderr.puts 'operator: ' + operator.inspect
|
156
|
+
# $stderr.puts 'operands: ' + operands.inspect
|
157
|
+
# $stderr.puts 'operands_consumed: ' + operands_consumed.inspect
|
158
|
+
# $stderr.puts "^^^^^^^^^^^^^^^"
|
159
|
+
raise exc
|
156
160
|
end
|
157
161
|
unless aRuntime.include?(var_key.value)
|
158
162
|
err = StandardError
|
@@ -162,11 +166,13 @@ module Skeem
|
|
162
166
|
end
|
163
167
|
procedure = aRuntime.environment.fetch(var_key.value)
|
164
168
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
169
|
+
unless var_key.nil?
|
170
|
+
# $stderr.puts "## In ProcCall #{var_key.value} #############"
|
171
|
+
# $stderr.puts 'operator: ' + operator.inspect
|
172
|
+
# $stderr.puts 'operands: ' + operands.inspect
|
173
|
+
# $stderr.puts "## CALL(#{var_key.value}) ###################"
|
174
|
+
# $stderr.puts 'callee: ' + procedure.inspect
|
175
|
+
end
|
170
176
|
result = procedure.call(aRuntime, self)
|
171
177
|
operands_consumed = true
|
172
178
|
aRuntime.pop_call
|
@@ -321,7 +327,8 @@ module Skeem
|
|
321
327
|
end
|
322
328
|
|
323
329
|
def evaluate(aRuntime)
|
324
|
-
formals.evaluate(aRuntime)
|
330
|
+
# formals.evaluate(aRuntime)
|
331
|
+
self
|
325
332
|
end
|
326
333
|
=begin
|
327
334
|
TODO
|
@@ -336,7 +343,9 @@ module Skeem
|
|
336
343
|
def call(aRuntime, aProcedureCall)
|
337
344
|
aRuntime.nest
|
338
345
|
bind_locals(aRuntime, aProcedureCall)
|
346
|
+
# $stderr.puts 'LOCALS vvvvvvvvvvv'
|
339
347
|
# $stderr.puts aRuntime.environment.inspect
|
348
|
+
# $stderr.puts 'LOCALS ^^^^^^^^^^^'
|
340
349
|
result = evaluate_defs(aRuntime)
|
341
350
|
result = evaluate_sequence(aRuntime)
|
342
351
|
aRuntime.unnest
|
@@ -391,6 +400,7 @@ module Skeem
|
|
391
400
|
a_def = SkmDefinition.new(position, variadic_arg_name, args_coll)
|
392
401
|
a_def.evaluate(aRuntime)
|
393
402
|
end
|
403
|
+
aProcedureCall.operands_consumed = true
|
394
404
|
end
|
395
405
|
|
396
406
|
def evaluate_defs(aRuntime)
|
@@ -402,8 +412,16 @@ module Skeem
|
|
402
412
|
if sequence
|
403
413
|
sequence.each do |cmd|
|
404
414
|
if cmd.kind_of?(SkmLambda)
|
405
|
-
|
406
|
-
|
415
|
+
caller_index = -2
|
416
|
+
loop do
|
417
|
+
raise StandardError, "Missing argument" unless aRuntime.caller(caller_index)
|
418
|
+
unless aRuntime.caller(caller_index).operands_consumed
|
419
|
+
aRuntime.caller(caller_index).operands_consumed = true
|
420
|
+
result = cmd.call(aRuntime, aRuntime.caller(caller_index))
|
421
|
+
break
|
422
|
+
end
|
423
|
+
caller_index -= 1
|
424
|
+
end
|
407
425
|
else
|
408
426
|
result = cmd.evaluate(aRuntime)
|
409
427
|
end
|
@@ -413,9 +431,11 @@ module Skeem
|
|
413
431
|
result
|
414
432
|
end
|
415
433
|
|
434
|
+
# Purpose: bind each formal from lambda to an actual value from the call
|
416
435
|
def bind_required_locals(aRuntime, aProcedureCall)
|
417
436
|
max_index = required_arity - 1
|
418
437
|
actuals = aProcedureCall.operands.members
|
438
|
+
formal_names = formals.formals.map(&:value)
|
419
439
|
|
420
440
|
formals.formals.each_with_index do |arg_name, index|
|
421
441
|
arg = actuals[index]
|
@@ -430,8 +450,13 @@ module Skeem
|
|
430
450
|
# IMPORTANT: execute procedure call in argument list now
|
431
451
|
arg = arg.evaluate(aRuntime) if arg.kind_of?(ProcedureCall)
|
432
452
|
a_def = SkmDefinition.new(position, arg_name, arg)
|
433
|
-
|
434
|
-
# $stderr.puts "LOCAL #{
|
453
|
+
# $stderr.puts "Procedure call #{aProcedureCall.operator.inspect}"
|
454
|
+
# $stderr.puts "LOCAL #{arg_name.value} #{arg.inspect}"
|
455
|
+
if arg.kind_of?(SkmVariableReference) && !formal_names.include?(arg.value)
|
456
|
+
aRuntime.define(arg_name, a_def)
|
457
|
+
else
|
458
|
+
a_def.evaluate(aRuntime)
|
459
|
+
end
|
435
460
|
break if index >= max_index
|
436
461
|
end
|
437
462
|
end
|
@@ -88,13 +88,14 @@ module Skeem
|
|
88
88
|
|
89
89
|
class SkmVariableReference < SkmUnaryExpression
|
90
90
|
alias variable child
|
91
|
-
|
91
|
+
|
92
92
|
def eqv?(other)
|
93
93
|
child == other.child
|
94
94
|
end
|
95
95
|
|
96
96
|
def evaluate(aRuntime)
|
97
97
|
var_key = variable.evaluate(aRuntime)
|
98
|
+
# $stderr.puts "Variable #{variable.inspect}"
|
98
99
|
aRuntime.evaluate(var_key)
|
99
100
|
end
|
100
101
|
|
data/lib/skeem/version.rb
CHANGED
@@ -621,6 +621,24 @@ SKEEM
|
|
621
621
|
result = subject.run(source)
|
622
622
|
expect(result.last.members).to eq([25])
|
623
623
|
end
|
624
|
+
|
625
|
+
it 'should implement lambda that calls second-order functions' do
|
626
|
+
source = <<-SKEEM
|
627
|
+
(define twice
|
628
|
+
(lambda (x)
|
629
|
+
(* 2 x)))
|
630
|
+
(define compose
|
631
|
+
(lambda (f g)
|
632
|
+
(lambda (x)
|
633
|
+
(f (g x)))))
|
634
|
+
(define repeat
|
635
|
+
(lambda (f)
|
636
|
+
(compose f f)))
|
637
|
+
((repeat twice) 5)
|
638
|
+
SKEEM
|
639
|
+
result = subject.run(source)
|
640
|
+
expect(result.members.last).to eq(20)
|
641
|
+
end
|
624
642
|
end # context
|
625
643
|
end # describe
|
626
644
|
end # module
|
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.28
|
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-12-
|
11
|
+
date: 2018-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|