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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4738bc3d483df0325cce143200b02e5c8cac7afe
4
- data.tar.gz: 8f4560eaa88c6e754bd423bdf3c1f62a35063b75
3
+ metadata.gz: 17793fa7c6e636874b0d7fe8515d745b7ff664af
4
+ data.tar.gz: f24f83ad056e1af1ecac866e2daa649c94e544e6
5
5
  SHA512:
6
- metadata.gz: 99e55d28f19fe7d4cb9a2d18a066a12fa43ffc2dfe59b1e5ac3e2795202c67b122e0fce2a9862871accb936eb58320870588c7eb622b4ee714c3e7bcb22eb5bc
7
- data.tar.gz: 12e216d00ceb2e16ca2d27711bc47449e0ff49438ad9b42d52ae677368624cf15c3c80babef8a70aa740e0cdee8b619697aae871fb2962767e87af2f633068c0
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
@@ -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
@@ -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'
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.0.14'.freeze
2
+ VERSION = '0.0.15'.freeze
3
3
  end
data/skeem.gemspec CHANGED
@@ -19,6 +19,7 @@ module PkgExtending
19
19
  'bin/*.rb',
20
20
  'lib/*.*',
21
21
  'lib/**/*.rb',
22
+ 'lib/**/*.skm',
22
23
  'spec/**/*.rb',
23
24
  ]
24
25
  aPackage.files = file_list
@@ -8,8 +8,8 @@ module Skeem
8
8
  expect { Interpreter.new() }.not_to raise_error
9
9
  end
10
10
 
11
- it 'should not have a parser' do
12
- expect(subject.parser).to be_nil
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
- # 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
- # subject.run(source)
166
- # expect(result.value).to eq(3628800)
167
- # end
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.14
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-23 00:00:00.000000000 Z
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