klam 0.0.1
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.
- 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
|