heist 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|