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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a462458401748edba53f3c95f80b56478d7cfeb0
4
- data.tar.gz: bca52ec89e55cfe23c95e644da601fd2557877c8
3
+ metadata.gz: 9c6cb859a4082620c599599f02f5948ee5608d79
4
+ data.tar.gz: 742acc6b351efce05a6d40f7c9b558368c734fd5
5
5
  SHA512:
6
- metadata.gz: fbcbaf830c1ba588cd34700f7ebc4f7815b0972efa8ddd496fbda977538e2d5921cdb88830e880ee2cc4c6a7ecb6f214d903ea945a970b46653d366de22b4fc0
7
- data.tar.gz: 959251339c07128dc76a7557761d915cacea326432bf4ab0e3728d894f63bf2fe609d743ea07b1b0753ca65d728528e2d4fe8b3b246bf381ddd0b74533aca1ca
6
+ metadata.gz: fc51a07506b30450c78fd538a9127926378d6fdc3d165a1a3e075424295876a2727734bc4b969895f6f6bc76ea3f7c6a5e5ea6cdaec9495556a34b3d8e7c8c80
7
+ data.tar.gz: 076b28ff2fc211ed0ae3e2bf3cdfa08f4d220f5682c72f8f59e98dfe84f2555aa9ebbb529e08d94c24349e3845aad836c64eb541c5c2f414f917678fc36f096b
@@ -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
- case entry
32
- when Primitive::PrimitiveProcedure
33
- entry
34
- when SkmDefinition
35
- entry.expression.evaluate(self)
36
- else
37
- raise StandardError, entry.inspect
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
@@ -68,7 +68,7 @@ module Skeem
68
68
  end
69
69
  end
70
70
  else
71
- # INFINITE LOOP DANGER: definition of 'x' is a reference to '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
- unless [SkmLambda, Primitive::PrimitiveProcedure].include?(expression.class)
100
- err_msg = "Expected a SkmLambda instead of #{expression.class}"
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
- expression.call(aRuntime, aProcedureCall)
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
- # $stderr.puts "## In ProcCall #{var_key.value} #############"
166
- # $stderr.puts 'operator: ' + operator.inspect
167
- # $stderr.puts 'operands: ' + operands.inspect
168
- # $stderr.puts "## CALL(#{var_key.value}) ###################"
169
- # $stderr.puts 'callee: ' + procedure.inspect
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
- aRuntime.caller(-2).operands_consumed = true
406
- result = cmd.call(aRuntime, aRuntime.caller(-2))
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
- a_def.evaluate(aRuntime)
434
- # $stderr.puts "LOCAL #{a_def.inspect}"
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
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.0.27'.freeze
2
+ VERSION = '0.0.28'.freeze
3
3
  end
@@ -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.27
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-03 00:00:00.000000000 Z
11
+ date: 2018-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley