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