shen-ruby 0.3.1 → 0.4.0
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/.gitignore +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -2
- data/HISTORY.md +12 -0
- data/README.md +10 -7
- data/Rakefile +92 -0
- data/bin/srrepl +2 -2
- data/k_lambda_spec/primitives/arithmetic_spec.rb +175 -0
- data/k_lambda_spec/primitives/assignments_spec.rb +44 -0
- data/k_lambda_spec/primitives/generic_functions_spec.rb +115 -2
- data/k_lambda_spec/primitives/lists_spec.rb +40 -0
- data/k_lambda_spec/primitives/strings_spec.rb +77 -0
- data/k_lambda_spec/primitives/symbols_spec.rb +24 -0
- data/k_lambda_spec/primitives/vectors_spec.rb +92 -0
- data/k_lambda_spec/support/shared_examples.rb +93 -2
- data/k_lambda_spec/tail_recursion_spec.rb +30 -0
- data/lib/kl/compiler.rb +19 -33
- data/lib/kl/environment.rb +1 -0
- data/lib/kl/primitives/assignments.rb +1 -0
- data/lib/kl/primitives/generic_functions.rb +7 -0
- data/lib/kl/primitives/lists.rb +2 -0
- data/lib/kl/primitives/strings.rb +13 -5
- data/lib/kl/primitives/symbols.rb +1 -0
- data/lib/kl/primitives/vectors.rb +5 -0
- data/lib/shen_ruby/version.rb +1 -1
- data/shen-ruby.gemspec +1 -1
- data/shen/lib/shen_ruby/shen.rb +5 -6
- data/shen/release/benchmarks/benchmarks.shen +0 -4
- data/shen/release/benchmarks/interpreter.shen +2 -2
- data/shen/release/benchmarks/plato.jpg +0 -0
- data/shen/release/k_lambda/core.kl +171 -1000
- data/shen/release/k_lambda/declarations.kl +90 -992
- data/shen/release/k_lambda/load.kl +69 -81
- data/shen/release/k_lambda/macros.kl +113 -478
- data/shen/release/k_lambda/prolog.kl +250 -1307
- data/shen/release/k_lambda/reader.kl +115 -996
- data/shen/release/k_lambda/sequent.kl +154 -554
- data/shen/release/k_lambda/sys.kl +246 -562
- data/shen/release/k_lambda/t-star.kl +114 -3643
- data/shen/release/k_lambda/toplevel.kl +136 -221
- data/shen/release/k_lambda/track.kl +101 -206
- data/shen/release/k_lambda/types.kl +143 -298
- data/shen/release/k_lambda/writer.kl +93 -106
- data/shen/release/k_lambda/yacc.kl +77 -252
- data/shen/release/test_programs/README.shen +1 -1
- data/shen/release/test_programs/classes-typed.shen +1 -1
- data/shen/release/test_programs/interpreter.shen +2 -2
- data/shen/release/test_programs/metaprog.shen +2 -2
- data/shen/release/test_programs/prolog.shen +79 -0
- data/shen/release/test_programs/structures-typed.shen +2 -2
- data/shen/release/test_programs/tests.shen +19 -80
- data/shen/release/test_programs/yacc.shen +11 -15
- metadata +14 -6
- data/Gemfile.lock +0 -20
- data/shen/release/benchmarks/br.shen +0 -13
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Primitives for lists' do
|
4
|
+
describe '(cons Hd Tl)' do
|
5
|
+
it 'creates a list with Hd as the head and Tl as the tail' do
|
6
|
+
kl_eval('(cons a ())').should be_kind_of Kl::Cons
|
7
|
+
kl_eval('(hd (cons a ()))').should == :a
|
8
|
+
kl_eval('(tl (cons a (cons b ())))').should == kl_eval('(cons b ())')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'allows Tl to be a non-list' do
|
12
|
+
kl_eval('(tl (cons a b))').should == :b
|
13
|
+
end
|
14
|
+
|
15
|
+
include_examples 'partially-applicable function', %w(cons a b)
|
16
|
+
include_examples 'applicative order evaluation', %w(cons a b)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '(hd L)' do
|
20
|
+
it 'returns the head of L' do
|
21
|
+
kl_eval('(hd (cons a b))').should == :a
|
22
|
+
end
|
23
|
+
|
24
|
+
include_examples 'argument types', [:hd, "(cons a b)"], 1 => [:list, :dotted_pair]
|
25
|
+
include_examples 'partially-applicable function', [:hd, "(cons a b)"]
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '(tl L)' do
|
29
|
+
it 'returns the tail of L' do
|
30
|
+
kl_eval('(tl (cons a b))').should == :b
|
31
|
+
end
|
32
|
+
|
33
|
+
include_examples 'argument types', [:tl, "(cons a b)"], 1 => [:list, :dotted_pair]
|
34
|
+
include_examples 'partially-applicable function', [:tl, "(cons a b)"]
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'cons?' do
|
38
|
+
include_examples 'type predicate', 'cons?', [:list, :dotted_pair]
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Primitives for strings' do
|
4
|
+
describe '(pos S N)' do
|
5
|
+
it 'returns the character at zero-based index N of S as a unit string' do
|
6
|
+
kl_eval('(pos "ABC" 1)').should == "B"
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'raises an error if N is negative' do
|
10
|
+
expect {
|
11
|
+
kl_eval('(pos "ABC" -1)')
|
12
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises an error if N is >= the length of S' do
|
16
|
+
expect {
|
17
|
+
kl_eval('(pos "ABC" 3)')
|
18
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
19
|
+
expect {
|
20
|
+
kl_eval('(pos "ABC" 99)')
|
21
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
22
|
+
end
|
23
|
+
|
24
|
+
include_examples 'argument types', %w(pos "string" 1),
|
25
|
+
1 => [:string],
|
26
|
+
2 => [:integer]
|
27
|
+
include_examples 'partially-applicable function', %w(pos "string" 1)
|
28
|
+
include_examples 'applicative order evaluation', %w(pos "string" 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '(tlstr S)' do
|
32
|
+
it 'returns a string containing all but the first character of S' do
|
33
|
+
kl_eval('(tlstr "string")').should == "tring"
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'raises an error when S is the empty string' do
|
37
|
+
expect {
|
38
|
+
kl_eval('(tlstr "")')
|
39
|
+
}.to raise_error(Kl::Error, 'attempted to take tail of an empty string')
|
40
|
+
end
|
41
|
+
|
42
|
+
include_examples 'argument types', %w(tlstr "string"), 1 => [:string]
|
43
|
+
include_examples 'partially-applicable function', %w(tlstr "string")
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'string?' do
|
47
|
+
include_examples 'type predicate', 'string?', [:string]
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '(n->string N)' do
|
51
|
+
it 'returns a unit string containing the character with ASCII code N' do
|
52
|
+
kl_eval('(n->string 65)').should == "A"
|
53
|
+
end
|
54
|
+
|
55
|
+
include_examples 'argument types', %w(n->string 65), 1 => [:integer]
|
56
|
+
include_examples 'partially-applicable function', %w(n->string 65)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '(string->n S)' do
|
60
|
+
it 'returns the ASCII code of the unit string S' do
|
61
|
+
kl_eval('(string->n "A")').should == 65
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns the ASCII code of the first character of non-unit string S' do
|
65
|
+
kl_eval('(string->n "AB")').should == 65
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an error when S is the empty string' do
|
69
|
+
expect {
|
70
|
+
kl_eval('(string->n "")')
|
71
|
+
}.to raise_error(Kl::Error, 'attempted to get code point of empty string')
|
72
|
+
end
|
73
|
+
|
74
|
+
include_examples 'argument types', %w(string->n "A"), 1 => [:string]
|
75
|
+
include_examples 'partially-applicable function', %w(string->n "A")
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Primitives for symbols' do
|
4
|
+
describe 'intern' do
|
5
|
+
it 'converts a string to its corresponding symbol' do
|
6
|
+
kl_eval('(intern "foo")').should == :foo
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'supports characters not allowed in symbol literals' do
|
10
|
+
kl_eval('(intern "[{|}]")').should == :"[{|}]"
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'converts the string "true" to boolean true' do
|
14
|
+
kl_eval('(intern "true")').should == true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts the string "false" to boolean false' do
|
18
|
+
kl_eval('(intern "false")').should == false
|
19
|
+
end
|
20
|
+
|
21
|
+
include_examples 'argument types', %w(intern "foo"), 1 => [:string]
|
22
|
+
include_examples 'partially-applicable function', %w(intern "foo")
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Primitive functions for vectors' do
|
4
|
+
describe '(absvector N)' do
|
5
|
+
it 'returns a new absolute vector of size N' do
|
6
|
+
kl_eval('(absvector 3)').should be_kind_of Kl::Absvector
|
7
|
+
end
|
8
|
+
|
9
|
+
include_examples 'argument types', %w(absvector 7), 1 => [:integer]
|
10
|
+
include_examples 'partially-applicable function', %w(absvector 7)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '(address-> V N Value)' do
|
14
|
+
before(:each) do
|
15
|
+
kl_eval('(set *vec* (absvector 5))')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the vector V updated with Value at index N' do
|
19
|
+
kl_eval('(address-> (value *vec*) 3 37)').should be_kind_of Kl::Absvector
|
20
|
+
kl_eval('(<-address (value *vec*) 3)').should == 37
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises an error if N is negative' do
|
24
|
+
expect {
|
25
|
+
kl_eval('(address-> (value *vec*) -1 37)')
|
26
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises an error if N is >= the size of the vector' do
|
30
|
+
expect {
|
31
|
+
kl_eval('(address-> (value *vec*) 5 37)')
|
32
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
33
|
+
expect {
|
34
|
+
kl_eval('(address-> (value *vec*) 99 37)')
|
35
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
36
|
+
end
|
37
|
+
|
38
|
+
include_examples 'argument types',
|
39
|
+
['address->', '(value *vec*)', '0', '37'],
|
40
|
+
1 => [:vector],
|
41
|
+
2 => [:integer]
|
42
|
+
include_examples 'partially-applicable function',
|
43
|
+
['address->', '(value *vec*)', '0', '37']
|
44
|
+
include_examples 'applicative order evaluation',
|
45
|
+
['address->', '(value *vec*)', '0', '37']
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '(<-address V N)' do
|
49
|
+
before(:each) do
|
50
|
+
kl_eval('(set *vec* (absvector 5))')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'returns the value previously stored at index N in V' do
|
54
|
+
kl_eval('(address-> (value *vec*) 3 37)')
|
55
|
+
kl_eval('(<-address (value *vec*) 3)').should == 37
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns an unspecified value if index N has not been stored to' do
|
59
|
+
expect {
|
60
|
+
kl_eval('(<-address (value *vec*) 3)')
|
61
|
+
}.to_not raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'raises an error if N is negative' do
|
65
|
+
expect {
|
66
|
+
kl_eval('(<-address (value *vec*) -1)')
|
67
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'raises an error if N is >= the size of the vector' do
|
71
|
+
expect {
|
72
|
+
kl_eval('(<-address (value *vec*) 5)')
|
73
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
74
|
+
expect {
|
75
|
+
kl_eval('(<-address (value *vec*) 99)')
|
76
|
+
}.to raise_error(Kl::Error, "out of bounds")
|
77
|
+
end
|
78
|
+
|
79
|
+
include_examples 'argument types',
|
80
|
+
['<-address', '(value *vec*)', '0'],
|
81
|
+
1 => [:vector],
|
82
|
+
2 => [:integer]
|
83
|
+
include_examples 'partially-applicable function',
|
84
|
+
['address->', '(value *vec*)', '0', '37']
|
85
|
+
include_examples 'applicative order evaluation',
|
86
|
+
['address->', '(value *vec*)', '0', '37']
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'absvector?' do
|
90
|
+
include_examples 'type predicate', 'absvector?', [:vector]
|
91
|
+
end
|
92
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# args should be an array containing the components of an example expression.
|
2
2
|
# E.g., to test partial application of +, you could use:
|
3
3
|
#
|
4
|
-
# include_examples "
|
4
|
+
# include_examples "partially-applicable function", %w(+ 1 2)
|
5
5
|
#
|
6
6
|
# The expression will be evaluated in its fully-expanded form for reference
|
7
7
|
# and then compared against various partial application scenarios.
|
@@ -20,7 +20,7 @@ end
|
|
20
20
|
|
21
21
|
shared_examples "non-partially-applicable function" do |args|
|
22
22
|
(0...(args.length - 1)).each do |arg_count|
|
23
|
-
description = "raises an error when
|
23
|
+
description = "raises an error when given #{arg_count} argument"
|
24
24
|
description << "s" unless arg_count == 1
|
25
25
|
it description do
|
26
26
|
partial_expression = "(#{args[0..arg_count].join(' ')})"
|
@@ -29,5 +29,96 @@ shared_examples "non-partially-applicable function" do |args|
|
|
29
29
|
}.to raise_error(Kl::Error, "#{args[0]} expects #{args.length - 1} arguments but was given #{arg_count}")
|
30
30
|
end
|
31
31
|
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# args should be an array containing the components of an example expression.
|
35
|
+
# E.g., to test applicative order evaluation of +, you could use:
|
36
|
+
#
|
37
|
+
# include_examples "applicative order evaluation", %w(+ 1 2)
|
38
|
+
shared_examples 'applicative order evaluation' do |args|
|
39
|
+
it 'evaluates its arguments from left to right' do
|
40
|
+
operator = args.shift
|
41
|
+
arg_indexes = (0...args.size).to_a
|
42
|
+
instrumented_args = args.zip(arg_indexes).map do |(arg, idx)|
|
43
|
+
"(kl-do (set *arg-order* (cn (value *arg-order*) \"#{idx}\")) #{arg})"
|
44
|
+
end
|
45
|
+
expected = arg_indexes.join
|
46
|
+
|
47
|
+
define_kl_do
|
48
|
+
kl_eval('(set *arg-order* "")')
|
49
|
+
kl_eval("(#{operator} #{instrumented_args.join(' ')})")
|
50
|
+
kl_eval('(value *arg-order*)').should == expected
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
KL_TYPE_EXAMPLES = {
|
55
|
+
integer: '1',
|
56
|
+
real: '1.0',
|
57
|
+
string: '"a string"',
|
58
|
+
symbol: 'a-symbol',
|
59
|
+
boolean: 'true',
|
60
|
+
list: '(cons 1 ())',
|
61
|
+
dotted_pair: '(cons 1 2)',
|
62
|
+
empty_list: '()',
|
63
|
+
function: '(lambda X X)',
|
64
|
+
vector: '(absvector 3)'
|
65
|
+
}
|
66
|
+
|
67
|
+
def type_with_article(type)
|
68
|
+
name = type.to_s.gsub(/_/, ' ')
|
69
|
+
if [:integer, :empty_list].include?(type)
|
70
|
+
'an ' + name
|
71
|
+
else
|
72
|
+
'a ' + name
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
shared_examples 'type predicate' do |predicate, accepted_types|
|
77
|
+
accepted_types.each do |type|
|
78
|
+
it "returns true when its argument is #{type_with_article(type)}" do
|
79
|
+
kl_eval("(#{predicate} #{KL_TYPE_EXAMPLES[type]})").should == true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns false when its argument is of any other type' do
|
84
|
+
rejected_types = KL_TYPE_EXAMPLES.keys - accepted_types
|
85
|
+
rejected_types.each do |type|
|
86
|
+
kl_eval("(#{predicate} #{KL_TYPE_EXAMPLES[type]})").should == false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
POSITION_NAMES = { 1 => 'first', 2 => 'second', 3 => 'third' }
|
32
92
|
|
93
|
+
def types_to_s(types)
|
94
|
+
if types.length > 2
|
95
|
+
types[0..-2].map { |t| type_with_article(t) }.join(', ') +
|
96
|
+
', or ' + type_with_article(types[-1])
|
97
|
+
else
|
98
|
+
types.map { |t| type_with_article(t) }.join(' or ')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
shared_examples 'argument types' do |expr, accepted_argument_types|
|
103
|
+
accepted_argument_types.to_a.sort.each do |(idx, accepted_types)|
|
104
|
+
type_str = types_to_s(accepted_types)
|
105
|
+
it "raises an error if its #{POSITION_NAMES[idx]} argument is not #{type_str}" do
|
106
|
+
accepted_types.each do |type|
|
107
|
+
other_expr = expr.dup
|
108
|
+
other_expr[idx] = KL_TYPE_EXAMPLES[type]
|
109
|
+
expect {
|
110
|
+
kl_eval("(#{other_expr.join(' ')})")
|
111
|
+
}.to_not raise_error
|
112
|
+
end
|
113
|
+
|
114
|
+
rejected_types = KL_TYPE_EXAMPLES.keys - accepted_types
|
115
|
+
rejected_types.each do |type|
|
116
|
+
other_expr = expr.dup
|
117
|
+
other_expr[idx] = KL_TYPE_EXAMPLES[type]
|
118
|
+
expect {
|
119
|
+
kl_eval("(#{other_expr.join(' ')})")
|
120
|
+
}.to raise_error(Kl::Error, /is not a/)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
33
124
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Tail recursion' do
|
4
|
+
it 'does not consume stack space for self tail calls' do
|
5
|
+
kl_eval <<-EOS
|
6
|
+
(defun count-down (X)
|
7
|
+
(if (= X 0)
|
8
|
+
success
|
9
|
+
(count-down (- X 1))))
|
10
|
+
EOS
|
11
|
+
kl_eval('(count-down 10000)').should == :success
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'does not consume stack space for mutually recursive tail calls' do
|
15
|
+
kl_eval <<-EOS
|
16
|
+
(defun even? (X)
|
17
|
+
(if (= X 1)
|
18
|
+
false
|
19
|
+
(odd? (- X 1))))
|
20
|
+
EOS
|
21
|
+
kl_eval <<-EOS
|
22
|
+
(defun odd? (X)
|
23
|
+
(if (= X 1)
|
24
|
+
true
|
25
|
+
(even? (- X 1))))
|
26
|
+
EOS
|
27
|
+
kl_eval('(even? 100000)').should == true
|
28
|
+
kl_eval('(odd? 100000)').should == false
|
29
|
+
end
|
30
|
+
end
|
data/lib/kl/compiler.rb
CHANGED
@@ -59,7 +59,7 @@ module Kl
|
|
59
59
|
when :let
|
60
60
|
compile_let(form, lexical_vars, in_tail_pos)
|
61
61
|
when :freeze
|
62
|
-
compile_freeze(form, lexical_vars)
|
62
|
+
compile_freeze(form, lexical_vars, in_tail_pos)
|
63
63
|
when :type
|
64
64
|
compile_type(form, lexical_vars, in_tail_pos)
|
65
65
|
when :if
|
@@ -78,10 +78,6 @@ module Kl
|
|
78
78
|
# when all of their arguments are available.
|
79
79
|
when :cons
|
80
80
|
compile_cons(form, lexical_vars, in_tail_pos)
|
81
|
-
when :hd
|
82
|
-
compile_hd(form, lexical_vars, in_tail_pos)
|
83
|
-
when :tl
|
84
|
-
compile_tl(form, lexical_vars, in_tail_pos)
|
85
81
|
when :"cons?"
|
86
82
|
compile_consp(form, lexical_vars, in_tail_pos)
|
87
83
|
else
|
@@ -93,10 +89,15 @@ module Kl
|
|
93
89
|
def compile_defun(form, lexical_vars)
|
94
90
|
name, arglist, body = destructure_form(form, 3)
|
95
91
|
unless name.kind_of? Symbol
|
96
|
-
raise Kl::Error,
|
92
|
+
raise Kl::Error, "#{name} is not a symbol"
|
97
93
|
end
|
98
|
-
unless
|
99
|
-
raise Kl::Error,
|
94
|
+
unless [Kl::Cons, Kl::EmptyList].include? arglist.class
|
95
|
+
raise Kl::Error, "#{arglist} is not a list"
|
96
|
+
end
|
97
|
+
arglist.each do |arg|
|
98
|
+
unless arg.kind_of? Symbol
|
99
|
+
raise Kl::Error, "#{arg} is not a symbol"
|
100
|
+
end
|
100
101
|
end
|
101
102
|
if PRIMITIVE_ARITIES.has_key?(name)
|
102
103
|
raise Kl::Error, "#{name} is primitive and may not be redefined"
|
@@ -115,7 +116,7 @@ module Kl
|
|
115
116
|
def compile_lambda(form, lexical_vars)
|
116
117
|
var, body = destructure_form(form, 2)
|
117
118
|
unless var.kind_of? Symbol
|
118
|
-
raise Kl::Error,
|
119
|
+
raise Kl::Error, "#{var} is not a symbol"
|
119
120
|
end
|
120
121
|
|
121
122
|
extended_vars = add_var(lexical_vars, var)
|
@@ -142,12 +143,17 @@ module Kl
|
|
142
143
|
end
|
143
144
|
|
144
145
|
# (freeze EXPR)
|
145
|
-
def compile_freeze(form, lexical_vars)
|
146
|
-
|
146
|
+
def compile_freeze(form, lexical_vars, in_tail_pos)
|
147
|
+
if form.count == 2
|
148
|
+
expr = destructure_form(form, 1).first
|
147
149
|
|
148
|
-
|
150
|
+
body = compile(expr, lexical_vars, true)
|
149
151
|
|
150
|
-
|
152
|
+
"::Kernel.lambda { #{body} }"
|
153
|
+
else
|
154
|
+
# Partial application falls back to normal application
|
155
|
+
compile_application(form, lexical_vars, in_tail_pos)
|
156
|
+
end
|
151
157
|
end
|
152
158
|
|
153
159
|
# (type EXPR T)
|
@@ -257,26 +263,6 @@ module Kl
|
|
257
263
|
end
|
258
264
|
end
|
259
265
|
|
260
|
-
# Inlined version of (hd L)
|
261
|
-
def compile_hd(form, lexical_vars, in_tail_pos)
|
262
|
-
if form.count == 2
|
263
|
-
expr = compile(form.tl.hd, lexical_vars, false)
|
264
|
-
"(#{expr}).hd"
|
265
|
-
else
|
266
|
-
compile_application(form, lexical_vars, in_tail_pos)
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
# Inlined version of (tl L)
|
271
|
-
def compile_tl(form, lexical_vars, in_tail_pos)
|
272
|
-
if form.count == 2
|
273
|
-
expr = compile(form.tl.hd, lexical_vars, false)
|
274
|
-
"(#{expr}).tl"
|
275
|
-
else
|
276
|
-
compile_application(form, lexical_vars, in_tail_pos)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
266
|
# Inlined version of (cons? X)
|
281
267
|
def compile_consp(form, lexical_vars, in_tail_pos)
|
282
268
|
if form.count == 2
|