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