skeem 0.0.15 → 0.0.16
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/CHANGELOG.md +15 -0
- data/lib/skeem/environment.rb +14 -0
- data/lib/skeem/grammar.rb +4 -1
- data/lib/skeem/primitive/primitive_builder.rb +48 -3
- data/lib/skeem/runtime.rb +15 -0
- data/lib/skeem/s_expr_builder.rb +22 -2
- data/lib/skeem/s_expr_nodes.rb +32 -9
- data/lib/skeem/standard/base.skm +23 -7
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/environment_spec.rb +13 -1
- data/spec/skeem/interpreter_spec.rb +82 -6
- data/spec/skeem/runtime_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b34c77d5c2d4f0893f69e79e8973b4c6eca3481
|
4
|
+
data.tar.gz: f10a360e77925612bd6c95bb5e160417ba538983
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da4f16148a354cb6ee8553d46e204ed97e27a88a117727a1c6a18f8441b5ed08a93fe56db11ade0fc903e934b60002315a98a70ef9b1a83d5015f7246f27ab4a
|
7
|
+
data.tar.gz: c75610b85fa5fa4a56c66832e19e193b401118dce728c5dacd755f5d570d3898939a11c2aa46ba83b9d1a6cde23d1a9e865657957dccc565e90c02c8806499aa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## [0.0.16] - 2018-10-06
|
2
|
+
- Added built-in procedures `odd?`, `even?`, `square`, and `floor-remainder` (`modulo`).
|
3
|
+
- Supports procedures without argument.
|
4
|
+
- Implements second syntax form for variable definition.
|
5
|
+
- Fixed nasty bug when same variable name used in nested procedure calls.
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Method `Environment#depth to count the nesting levels
|
9
|
+
- File `primitive_builder.rb` implementation of: `odd?`, `even?`, `square`, `floor-remainder`, `modulo` procedures.
|
10
|
+
- File `grammar.rb` rule for second syntax form for variable definition.
|
11
|
+
- File `grammar.rb` rule for calling procedures without argument.
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- Method `SkmDefinition#evaluate` Infinite recursion when a variable, say x, referred to a variable with same name in outer scope.
|
15
|
+
|
1
16
|
## [0.0.15] - 2018-09-30
|
2
17
|
Recursive functions are now supported.
|
3
18
|
Interpreter pre-loads a Scheme file with standard procedures (zero?, positive?, negative?, abs)
|
data/lib/skeem/environment.rb
CHANGED
@@ -47,5 +47,19 @@ module Skeem
|
|
47
47
|
|
48
48
|
my_result
|
49
49
|
end
|
50
|
+
|
51
|
+
# The number of outer parents the current environment has.
|
52
|
+
# @return [Integer] The nesting levels
|
53
|
+
def depth
|
54
|
+
count = 0
|
55
|
+
|
56
|
+
curr_env = self
|
57
|
+
while curr_env.outer
|
58
|
+
count += 1
|
59
|
+
curr_env = curr_env.outer
|
60
|
+
end
|
61
|
+
|
62
|
+
count
|
63
|
+
end
|
50
64
|
end # class
|
51
65
|
end # module
|
data/lib/skeem/grammar.rb
CHANGED
@@ -27,6 +27,7 @@ module Skeem
|
|
27
27
|
rule 'cmd_or_def' => 'definition'
|
28
28
|
rule 'command' => 'expression'
|
29
29
|
rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN').as 'definition'
|
30
|
+
rule('definition' => 'LPAREN DEFINE LPAREN IDENTIFIER def_formals RPAREN body RPAREN').as 'alt_definition'
|
30
31
|
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
31
32
|
rule 'expression' => 'literal'
|
32
33
|
rule 'expression' => 'procedure_call'
|
@@ -36,13 +37,15 @@ module Skeem
|
|
36
37
|
rule 'self-evaluating' => 'BOOLEAN'
|
37
38
|
rule 'self-evaluating' => 'number'
|
38
39
|
rule 'self-evaluating' => 'STRING_LIT'
|
39
|
-
rule
|
40
|
+
rule('procedure_call' => 'LPAREN operator RPAREN').as 'proc_call_nullary'
|
40
41
|
rule('procedure_call' => 'LPAREN operator operand_plus RPAREN').as 'proc_call_args'
|
41
42
|
rule('operand_plus' => 'operand_plus operand').as 'multiple_operands'
|
42
43
|
rule('operand_plus' => 'operand').as 'last_operand'
|
43
44
|
rule 'operator' => 'expression'
|
44
45
|
rule 'operand' => 'expression'
|
45
46
|
rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
|
47
|
+
rule 'def_formals' => 'identifier_star'
|
48
|
+
# rule('def_formals' => 'identifier_star period identifier').as 'dotted_formals'
|
46
49
|
rule('formals' => 'LPAREN identifier_star RPAREN').as 'identifiers_as_formals'
|
47
50
|
rule 'formals' => 'IDENTIFIER'
|
48
51
|
rule 'formals' => 'LPAREN identifier_plus PERIOD IDENTIFIER RPAREN'
|
@@ -12,6 +12,8 @@ module Skeem
|
|
12
12
|
add_boolean_procedures(aRuntime)
|
13
13
|
add_string_procedures(aRuntime)
|
14
14
|
add_symbol_procedures(aRuntime)
|
15
|
+
add_output_procedures(aRuntime)
|
16
|
+
add_special_procedures(aRuntime)
|
15
17
|
end
|
16
18
|
|
17
19
|
private
|
@@ -21,6 +23,7 @@ module Skeem
|
|
21
23
|
def_procedure(aRuntime, create_minus)
|
22
24
|
def_procedure(aRuntime, create_multiply)
|
23
25
|
def_procedure(aRuntime, create_divide)
|
26
|
+
def_procedure(aRuntime, create_modulo)
|
24
27
|
end
|
25
28
|
|
26
29
|
def add_comparison(aRuntime)
|
@@ -50,6 +53,14 @@ module Skeem
|
|
50
53
|
def_procedure(aRuntime, create_symbol?)
|
51
54
|
end
|
52
55
|
|
56
|
+
def add_output_procedures(aRuntime)
|
57
|
+
def_procedure(aRuntime, create_newline)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_special_procedures(aRuntime)
|
61
|
+
def_procedure(aRuntime, create_debug)
|
62
|
+
end
|
63
|
+
|
53
64
|
def create_plus()
|
54
65
|
plus_code = ->(runtime, arglist) do
|
55
66
|
first_one = arglist.head.evaluate(runtime)
|
@@ -102,6 +113,20 @@ module Skeem
|
|
102
113
|
['/', divide_code]
|
103
114
|
end
|
104
115
|
|
116
|
+
|
117
|
+
def create_modulo()
|
118
|
+
modulo_code = ->(runtime, arglist) do
|
119
|
+
operand_1 = arglist.head.evaluate(runtime)
|
120
|
+
operands = arglist.tail.to_eval_enum(runtime)
|
121
|
+
operand_2 = operands.first.evaluate(runtime)
|
122
|
+
raw_result = operand_1.value.modulo(operand_2.value)
|
123
|
+
to_skm(raw_result)
|
124
|
+
end
|
125
|
+
|
126
|
+
['floor-remainder', modulo_code, 'modulo', modulo_code]
|
127
|
+
end
|
128
|
+
|
129
|
+
|
105
130
|
def create_equal
|
106
131
|
equal_code = ->(runtime, arglist) do
|
107
132
|
first_one = arglist.head.evaluate(runtime)
|
@@ -232,9 +257,29 @@ module Skeem
|
|
232
257
|
['symbol?', pred_code]
|
233
258
|
end
|
234
259
|
|
235
|
-
def
|
236
|
-
|
237
|
-
|
260
|
+
def create_newline
|
261
|
+
nl_code = ->(runtime, arg) do
|
262
|
+
# @TODO: make output stream configurable
|
263
|
+
print "\n"
|
264
|
+
end
|
265
|
+
|
266
|
+
['newline', nl_code]
|
267
|
+
end
|
268
|
+
|
269
|
+
def create_debug
|
270
|
+
debug_code = ->(runtime, arg) do
|
271
|
+
require 'debug'
|
272
|
+
end
|
273
|
+
|
274
|
+
['debug', debug_code]
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
def def_procedure(aRuntime, pairs)
|
279
|
+
pairs.each_slice(2) do |(name, code)|
|
280
|
+
func = PrimitiveProcedure.new(name, code)
|
281
|
+
define(aRuntime, func.identifier, func)
|
282
|
+
end
|
238
283
|
end
|
239
284
|
|
240
285
|
def define(aRuntime, aKey, anEntry)
|
data/lib/skeem/runtime.rb
CHANGED
@@ -24,6 +24,21 @@ module Skeem
|
|
24
24
|
environment.bindings.clear
|
25
25
|
@environment = environment.outer
|
26
26
|
end
|
27
|
+
|
28
|
+
def depth()
|
29
|
+
return environment.depth
|
30
|
+
end
|
31
|
+
|
32
|
+
# Make the outer enviromnent thecurrent one inside the provided block
|
33
|
+
def pop
|
34
|
+
env = environment
|
35
|
+
@environment = environment.outer
|
36
|
+
env
|
37
|
+
end
|
38
|
+
|
39
|
+
def push(anEnvironment)
|
40
|
+
@environment = anEnvironment
|
41
|
+
end
|
27
42
|
|
28
43
|
private
|
29
44
|
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -61,11 +61,23 @@ module Skeem
|
|
61
61
|
def reduce_definition(_production, aRange, _tokens, theChildren)
|
62
62
|
SkmDefinition.new(aRange, theChildren[2], theChildren[3])
|
63
63
|
end
|
64
|
+
|
65
|
+
# rule('definition' => 'LPAREN DEFINE LPAREN IDENTIFIER def_formals RPAREN body RPAREN').as 'alt_definition'
|
66
|
+
# Equivalent to: (define IDENTIFIER (lambda (formals) body))
|
67
|
+
def reduce_alt_definition(_production, aRange, _tokens, theChildren)
|
68
|
+
lmbd = SkmLambda.new(aRange, theChildren[4], theChildren[6])
|
69
|
+
SkmDefinition.new(aRange, theChildren[3], lmbd)
|
70
|
+
end
|
64
71
|
|
65
72
|
# rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
66
73
|
def reduce_variable_reference(_production, aRange, _tokens, theChildren)
|
67
74
|
SkmVariableReference.new(aRange, theChildren[0])
|
68
75
|
end
|
76
|
+
|
77
|
+
# rule('procedure_call' => 'LPAREN operator RPAREN').as 'proc_call_nullary'
|
78
|
+
def reduce_proc_call_nullary(_production, aRange, _tokens, theChildren)
|
79
|
+
ProcedureCall.new(aRange, theChildren[1], [])
|
80
|
+
end
|
69
81
|
|
70
82
|
# rule('proc_call_args' => 'LPAREN operator operand_plus RPAREN')
|
71
83
|
def reduce_proc_call_args(_production, aRange, _tokens, theChildren)
|
@@ -83,10 +95,18 @@ module Skeem
|
|
83
95
|
end
|
84
96
|
|
85
97
|
# rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
|
86
|
-
def reduce_lambda_expression(_production,
|
87
|
-
lmbd = SkmLambda.new(
|
98
|
+
def reduce_lambda_expression(_production, aRange, _tokens, theChildren)
|
99
|
+
lmbd = SkmLambda.new(aRange, theChildren[2], theChildren[3])
|
100
|
+
# $stderr.puts lmbd.inspect
|
101
|
+
lmbd
|
88
102
|
end
|
89
103
|
|
104
|
+
# rule('def_formals' => 'identifier_star period identifier').as 'dotted_formals'
|
105
|
+
def reduce_last_operand(_production, _range, _tokens, theChildren)
|
106
|
+
[theChildren.last]
|
107
|
+
end
|
108
|
+
|
109
|
+
|
90
110
|
# rule('formals' => 'LPAREN identifier_star RPAREN').as 'identifiers_as_formals'
|
91
111
|
def reduce_identifiers_as_formals(_production, _range, _tokens, theChildren)
|
92
112
|
theChildren[1]
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -200,6 +200,7 @@ module Skeem
|
|
200
200
|
# Construct an Enumerator that will return iteratively the result
|
201
201
|
# of 'evaluate' method of each members of self.
|
202
202
|
def to_eval_enum(aRuntime)
|
203
|
+
=begin
|
203
204
|
elements = self.members
|
204
205
|
|
205
206
|
new_enum = Enumerator.new do |result|
|
@@ -208,6 +209,8 @@ module Skeem
|
|
208
209
|
end
|
209
210
|
|
210
211
|
new_enum
|
212
|
+
=end
|
213
|
+
members.map { |elem| elem.evaluate(aRuntime) }
|
211
214
|
end
|
212
215
|
|
213
216
|
# Part of the 'visitee' role in Visitor design pattern.
|
@@ -245,9 +248,29 @@ module Skeem
|
|
245
248
|
|
246
249
|
def evaluate(aRuntime)
|
247
250
|
var_key = variable.evaluate(aRuntime)
|
248
|
-
aRuntime.define(var_key, self)
|
249
|
-
|
250
|
-
|
251
|
+
aRuntime.define(var_key, self)
|
252
|
+
case expression
|
253
|
+
when SkmLambda
|
254
|
+
result = expression.evaluate(aRuntime)
|
255
|
+
|
256
|
+
when SkmVariableReference
|
257
|
+
other_key = expression.variable.evaluate(aRuntime)
|
258
|
+
if var_key.value != other_key.value
|
259
|
+
result = expression.evaluate(aRuntime)
|
260
|
+
else
|
261
|
+
# INFINITE LOOP DANGER: definition of 'x' is a reference to 'x'!
|
262
|
+
# Way out: the lookup for the reference should start from outer
|
263
|
+
# environment.
|
264
|
+
env = aRuntime.pop
|
265
|
+
@expression = expression.evaluate(aRuntime)
|
266
|
+
aRuntime.push(env)
|
267
|
+
result = expression
|
268
|
+
end
|
269
|
+
else
|
270
|
+
result = self
|
271
|
+
end
|
272
|
+
|
273
|
+
result
|
251
274
|
end
|
252
275
|
|
253
276
|
# call method should only invoked when the expression is a SkmLambda
|
@@ -325,10 +348,10 @@ module Skeem
|
|
325
348
|
raise err, err_msg
|
326
349
|
end
|
327
350
|
procedure = aRuntime.environment.fetch(var_key.value)
|
328
|
-
# puts "## CALL(#{var_key.value}) ###################"
|
329
|
-
# puts operands.inspect
|
351
|
+
# $stderr.puts "## CALL(#{var_key.value}) ###################"
|
352
|
+
# $stderr.puts operands.inspect
|
330
353
|
result = procedure.call(aRuntime, self)
|
331
|
-
# puts "## RETURN #{result.inspect}"
|
354
|
+
# $stderr.puts "## RETURN #{result.inspect}"
|
332
355
|
result
|
333
356
|
end
|
334
357
|
|
@@ -394,7 +417,7 @@ module Skeem
|
|
394
417
|
aRuntime.nest
|
395
418
|
bind_locals(aRuntime, aProcedureCall)
|
396
419
|
# TODO remove next line
|
397
|
-
# puts aRuntime.environment.inspect
|
420
|
+
# $stderr.puts aRuntime.environment.inspect
|
398
421
|
result = evaluate_defs(aRuntime)
|
399
422
|
result = evaluate_sequence(aRuntime)
|
400
423
|
aRuntime.unnest
|
@@ -418,12 +441,12 @@ module Skeem
|
|
418
441
|
if arg.nil?
|
419
442
|
raise StandardError, "Unbound variable: '#{arg_name.value}'"
|
420
443
|
end
|
421
|
-
|
444
|
+
|
422
445
|
# IMPORTANT: execute procedure call in argument list now
|
423
446
|
arg = arg.evaluate(aRuntime) if arg.kind_of?(ProcedureCall)
|
424
447
|
a_def = SkmDefinition.new(position, arg_name, arg)
|
425
448
|
a_def.evaluate(aRuntime)
|
426
|
-
# puts "LOCAL #{a_def.inspect}"
|
449
|
+
# $stderr.puts "LOCAL #{a_def.inspect}"
|
427
450
|
end
|
428
451
|
end
|
429
452
|
|
data/lib/skeem/standard/base.skm
CHANGED
@@ -1,25 +1,41 @@
|
|
1
1
|
; Standard R7RS procedures from section 6.2.6
|
2
|
-
(define zero?
|
2
|
+
(define zero?
|
3
3
|
(lambda (z)
|
4
4
|
(if (= z 0)
|
5
5
|
#t
|
6
6
|
#f)))
|
7
7
|
|
8
8
|
; Return true if x greater or equal to zero; false otherwise
|
9
|
-
(define positive?
|
9
|
+
(define positive?
|
10
10
|
(lambda (x)
|
11
11
|
(if (>= x 0)
|
12
12
|
#t
|
13
13
|
#f)))
|
14
14
|
|
15
|
-
(define negative?
|
15
|
+
(define negative?
|
16
16
|
(lambda (x)
|
17
17
|
(if (< x 0)
|
18
18
|
#t
|
19
19
|
#f)))
|
20
|
-
|
21
|
-
(define
|
20
|
+
|
21
|
+
(define odd?
|
22
|
+
(lambda (n)
|
23
|
+
(if (= (modulo n 2) 1)
|
24
|
+
#t
|
25
|
+
#f)))
|
26
|
+
|
27
|
+
(define even?
|
28
|
+
(lambda (n)
|
29
|
+
(if (= (modulo n 2) 0)
|
30
|
+
#t
|
31
|
+
#f)))
|
32
|
+
|
33
|
+
(define abs
|
22
34
|
(lambda (x)
|
23
|
-
(if (
|
35
|
+
(if (positive? x)
|
24
36
|
x
|
25
|
-
(- x))))
|
37
|
+
(- x))))
|
38
|
+
|
39
|
+
(define square
|
40
|
+
(lambda (z)
|
41
|
+
(* z z)))
|
data/lib/skeem/version.rb
CHANGED
@@ -3,14 +3,26 @@ require_relative '../../lib/skeem/environment' # Load the class under test
|
|
3
3
|
|
4
4
|
module Skeem
|
5
5
|
describe Environment do
|
6
|
+
let(:sample_env) { Environment.new }
|
6
7
|
context 'Initialization:' do
|
7
|
-
it '
|
8
|
+
it 'could be initialized without argument' do
|
8
9
|
expect { Environment.new() }.not_to raise_error
|
9
10
|
end
|
11
|
+
|
12
|
+
it 'could be initialized with optional argument' do
|
13
|
+
expect { Environment.new(sample_env) }.not_to raise_error
|
14
|
+
end
|
10
15
|
|
11
16
|
it 'should have no default bindings' do
|
12
17
|
expect(subject).to be_empty
|
13
18
|
end
|
19
|
+
|
20
|
+
it 'should have depth of zero or one' do
|
21
|
+
expect(subject.depth).to be_zero
|
22
|
+
|
23
|
+
instance = Environment.new(sample_env)
|
24
|
+
expect(instance.depth).to eq(1)
|
25
|
+
end
|
14
26
|
end # context
|
15
27
|
|
16
28
|
context 'Provided services:' do
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'stringio'
|
1
2
|
require_relative '../spec_helper' # Use the RSpec framework
|
2
3
|
require_relative '../../lib/skeem/interpreter' # Load the class under test
|
3
4
|
|
@@ -128,8 +129,9 @@ SKEEM
|
|
128
129
|
it 'should implement the lambda function with one arg' do
|
129
130
|
source = <<-SKEEM
|
130
131
|
; Simplified 'abs' function implementation
|
131
|
-
(define abs
|
132
|
-
(
|
132
|
+
(define abs
|
133
|
+
(lambda (x)
|
134
|
+
(if (< x 0) (- x) x)))
|
133
135
|
SKEEM
|
134
136
|
subject.run(source)
|
135
137
|
result = subject.run('(abs -3)')
|
@@ -143,8 +145,9 @@ SKEEM
|
|
143
145
|
it 'should implement the lambda function with two args' do
|
144
146
|
source = <<-SKEEM
|
145
147
|
; Simplified 'min' function implementation
|
146
|
-
(define min
|
147
|
-
(
|
148
|
+
(define min
|
149
|
+
(lambda (x y)
|
150
|
+
(if (< x y) x y)))
|
148
151
|
SKEEM
|
149
152
|
subject.run(source)
|
150
153
|
result = subject.run('(min 1 2)')
|
@@ -159,12 +162,25 @@ SKEEM
|
|
159
162
|
source = <<-SKEEM
|
160
163
|
; Example from R7RS section 4.1.5
|
161
164
|
(define fact (lambda (n)
|
162
|
-
(if (<= n 1)
|
165
|
+
(if (<= n 1)
|
166
|
+
1
|
167
|
+
(* n (fact (- n 1))))))
|
163
168
|
(fact 10)
|
164
169
|
SKEEM
|
165
170
|
result = subject.run(source)
|
166
171
|
expect(result.value).to eq(3628800)
|
167
172
|
end
|
173
|
+
|
174
|
+
it 'should implement the compact define + lambda syntax' do
|
175
|
+
source = <<-SKEEM
|
176
|
+
; Alternative syntax to: (define f (lambda x (+ x 42)))
|
177
|
+
(define (f x)
|
178
|
+
(+ x 42))
|
179
|
+
(f 23)
|
180
|
+
SKEEM
|
181
|
+
result = subject.run(source)
|
182
|
+
expect(result.value).to eq(65)
|
183
|
+
end
|
168
184
|
end # context
|
169
185
|
|
170
186
|
context 'Built-in primitive procedures' do
|
@@ -218,6 +234,20 @@ SKEEM
|
|
218
234
|
expect(result).to be_kind_of(SkmInteger)
|
219
235
|
expect(result.value).to eq(210)
|
220
236
|
end
|
237
|
+
|
238
|
+
it 'should implement the floor-remainder (modulo) procedure' do
|
239
|
+
checks = [
|
240
|
+
['(modulo 16 4)', 0],
|
241
|
+
['(modulo 5 2)', 1],
|
242
|
+
['(modulo -45.0 7)', 4.0],
|
243
|
+
['(modulo 10.0 -3.0)', -2.0],
|
244
|
+
['(modulo -17 -9)', -8]
|
245
|
+
]
|
246
|
+
checks.each do |(skeem_expr, expectation)|
|
247
|
+
result = subject.run(skeem_expr)
|
248
|
+
expect(result.value).to eq(expectation)
|
249
|
+
end
|
250
|
+
end
|
221
251
|
|
222
252
|
it 'should implement the equality operator' do
|
223
253
|
checks = [
|
@@ -376,6 +406,14 @@ SKEEM
|
|
376
406
|
expect(result.value).to eq(expectation)
|
377
407
|
end
|
378
408
|
end
|
409
|
+
|
410
|
+
it 'should implement the newline procedure' do
|
411
|
+
default_stdout = $stdout
|
412
|
+
$stdout = StringIO.new()
|
413
|
+
subject.run('(newline) (newline) (newline)')
|
414
|
+
expect($stdout.string).to match(/\n\n\n$/)
|
415
|
+
$stdout = default_stdout
|
416
|
+
end
|
379
417
|
end # context
|
380
418
|
|
381
419
|
context 'Built-in standard procedures' do
|
@@ -439,6 +477,32 @@ SKEEM
|
|
439
477
|
end
|
440
478
|
end
|
441
479
|
|
480
|
+
it 'should implement the even? predicate' do
|
481
|
+
checks = [
|
482
|
+
['(even? 0)', true],
|
483
|
+
['(even? 1)', false],
|
484
|
+
['(even? 2.0)', true],
|
485
|
+
['(even? -120762398465)', false]
|
486
|
+
]
|
487
|
+
checks.each do |(skeem_expr, expectation)|
|
488
|
+
result = subject.run(skeem_expr)
|
489
|
+
expect(result.value).to eq(expectation)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'should implement the odd? predicate' do
|
494
|
+
checks = [
|
495
|
+
['(odd? 0)', false],
|
496
|
+
['(odd? 1)', true],
|
497
|
+
['(odd? 2.0)', false],
|
498
|
+
['(odd? -120762398465)', true]
|
499
|
+
]
|
500
|
+
checks.each do |(skeem_expr, expectation)|
|
501
|
+
result = subject.run(skeem_expr)
|
502
|
+
expect(result.value).to eq(expectation)
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
442
506
|
it 'should implement the abs function' do
|
443
507
|
checks = [
|
444
508
|
['(abs 3.1)', 3.1],
|
@@ -452,7 +516,19 @@ SKEEM
|
|
452
516
|
result = subject.run(skeem_expr)
|
453
517
|
expect(result.value).to eq(expectation)
|
454
518
|
end
|
455
|
-
end
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'should implement the square function' do
|
522
|
+
checks = [
|
523
|
+
['(square 42)', 1764],
|
524
|
+
['(square 2.0)', 4.0],
|
525
|
+
['(square -7)', 49]
|
526
|
+
]
|
527
|
+
checks.each do |(skeem_expr, expectation)|
|
528
|
+
result = subject.run(skeem_expr)
|
529
|
+
expect(result.value).to eq(expectation)
|
530
|
+
end
|
531
|
+
end
|
456
532
|
end # context
|
457
533
|
end # describe
|
458
534
|
end # module
|
data/spec/skeem/runtime_spec.rb
CHANGED
@@ -32,17 +32,24 @@ module Skeem
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should add nested environment' do
|
35
|
+
expect(subject.depth).to be_zero
|
35
36
|
env_before = subject.environment
|
36
37
|
subject.nest
|
38
|
+
|
37
39
|
expect(subject.environment).not_to eq(env_before)
|
38
40
|
expect(subject.environment.outer).to eq(env_before)
|
41
|
+
expect(subject.depth).to eq(1)
|
39
42
|
end
|
40
43
|
|
41
44
|
it 'should remove nested environment' do
|
45
|
+
expect(subject.depth).to be_zero
|
42
46
|
subject.nest
|
43
47
|
outer_before = subject.environment.outer
|
48
|
+
expect(subject.depth).to eq(1)
|
49
|
+
|
44
50
|
subject.unnest
|
45
51
|
expect(subject.environment).to eq(outer_before)
|
52
|
+
expect(subject.depth).to be_zero
|
46
53
|
end
|
47
54
|
end # context
|
48
55
|
end # describe
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skeem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|