heist 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/test/numbers.scm CHANGED
@@ -1,19 +1,41 @@
1
- (assert (eqv? 42 42))
2
- (assert (not (eqv? 42 #f)))
3
- (assert (not (eqv? 42 42.0)))
4
1
  (assert (= 42 42))
5
2
  (assert (= 42 42.0))
6
3
 
7
4
  (assert (number? 42))
8
5
  (assert (not (number? #t)))
9
- ;(assert (complex? 2+3i))
10
- ;(assert (not (real? 2+3i)))
6
+ (assert (complex? 2+3i))
7
+ (assert (not (real? 2+3i)))
11
8
  (assert (real? 3.1416))
12
9
  (assert (real? 22/7))
13
10
  (assert (real? 42))
14
- ;(assert (not (rational? 2+3i)))
15
- ;(assert (not (rational? 3.1416)))
16
- ;(assert (rational? 22/7))
11
+ (assert (not (rational? 2+3i)))
12
+ (assert (not (rational? 3.1416)))
13
+ (assert (rational? 22/7))
17
14
  (assert (not (integer? 22/7)))
18
15
  (assert (integer? 42))
19
16
 
17
+ (assert (zero? 0))
18
+ (assert (not (zero? 1)))
19
+ (assert (odd? 1))
20
+ (assert (not (odd? 2)))
21
+ (assert (even? 6))
22
+ (assert (not (even? 7)))
23
+ (assert (positive? 5))
24
+ (assert (not (positive? -4)))
25
+ (assert (negative? -13))
26
+ (assert (not (negative? 0)))
27
+
28
+ (assert-equal 9 (max 8 2 7 3 9 5))
29
+ (assert-equal 2 (min 8 2 7 3 9 5))
30
+
31
+ (assert (exact? 8))
32
+ (assert (exact? 4/3))
33
+ (assert (exact? 5+3i))
34
+ (assert (inexact? 8.5))
35
+ (assert (inexact? 8.5+4i))
36
+
37
+ (assert (rational? (/ 4 3)))
38
+ (assert (rational? (/ 4)))
39
+
40
+ (assert-equal 1 (make-polar 1 0))
41
+
data/test/test_heist.rb CHANGED
@@ -13,7 +13,7 @@ Class.new(Test::Unit::TestCase) do
13
13
  def setup
14
14
  return @@env if @@env
15
15
  @@env = Heist::Runtime.new(Heist::BIN_SPEC.parse($args))
16
- Heist.info(@@env)
16
+ puts @@env.info
17
17
 
18
18
  @@env.define('assert') do |value|
19
19
  assert(value)
@@ -21,18 +21,21 @@ Class.new(Test::Unit::TestCase) do
21
21
  @@env.define('assert-equal') do |expected, actual|
22
22
  assert_equal(expected, actual)
23
23
  end
24
- @@env.syntax('assert-raise') do |scope, name, expression|
25
- exception = Heist.const_get(name.to_s)
26
- assert_raise(exception) { @@env.eval(expression) }
24
+ @@env.syntax('assert-raise') do |scope, cells|
25
+ exception = Heist.const_get(cells.car.to_s)
26
+ assert_raise(exception) { scope.eval(cells.cdr.car) }
27
27
  end
28
28
  end
29
29
 
30
30
  %w[ booleans
31
31
  numbers
32
+ lists
33
+ equivalence
32
34
  arithmetic
33
35
  define_values
34
36
  define_functions
35
37
  closures
38
+ functional
36
39
  let
37
40
  conditionals
38
41
  file_loading
@@ -45,6 +48,39 @@ Class.new(Test::Unit::TestCase) do
45
48
  end
46
49
  end
47
50
 
51
+ def test_cons
52
+ cons = Heist::Runtime::Cons
53
+
54
+ empty = cons[[]]
55
+ assert empty.list?
56
+ assert !empty.pair?
57
+ assert_equal cons::NULL, empty
58
+ assert_equal 0, empty.length
59
+
60
+ single = cons[[4]]
61
+ assert single.list?
62
+ assert single.pair?
63
+ assert_equal 1, single.length
64
+
65
+ multi = cons[[2,4,7]]
66
+ assert multi.list?
67
+ assert multi.pair?
68
+ assert_equal 3, multi.length
69
+
70
+ multi.tail.cdr = 8
71
+ assert multi.pair?
72
+ assert !multi.list?
73
+ assert_raise(Heist::TypeError) { multi.size }
74
+
75
+ nested = cons[[2,4,6,cons.new(7,8)]]
76
+ assert nested.list?
77
+ assert nested.pair?
78
+ assert_equal 4, nested.length
79
+ assert !nested.cdr.cdr.cdr.car.list?
80
+ assert nested.cdr.cdr.cdr.car.pair?
81
+ assert_equal 8, nested.cdr.cdr.cdr.car.cdr
82
+ end
83
+
48
84
  def test_macro_hygiene
49
85
  @@env.run($dir + '/' + (@@env.hygienic? ? 'hygienic' : 'unhygienic'))
50
86
  end
@@ -55,14 +91,25 @@ Class.new(Test::Unit::TestCase) do
55
91
  end
56
92
 
57
93
  def test_quotes
58
- assert_equal 7, @@env.eval("(+ 3 4)")
59
- assert_equal [:+, 3, 4], @@env.eval("'(+ 3 4)").to_a
60
- assert Heist::Runtime::List === @@env.eval("'(+ 3 4)")
61
- assert_equal 7, @@env.eval("(+ '3 4)")
62
- assert_equal [:+, [:-, 7, 9], 4], @@env.eval("'(+ (- 7 9) 4)").to_a
63
- assert_equal [7, 9, 6], @@env.eval("`(7 ,(+ 4 5) 6)").to_a
64
- assert Heist::Runtime::List === @@env.eval("`(7 ,(+ 4 5) 6)")
65
- assert_equal [3, 7, 6, 2, 6, 9], @@env.eval("`(3 7 6 ,@((lambda () '(2 6))) 9)").to_a
94
+ cons = Heist::Runtime::Cons
95
+ c = cons.method(:new)
96
+
97
+ assert_equal 7, @@env.eval("(+ 3 4)")
98
+ assert_equal [:+, 3, 4], @@env.eval("'(+ 3 4)").to_ruby
99
+ assert cons === @@env.eval("'(+ 3 4)")
100
+ assert_equal 7, @@env.eval("(+ '3 4)")
101
+ assert_equal c[1,8], @@env.eval("'(1 . 8)")
102
+ assert_equal c[1,8], @@env.eval("`(1 . 8)")
103
+ assert_equal [:+, [:-, 7, 9], 4], @@env.eval("'(+ (- 7 9) 4)").to_ruby
104
+ assert_equal [7, 9, 6], @@env.eval("`(7 ,(+ 4 5) 6)").to_ruby
105
+ assert cons === @@env.eval("`(7 ,(+ 4 5) 6)")
106
+ assert_equal [3, 7, 6, 2, 6, 9], @@env.eval("`(3 7 6 ,@((lambda () '(2 6))) 9)").to_ruby
107
+ assert_equal [1, 2, 10], @@env.eval("`(1 2 ,(+ 4 6))").to_ruby
108
+ assert_equal [3, 2, 9, 8], @@env.eval("`(,(/ 9 3) 2 ,@(list 9 8))").to_ruby
109
+ assert_equal [1, 2, 4, 9, 8, 5], @@env.eval("`(,@(list 1 2) 4 ,@(list 9 8) 5)").to_ruby
110
+ assert_equal c[9,c[8,c[5,7]]], @@env.eval("`(,@(list 9 8) 5 . 7)")
111
+ assert_equal c[9,c[8,24]], @@env.eval("`(,@(list 9 8) . ,(* 4 6))")
112
+ assert_equal [:quote, []], @@env.eval("''()").to_ruby
66
113
  end
67
114
 
68
115
  def test_birds
@@ -80,5 +127,13 @@ Class.new(Test::Unit::TestCase) do
80
127
 
81
128
  assert_equal 45, @@env.eval("((K 45) 6)")
82
129
  end
130
+
131
+ def test_ruby_execution
132
+ expr = [[:lambda, [:x], [:+, 1, :x]], 3]
133
+ assert_equal 4, @@env.exec(expr)
134
+ list = Heist.parse(expr)
135
+ assert Heist::Runtime::Cons === list
136
+ assert_equal expr, list.to_ruby
137
+ end
83
138
  end
84
139
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Coglan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-24 00:00:00 +00:00
12
+ date: 2009-04-01 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -57,37 +57,37 @@ extra_rdoc_files:
57
57
  files:
58
58
  - History.txt
59
59
  - Manifest.txt
60
- - README.txt
61
60
  - Rakefile
61
+ - README.txt
62
62
  - bin/heist
63
- - lib/heist.rb
64
63
  - lib/bin_spec.rb
64
+ - lib/heist.rb
65
65
  - lib/repl.rb
66
+ - lib/builtin/library.scm
66
67
  - lib/builtin/primitives.rb
67
- - lib/builtin/syntax.rb
68
68
  - lib/builtin/syntax.scm
69
- - lib/builtin/library.scm
70
- - lib/parser/scheme.tt
71
- - lib/parser/scheme.rb
72
69
  - lib/parser/nodes.rb
73
- - lib/runtime/runtime.rb
74
- - lib/runtime/data/expression.rb
75
- - lib/runtime/data/identifier.rb
76
- - lib/runtime/data/list.rb
70
+ - lib/parser/ruby.rb
71
+ - lib/parser/scheme.rb
72
+ - lib/parser/scheme.tt
73
+ - lib/runtime/callable/continuation.rb
77
74
  - lib/runtime/callable/function.rb
75
+ - lib/runtime/callable/syntax.rb
78
76
  - lib/runtime/callable/macro.rb
79
77
  - lib/runtime/callable/macro/matches.rb
80
- - lib/runtime/callable/macro/splice.rb
78
+ - lib/runtime/callable/macro/tree.rb
81
79
  - lib/runtime/callable/macro/expansion.rb
82
- - lib/runtime/callable/continuation.rb
83
- - lib/runtime/stack.rb
84
- - lib/runtime/stackless.rb
80
+ - lib/runtime/data/cons.rb
81
+ - lib/runtime/data/expression.rb
82
+ - lib/runtime/data/identifier.rb
83
+ - lib/runtime/binding.rb
85
84
  - lib/runtime/frame.rb
85
+ - lib/runtime/runtime.rb
86
86
  - lib/runtime/scope.rb
87
- - lib/runtime/binding.rb
87
+ - lib/runtime/stack.rb
88
+ - lib/runtime/stackless.rb
88
89
  - lib/stdlib/benchmark.scm
89
90
  - lib/stdlib/birdhouse.scm
90
- - test/test_heist.rb
91
91
  - test/arithmetic.scm
92
92
  - test/benchmarks.scm
93
93
  - test/booleans.scm
@@ -97,15 +97,19 @@ files:
97
97
  - test/define_functions.scm
98
98
  - test/define_values.scm
99
99
  - test/delay.scm
100
+ - test/equivalence.scm
100
101
  - test/file_loading.scm
102
+ - test/functional.scm
103
+ - test/hygienic.scm
101
104
  - test/let.scm
102
105
  - test/lib.scm
106
+ - test/lists.scm
103
107
  - test/macro-helpers.scm
104
108
  - test/macros.scm
105
- - test/hygienic.scm
106
- - test/unhygienic.scm
107
- - test/plt-macros.txt
108
109
  - test/numbers.scm
110
+ - test/plt-macros.txt
111
+ - test/test_heist.rb
112
+ - test/unhygienic.scm
109
113
  - test/vars.scm
110
114
  has_rdoc: true
111
115
  homepage: Heist is a Scheme interpreter written in Ruby. It provides an executable
@@ -1,166 +0,0 @@
1
- # Control structures
2
-
3
- # (cond) goes through a list of tests, evaluating each one
4
- # in order of appearance. Once a matching precondition is
5
- # found, its consequent is tail-called and no further
6
- # preconditions are evaluated.
7
- syntax('cond') do |scope, *pairs|
8
- result = nil
9
- pairs.each do |list|
10
- next if result
11
- test = list.first.to_s == 'else' || Heist.evaluate(list.first, scope)
12
- next unless test
13
- result = list[1].to_s == '=>' ?
14
- Heist.evaluate(list[2], scope).call(scope, [test]) :
15
- Body.new(list.rest, scope)
16
- end
17
- result
18
- end
19
-
20
- # (case) acts like Ruby's case statement. The value of the
21
- # given expression is compared against a series of lists;
22
- # once a list is found to include the value, the expressions
23
- # following the list are evaluated and no further lists
24
- # are tested.
25
- syntax('case') do |scope, key, *clauses|
26
- value = Heist.evaluate(key, scope)
27
- result = nil
28
- clauses.each do |list|
29
- next if result
30
- values = call('quote', scope, list.first)
31
- result = Body.new(list.rest, scope) if values == :else or
32
- values.include?(value)
33
- end
34
- result
35
- end
36
-
37
- #----------------------------------------------------------------
38
-
39
- # Binding constructs
40
-
41
- # (let), (let*) and (letrec) each create a new scope and bind
42
- # values to some symbols before executing a series of lists.
43
- # They differ according to how they evaluate the bound values.
44
-
45
- # (let) evaluates values in the enclosing scope, so lambdas will
46
- # not be able to refer to other values assigned using the (let).
47
- syntax('let') do |scope, assignments, *body|
48
- if Identifier === assignments
49
- name = assignments
50
- assignments = body.first
51
- formals = assignments.map { |pair| pair.first }
52
- values = assignments.map { |pair| pair.last }
53
- closure = Scope.new(scope)
54
- closure[name] = Function.new(closure, formals, body[1..-1])
55
- closure[name].call(scope, values)
56
- else
57
- closure = Scope.new(scope)
58
- assignments.each do |assign|
59
- closure[assign.first] = Heist.evaluate(assign.last, scope)
60
- end
61
- call('begin', closure, *body)
62
- end
63
- end
64
-
65
- # (let*) creates a new scope for each variable and evaluates
66
- # each expression in its enclosing scope. Basically a shorthand
67
- # for several nested (let)s. Variables may refer to those that
68
- # preceed them but not vice versa.
69
- syntax('let*') do |scope, assignments, *body|
70
- closure = assignments.inject(scope) do |outer, assign|
71
- inner = Scope.new(outer)
72
- inner[assign.first] = Heist.evaluate(assign.last, outer)
73
- inner
74
- end
75
- call('begin', closure, *body)
76
- end
77
-
78
- # (letrec) evaluates values in the inner scope, so lambdas are
79
- # able to refer to other values assigned using the (letrec).
80
- syntax('letrec') do |scope, assignments, *body|
81
- closure = Scope.new(scope)
82
- assignments.each do |assign|
83
- closure[assign.first] = Heist.evaluate(assign.last, closure)
84
- end
85
- call('begin', closure, *body)
86
- end
87
-
88
- syntax('let-syntax') do |*args|
89
- call('let', *args)
90
- end
91
-
92
- syntax('letrec-syntax') do |*args|
93
- call('letrec', *args)
94
- end
95
-
96
- #----------------------------------------------------------------
97
-
98
- # Iteration
99
-
100
- # (do) is similar to the 'while' construct in procedural
101
- # languages. It assigns initial values to a set of variables,
102
- # then performs the list of given commands in a loop. If
103
- # before any iteration the test is found to be false, the
104
- # loop is halted and the value of the expression following
105
- # the test is returned.
106
- syntax('do') do |scope, assignments, test, *commands|
107
- closure = Scope.new(scope)
108
- assignments.each do |assign|
109
- closure[assign.first] = Heist.evaluate(assign[1], scope)
110
- end
111
- while not Heist.evaluate(test.first, closure)
112
- commands.each { |expr| Heist.evaluate(expr, closure) }
113
- temp = {}
114
- assignments.each do |assign|
115
- step = assign[2] || assign[0]
116
- temp[assign.first] = Heist.evaluate(step, closure)
117
- end
118
- assignments.each do |assign|
119
- closure[assign.first] = temp[assign.first]
120
- end
121
- end
122
- call('begin', closure, *test.rest)
123
- end
124
-
125
- #----------------------------------------------------------------
126
-
127
- # Boolean combinators
128
-
129
- # (and) returns the first falsey value returned by the list
130
- # of expressions, or returns the value of the last expression
131
- # if all values are truthy.
132
- syntax('and') do |scope, *args|
133
- result = true
134
- args.each do |arg|
135
- next if not result
136
- result = Heist.evaluate(arg, scope)
137
- end
138
- result
139
- end
140
-
141
- # (or) returns the first truthy value returned by the list
142
- # of expressions, or returns the value of the last expression
143
- # if all values are falsey.
144
- syntax('or') do |scope, *args|
145
- result = false
146
- args.each do |arg|
147
- next if result
148
- result = Heist.evaluate(arg, scope)
149
- end
150
- result
151
- end
152
-
153
- #----------------------------------------------------------------
154
-
155
- # Delayed evaluation
156
-
157
- # (delay) allows the evaluation of an expression to be delayed
158
- # by wrapping it in a promise. Use (force) to evaluate the promise
159
- # at a later time. The expression inside a promise is only
160
- # ever evaluated once, so a promise can be implemented as a
161
- # memoized closure.
162
- syntax('delay') do |scope, expression|
163
- promise = Binding.new(expression, scope)
164
- Function.new(scope) { promise.extract }
165
- end
166
-
@@ -1,56 +0,0 @@
1
- module Heist
2
- class Runtime
3
- class Macro
4
-
5
- class Splice
6
- attr_reader :name, :depth
7
-
8
- def initialize(name, depth)
9
- @name, @depth = name, depth
10
- @data = []
11
- (0...@depth).inject(@data) { |list, d| list << []; list.last }
12
- @indexes = (0..@depth).map { 0 }
13
- @stack = []
14
- end
15
-
16
- def <<(value)
17
- @stack.pop.call() while not @stack.empty?
18
- tail(@depth) << value
19
- end
20
-
21
- def mark!(depth)
22
- @stack << lambda { tail(depth) << [] }
23
- end
24
-
25
- def size(depth)
26
- current(depth).size
27
- end
28
-
29
- def read
30
- current(@depth)[@indexes[@depth]]
31
- end
32
-
33
- def shift!(depth)
34
- @indexes[depth] += 1
35
- @indexes[depth] = 0 if @indexes[depth] >= current(depth).size
36
- end
37
-
38
- def to_s(depth = 0)
39
- "#{@name}#{' ...' * (@depth - depth)}"
40
- end
41
-
42
- private
43
-
44
- def tail(depth)
45
- (0...depth).inject(@data) { |list, d| list.last }
46
- end
47
-
48
- def current(depth)
49
- @indexes[0...depth].inject(@data) { |list, i| list[i] }
50
- end
51
- end
52
-
53
- end
54
- end
55
- end
56
-