skeem 0.0.14 → 0.0.15
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 +14 -0
- data/README.md +15 -1
- data/lib/skeem/interpreter.rb +16 -0
- data/lib/skeem/s_expr_builder.rb +0 -2
- data/lib/skeem/s_expr_nodes.rb +8 -17
- data/lib/skeem/standard/base.skm +25 -0
- data/lib/skeem/version.rb +1 -1
- data/skeem.gemspec +1 -0
- data/spec/skeem/interpreter_spec.rb +90 -13
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17793fa7c6e636874b0d7fe8515d745b7ff664af
|
4
|
+
data.tar.gz: f24f83ad056e1af1ecac866e2daa649c94e544e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64d9feba80f8ac945161c326a8783cdd34babf4f46bbec94020192ad7643a408be059c72e922bf452387dff253708d2b855d7adbac93b9bb9fff0cf4f354bbce
|
7
|
+
data.tar.gz: 00f745fc5abeaa2f1f6d83007b21bc0cb7a4fbc3974d79f71be89c19324857a543339328d406a04ca5dd130e36c789c163e3b982c3be87b879b1978fbb277492
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.0.15] - 2018-09-30
|
2
|
+
Recursive functions are now supported.
|
3
|
+
Interpreter pre-loads a Scheme file with standard procedures (zero?, positive?, negative?, abs)
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- File `base.skm` with standard Scheme procedures `zero?`, `positive?`, `negative?`, `abs`
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- Class `Interpreter#initialize` now execute a Scheme file containing a number of standard procedures.
|
10
|
+
- File `README.md` Added third demo snippet showing example of recursive lambda function.
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
- Method `SkmLambda#bind_locals` now execute any procedure call in argument list before executing the lambda itself.
|
14
|
+
|
1
15
|
## [0.0.14] - 2018-09-23
|
2
16
|
Added `lambda` (anonymous function). This is an initial implementation that doesn't support recursion yet.
|
3
17
|
|
data/README.md
CHANGED
@@ -55,7 +55,6 @@ At this stage, the gem consists of a bare-bones interpreter.
|
|
55
55
|
```
|
56
56
|
|
57
57
|
### Example 2 (Defining a function)
|
58
|
-
Remark: Skeem 0.0.14 doesn't support recursive functions yet.
|
59
58
|
|
60
59
|
```ruby
|
61
60
|
require 'skeem'
|
@@ -79,6 +78,21 @@ Remark: Skeem 0.0.14 doesn't support recursive functions yet.
|
|
79
78
|
result = schemer.run(scheme_code)
|
80
79
|
puts result.value # => 3
|
81
80
|
```
|
81
|
+
### Example 3 (Defining a recursive function)
|
82
|
+
```ruby
|
83
|
+
require 'skeem'
|
84
|
+
|
85
|
+
schemer = Skeem::Interpreter.new
|
86
|
+
scheme_code = <<-SKEEM
|
87
|
+
; Compute the factorial of 100
|
88
|
+
(define fact (lambda (n)
|
89
|
+
(if (<= n 1) 1 (* n (fact (- n 1))))))
|
90
|
+
(fact 100)
|
91
|
+
SKEEM
|
92
|
+
|
93
|
+
result = schemer.run(scheme_code)
|
94
|
+
puts result.value # => 9332621544394415268169923885626670049071596826438162146859296389521759999322991560894146397615651828625369792082722375825118521091686400000000000000000000000
|
95
|
+
```
|
82
96
|
|
83
97
|
Roadmap:
|
84
98
|
- Extend language support
|
data/lib/skeem/interpreter.rb
CHANGED
@@ -12,6 +12,7 @@ module Skeem
|
|
12
12
|
def initialize()
|
13
13
|
@runtime = Runtime.new(Environment.new)
|
14
14
|
add_primitives(runtime)
|
15
|
+
add_standard(runtime)
|
15
16
|
end
|
16
17
|
|
17
18
|
def run(source)
|
@@ -19,5 +20,20 @@ module Skeem
|
|
19
20
|
@ptree = parser.parse(source)
|
20
21
|
return @ptree.root.evaluate(runtime)
|
21
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def add_standard(aRuntime)
|
27
|
+
std_pathname = File.dirname(__FILE__) + '/standard/base.skm'
|
28
|
+
load_lib(std_pathname)
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_lib(aPathname)
|
32
|
+
lib_source = nil
|
33
|
+
File.open(aPathname, 'r') do |lib|
|
34
|
+
lib_source = lib.read
|
35
|
+
run(lib_source)
|
36
|
+
end
|
37
|
+
end
|
22
38
|
end # class
|
23
39
|
end # module
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -85,8 +85,6 @@ module Skeem
|
|
85
85
|
# rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
|
86
86
|
def reduce_lambda_expression(_production, _range, _tokens, theChildren)
|
87
87
|
lmbd = SkmLambda.new(_range, theChildren[2], theChildren[3])
|
88
|
-
# puts lmbd.inspect
|
89
|
-
lmbd
|
90
88
|
end
|
91
89
|
|
92
90
|
# rule('formals' => 'LPAREN identifier_star RPAREN').as 'identifiers_as_formals'
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -325,7 +325,11 @@ module Skeem
|
|
325
325
|
raise err, err_msg
|
326
326
|
end
|
327
327
|
procedure = aRuntime.environment.fetch(var_key.value)
|
328
|
+
# puts "## CALL(#{var_key.value}) ###################"
|
329
|
+
# puts operands.inspect
|
328
330
|
result = procedure.call(aRuntime, self)
|
331
|
+
# puts "## RETURN #{result.inspect}"
|
332
|
+
result
|
329
333
|
end
|
330
334
|
|
331
335
|
def inspect
|
@@ -367,21 +371,6 @@ module Skeem
|
|
367
371
|
result
|
368
372
|
end
|
369
373
|
end # class
|
370
|
-
|
371
|
-
=begin
|
372
|
-
<Skeem::SkmLambda:
|
373
|
-
@formals [<Skeem::SkmIdentifier: x>]
|
374
|
-
@definitions nil
|
375
|
-
@sequence <Skeem::SkmList:
|
376
|
-
<Skeem::SkmCondition:
|
377
|
-
@test <Skeem::ProcedureCall: <Skeem::SkmIdentifier: <>,
|
378
|
-
<Skeem::SkmList: <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>,
|
379
|
-
<Skeem::SkmInteger: 0>>>,
|
380
|
-
@consequent <Skeem::ProcedureCall:
|
381
|
-
<Skeem::SkmIdentifier: ->,
|
382
|
-
<Skeem::SkmList: <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>>>,
|
383
|
-
@alternate <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>>>>
|
384
|
-
=end
|
385
374
|
|
386
375
|
class SkmLambda < SkmElement
|
387
376
|
# @!attribute [r] formals
|
@@ -427,12 +416,14 @@ module Skeem
|
|
427
416
|
formals.each_with_index do |arg_name, index|
|
428
417
|
arg = arguments[index]
|
429
418
|
if arg.nil?
|
430
|
-
p aProcedureCall.operands.members
|
431
419
|
raise StandardError, "Unbound variable: '#{arg_name.value}'"
|
432
420
|
end
|
433
|
-
|
421
|
+
|
422
|
+
# IMPORTANT: execute procedure call in argument list now
|
423
|
+
arg = arg.evaluate(aRuntime) if arg.kind_of?(ProcedureCall)
|
434
424
|
a_def = SkmDefinition.new(position, arg_name, arg)
|
435
425
|
a_def.evaluate(aRuntime)
|
426
|
+
# puts "LOCAL #{a_def.inspect}"
|
436
427
|
end
|
437
428
|
end
|
438
429
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
; Standard R7RS procedures from section 6.2.6
|
2
|
+
(define zero?
|
3
|
+
(lambda (z)
|
4
|
+
(if (= z 0)
|
5
|
+
#t
|
6
|
+
#f)))
|
7
|
+
|
8
|
+
; Return true if x greater or equal to zero; false otherwise
|
9
|
+
(define positive?
|
10
|
+
(lambda (x)
|
11
|
+
(if (>= x 0)
|
12
|
+
#t
|
13
|
+
#f)))
|
14
|
+
|
15
|
+
(define negative?
|
16
|
+
(lambda (x)
|
17
|
+
(if (< x 0)
|
18
|
+
#t
|
19
|
+
#f)))
|
20
|
+
|
21
|
+
(define abs
|
22
|
+
(lambda (x)
|
23
|
+
(if (>= x 0)
|
24
|
+
x
|
25
|
+
(- x))))
|
data/lib/skeem/version.rb
CHANGED
data/skeem.gemspec
CHANGED
@@ -8,8 +8,8 @@ module Skeem
|
|
8
8
|
expect { Interpreter.new() }.not_to raise_error
|
9
9
|
end
|
10
10
|
|
11
|
-
it 'should
|
12
|
-
expect(subject.parser).
|
11
|
+
it 'should have a parser' do
|
12
|
+
expect(subject.parser).not_to be_nil
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should have a runtime object' do
|
@@ -154,17 +154,17 @@ SKEEM
|
|
154
154
|
result = subject.run('(min 2 2)')
|
155
155
|
expect(result.value).to eq(2)
|
156
156
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
157
|
+
|
158
|
+
it 'should implement recursive functions' do
|
159
|
+
source = <<-SKEEM
|
160
|
+
; Example from R7RS section 4.1.5
|
161
|
+
(define fact (lambda (n)
|
162
|
+
(if (<= n 1) 1 (* n (fact (- n 1))))))
|
163
|
+
(fact 10)
|
164
|
+
SKEEM
|
165
|
+
result = subject.run(source)
|
166
|
+
expect(result.value).to eq(3628800)
|
167
|
+
end
|
168
168
|
end # context
|
169
169
|
|
170
170
|
context 'Built-in primitive procedures' do
|
@@ -377,5 +377,82 @@ SKEEM
|
|
377
377
|
end
|
378
378
|
end
|
379
379
|
end # context
|
380
|
+
|
381
|
+
context 'Built-in standard procedures' do
|
382
|
+
it 'should implement the zero? predicate' do
|
383
|
+
checks = [
|
384
|
+
['(zero? 3.1)', false],
|
385
|
+
['(zero? -3.1)', false],
|
386
|
+
['(zero? 0)', true],
|
387
|
+
['(zero? 0.0)', true],
|
388
|
+
['(zero? 3)', false],
|
389
|
+
['(zero? -3)', false]
|
390
|
+
]
|
391
|
+
checks.each do |(skeem_expr, expectation)|
|
392
|
+
result = subject.run(skeem_expr)
|
393
|
+
expect(result.value).to eq(expectation)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should implement the positive? predicate' do
|
398
|
+
checks = [
|
399
|
+
['(positive? 3.1)', true],
|
400
|
+
['(positive? -3.1)', false],
|
401
|
+
['(positive? 0)', true],
|
402
|
+
['(positive? 0.0)', true],
|
403
|
+
['(positive? 3)', true],
|
404
|
+
['(positive? -3)', false]
|
405
|
+
]
|
406
|
+
checks.each do |(skeem_expr, expectation)|
|
407
|
+
result = subject.run(skeem_expr)
|
408
|
+
expect(result.value).to eq(expectation)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'should implement the positive? predicate' do
|
413
|
+
checks = [
|
414
|
+
['(positive? 3.1)', true],
|
415
|
+
['(positive? -3.1)', false],
|
416
|
+
['(positive? 0)', true],
|
417
|
+
['(positive? 0.0)', true],
|
418
|
+
['(positive? 3)', true],
|
419
|
+
['(positive? -3)', false]
|
420
|
+
]
|
421
|
+
checks.each do |(skeem_expr, expectation)|
|
422
|
+
result = subject.run(skeem_expr)
|
423
|
+
expect(result.value).to eq(expectation)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'should implement the negative? predicate' do
|
428
|
+
checks = [
|
429
|
+
['(negative? 3.1)', false],
|
430
|
+
['(negative? -3.1)', true],
|
431
|
+
['(negative? 0)', false],
|
432
|
+
['(negative? 0.0)', false],
|
433
|
+
['(negative? 3)', false],
|
434
|
+
['(negative? -3)', true]
|
435
|
+
]
|
436
|
+
checks.each do |(skeem_expr, expectation)|
|
437
|
+
result = subject.run(skeem_expr)
|
438
|
+
expect(result.value).to eq(expectation)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
it 'should implement the abs function' do
|
443
|
+
checks = [
|
444
|
+
['(abs 3.1)', 3.1],
|
445
|
+
['(abs -3.1)', 3.1],
|
446
|
+
['(abs 0)', 0],
|
447
|
+
['(abs 0.0)', 0],
|
448
|
+
['(abs 3)', 3],
|
449
|
+
['(abs -7)', 7]
|
450
|
+
]
|
451
|
+
checks.each do |(skeem_expr, expectation)|
|
452
|
+
result = subject.run(skeem_expr)
|
453
|
+
expect(result.value).to eq(expectation)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end # context
|
380
457
|
end # describe
|
381
458
|
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.15
|
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-09-
|
11
|
+
date: 2018-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/skeem/runtime.rb
|
96
96
|
- lib/skeem/s_expr_builder.rb
|
97
97
|
- lib/skeem/s_expr_nodes.rb
|
98
|
+
- lib/skeem/standard/base.skm
|
98
99
|
- lib/skeem/stoken.rb
|
99
100
|
- lib/skeem/tokenizer.rb
|
100
101
|
- lib/skeem/version.rb
|