heist 0.3.1 → 0.3.2
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.
- data/History.txt +12 -0
- data/Manifest.txt +25 -23
- data/Rakefile +7 -0
- data/lib/builtin/library.rb +1 -0
- data/lib/builtin/library.scm +15 -19
- data/lib/heist.rb +3 -3
- data/lib/parser/nodes.rb +4 -4
- data/lib/parser/ruby.rb +6 -1
- data/lib/repl.rb +2 -2
- data/lib/runtime/binding.rb +11 -0
- data/lib/runtime/callable/macro/matches.rb +1 -1
- data/lib/runtime/callable/macro/tree.rb +2 -1
- data/lib/runtime/data/cons.rb +20 -4
- data/lib/runtime/data/identifier.rb +2 -1
- data/lib/runtime/runtime.rb +29 -9
- data/lib/runtime/scope.rb +32 -9
- data/lib/trie.rb +14 -0
- data/test/{lib.scm → helpers/lib.scm} +0 -0
- data/test/{macro-helpers.scm → helpers/macro-helpers.scm} +0 -0
- data/test/{vars.scm → helpers/vars.scm} +0 -0
- data/test/{arithmetic.scm → scheme_tests/arithmetic.scm} +0 -0
- data/test/{benchmarks.scm → scheme_tests/benchmarks.scm} +0 -0
- data/test/{booleans.scm → scheme_tests/booleans.scm} +0 -0
- data/test/{closures.scm → scheme_tests/closures.scm} +0 -0
- data/test/{conditionals.scm → scheme_tests/conditionals.scm} +0 -0
- data/test/{continuations.scm → scheme_tests/continuations.scm} +0 -0
- data/test/{define_functions.scm → scheme_tests/define_functions.scm} +0 -0
- data/test/{define_values.scm → scheme_tests/define_values.scm} +0 -0
- data/test/{delay.scm → scheme_tests/delay.scm} +0 -0
- data/test/{equivalence.scm → scheme_tests/equivalence.scm} +0 -0
- data/test/{file_loading.scm → scheme_tests/file_loading.scm} +2 -2
- data/test/{functional.scm → scheme_tests/functional.scm} +0 -0
- data/test/{hygienic.scm → scheme_tests/hygienic.scm} +1 -1
- data/test/{let.scm → scheme_tests/let.scm} +0 -0
- data/test/{lists.scm → scheme_tests/lists.scm} +0 -0
- data/test/{macros.scm → scheme_tests/macros.scm} +42 -1
- data/test/{numbers.scm → scheme_tests/numbers.scm} +0 -0
- data/test/scheme_tests/protection.scm +13 -0
- data/test/{strings.scm → scheme_tests/strings.scm} +0 -0
- data/test/{unhygienic.scm → scheme_tests/unhygienic.scm} +1 -1
- data/test/{vectors.scm → scheme_tests/vectors.scm} +0 -0
- data/test/test_heist.rb +43 -36
- metadata +52 -28
data/History.txt
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== Version 0.3.2 (2010-01-16)
|
2
|
+
|
3
|
+
* Built-in library code is executed in a protected scope so that redefinitions of
|
4
|
+
core functions in user code do not break implementations of library functions
|
5
|
+
* The core library is compiled to a Ruby representation that loads faster
|
6
|
+
* Macros correctly transcribe empty lists appearing in the input
|
7
|
+
* Macro variables may appear at greater ellipsis depth in templates than in corresponding patterns
|
8
|
+
* Fix bug in macro literal identifier recognition
|
9
|
+
* Identifier comparison is now case-insensitive
|
10
|
+
* The REPL prints quote/unquote expressions using shorthand notation
|
11
|
+
|
12
|
+
|
1
13
|
=== Version 0.3.1 (2009-08-23)
|
2
14
|
|
3
15
|
* Added the (rationalize) procedure
|
data/Manifest.txt
CHANGED
@@ -8,6 +8,7 @@ lib/heist.rb
|
|
8
8
|
lib/repl.rb
|
9
9
|
lib/trie.rb
|
10
10
|
lib/builtin/library.scm
|
11
|
+
lib/builtin/library.rb
|
11
12
|
lib/builtin/primitives.rb
|
12
13
|
lib/builtin/syntax.scm
|
13
14
|
lib/parser/nodes.rb
|
@@ -34,29 +35,30 @@ lib/runtime/stack.rb
|
|
34
35
|
lib/runtime/stackless.rb
|
35
36
|
lib/stdlib/benchmark.scm
|
36
37
|
lib/stdlib/birdhouse.scm
|
37
|
-
test/
|
38
|
-
test/
|
39
|
-
test/
|
40
|
-
test/
|
41
|
-
test/
|
42
|
-
test/
|
43
|
-
test/
|
44
|
-
test/
|
45
|
-
test/
|
46
|
-
test/
|
47
|
-
test/
|
48
|
-
test/
|
49
|
-
test/
|
50
|
-
test/
|
51
|
-
test/
|
52
|
-
test/
|
53
|
-
test/
|
54
|
-
test/
|
55
|
-
test/
|
38
|
+
test/helpers/lib.scm
|
39
|
+
test/helpers/macro-helpers.scm
|
40
|
+
test/helpers/vars.scm
|
41
|
+
test/scheme_tests/arithmetic.scm
|
42
|
+
test/scheme_tests/benchmarks.scm
|
43
|
+
test/scheme_tests/booleans.scm
|
44
|
+
test/scheme_tests/closures.scm
|
45
|
+
test/scheme_tests/conditionals.scm
|
46
|
+
test/scheme_tests/continuations.scm
|
47
|
+
test/scheme_tests/define_functions.scm
|
48
|
+
test/scheme_tests/define_values.scm
|
49
|
+
test/scheme_tests/delay.scm
|
50
|
+
test/scheme_tests/equivalence.scm
|
51
|
+
test/scheme_tests/file_loading.scm
|
52
|
+
test/scheme_tests/functional.scm
|
53
|
+
test/scheme_tests/hygienic.scm
|
54
|
+
test/scheme_tests/let.scm
|
55
|
+
test/scheme_tests/lists.scm
|
56
|
+
test/scheme_tests/macros.scm
|
57
|
+
test/scheme_tests/numbers.scm
|
58
|
+
test/scheme_tests/protection.scm
|
59
|
+
test/scheme_tests/strings.scm
|
60
|
+
test/scheme_tests/unhygienic.scm
|
61
|
+
test/scheme_tests/vectors.scm
|
56
62
|
test/plt-macros.txt
|
57
|
-
test/strings.scm
|
58
63
|
test/test_heist.rb
|
59
|
-
test/unhygienic.scm
|
60
|
-
test/vars.scm
|
61
|
-
test/vectors.scm
|
62
64
|
|
data/Rakefile
CHANGED
@@ -9,6 +9,13 @@ Hoe.spec('heist') do |p|
|
|
9
9
|
p.extra_deps = %w(oyster treetop)
|
10
10
|
end
|
11
11
|
|
12
|
+
file "lib/builtin/library.rb" => "lib/builtin/library.scm" do |t|
|
13
|
+
program = Heist.parse(File.read t.prerequisites.first).convert!
|
14
|
+
File.open(t.name, 'w') { |f| f.write 'program ' + program.to_ruby.inspect }
|
15
|
+
end
|
16
|
+
|
17
|
+
task :compile => "lib/builtin/library.rb"
|
18
|
+
|
12
19
|
namespace :spec do
|
13
20
|
task :r5rs do
|
14
21
|
procedures = Dir['r5rs/*.html'].
|
@@ -0,0 +1 @@
|
|
1
|
+
program [[:define, :quit, :exit], [:define, [:newline], [:display, "\n"]], [:define, [:force, :promise], [:promise]], [:define, :"call/cc", :"call-with-current-continuation"], [:define, :eq?, :eqv?], [:define, [:not, :x], [:if, :x, false, true]], [:define, :true, true], [:define, :false, false], [:define, [:boolean?, :x], [:or, [:eqv?, :x, true], [:eqv?, :x, false]]], [:define, :number?, :complex?], [:define, [:exact?, :x], [:or, [:rational?, :x], [:and, [:not, [:zero?, [:"imag-part", :x]]], [:exact?, [:"real-part", :x]], [:exact?, [:"imag-part", :x]]]]], [:define, [:inexact?, :x], [:not, [:exact?, :x]]], [:define, [:"=", :".", :args], [:define, [:iter, :x, :rest], [:if, [:null?, :rest], true, [:let, [[:y, [:car, :rest]]], [:if, [:or, [:not, [:number?, :x]], [:not, [:number?, :y]], [:not, [:equal?, :x, :y]]], false, [:iter, :x, [:cdr, :rest]]]]]], [:iter, [:car, :args], [:cdr, :args]]], [:define, [:zero?, :x], [:eqv?, :x, 0]], [:define, [:positive?, :x], [:>, :x, 0]], [:define, [:negative?, :x], [:<, :x, 0]], [:define, [:odd?, :x], [:"=", 1, [:remainder, :x, 2]]], [:define, [:even?, :x], [:zero?, [:remainder, :x, 2]]], [:define, [:max, :".", :values], [:foldr, [:lambda, [:a, :b], [:if, [:>=, :a, :b], :a, :b]], [:car, :values], [:cdr, :values]]], [:define, [:min, :".", :values], [:foldr, [:lambda, [:a, :b], [:if, [:<=, :a, :b], :a, :b]], [:car, :values], [:cdr, :values]]], [:define, [:abs, :x], [:if, [:negative?, :x], [:-, :x], :x]], [:define, [:quotient, :x, :y], [:let, [[:result, [:/, :x, :y]]], [[:if, [:positive?, :result], :floor, :ceiling], :result]]], [:define, [:remainder, :x, :y], [:-, [:round, :x], [:*, [:round, :y], [:quotient, :x, :y]]]], [:define, [:modulo, :x, :y], [:+, [:remainder, :x, :y], [:if, [:negative?, [:*, :x, :y]], [:round, :y], 0]]], [:define, [:gcd, :x, :y, :".", :rest], [:if, [:null?, :rest], [:if, [:zero?, :y], [:abs, :x], [:gcd, :y, [:remainder, :x, :y]]], [:apply, :gcd, [:cons, [:gcd, :x, :y], :rest]]]], [:define, [:lcm, :x, :y, :".", :rest], [:if, [:null?, :rest], [:/, [:abs, [:*, :x, :y]], [:gcd, :x, :y]], [:apply, :lcm, [:cons, [:lcm, :x, :y], :rest]]]], [:define, :ceiling, :ceil], [:define, [:rationalize, :x, :tolerance], [:cond, [[:rational?, :x], :x], [[:not, [:zero?, [:"imag-part", :x]]], [:"make-rectangular", [:rationalize, [:"real-part", :x], :tolerance], [:rationalize, [:"imag-part", :x], :tolerance]]], [:else, [:"let*", [[:t, [:abs, :tolerance]], [:a, [:-, :x, :t]], [:b, [:+, :x, :t]]], [:do, [[:i, 1, [:+, :i, 1]], [:z, false]], [[:number?, :z], :z], [:let, [[:p, [:ceiling, [:*, :a, :i]]], [:q, [:floor, [:*, :b, :i]]]], [:if, [:<=, :p, :q], [:set!, :z, [:/, [:if, [:positive?, :p], :p, :q], :i]]]]]]]]], [:define, [:"make-polar", :magnitude, :angle], [:let, [[:re, [:*, :magnitude, [:cos, :angle]]], [:im, [:*, :magnitude, [:sin, :angle]]]], [:"make-rectangular", :re, :im]]], [:define, [:magnitude, :z], [:let, [[:re, [:"real-part", :z]], [:im, [:"imag-part", :z]]], [:sqrt, [:+, [:*, :re, :re], [:*, :im, :im]]]]], [:define, [:angle, :z], [:let, [[:re, [:"real-part", :z]], [:im, [:"imag-part", :z]]], [:atan, :im, :re]]], [:define, [:factorial, :x], [:define, [:iter, :y, :acc], [:if, [:zero?, :y], :acc, [:iter, [:-, :y, 1], [:*, :y, :acc]]]], [:iter, :x, 1]], [:define, [:null?, :object], [:eqv?, [:quote, []], :object]], [:define, [:list?, :object], [:or, [:null?, :object], [:and, [:pair?, :object], [:list?, [:cdr, :object]]]]], [:define, [:list, :".", :args], :args], [:define, [:length, :object], [:define, [:iter, :list, :acc], [:if, [:null?, :list], :acc, [:iter, [:cdr, :list], [:+, 1, :acc]]]], [:iter, :object, 0]], [:define, [:append, :first, :".", :rest], [:cond, [[:null?, :rest], :first], [[:null?, :first], [:apply, :append, :rest]], [:else, [:cons, [:car, :first], [:append, [:cdr, :first], [:apply, :append, :rest]]]]]], [:define, [:reverse, :object], [:if, [:null?, :object], :object, [:append, [:reverse, [:cdr, :object]], [:list, [:car, :object]]]]], [:define, [:"list-tail", :list, :k], [:do, [[:pair, :list, [:cdr, :pair]], [:i, :k, [:-, :i, 1]]], [[:zero?, :i], :pair]]], [:define, [:"list-ref", :list, :k], [:car, [:"list-tail", :list, :k]]], [:define, [:"list-transform-search", :transform], [:lambda, [:predicate], [:lambda, [:object, :list], [:do, [[:pair, :list, [:cdr, :pair]]], [[:or, [:null?, :pair], [:predicate, [:car, [:transform, :pair]], :object]], [:if, [:null?, :pair], false, [:transform, :pair]]]]]]], [:define, :"list-search", [:"list-transform-search", [:lambda, [:x], :x]]], [:define, :memq, [:"list-search", :eq?]], [:define, :memv, [:"list-search", :eqv?]], [:define, :member, [:"list-search", :equal?]], [:define, :"assoc-list-search", [:"list-transform-search", :car]], [:define, :assq, [:"assoc-list-search", :eq?]], [:define, :assv, [:"assoc-list-search", :eqv?]], [:define, :assoc, [:"assoc-list-search", :equal?]], [:define, [:map, :proc, :list1, :".", :list2], [:if, [:null?, :list1], :list1, [:if, [:null?, :list2], [:cons, [:proc, [:car, :list1]], [:map, :proc, [:cdr, :list1]]], [:"let*", [[:all, [:cons, :list1, :list2]], [:args, [:map, :car, :all]], [:rest, [:map, :cdr, :all]]], [:cons, [:apply, :proc, :args], [:apply, :map, [:cons, :proc, :rest]]]]]]], [:define, [:"for-each", :proc, :list1, :".", :list2], [:do, [[:pair, :list1, [:cdr, :pair]], [:others, :list2, [:map, :cdr, :others]]], [[:null?, :pair], [:quote, []]], [:apply, :proc, [:cons, [:car, :pair], [:map, :car, :others]]]]], [:define, [:foldr, :proc, :value, :list], [:if, [:null?, :list], :value, [:proc, [:car, :list], [:foldr, :proc, :value, [:cdr, :list]]]]], [:define, [:sublist, :list, :start, :end], [:cond, [[:null?, :list], [:quote, []]], [[:>, :start, 0], [:sublist, [:cdr, :list], [:-, :start, 1], [:-, :end, 1]]], [[:<=, :end, 0], [:quote, []]], [:else, [:cons, [:car, :list], [:sublist, [:cdr, :list], 0, [:-, :end, 1]]]]]], [:define, [:char, :string], [:if, [:and, [:string?, :string], [:"=", [:"string-length", :string], 1]], [:"string-ref", :string, 0], [:quote, []]]], [:define, [:"char-upper-case?", :letter], [:and, [:char?, :letter], [:let, [[:code, [:"char->integer", :letter]]], [:and, [:>=, :code, 65], [:<=, :code, 90]]]]], [:define, [:"char-lower-case?", :letter], [:and, [:char?, :letter], [:let, [[:code, [:"char->integer", :letter]]], [:and, [:>=, :code, 97], [:<=, :code, 122]]]]], [:define, [:"char-alphabetic?", :char], [:or, [:"char-upper-case?", :char], [:"char-lower-case?", :char]]], [:define, [:"char-numeric?", :char], [:and, [:char?, :char], [:let, [[:code, [:"char->integer", :char]]], [:and, [:>=, :code, 48], [:<=, :code, 57]]]]], [:define, [:"char-whitespace?", :char], [:and, [:char?, :char], [:if, [:member, [:"char->integer", :char], [:quote, [9, 10, 32]]], true, false]]], [:define, [:"char-upcase", :char], [:let, [[:code, [:"char->integer", :char]]], [:if, [:and, [:>=, :code, 97], [:<=, :code, 122]], [:"integer->char", [:-, :code, 32]], [:"integer->char", :code]]]], [:define, [:"char-downcase", :char], [:let, [[:code, [:"char->integer", :char]]], [:if, [:and, [:>=, :code, 65], [:<=, :code, 90]], [:"integer->char", [:+, :code, 32]], [:"integer->char", :code]]]], [:define, [:"char-compare-ci", :operator], [:lambda, [:x, :y], [:operator, [:"char-downcase", :x], [:"char-downcase", :y]]]], [:define, :"char-ci=?", [:"char-compare-ci", :"char=?"]], [:define, :"char-ci<?", [:"char-compare-ci", :"char<?"]], [:define, :"char-ci>?", [:"char-compare-ci", :"char>?"]], [:define, :"char-ci<=?", [:"char-compare-ci", :"char<=?"]], [:define, :"char-ci>=?", [:"char-compare-ci", :"char>=?"]], [:define, [:string, :".", :chars], [:"list->string", :chars]], [:define, [:"string-compare", :string1, :string2, :"char-less?", :"char-greater?"], [:if, [:or, [:not, [:string?, :string1]], [:not, [:string?, :string2]]], [:error, "Expected two strings as arguments"], [:do, [[:pair1, [:"string->list", :string1], [:cdr, :pair1]], [:pair2, [:"string->list", :string2], [:cdr, :pair2]], [:diff, [:quote, []]]], [[:integer?, :diff], :diff], [:set!, :diff, [:cond, [[:null?, :pair1], [:if, [:null?, :pair2], 0, -1]], [[:null?, :pair2], 1], [:else, [:let, [[:char1, [:car, :pair1]], [:char2, [:car, :pair2]]], [:cond, [[:"char-less?", :char1, :char2], -1], [[:"char-greater?", :char1, :char2], 1], [:else, [:quote, []]]]]]]]]]], [:define, [:"string=?", :string1, :string2], [:zero?, [:"string-compare", :string1, :string2, :"char<?", :"char>?"]]], [:define, [:"string-ci=?", :string1, :string2], [:zero?, [:"string-compare", :string1, :string2, :"char-ci<?", :"char-ci>?"]]], [:define, [:"string<?", :string1, :string2], [:"=", [:"string-compare", :string1, :string2, :"char<?", :"char>?"], -1]], [:define, [:"string>?", :string1, :string2], [:"=", [:"string-compare", :string1, :string2, :"char<?", :"char>?"], 1]], [:define, [:"string<=?", :string1, :string2], [:not, [:"string>?", :string1, :string2]]], [:define, [:"string>=?", :string1, :string2], [:not, [:"string<?", :string1, :string2]]], [:define, [:"string-ci<?", :string1, :string2], [:"=", [:"string-compare", :string1, :string2, :"char-ci<?", :"char-ci>?"], -1]], [:define, [:"string-ci>?", :string1, :string2], [:"=", [:"string-compare", :string1, :string2, :"char-ci<?", :"char-ci>?"], 1]], [:define, [:"string-ci<=?", :string1, :string2], [:not, [:"string-ci>?", :string1, :string2]]], [:define, [:"string-ci>=?", :string1, :string2], [:not, [:"string-ci<?", :string1, :string2]]], [:define, [:substring, :string, :start, :end], [:"list->string", [:sublist, [:"string->list", :string], :start, :end]]], [:define, [:"list->string", :chars], [:"let*", [[:size, [:length, :chars]], [:str, [:"make-string", :size]]], [:do, [[:list, :chars, [:cdr, :list]], [:i, 0, [:+, :i, 1]]], [[:"=", :i, :size], :str], [:"string-set!", :str, :i, [:car, :list]]]]], [:define, [:"string->list", :string], [:let, [[:size, [:"string-length", :string]]], [:do, [[:i, :size, [:-, :i, 1]], [:list, [:quote, []], [:cons, [:"string-ref", :string, [:-, :i, 1]], :list]]], [[:zero?, :i], :list]]]], [:define, [:"string-copy", :string], [:"list->string", [:"string->list", :string]]], [:define, [:"string-fill!", :string, :char], [:let, [[:size, [:"string-length", :string]]], [:do, [[:i, :size, [:-, :i, 1]]], [[:zero?, :i], :string], [:"string-set!", :string, [:-, :i, 1], :char]]]], [:define, [:"string-append", :".", :strings], [:"list->string", [:apply, :append, [:map, :"string->list", :strings]]]], [:define, [:vector, :".", :args], [:"list->vector", :args]], [:define, [:"list->vector", :list], [:"let*", [[:size, [:length, :list]], [:"new-vector", [:"make-vector", :size]]], [:do, [[:i, 0, [:+, :i, 1]], [:pair, :list, [:cdr, :pair]]], [[:"=", :i, :size], :"new-vector"], [:"vector-set!", :"new-vector", :i, [:car, :pair]]]]], [:define, [:"vector->list", :vector], [:do, [[:i, [:"vector-length", :vector], [:-, :i, 1]], [:pair, [:quote, []], [:cons, [:"vector-ref", :vector, [:-, :i, 1]], :pair]]], [[:zero?, :i], :pair]]], [:define, [:"vector-fill!", :vector, :fill], [:do, [[:i, [:"vector-length", :vector], [:-, :i, 1]]], [[:zero?, :i], :vector], [:"vector-set!", :vector, [:-, :i, 1], :fill]]]]
|
data/lib/builtin/library.scm
CHANGED
@@ -258,15 +258,12 @@
|
|
258
258
|
; The final argument is not copied and the return value of
|
259
259
|
; (append) shares structure with it.
|
260
260
|
(define (append first . rest)
|
261
|
-
(
|
262
|
-
|
263
|
-
|
264
|
-
(
|
265
|
-
|
266
|
-
|
267
|
-
((null? (cdr pair))
|
268
|
-
(set-cdr! pair (apply append rest))))
|
269
|
-
copy))))
|
261
|
+
(cond [(null? rest) first]
|
262
|
+
[(null? first) (apply append rest)]
|
263
|
+
[else
|
264
|
+
(cons (car first)
|
265
|
+
(append (cdr first)
|
266
|
+
(apply append rest)))]))
|
270
267
|
|
271
268
|
; (reverse list)
|
272
269
|
; Returns a newly allocated list consisting of the
|
@@ -365,6 +362,14 @@
|
|
365
362
|
(proc (car list)
|
366
363
|
(foldr proc value (cdr list)))))
|
367
364
|
|
365
|
+
; (sublist list start end)
|
366
|
+
(define (sublist list start end)
|
367
|
+
(cond [(null? list) '()]
|
368
|
+
[(> start 0) (sublist (cdr list) (- start 1) (- end 1))]
|
369
|
+
[(<= end 0) '()]
|
370
|
+
[else (cons (car list)
|
371
|
+
(sublist (cdr list) 0 (- end 1)))]))
|
372
|
+
|
368
373
|
;----------------------------------------------------------------
|
369
374
|
|
370
375
|
; Character functions
|
@@ -528,16 +533,7 @@
|
|
528
533
|
; Returns a string composed of the characters from start (inclusive)
|
529
534
|
; to end (exclusive) in string
|
530
535
|
(define (substring string start end)
|
531
|
-
(
|
532
|
-
(cond [(< start 0) (error "start index must be positive")]
|
533
|
-
[(> end size) (error "end index must be <= the length of string")]
|
534
|
-
[(> start end) (error "start must be <= end index")]
|
535
|
-
[else
|
536
|
-
(let* ([subsize (- end start)]
|
537
|
-
[substr (make-string subsize)])
|
538
|
-
(do ([i 0 (+ i 1)])
|
539
|
-
((= i subsize) substr)
|
540
|
-
(string-set! substr i (string-ref string (+ start i)))))])))
|
536
|
+
(list->string (sublist (string->list string) start end)))
|
541
537
|
|
542
538
|
; (list->string chars)
|
543
539
|
; Returns a new string formed by combining the list
|
data/lib/heist.rb
CHANGED
@@ -9,7 +9,7 @@ require 'treetop'
|
|
9
9
|
# utility methods that don't belong anywhere else. See the README for an
|
10
10
|
# overview of Heist's features.
|
11
11
|
module Heist
|
12
|
-
VERSION = '0.3.
|
12
|
+
VERSION = '0.3.2'
|
13
13
|
|
14
14
|
ROOT_PATH = File.expand_path(File.dirname(__FILE__))
|
15
15
|
PARSER_PATH = ROOT_PATH + '/parser/'
|
@@ -24,8 +24,8 @@ module Heist
|
|
24
24
|
require ROOT_PATH + '/trie'
|
25
25
|
require ROOT_PATH + '/repl'
|
26
26
|
|
27
|
-
LOAD_PATH = [LIB_PATH]
|
28
|
-
|
27
|
+
LOAD_PATH = [BUILTIN_PATH, LIB_PATH]
|
28
|
+
FILE_EXTS = [""] + %w[.rb .scm .ss]
|
29
29
|
|
30
30
|
class HeistError < StandardError; end
|
31
31
|
class RuntimeError < HeistError; end
|
data/lib/parser/nodes.rb
CHANGED
@@ -12,10 +12,10 @@ module Heist
|
|
12
12
|
# In Scheme, this list includes the various quoting symbols that can be used
|
13
13
|
# as shorthands for calling quoting functions.
|
14
14
|
SHORTHANDS = {
|
15
|
-
"'" =>
|
16
|
-
"`" =>
|
17
|
-
"," =>
|
18
|
-
",@" =>
|
15
|
+
"'" => 'quote',
|
16
|
+
"`" => 'quasiquote',
|
17
|
+
"," => 'unquote',
|
18
|
+
",@" => 'unquote-splicing'
|
19
19
|
}
|
20
20
|
|
21
21
|
# +Program+ is the root of the parse tree; parsing any string of Scheme code
|
data/lib/parser/ruby.rb
CHANGED
@@ -12,11 +12,16 @@ module Heist
|
|
12
12
|
#
|
13
13
|
class RubyParser
|
14
14
|
|
15
|
+
DOT = :'.'
|
16
|
+
|
15
17
|
# Parses a single piece of Ruby data in
|
16
18
|
def parse(source)
|
17
19
|
case source
|
18
20
|
when Array then
|
19
|
-
|
21
|
+
members, tail = *(source[-2] == DOT ? [source[0..-3], source.last] : [source, nil])
|
22
|
+
list = Runtime::Cons.construct(members) { |cell| parse(cell) }
|
23
|
+
list.tail.cdr = parse(tail) if tail
|
24
|
+
list
|
20
25
|
when Symbol then
|
21
26
|
Runtime::Identifier.new(source)
|
22
27
|
else
|
data/lib/repl.rb
CHANGED
@@ -5,7 +5,7 @@ module Heist
|
|
5
5
|
|
6
6
|
def initialize(options = {})
|
7
7
|
@runtime = Runtime.new(options)
|
8
|
-
@scope = Runtime::FileScope.new(@runtime.
|
8
|
+
@scope = Runtime::FileScope.new(@runtime.user_scope, File.expand_path('.'))
|
9
9
|
@results = []
|
10
10
|
|
11
11
|
@runtime.define('~') { |x| @results[-x] }
|
@@ -17,7 +17,7 @@ module Heist
|
|
17
17
|
puts @runtime.info
|
18
18
|
|
19
19
|
Readline.completion_append_character = nil
|
20
|
-
Readline.completion_proc = @runtime.
|
20
|
+
Readline.completion_proc = @runtime.user_scope.method(:longest_prefix)
|
21
21
|
|
22
22
|
loop do
|
23
23
|
begin
|
data/lib/runtime/binding.rb
CHANGED
@@ -42,6 +42,17 @@ module Heist
|
|
42
42
|
force!
|
43
43
|
end
|
44
44
|
|
45
|
+
# We provide an equality method so that a bound +Identifier+ produced
|
46
|
+
# by expanding a macro can be matched against literal identifiers in
|
47
|
+
# another macro pattern.
|
48
|
+
def ==(identifier)
|
49
|
+
@expression == identifier
|
50
|
+
end
|
51
|
+
|
52
|
+
def innermost_binding(identifier)
|
53
|
+
@scope
|
54
|
+
end
|
55
|
+
|
45
56
|
# Returns a string representation of the binding's +Expression+.
|
46
57
|
def to_s
|
47
58
|
@expression.to_s
|
@@ -88,7 +88,6 @@ module Heist
|
|
88
88
|
# seeing as the pattern should be followed by the same number of ellipses
|
89
89
|
# every time it is encountered.
|
90
90
|
def <<(value)
|
91
|
-
return if Cons::NULL == value
|
92
91
|
tail(@depth) << value
|
93
92
|
end
|
94
93
|
|
@@ -102,6 +101,7 @@ module Heist
|
|
102
101
|
# to one of the values in <tt>@indexes</tt>. The macro expander calls this
|
103
102
|
# while walking a template to iterate over repetition branches.
|
104
103
|
def shift!(depth)
|
104
|
+
return if depth > @depth
|
105
105
|
indexes[depth] += 1
|
106
106
|
indexes[depth] = 0 if indexes[depth] >= current(depth).size
|
107
107
|
end
|
@@ -110,6 +110,7 @@ module Heist
|
|
110
110
|
# read branch at the given +depth+. Returns zero if no branch exists at
|
111
111
|
# the given indexes.
|
112
112
|
def size(depth)
|
113
|
+
return nil if depth > @depth
|
113
114
|
current(depth).size rescue 0
|
114
115
|
end
|
115
116
|
|
data/lib/runtime/data/cons.rb
CHANGED
@@ -60,6 +60,10 @@ module Heist
|
|
60
60
|
# An array of all the c[ad]+r functions supported by Heist
|
61
61
|
ACCESSORS = cadr_combos
|
62
62
|
|
63
|
+
# For stringifying purposes, we need an inverted copy of the table
|
64
|
+
# of quoting shorthand symbols
|
65
|
+
SHORTHANDS = Scheme::SHORTHANDS.invert
|
66
|
+
|
63
67
|
class << self
|
64
68
|
# Creates a new list from the elements of the enumerable object +enum+,
|
65
69
|
# and returns the +Cons+ that forms the head of the list. If +enum+ is
|
@@ -214,15 +218,27 @@ module Heist
|
|
214
218
|
# Returns a pure Ruby representation of the list, with any Heist
|
215
219
|
# specific objects converted to basic Ruby equivalents.
|
216
220
|
def to_ruby
|
217
|
-
|
221
|
+
members = []
|
222
|
+
tail = each do |cell|
|
223
|
+
members << (cell.respond_to?(:to_ruby) ? cell.to_ruby : cell)
|
224
|
+
end
|
225
|
+
if NULL != tail.cdr
|
226
|
+
members << RubyParser::DOT
|
227
|
+
members << (tail.cdr.respond_to?(:to_ruby) ? tail.cdr.to_ruby : tail.cdr)
|
228
|
+
end
|
229
|
+
members
|
218
230
|
end
|
219
231
|
|
220
232
|
# Returns a Scheme-style string representation of the list.
|
221
233
|
def to_s
|
222
234
|
strings = []
|
223
|
-
|
224
|
-
|
225
|
-
|
235
|
+
if Identifier === @car and SHORTHANDS.has_key?(@car.to_s) and list? and length == 2
|
236
|
+
SHORTHANDS[@car.to_s] + Heist.stringify(@cdr.car)
|
237
|
+
else
|
238
|
+
tail = each { |value| strings << Heist.stringify(value) }.cdr
|
239
|
+
'(' + (strings * ' ') +
|
240
|
+
(tail == NULL ? '' : ' . ' + Heist.stringify(tail)) + ')'
|
241
|
+
end
|
226
242
|
end
|
227
243
|
alias :inspect :to_s
|
228
244
|
end
|
@@ -30,7 +30,8 @@ module Heist
|
|
30
30
|
|
31
31
|
# Returns +true+ if the receiver has the same name as the argument.
|
32
32
|
def ==(other)
|
33
|
-
|
33
|
+
return true if Binding === other and other == self
|
34
|
+
Identifier === other and @orginal_name.downcase == other.name.downcase
|
34
35
|
end
|
35
36
|
|
36
37
|
# Returns a raw Ruby representation of the identifier, for which
|
data/lib/runtime/runtime.rb
CHANGED
@@ -5,7 +5,14 @@ module Heist
|
|
5
5
|
# the standard set of primitive functions and special forms as defined
|
6
6
|
# in <tt>lib/builtin</tt>.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# User code runs in another scope descended from the top-level. This is
|
9
|
+
# done so that user-level redefinitions of built-in functions do not break
|
10
|
+
# other built-in functions that refer to the redefined names; lexical
|
11
|
+
# scoping ensures that built-in functions can only refer to other bindings
|
12
|
+
# in the top-level scope so user-level bindings do not affect the built-in
|
13
|
+
# library functions.
|
14
|
+
#
|
15
|
+
# +Runtime+ exposes several methods from the user-level +Scope+ object,
|
9
16
|
# allowing runtime objects to be used as interfaces for defining
|
10
17
|
# functions, eval'ing code and running source files.
|
11
18
|
#
|
@@ -22,9 +29,11 @@ module Heist
|
|
22
29
|
end
|
23
30
|
|
24
31
|
extend Forwardable
|
25
|
-
def_delegators(:@
|
32
|
+
def_delegators(:@user_scope, :[], :eval, :exec, :program, :define, :syntax, :run, :load)
|
33
|
+
|
34
|
+
attr_accessor :stack, :top_level, :user_scope
|
26
35
|
|
27
|
-
|
36
|
+
BUILTIN_LIBRARIES = %w[primitives syntax library]
|
28
37
|
|
29
38
|
# A +Runtime+ is initialized using a set of options. The available
|
30
39
|
# options include the following, all of which are +false+ unless
|
@@ -39,16 +48,27 @@ module Heist
|
|
39
48
|
@continuations = !!options[:continuations]
|
40
49
|
@hygienic = !options[:unhygienic]
|
41
50
|
|
42
|
-
@top_level
|
43
|
-
@
|
44
|
-
|
45
|
-
run("#{ BUILTIN_PATH }primitives.rb")
|
46
|
-
run("#{ BUILTIN_PATH }syntax.scm")
|
47
|
-
run("#{ BUILTIN_PATH }library.scm")
|
51
|
+
@top_level = Scope.new(self)
|
52
|
+
@user_scope = Scope.new(@top_level)
|
53
|
+
@stack = stackless? ? Stackless.new : Stack.new
|
48
54
|
|
55
|
+
load_builtins(options)
|
49
56
|
@start_time = Time.now.to_f
|
50
57
|
end
|
51
58
|
|
59
|
+
# To stop user-space redefinitions of built-in functions from breaking
|
60
|
+
# the standard library, we define builtins in a privileged scope, one up
|
61
|
+
# from the scope that user code runs in. We then bind the names in 'user
|
62
|
+
# space' to stop (set!) from reaching into our privileged top level.
|
63
|
+
def load_builtins(options = {})
|
64
|
+
libraries = (options[:only] || BUILTIN_LIBRARIES) - (options[:except] || [])
|
65
|
+
|
66
|
+
libraries.each do |library|
|
67
|
+
@top_level.run(@top_level.expand_path(library))
|
68
|
+
end
|
69
|
+
@user_scope.each_var(&@user_scope.method(:[]=))
|
70
|
+
end
|
71
|
+
|
52
72
|
# Returns the length of time the +Runtime+ has been alive for, as a
|
53
73
|
# number in microseconds.
|
54
74
|
def elapsed_time
|
data/lib/runtime/scope.rb
CHANGED
@@ -135,6 +135,15 @@ module Heist
|
|
135
135
|
def syntax(name, &block)
|
136
136
|
self[name] = Syntax.new(self, &block)
|
137
137
|
end
|
138
|
+
|
139
|
+
# Calls the given +block+ with the name of every variable visible in
|
140
|
+
# the +Scope+ (given as a +Symbol+) and its corresponding value.
|
141
|
+
def each_var(&block)
|
142
|
+
@parent.each_var(&block) if @parent.respond_to?(:each_var)
|
143
|
+
@symbols.each do |key, value|
|
144
|
+
block.call((key * '').to_sym, value)
|
145
|
+
end
|
146
|
+
end
|
138
147
|
|
139
148
|
# Parses and executes the given string of source code in the receiving
|
140
149
|
# +Scope+. Accepts strings of Scheme source and arrays of Ruby data to
|
@@ -145,6 +154,11 @@ module Heist
|
|
145
154
|
end
|
146
155
|
alias :exec :eval
|
147
156
|
|
157
|
+
# Executes an array of Scheme statements expressed as Ruby data.
|
158
|
+
def program(expressions)
|
159
|
+
expressions.map { |expr| exec(expr) }.last
|
160
|
+
end
|
161
|
+
|
148
162
|
# Returns the longest shared prefix match for the given variable name
|
149
163
|
# stub, used to support autocompletion in the REPL.
|
150
164
|
def longest_prefix(name)
|
@@ -157,7 +171,6 @@ module Heist
|
|
157
171
|
# sure we use 'obscure' names here.
|
158
172
|
def run(_path)
|
159
173
|
return instance_eval(File.read(_path)) if File.extname(_path) == '.rb'
|
160
|
-
_path = _path + FILE_EXT unless File.file?(_path)
|
161
174
|
_source = Heist.parse(File.read(_path))
|
162
175
|
_scope = FileScope.new(self, _path)
|
163
176
|
_source.eval(_scope)
|
@@ -168,13 +181,9 @@ module Heist
|
|
168
181
|
# is found, the path is assumed to refer to a module from the Heist
|
169
182
|
# standard library. The <tt>(load)</tt> primitive is a wrapper
|
170
183
|
# around this method.
|
171
|
-
def load(
|
172
|
-
|
173
|
-
|
174
|
-
end
|
175
|
-
return false unless dir
|
176
|
-
runtime.run("#{dir}/#{path}")
|
177
|
-
true
|
184
|
+
def load(file)
|
185
|
+
path = expand_path(file)
|
186
|
+
runtime.run(path) if path
|
178
187
|
end
|
179
188
|
|
180
189
|
# Returns the path of the current file. The receiving scope must have
|
@@ -183,6 +192,20 @@ module Heist
|
|
183
192
|
@path || @parent.current_file rescue nil
|
184
193
|
end
|
185
194
|
|
195
|
+
# Returns an absolute path to a requested library based on searching
|
196
|
+
# the current load path. The file extension may be omitted, suitable
|
197
|
+
# extensions being listed in Heist::FILE_EXTS.
|
198
|
+
def expand_path(path)
|
199
|
+
load_path.each do |dir|
|
200
|
+
test_path = File.expand_path(File.join(dir, path))
|
201
|
+
FILE_EXTS.each do |ext|
|
202
|
+
full_path = test_path + ext
|
203
|
+
return full_path if File.file?(full_path)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
186
209
|
private
|
187
210
|
|
188
211
|
# Calls the named primitive function with the given arguments, and
|
@@ -206,7 +229,7 @@ module Heist
|
|
206
229
|
# the directory of the current file if the receiving +Scope+ has a
|
207
230
|
# +FileScope+ as an ancestor.
|
208
231
|
def load_path
|
209
|
-
paths, file = [], current_file
|
232
|
+
paths, file = [""], current_file
|
210
233
|
paths << File.dirname(file) if file
|
211
234
|
paths + LOAD_PATH
|
212
235
|
end
|
data/lib/trie.rb
CHANGED
@@ -38,6 +38,20 @@ module Heist
|
|
38
38
|
@children = {}
|
39
39
|
end
|
40
40
|
|
41
|
+
# Iterates over each child key of the +Trie+, calling the given +block+
|
42
|
+
# with each key and corresponding value. Like iterating over a flat +Hash+.
|
43
|
+
def each_child
|
44
|
+
@children.each { |key, subtree| yield(key, subtree) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Iterates over the whole +Trie+, calling the given +block+ with each
|
48
|
+
# composite key and corresponding value. Each key will be an +Array+ matching
|
49
|
+
# the route to get from the root of the +Trie+ to the current node.
|
50
|
+
def each(prefix = [], &block)
|
51
|
+
each_child { |path, subtree| subtree.each(prefix + [path], &block) }
|
52
|
+
yield(prefix, @value) unless @value.nil?
|
53
|
+
end
|
54
|
+
|
41
55
|
# Returns +true+ iff the given +key+ is present in the +Trie+. They key
|
42
56
|
# must match a complete key sequence that maps to a value, not a partial
|
43
57
|
# prefix with no value attached.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
(load "macro-helpers")
|
1
|
+
(load "../helpers/macro-helpers")
|
2
2
|
|
3
3
|
; Basic test: no subpatterns or ellipses
|
4
4
|
|
@@ -43,6 +43,13 @@
|
|
43
43
|
|
44
44
|
(assert-equal 8 (dont-rename-else #f 6 8))
|
45
45
|
|
46
|
+
; Check that empty lists are stored as matches and appear in output
|
47
|
+
(let-syntax ([quote-match (syntax-rules (quote)
|
48
|
+
[(_ 'arg ...) '(arg ...)])])
|
49
|
+
(assert-equal '(4 5 6) (quote-match '4 '5 '6))
|
50
|
+
(assert-equal '(4 5 ()) (quote-match '4 '5 '()))
|
51
|
+
(assert-equal '(4 () 6) (quote-match '4 '() '6)))
|
52
|
+
|
46
53
|
; Check that keywords are ignored if locally bound
|
47
54
|
; example from R6RS -- http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.19
|
48
55
|
(assert-equal 'ok (let ((=> #f))
|
@@ -83,6 +90,15 @@
|
|
83
90
|
(assert-equal 3 (iffy 7 #f 3))
|
84
91
|
|
85
92
|
|
93
|
+
; Test that bound and non-bound symbols can be matched correctly
|
94
|
+
|
95
|
+
(letrec-syntax ((foo (syntax-rules (=)
|
96
|
+
((foo = x) x)))
|
97
|
+
(bar (syntax-rules ()
|
98
|
+
((bar x) (foo = x)))))
|
99
|
+
(assert-equal 5 (bar 5)))
|
100
|
+
|
101
|
+
|
86
102
|
; Test improper patterns
|
87
103
|
(define-syntax rest (syntax-rules ()
|
88
104
|
[(_ foo bar . rest)
|
@@ -314,6 +330,31 @@
|
|
314
330
|
(assert-equal '() (double-up))
|
315
331
|
|
316
332
|
|
333
|
+
; Test that pattern variables may appear at a greater
|
334
|
+
; repetition depth in the template than they do in the pattern
|
335
|
+
|
336
|
+
(let-syntax ((repeater (syntax-rules ()
|
337
|
+
[(_ one (many ...))
|
338
|
+
'((one many) ...)]))
|
339
|
+
|
340
|
+
(root-v-2 (syntax-rules ()
|
341
|
+
[(_ one (many ...) ...)
|
342
|
+
'(((one many) ...) ...)]))
|
343
|
+
|
344
|
+
(1-v-2 (syntax-rules ()
|
345
|
+
[(_ (one ...) (many ...) ...)
|
346
|
+
'(((one many) ...) ...)])))
|
347
|
+
|
348
|
+
(assert-equal '((a 2) (a 3) (a 4))
|
349
|
+
(repeater a (2 3 4)))
|
350
|
+
|
351
|
+
(assert-equal '(((a 1) (a 2)) ((a 6)) () ((a 3) (a 6) (a 8)))
|
352
|
+
(root-v-2 a (1 2) (6) () (3 6 8)))
|
353
|
+
|
354
|
+
(assert-equal '(((a 1) (a 2)) ((b 6)) () ((d 3) (d 6) (d 8)))
|
355
|
+
(1-v-2 (a b c d) (1 2) (6) () (3 6 8))))
|
356
|
+
|
357
|
+
|
317
358
|
; R5RS version of (let), uses ellipsis after lists in patterns
|
318
359
|
|
319
360
|
(define-syntax r5rs-let
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
; Check that user-level redefinitions of core functions does
|
2
|
+
; not break other core functions implemented in Scheme
|
3
|
+
|
4
|
+
(define (check-map-integrity)
|
5
|
+
(assert-equal '(1 4 9 16)
|
6
|
+
(map (lambda (x) (* x x))
|
7
|
+
'(1 2 3 4))))
|
8
|
+
(define cons #f)
|
9
|
+
(check-map-integrity)
|
10
|
+
|
11
|
+
(set! null? #f)
|
12
|
+
(check-map-integrity)
|
13
|
+
|
File without changes
|
File without changes
|
data/test/test_heist.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
$VERBOSE = nil
|
2
|
-
$dir = File.dirname(__FILE__)
|
2
|
+
$dir = File.expand_path(File.dirname(__FILE__))
|
3
3
|
|
4
4
|
$args = ARGV.map { |opt| "-#{opt}" }
|
5
5
|
|
@@ -8,20 +8,22 @@ require $dir + "/../lib/bin_spec"
|
|
8
8
|
require "test/unit"
|
9
9
|
|
10
10
|
Class.new(Test::Unit::TestCase) do
|
11
|
-
|
11
|
+
@env = nil
|
12
12
|
|
13
13
|
def setup
|
14
|
-
return
|
15
|
-
|
16
|
-
puts @@env.info
|
14
|
+
return @env if @env
|
15
|
+
@env = Heist::Runtime.new(Heist::BIN_SPEC.parse($args))
|
17
16
|
|
18
|
-
|
17
|
+
puts @env.info unless defined?(@@info_printed)
|
18
|
+
@@info_printed = true
|
19
|
+
|
20
|
+
@env.define('assert') do |value|
|
19
21
|
assert(value)
|
20
22
|
end
|
21
|
-
|
23
|
+
@env.define('assert-equal') do |expected, actual|
|
22
24
|
assert_equal(expected, actual)
|
23
25
|
end
|
24
|
-
|
26
|
+
@env.syntax('assert-raise') do |scope, cells|
|
25
27
|
exception = Heist.const_get(cells.car.to_s)
|
26
28
|
assert_raise(exception) { scope.eval(cells.cdr.car) }
|
27
29
|
end
|
@@ -43,10 +45,11 @@ Class.new(Test::Unit::TestCase) do
|
|
43
45
|
file_loading
|
44
46
|
macros
|
45
47
|
delay
|
48
|
+
protection
|
46
49
|
|
47
50
|
].each do |test|
|
48
51
|
define_method('test_' + test) do
|
49
|
-
|
52
|
+
@env.run($dir + '/scheme_tests/' + test + '.scm')
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
@@ -84,58 +87,62 @@ Class.new(Test::Unit::TestCase) do
|
|
84
87
|
end
|
85
88
|
|
86
89
|
def test_macro_hygiene
|
87
|
-
|
90
|
+
@env.run($dir + '/scheme_tests/' + (@env.hygienic? ? 'hygienic' : 'unhygienic') + '.scm')
|
88
91
|
end
|
89
92
|
|
90
93
|
def test_continuations
|
91
|
-
return if
|
92
|
-
|
94
|
+
return if @env.stackless?
|
95
|
+
@env.run($dir + '/scheme_tests/continuations.scm')
|
93
96
|
end
|
94
97
|
|
95
|
-
def
|
98
|
+
def test_quotation
|
96
99
|
cons = Heist::Runtime::Cons
|
97
100
|
c = cons.method(:new)
|
98
101
|
|
99
|
-
assert_equal 7,
|
100
|
-
assert_equal [:+, 3, 4],
|
101
|
-
assert cons ===
|
102
|
-
assert_equal 7,
|
103
|
-
assert_equal c[1,8],
|
104
|
-
assert_equal c[1,8],
|
105
|
-
assert_equal [:+, [:-, 7, 9], 4],
|
106
|
-
assert_equal [7, 9, 6],
|
107
|
-
assert cons ===
|
108
|
-
assert_equal [3, 7, 6, 2, 6, 9],
|
109
|
-
assert_equal [1, 2, 10],
|
110
|
-
assert_equal [3, 2, 9, 8],
|
111
|
-
assert_equal [1, 2, 4, 9, 8, 5],
|
112
|
-
assert_equal c[9,c[8,c[5,7]]],
|
113
|
-
assert_equal c[9,c[8,24]],
|
114
|
-
assert_equal [:quote, []],
|
102
|
+
assert_equal 7, @env.eval("(+ 3 4)")
|
103
|
+
assert_equal [:+, 3, 4], @env.eval("'(+ 3 4)").to_ruby
|
104
|
+
assert cons === @env.eval("'(+ 3 4)")
|
105
|
+
assert_equal 7, @env.eval("(+ '3 4)")
|
106
|
+
assert_equal c[1,8], @env.eval("'(1 . 8)")
|
107
|
+
assert_equal c[1,8], @env.eval("`(1 . 8)")
|
108
|
+
assert_equal [:+, [:-, 7, 9], 4], @env.eval("'(+ (- 7 9) 4)").to_ruby
|
109
|
+
assert_equal [7, 9, 6], @env.eval("`(7 ,(+ 4 5) 6)").to_ruby
|
110
|
+
assert cons === @env.eval("`(7 ,(+ 4 5) 6)")
|
111
|
+
assert_equal [3, 7, 6, 2, 6, 9], @env.eval("`(3 7 6 ,@((lambda () '(2 6))) 9)").to_ruby
|
112
|
+
assert_equal [1, 2, 10], @env.eval("`(1 2 ,(+ 4 6))").to_ruby
|
113
|
+
assert_equal [3, 2, 9, 8], @env.eval("`(,(/ 9 3) 2 ,@(list 9 8))").to_ruby
|
114
|
+
assert_equal [1, 2, 4, 9, 8, 5], @env.eval("`(,@(list 1 2) 4 ,@(list 9 8) 5)").to_ruby
|
115
|
+
assert_equal c[9,c[8,c[5,7]]], @env.eval("`(,@(list 9 8) 5 . 7)")
|
116
|
+
assert_equal c[9,c[8,24]], @env.eval("`(,@(list 9 8) . ,(* 4 6))")
|
117
|
+
assert_equal [:quote, []], @env.eval("''()").to_ruby
|
115
118
|
end
|
116
119
|
|
117
|
-
def
|
118
|
-
return unless
|
119
|
-
|
120
|
+
def test_birdhouse
|
121
|
+
return unless @env.lazy?
|
122
|
+
@env.eval('(load "birdhouse")')
|
120
123
|
|
121
|
-
|
124
|
+
@env.eval <<-CODE
|
122
125
|
(define factorial (Y
|
123
126
|
(lambda (rec)
|
124
127
|
(lambda (x)
|
125
128
|
(if (= x 0) 1 (* x (rec (- x 1))))))))
|
126
129
|
CODE
|
127
130
|
assert_equal (1..6).inject { |a,b| a*b },
|
128
|
-
|
131
|
+
@env.eval("(factorial 6)")
|
129
132
|
|
130
|
-
assert_equal 45,
|
133
|
+
assert_equal 45, @env.eval("((K 45) 6)")
|
131
134
|
end
|
132
135
|
|
133
136
|
def test_ruby_execution
|
134
137
|
expr = [[:lambda, [:x], [:+, 1, :x]], 3]
|
135
|
-
assert_equal 4,
|
138
|
+
assert_equal 4, @env.exec(expr)
|
136
139
|
list = Heist.parse(expr)
|
137
140
|
assert Heist::Runtime::Cons === list
|
138
141
|
assert_equal expr, list.to_ruby
|
142
|
+
|
143
|
+
cons = Heist::Runtime::Cons.method(:new)
|
144
|
+
assert_equal cons[3,cons[4,5]], Heist.parse([3, 4, :'.', 5])
|
145
|
+
assert_equal [3, 4, :'.', 5], cons[3,cons[4,5]].to_ruby
|
139
146
|
end
|
140
147
|
end
|
141
148
|
|
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.3.
|
4
|
+
version: 0.3.2
|
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:
|
12
|
+
date: 2010-01-16 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +32,26 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rubyforge
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.0.3
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: gemcutter
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.3.0
|
54
|
+
version:
|
35
55
|
- !ruby/object:Gem::Dependency
|
36
56
|
name: hoe
|
37
57
|
type: :development
|
@@ -40,7 +60,7 @@ dependencies:
|
|
40
60
|
requirements:
|
41
61
|
- - ">="
|
42
62
|
- !ruby/object:Gem::Version
|
43
|
-
version: 2.
|
63
|
+
version: 2.5.0
|
44
64
|
version:
|
45
65
|
description: ""
|
46
66
|
email:
|
@@ -64,6 +84,7 @@ files:
|
|
64
84
|
- lib/repl.rb
|
65
85
|
- lib/trie.rb
|
66
86
|
- lib/builtin/library.scm
|
87
|
+
- lib/builtin/library.rb
|
67
88
|
- lib/builtin/primitives.rb
|
68
89
|
- lib/builtin/syntax.scm
|
69
90
|
- lib/parser/nodes.rb
|
@@ -90,33 +111,36 @@ files:
|
|
90
111
|
- lib/runtime/stackless.rb
|
91
112
|
- lib/stdlib/benchmark.scm
|
92
113
|
- lib/stdlib/birdhouse.scm
|
93
|
-
- test/
|
94
|
-
- test/
|
95
|
-
- test/
|
96
|
-
- test/
|
97
|
-
- test/
|
98
|
-
- test/
|
99
|
-
- test/
|
100
|
-
- test/
|
101
|
-
- test/
|
102
|
-
- test/
|
103
|
-
- test/
|
104
|
-
- test/
|
105
|
-
- test/
|
106
|
-
- test/
|
107
|
-
- test/
|
108
|
-
- test/
|
109
|
-
- test/
|
110
|
-
- test/
|
111
|
-
- test/
|
114
|
+
- test/helpers/lib.scm
|
115
|
+
- test/helpers/macro-helpers.scm
|
116
|
+
- test/helpers/vars.scm
|
117
|
+
- test/scheme_tests/arithmetic.scm
|
118
|
+
- test/scheme_tests/benchmarks.scm
|
119
|
+
- test/scheme_tests/booleans.scm
|
120
|
+
- test/scheme_tests/closures.scm
|
121
|
+
- test/scheme_tests/conditionals.scm
|
122
|
+
- test/scheme_tests/continuations.scm
|
123
|
+
- test/scheme_tests/define_functions.scm
|
124
|
+
- test/scheme_tests/define_values.scm
|
125
|
+
- test/scheme_tests/delay.scm
|
126
|
+
- test/scheme_tests/equivalence.scm
|
127
|
+
- test/scheme_tests/file_loading.scm
|
128
|
+
- test/scheme_tests/functional.scm
|
129
|
+
- test/scheme_tests/hygienic.scm
|
130
|
+
- test/scheme_tests/let.scm
|
131
|
+
- test/scheme_tests/lists.scm
|
132
|
+
- test/scheme_tests/macros.scm
|
133
|
+
- test/scheme_tests/numbers.scm
|
134
|
+
- test/scheme_tests/protection.scm
|
135
|
+
- test/scheme_tests/strings.scm
|
136
|
+
- test/scheme_tests/unhygienic.scm
|
137
|
+
- test/scheme_tests/vectors.scm
|
112
138
|
- test/plt-macros.txt
|
113
|
-
- test/strings.scm
|
114
139
|
- test/test_heist.rb
|
115
|
-
- test/unhygienic.scm
|
116
|
-
- test/vars.scm
|
117
|
-
- test/vectors.scm
|
118
140
|
has_rdoc: true
|
119
141
|
homepage: http://github.com/jcoglan/heist
|
142
|
+
licenses: []
|
143
|
+
|
120
144
|
post_install_message:
|
121
145
|
rdoc_options:
|
122
146
|
- --main
|
@@ -138,9 +162,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
162
|
requirements: []
|
139
163
|
|
140
164
|
rubyforge_project: heist
|
141
|
-
rubygems_version: 1.3.
|
165
|
+
rubygems_version: 1.3.5
|
142
166
|
signing_key:
|
143
|
-
specification_version:
|
167
|
+
specification_version: 3
|
144
168
|
summary: ""
|
145
169
|
test_files:
|
146
170
|
- test/test_heist.rb
|