klam 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +0 -0
- data/.travis.yml +8 -0
- data/Gemfile +1 -0
- data/LICENSE.txt +19 -0
- data/PROGRESS.asciidoc +105 -0
- data/README.asciidoc +11 -0
- data/Rakefile +5 -0
- data/klam.gemspec +28 -0
- data/lib/klam.rb +16 -0
- data/lib/klam/compilation_stages.rb +4 -0
- data/lib/klam/compilation_stages/convert_freezes_to_lambdas.rb +17 -0
- data/lib/klam/compilation_stages/convert_lexical_variables.rb +79 -0
- data/lib/klam/compilation_stages/convert_partial_applications_to_lambdas.rb +35 -0
- data/lib/klam/compilation_stages/convert_self_tail_calls_to_loops.rb +147 -0
- data/lib/klam/compilation_stages/curry_abstraction_applications.rb +33 -0
- data/lib/klam/compilation_stages/emit_ruby.rb +232 -0
- data/lib/klam/compilation_stages/kl_to_internal_representation.rb +21 -0
- data/lib/klam/compilation_stages/make_abstractions_monadic.rb +26 -0
- data/lib/klam/compilation_stages/make_abstractions_variadic.rb +23 -0
- data/lib/klam/compilation_stages/simplify_boolean_operations.rb +74 -0
- data/lib/klam/compilation_stages/strip_type_declarations.rb +24 -0
- data/lib/klam/compiler.rb +63 -0
- data/lib/klam/cons.rb +18 -0
- data/lib/klam/converters.rb +4 -0
- data/lib/klam/converters/.list.rb.swp +0 -0
- data/lib/klam/converters/list.rb +29 -0
- data/lib/klam/environment.rb +61 -0
- data/lib/klam/error.rb +4 -0
- data/lib/klam/lexer.rb +185 -0
- data/lib/klam/primitives.rb +4 -0
- data/lib/klam/primitives/arithmetic.rb +49 -0
- data/lib/klam/primitives/assignments.rb +13 -0
- data/lib/klam/primitives/boolean_operations.rb +22 -0
- data/lib/klam/primitives/error_handling.rb +19 -0
- data/lib/klam/primitives/generic_functions.rb +19 -0
- data/lib/klam/primitives/lists.rb +23 -0
- data/lib/klam/primitives/streams.rb +32 -0
- data/lib/klam/primitives/strings.rb +58 -0
- data/lib/klam/primitives/symbols.rb +16 -0
- data/lib/klam/primitives/time.rb +19 -0
- data/lib/klam/primitives/vectors.rb +26 -0
- data/lib/klam/reader.rb +46 -0
- data/lib/klam/template.rb +38 -0
- data/lib/klam/variable.rb +21 -0
- data/lib/klam/variable_generator.rb +12 -0
- data/lib/klam/version.rb +3 -0
- data/spec/functional/application_spec.rb +94 -0
- data/spec/functional/atoms_spec.rb +56 -0
- data/spec/functional/extensions/do_spec.rb +22 -0
- data/spec/functional/primitives/assignments_spec.rb +38 -0
- data/spec/functional/primitives/boolean_operations_spec.rb +133 -0
- data/spec/functional/primitives/error_handling_spec.rb +22 -0
- data/spec/functional/primitives/generic_functions_spec.rb +82 -0
- data/spec/functional/tail_call_optimization_spec.rb +71 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/unit/klam/compilation_stages/convert_lexical_variables_spec.rb +58 -0
- data/spec/unit/klam/compilation_stages/convert_self_tail_calls_to_loops_spec.rb +33 -0
- data/spec/unit/klam/compilation_stages/curry_abstraction_applications_spec.rb +19 -0
- data/spec/unit/klam/compilation_stages/make_abstractions_variadic_spec.rb +12 -0
- data/spec/unit/klam/converters/list_spec.rb +57 -0
- data/spec/unit/klam/lexer_spec.rb +149 -0
- data/spec/unit/klam/primitives/arithmetic_spec.rb +153 -0
- data/spec/unit/klam/primitives/boolean_operations_spec.rb +39 -0
- data/spec/unit/klam/primitives/error_handling_spec.rb +19 -0
- data/spec/unit/klam/primitives/lists_spec.rb +49 -0
- data/spec/unit/klam/primitives/strings_spec.rb +53 -0
- data/spec/unit/klam/primitives/symbols_spec.rb +19 -0
- data/spec/unit/klam/primitives/time_spec.rb +16 -0
- data/spec/unit/klam/primitives/vectors_spec.rb +55 -0
- data/spec/unit/klam/reader_spec.rb +47 -0
- data/spec/unit/klam/template_spec.rb +28 -0
- data/spec/unit/klam/variable_spec.rb +22 -0
- data/spec/unit/klam/version_spec.rb +7 -0
- metadata +225 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::CompilationStages::ConvertSelfTailCallsToLoops do
|
4
|
+
include Klam::CompilationStages::ConvertSelfTailCallsToLoops
|
5
|
+
it 'converts self tail calls to loop/recur' do
|
6
|
+
# For simplicity the vars below are symbols, but will be
|
7
|
+
# Klam::Variables in practice. They do not come into play for
|
8
|
+
# the conversion, though.
|
9
|
+
expr = [:defun, :f, [:X, :Y],
|
10
|
+
[:if, true,
|
11
|
+
[:f, 7, 8],
|
12
|
+
[:let, :Z, 37,
|
13
|
+
[:f, :Z, 99]]]]
|
14
|
+
expected = [:defun, :f, [:X, :Y],
|
15
|
+
[:"[LOOP]", :f, [:X, :Y],
|
16
|
+
[:if, true,
|
17
|
+
[:"[RECUR]", [:X, :Y], [7, 8]],
|
18
|
+
[:let, :Z, 37,
|
19
|
+
[:"[RECUR]", [:X, :Y], [:Z, 99]]]]]]
|
20
|
+
|
21
|
+
expect(convert_self_tail_calls_to_loops(expr)).to eq(expected)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does not convert partial calls' do
|
25
|
+
expr = [:defun, :f, [:X, :Y],
|
26
|
+
[:f, :X]]
|
27
|
+
expected = [:defun, :f, [:X, :Y],
|
28
|
+
[:"[LOOP]", :f, [:X, :Y],
|
29
|
+
[:f, :X]]]
|
30
|
+
|
31
|
+
expect(convert_self_tail_calls_to_loops(expr)).to eq(expected)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::CompilationStages::CurryAbstractionApplications do
|
4
|
+
include Klam::CompilationStages::CurryAbstractionApplications
|
5
|
+
it 'converts to applying one argument at a time' do
|
6
|
+
expr = [[:foo], 1, 2, 3]
|
7
|
+
expected = [[[[:foo], 1], 2], 3]
|
8
|
+
|
9
|
+
expect(curry_abstraction_applications(expr)).to eq(expected)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'converts variable application to curried form' do
|
13
|
+
var = Klam::Variable.new('foo')
|
14
|
+
expr = [var, 1, 2, 3]
|
15
|
+
expected = [[[var, 1], 2], 3]
|
16
|
+
|
17
|
+
expect(curry_abstraction_applications(expr)).to eq(expected)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::CompilationStages::MakeAbstractionsVariadic do
|
4
|
+
include Klam::CompilationStages::MakeAbstractionsVariadic
|
5
|
+
|
6
|
+
it 'converts the single Kl lambda param to a one-element list' do
|
7
|
+
expr = [:lambda, :X, [:lambda, :Y, [:+, :X, :Y]]]
|
8
|
+
expected = [:lambda, [:X], [:lambda, [:Y], [:+, :X, :Y]]]
|
9
|
+
|
10
|
+
expect(make_abstractions_variadic(expr)).to eq(expected)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::Converters::List do
|
4
|
+
include Klam::Converters::List
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@empty_list = Klam::Primitives::Lists::EMPTY_LIST
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.arrayToList' do
|
11
|
+
it 'returns the empty list when given an empty array' do
|
12
|
+
expect(arrayToList([])).to be @empty_list
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'handles nested empty lists' do
|
16
|
+
expect(arrayToList([[]])).to eq(cons(@empty_list, @empty_list))
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns the corresponding list for a non-empty array' do
|
20
|
+
expect(arrayToList([1, 2])).to eq(cons(1, cons(2, @empty_list)))
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'recursively converts nested arrays to nested lists' do
|
24
|
+
array1 = [1, 2]
|
25
|
+
list1 = arrayToList(array1)
|
26
|
+
array2 = [:a, :b, :c]
|
27
|
+
list2 = arrayToList(array2)
|
28
|
+
|
29
|
+
expect(arrayToList([array1, array2]))
|
30
|
+
.to eq(cons(list1, cons(list2, @empty_list)))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.listToArray' do
|
35
|
+
it 'returns an empty array when given the empty list' do
|
36
|
+
expect(listToArray(@empty_list)).to eq([])
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'handles nested empty lists' do
|
40
|
+
expect(listToArray(cons(@empty_list, @empty_list))).to eq([[]])
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns the corresponding array for a non-emtpy list' do
|
44
|
+
expect(listToArray(cons(1, cons(2, @empty_list)))).to eq([1, 2])
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'recursively converts nested lists to nested arrays' do
|
48
|
+
list1 = cons(1, cons(2, @empty_list))
|
49
|
+
array1 = listToArray(list1)
|
50
|
+
list2 = cons(:a, cons(:b, cons(:c, @empty_list)))
|
51
|
+
array2 = listToArray(list2)
|
52
|
+
|
53
|
+
expect(listToArray(cons(list1, cons(list2, @empty_list))))
|
54
|
+
.to eq([array1, array2])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::Lexer do
|
4
|
+
def lexer(str)
|
5
|
+
Klam::Lexer.new(StringIO.new(str))
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'syntax tokens' do
|
9
|
+
it 'reads ( as a Klam::Lexer::OpenParen' do
|
10
|
+
expect(lexer("(").next).to be_kind_of(Klam::Lexer::OpenParen)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'reads ) as a Klam::Lexer::CloseParen' do
|
14
|
+
expect(lexer(")").next).to be_kind_of(Klam::Lexer::CloseParen)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'string tokens' do
|
19
|
+
it 'reads double-quoted strings' do
|
20
|
+
expect(lexer('"Fred"').next).to eq("Fred")
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'throws Klam::SyntaxError on unterminated strings' do
|
24
|
+
expect {
|
25
|
+
lexer('"Fred').next
|
26
|
+
}.to raise_error(Klam::SyntaxError, "unterminated string")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'symbols' do
|
31
|
+
it 'reads sign characters not followed by digits as symbols' do
|
32
|
+
expect(lexer('-').next).to eq('-'.to_sym)
|
33
|
+
expect(lexer('+').next).to eq('+'.to_sym)
|
34
|
+
expect(lexer('--+-').next).to eq('--+-'.to_sym)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'reads double decimal points followed by digits as symbols' do
|
38
|
+
expect(lexer('..77').next).to eq('..77'.to_sym)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "accepts =-*/+_?$!@~><&%'#`;:{} in symbols" do
|
42
|
+
all_punctuation = "=-*/+_?$!@~><&%'#`;:{}"
|
43
|
+
sym = lexer(all_punctuation).next
|
44
|
+
expect(sym).to be_kind_of(Symbol)
|
45
|
+
expect(sym.to_s).to eq(all_punctuation)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'numbers' do
|
50
|
+
it 'reads integers as Fixnums' do
|
51
|
+
num = lexer("37").next
|
52
|
+
expect(num).to be_kind_of(Fixnum)
|
53
|
+
expect(num).to eq(37)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'reads floating points as Floats' do
|
57
|
+
num = lexer("37.42").next
|
58
|
+
expect(num).to be_kind_of(Float)
|
59
|
+
expect(num).to eq(37.42)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'with an odd number of leading minuses are negative' do
|
63
|
+
expect(lexer('-1').next).to eq(-1)
|
64
|
+
expect(lexer('---1').next).to eq(-1)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'with an even number of leading minuses are positive' do
|
68
|
+
expect(lexer('--1').next).to eq(1)
|
69
|
+
expect(lexer('----1').next).to eq(1)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'with leading + does not change sign' do
|
73
|
+
expect(lexer('+-1').next).to eq(-1)
|
74
|
+
expect(lexer('-+--1').next).to eq(-1)
|
75
|
+
expect(lexer('-+-+1').next).to eq(1)
|
76
|
+
expect(lexer('+-+-+-+-+1').next).to eq(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'allows leading decimal points' do
|
80
|
+
expect(lexer('.9').next).to eq(0.9)
|
81
|
+
expect(lexer('-.9').next).to eq(-0.9)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'treats a trailing decimal followed by EOF as a symbol' do
|
85
|
+
l = lexer('7.')
|
86
|
+
num = l.next
|
87
|
+
expect(num).to be_kind_of(Fixnum)
|
88
|
+
expect(num).to eq(7)
|
89
|
+
|
90
|
+
sym = l.next
|
91
|
+
expect(sym).to be_kind_of(Symbol)
|
92
|
+
expect(sym.to_s).to eq('.')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'treats a trailing decimal followed by non-digit as a symbol' do
|
96
|
+
l = lexer('7.a')
|
97
|
+
num = l.next
|
98
|
+
expect(num).to be_kind_of(Fixnum)
|
99
|
+
expect(num).to eq(7)
|
100
|
+
|
101
|
+
sym = l.next
|
102
|
+
expect(sym).to be_kind_of(Symbol)
|
103
|
+
expect(sym.to_s).to eq('.a')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'handles multiple decimal points like shen does' do
|
107
|
+
l = lexer('7.8.9')
|
108
|
+
expect(l.next).to eq(7.8)
|
109
|
+
expect(l.next).to eq(0.9)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'booleans' do
|
114
|
+
it 'reads true as boolean true' do
|
115
|
+
expect(lexer('true').next).to be_kind_of(TrueClass)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'reads false as boolean false' do
|
119
|
+
expect(lexer('false').next).to be_kind_of(FalseClass)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'whitespace' do
|
124
|
+
it 'is ignored between tokens' do
|
125
|
+
l = lexer(" (\n\t) ")
|
126
|
+
expect(l.next).to be_kind_of(Klam::Lexer::OpenParen)
|
127
|
+
expect(l.next).to be_kind_of(Klam::Lexer::CloseParen)
|
128
|
+
expect(l.next).to be_nil
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'is left intact in strings' do
|
132
|
+
expect(lexer(' "one two" ').next).to eq("one two")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'works with these all together' do
|
137
|
+
l = lexer('(12 quick m-*$ RAN `fast\' -.7) "oh 12 yeah!" ')
|
138
|
+
expect(l.next).to be_kind_of(Klam::Lexer::OpenParen)
|
139
|
+
expect(l.next).to eq(12)
|
140
|
+
expect(l.next).to eq(:quick)
|
141
|
+
expect(l.next).to eq('m-*$'.to_sym)
|
142
|
+
expect(l.next).to eq(:RAN)
|
143
|
+
expect(l.next).to eq("`fast'".to_sym)
|
144
|
+
expect(l.next).to eq(-0.7)
|
145
|
+
expect(l.next).to be_kind_of(Klam::Lexer::CloseParen)
|
146
|
+
expect(l.next).to eq("oh 12 yeah!")
|
147
|
+
expect(l.next).to be_nil
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::Primitives::Arithmetic do
|
4
|
+
include Klam::Primitives::Arithmetic
|
5
|
+
|
6
|
+
describe '+' do
|
7
|
+
it 'adds its first argument to its second' do
|
8
|
+
expect(send(:+, 1, 2)).to be(3)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns an integer when both arguments are integers' do
|
12
|
+
expect(send(:+, 1, 2)).to be_kind_of(Fixnum)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns a real when either arguments are reals' do
|
16
|
+
real_first = send(:+, 1.1, 2)
|
17
|
+
real_second = send(:+, 1, 2.1)
|
18
|
+
real_both = send(:+, 1.1, 2.1)
|
19
|
+
types = [real_first, real_second, real_both].map(&:class)
|
20
|
+
|
21
|
+
expect(types.uniq).to eq([Float])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '-' do
|
26
|
+
it 'subtracts its second argument from its second' do
|
27
|
+
expect(send(:-, 1, 2)).to be(-1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns an integer when both arguments are integers' do
|
31
|
+
expect(send(:-, 1, 2)).to be_kind_of(Fixnum)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns a real when either arguments are reals' do
|
35
|
+
real_first = send(:-, 1.1, 2)
|
36
|
+
real_second = send(:-, 1, 2.1)
|
37
|
+
real_both = send(:-, 1.1, 2.1)
|
38
|
+
types = [real_first, real_second, real_both].map(&:class)
|
39
|
+
|
40
|
+
expect(types.uniq).to eq([Float])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '*' do
|
45
|
+
it 'multiplies its first argument by its second' do
|
46
|
+
expect(send(:*, 2, 3)).to be(6)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns an integer when both arguments are integers' do
|
50
|
+
expect(send(:*, 1, 2)).to be_kind_of(Fixnum)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'returns a real when either arguments are reals' do
|
54
|
+
real_first = send(:*, 1.1, 2)
|
55
|
+
real_second = send(:*, 1, 2.1)
|
56
|
+
real_both = send(:*, 1.1, 2.1)
|
57
|
+
types = [real_first, real_second, real_both].map(&:class)
|
58
|
+
|
59
|
+
expect(types.uniq).to eq([Float])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '/' do
|
64
|
+
it 'divides its first argument by its second' do
|
65
|
+
expect(send(:/, 6, 3)).to be(2)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns an integer when both arguments are integers and there is no remainder' do
|
69
|
+
expect(send(:/, 6, 2)).to be_kind_of(Fixnum)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns a real otherwise' do
|
73
|
+
real_first = send(:/, 1.1, 2)
|
74
|
+
real_second = send(:/, 1, 2.1)
|
75
|
+
real_both = send(:/, 1.1, 2.1)
|
76
|
+
having_remainder = send(:/, 3, 2)
|
77
|
+
types = [real_first, real_second, real_both, having_remainder]
|
78
|
+
.map(&:class)
|
79
|
+
|
80
|
+
expect(types.uniq).to eq([Float])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '<' do
|
85
|
+
it 'returns true is the first argument is less than the second' do
|
86
|
+
expect(send(:<, 1, 2)).to be(true)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns false if the first argument is equal to the second' do
|
90
|
+
expect(send(:<, 2, 2)).to be(false)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns false if the first argument is greater than the second' do
|
94
|
+
expect(send(:<, 3, 2)).to be(false)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '>' do
|
99
|
+
it 'returns false is the first argument is less than the second' do
|
100
|
+
expect(send(:>, 1, 2)).to be(false)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns false if the first argument is equal to the second' do
|
104
|
+
expect(send(:>, 2, 2)).to be(false)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns true if the first argument is greater than the second' do
|
108
|
+
expect(send(:>, 3, 2)).to be(true)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '<=' do
|
113
|
+
it 'returns true is the first argument is less than the second' do
|
114
|
+
expect(send(:<=, 1, 2)).to be(true)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'returns true if the first argument is equal to the second' do
|
118
|
+
expect(send(:<=, 2, 2)).to be(true)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'returns false if the first argument is greater than the second' do
|
122
|
+
expect(send(:<=, 3, 2)).to be(false)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '>=' do
|
127
|
+
it 'returns false is the first argument is less than the second' do
|
128
|
+
expect(send(:>=, 1, 2)).to be(false)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'returns true if the first argument is equal to the second' do
|
132
|
+
expect(send(:>=, 2, 2)).to be(true)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'returns true if the first argument is greater than the second' do
|
136
|
+
expect(send(:>=, 3, 2)).to be(true)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'number?' do
|
141
|
+
it 'returns true for integers' do
|
142
|
+
expect(number?(1)).to be(true)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'returns true for reals' do
|
146
|
+
expect(number?(1.1)).to be(true)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'returns false otherwise' do
|
150
|
+
expect(number?('hi')).to be(false)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Klam::Primitives::BooleanOperations do
|
4
|
+
include Klam::Primitives::BooleanOperations
|
5
|
+
|
6
|
+
describe '(if TestVal TrueVal FalseVal)' do
|
7
|
+
it 'returns TrueVal if TestVal is true' do
|
8
|
+
expect(send(:if, true, :foo, :bar)).to eq(:foo)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns FalseVal if TestVal is false' do
|
12
|
+
expect(send(:if, false, :foo, :bar)).to eq(:bar)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '(and A B)' do
|
17
|
+
it 'returns true when both A and B are true' do
|
18
|
+
expect(send(:and, true, true)).to be(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns false otherwise' do
|
22
|
+
expect(send(:and, false, true)).to be(false)
|
23
|
+
expect(send(:and, true, false)).to be(false)
|
24
|
+
expect(send(:and, false, false)).to be(false)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '(or A B)' do
|
29
|
+
it 'returns false when both A and B are false' do
|
30
|
+
expect(send(:or, false, false)).to be(false)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns true otherwise' do
|
34
|
+
expect(send(:or, false, true)).to be(true)
|
35
|
+
expect(send(:or, true, false)).to be(true)
|
36
|
+
expect(send(:or, true, true)).to be(true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|