skeem 0.2.21 → 0.2.22
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 +4 -4
- data/.rubocop.yml +33 -337
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +1 -1
- data/lib/skeem/grammar.rb +13 -13
- data/lib/skeem/interpreter.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +1 -1
- data/lib/skeem/primitive/primitive_procedure.rb +1 -1
- data/lib/skeem/runtime.rb +2 -0
- data/lib/skeem/s_expr_nodes.rb +5 -3
- data/lib/skeem/tokenizer.rb +15 -20
- data/lib/skeem/version.rb +1 -1
- data/lib/skeem.rb +2 -2
- data/skeem.gemspec +8 -5
- data/spec/skeem/datum_dsl_spec.rb +50 -50
- data/spec/skeem/element_visitor_spec.rb +108 -108
- data/spec/skeem/interpreter_spec.rb +171 -169
- data/spec/skeem/lambda_spec.rb +27 -27
- data/spec/skeem/parser_spec.rb +27 -25
- data/spec/skeem/primitive/primitive_builder_spec.rb +127 -131
- data/spec/skeem/primitive/primitive_procedure_spec.rb +28 -28
- data/spec/skeem/runtime_spec.rb +52 -51
- data/spec/skeem/s_expr_nodes_spec.rb +31 -31
- data/spec/skeem/skm_compound_datum_spec.rb +36 -35
- data/spec/skeem/skm_element_spec.rb +35 -34
- data/spec/skeem/skm_empty_list_spec.rb +19 -19
- data/spec/skeem/skm_frame_spec.rb +49 -46
- data/spec/skeem/skm_pair_spec.rb +93 -93
- data/spec/skeem/skm_procedure_exec_spec.rb +11 -11
- data/spec/skeem/skm_simple_datum_spec.rb +102 -95
- data/spec/skeem/skm_unary_expression_spec.rb +60 -61
- data/spec/skeem/tokenizer_spec.rb +52 -52
- data/spec/skeem_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -2
- metadata +62 -18
data/spec/skeem/lambda_spec.rb
CHANGED
@@ -7,7 +7,7 @@ require_relative '../../lib/skeem/interpreter'
|
|
7
7
|
|
8
8
|
module Skeem
|
9
9
|
describe 'The interpreter and compound procedures' do
|
10
|
-
subject do
|
10
|
+
subject(:interpreter) do
|
11
11
|
# We load the interpreter with the primitive procedures only
|
12
12
|
Interpreter.new { |interp| interp.add_primitives(interp.runtime) }
|
13
13
|
end
|
@@ -30,85 +30,85 @@ SKEEM
|
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'Defining compound procedures:' do
|
33
|
-
it '
|
33
|
+
it 'accepts the definition of simple procedure with arity 1' do
|
34
34
|
source = "#{definition_set}\nsquare"
|
35
|
-
result =
|
35
|
+
result = interpreter.run(source)
|
36
36
|
|
37
37
|
square = result.last
|
38
|
-
expect(square).to
|
38
|
+
expect(square).to be_a(SkmLambda)
|
39
39
|
expect(square.arity).to eq(1)
|
40
|
-
expect(square.environment).to eq(
|
40
|
+
expect(square.environment).to eq(interpreter.runtime.environment)
|
41
41
|
end
|
42
42
|
|
43
|
-
it '
|
43
|
+
it 'accepts the definition of simple procedure with arity 2' do
|
44
44
|
source = "#{definition_set}\nsum-of-squares"
|
45
|
-
result =
|
45
|
+
result = interpreter.run(source)
|
46
46
|
|
47
47
|
square = result.last
|
48
|
-
expect(square).to
|
48
|
+
expect(square).to be_a(SkmLambda)
|
49
49
|
expect(square.arity).to eq(2)
|
50
|
-
expect(square.environment).to eq(
|
50
|
+
expect(square.environment).to eq(interpreter.runtime.environment)
|
51
51
|
end
|
52
52
|
end # context
|
53
53
|
|
54
54
|
context 'Calling compound procedures:' do
|
55
|
-
it '
|
55
|
+
it 'supports the call to a simple procedure with arity 1' do
|
56
56
|
# Case 1: argument is a simple datum
|
57
|
-
|
58
|
-
result =
|
57
|
+
interpreter.run(definition_set)
|
58
|
+
result = interpreter.run('(square 2)')
|
59
59
|
expect(result).to eq(4)
|
60
60
|
|
61
61
|
# Case 2: argument is a sub-expression
|
62
|
-
ptree =
|
62
|
+
ptree = interpreter.parse('(square (+ 2 1))')
|
63
63
|
proc_call = ptree.root
|
64
|
-
expect(proc_call.evaluate(
|
64
|
+
expect(proc_call.evaluate(interpreter.runtime)).to eq(9)
|
65
65
|
end
|
66
66
|
|
67
|
-
it '
|
67
|
+
it 'supports the call to a simple procedure with arity 2' do
|
68
68
|
source = "#{definition_set}\n(sum-of-squares 3 4)"
|
69
|
-
result =
|
69
|
+
result = interpreter.run(source)
|
70
70
|
|
71
71
|
expect(result.last).to eq(25)
|
72
72
|
end
|
73
73
|
|
74
|
-
it '
|
74
|
+
it 'supports the call to a nested lambda procedure' do
|
75
75
|
source = "#{definition_set}\n(f 5)"
|
76
|
-
result =
|
76
|
+
result = interpreter.run(source)
|
77
77
|
|
78
78
|
expect(result.last).to eq(136)
|
79
79
|
end
|
80
80
|
|
81
|
-
it '
|
81
|
+
it 'accepts calls to anonymous procedures' do
|
82
82
|
source = '((lambda (x) (+ x x)) 4)'
|
83
|
-
result =
|
83
|
+
result = interpreter.run(source)
|
84
84
|
expect(result).to eq(8)
|
85
85
|
end
|
86
86
|
|
87
|
-
it '
|
87
|
+
it 'accepts unary second-order lambdas' do
|
88
88
|
source = <<-SKEEM
|
89
89
|
(define add-with
|
90
90
|
(lambda (x) (lambda (y) (+ x y)))
|
91
91
|
)
|
92
92
|
(define add4 (add-with 4))
|
93
93
|
SKEEM
|
94
|
-
|
95
|
-
result =
|
94
|
+
interpreter.run(source)
|
95
|
+
result = interpreter.run('(add4 3)')
|
96
96
|
expect(result).to eq(7)
|
97
97
|
end
|
98
98
|
end # context
|
99
99
|
|
100
100
|
context 'More advanced features:' do
|
101
|
-
subject { Interpreter.new }
|
101
|
+
subject(:interpreter) { Interpreter.new }
|
102
102
|
|
103
|
-
it '
|
103
|
+
it 'implements binary second-order functions' do
|
104
104
|
source = <<-SKEEM
|
105
105
|
(define compose
|
106
106
|
(lambda (f g)
|
107
107
|
(lambda (x)
|
108
108
|
(f (g x)))))
|
109
109
|
SKEEM
|
110
|
-
|
111
|
-
result =
|
110
|
+
interpreter.run(source)
|
111
|
+
result = interpreter.run('((compose list square) 5)')
|
112
112
|
expect(result.last).to eq(25)
|
113
113
|
end
|
114
114
|
end # context
|
data/spec/skeem/parser_spec.rb
CHANGED
@@ -5,18 +5,20 @@ require_relative '../../lib/skeem/tokenizer' # Load the class under test
|
|
5
5
|
|
6
6
|
module Skeem
|
7
7
|
describe Parser do
|
8
|
+
subject(:parser) { described_class.new }
|
9
|
+
|
8
10
|
context 'Initialization:' do
|
9
|
-
it '
|
10
|
-
expect {
|
11
|
+
it 'is initialized without argument' do
|
12
|
+
expect { described_class.new }.not_to raise_error
|
11
13
|
end
|
12
14
|
|
13
|
-
it '
|
14
|
-
expect(
|
15
|
+
it 'has its parse engine initialized' do
|
16
|
+
expect(parser.engine).to be_a(Rley::Engine)
|
15
17
|
end
|
16
18
|
end # context
|
17
19
|
|
18
20
|
context 'Parsing literals:' do
|
19
|
-
it '
|
21
|
+
it 'parses isolated booleans' do
|
20
22
|
samples = [
|
21
23
|
['#f', false]
|
22
24
|
# ['#false', false],
|
@@ -24,13 +26,13 @@ module Skeem
|
|
24
26
|
# ['#true', true]
|
25
27
|
]
|
26
28
|
samples.each do |source, predicted|
|
27
|
-
ptree =
|
28
|
-
expect(ptree.root).to
|
29
|
+
ptree = parser.parse(source)
|
30
|
+
expect(ptree.root).to be_a(SkmBoolean)
|
29
31
|
expect(ptree.root.value).to eq(predicted)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
it '
|
35
|
+
it 'parses isolated integers' do
|
34
36
|
samples = [
|
35
37
|
['0', 0],
|
36
38
|
['3', 3],
|
@@ -39,14 +41,14 @@ module Skeem
|
|
39
41
|
['-12345', -12345]
|
40
42
|
]
|
41
43
|
samples.each do |source, predicted|
|
42
|
-
ptree =
|
43
|
-
expect(ptree.root).to
|
44
|
+
ptree = parser.parse(source)
|
45
|
+
expect(ptree.root).to be_a(SkmInteger)
|
44
46
|
expect(ptree.root.value).to eq(predicted)
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
50
|
# rubocop: disable Style/ExponentialNotation
|
49
|
-
it '
|
51
|
+
it 'parses isolated real numbers' do
|
50
52
|
samples = [
|
51
53
|
['0.0', 0.0],
|
52
54
|
['3.14', 3.14],
|
@@ -55,42 +57,42 @@ module Skeem
|
|
55
57
|
['-123e-45', -123e-45]
|
56
58
|
]
|
57
59
|
samples.each do |source, predicted|
|
58
|
-
ptree =
|
59
|
-
expect(ptree.root).to
|
60
|
+
ptree = parser.parse(source)
|
61
|
+
expect(ptree.root).to be_a(SkmReal)
|
60
62
|
expect(ptree.root.value).to eq(predicted)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
# rubocop: enable Style/ExponentialNotation
|
64
66
|
|
65
|
-
it '
|
67
|
+
it 'parses isolated strings' do
|
66
68
|
samples = [
|
67
69
|
['"Hello world!"', 'Hello world!']
|
68
70
|
]
|
69
71
|
samples.each do |source, predicted|
|
70
|
-
ptree =
|
71
|
-
expect(ptree.root).to
|
72
|
+
ptree = parser.parse(source)
|
73
|
+
expect(ptree.root).to be_a(SkmString)
|
72
74
|
expect(ptree.root.value).to eq(predicted)
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
76
|
-
it '
|
78
|
+
it 'parses isolated identifiers' do
|
77
79
|
samples = [
|
78
80
|
%w[the-word-recursion-has-many-meanings the-word-recursion-has-many-meanings]
|
79
81
|
]
|
80
82
|
samples.each do |source, predicted|
|
81
|
-
ptree =
|
82
|
-
expect(ptree.root).to
|
83
|
+
ptree = parser.parse(source)
|
84
|
+
expect(ptree.root).to be_a(SkmVariableReference)
|
83
85
|
expect(ptree.root.value).to eq(predicted)
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end # context
|
87
89
|
|
88
|
-
context 'Parsing forms:' do
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end # context
|
90
|
+
# context 'Parsing forms:' do
|
91
|
+
# # it 'parses definitions' do
|
92
|
+
# # source = '(define r 10)'
|
93
|
+
# # expect { parser.parse(source) }.not_to raise_error
|
94
|
+
# # end
|
95
|
+
# end # context
|
94
96
|
end # describe
|
95
97
|
end # module
|
96
98
|
|