skeem 0.2.17 → 0.2.18
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 +241 -13
- data/CHANGELOG.md +9 -0
- data/bin/skeem +4 -4
- data/lib/skeem/datum_dsl.rb +36 -35
- data/lib/skeem/grammar.rb +3 -3
- data/lib/skeem/interpreter.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +7 -12
- data/lib/skeem/primitive/primitive_procedure.rb +6 -5
- data/lib/skeem/runtime.rb +8 -10
- data/lib/skeem/s_expr_builder.rb +3 -13
- data/lib/skeem/s_expr_nodes.rb +34 -44
- data/lib/skeem/skeem_exception.rb +1 -0
- data/lib/skeem/skm_binding.rb +4 -5
- data/lib/skeem/skm_compound_datum.rb +2 -3
- data/lib/skeem/skm_element.rb +1 -1
- data/lib/skeem/skm_pair.rb +5 -2
- data/lib/skeem/skm_procedure_exec.rb +3 -0
- data/lib/skeem/skm_simple_datum.rb +12 -10
- data/lib/skeem/skm_unary_expression.rb +25 -26
- data/lib/skeem/tokenizer.rb +8 -4
- data/lib/skeem/version.rb +1 -1
- data/skeem.gemspec +4 -3
- data/spec/skeem/element_visitor_spec.rb +3 -1
- data/spec/skeem/interpreter_spec.rb +3 -1
- data/spec/skeem/lambda_spec.rb +4 -4
- data/spec/skeem/parser_spec.rb +2 -0
- data/spec/skeem/primitive/primitive_builder_spec.rb +5 -5
- data/spec/skeem/primitive/primitive_procedure_spec.rb +1 -1
- data/spec/skeem/skm_compound_datum_spec.rb +1 -1
- data/spec/skeem/skm_pair_spec.rb +5 -5
- data/spec/skeem/tokenizer_spec.rb +4 -2
- data/spec/spec_helper.rb +13 -10
- metadata +9 -9
data/lib/skeem/skm_element.rb
CHANGED
data/lib/skeem/skm_pair.rb
CHANGED
@@ -4,7 +4,10 @@ require_relative 'skm_empty_list'
|
|
4
4
|
|
5
5
|
module Skeem
|
6
6
|
class SkmPair < SkmElement
|
7
|
+
# @return [SkmElement]
|
7
8
|
attr_accessor :car
|
9
|
+
|
10
|
+
# @return [SkmElement]
|
8
11
|
attr_accessor :cdr
|
9
12
|
|
10
13
|
alias first car
|
@@ -168,8 +171,8 @@ module Skeem
|
|
168
171
|
begin
|
169
172
|
result = clone_evaluate(aRuntime)
|
170
173
|
rescue NoMethodError => e
|
171
|
-
$stderr.puts
|
172
|
-
$stderr.puts
|
174
|
+
$stderr.puts "SkmPair#evaluate: #{inspect}"
|
175
|
+
$stderr.puts "SkmPair as Array: #{to_a.inspect}"
|
173
176
|
raise e
|
174
177
|
end
|
175
178
|
end
|
@@ -6,7 +6,10 @@ module Skeem
|
|
6
6
|
# Abstract class. Root of class hierarchy needed for Interpreter
|
7
7
|
# design pattern
|
8
8
|
class SkmSimpleDatum < SkmElement
|
9
|
+
# @return [Rley::Syntax::Token] token object corresponding to Skeem element
|
9
10
|
attr_reader :token
|
11
|
+
|
12
|
+
# @return [Object]
|
10
13
|
attr_reader :value
|
11
14
|
|
12
15
|
def initialize(aToken, aPosition)
|
@@ -37,13 +40,11 @@ module Skeem
|
|
37
40
|
def ==(other)
|
38
41
|
return true if equal?(other)
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
result
|
43
|
+
if other.kind_of?(SkmSimpleDatum)
|
44
|
+
value == other.value
|
45
|
+
else
|
46
|
+
value == other
|
47
|
+
end
|
47
48
|
end
|
48
49
|
|
49
50
|
alias eqv? ==
|
@@ -104,10 +105,12 @@ module Skeem
|
|
104
105
|
false
|
105
106
|
end
|
106
107
|
|
108
|
+
# rubocop: disable Style/NegatedIfElseCondition
|
109
|
+
|
107
110
|
def eqv?(other)
|
108
111
|
return true if equal?(other)
|
109
112
|
|
110
|
-
|
113
|
+
if other.kind_of?(SkmNumber)
|
111
114
|
if exact? != other.exact?
|
112
115
|
false
|
113
116
|
else
|
@@ -116,9 +119,8 @@ module Skeem
|
|
116
119
|
else
|
117
120
|
value == other
|
118
121
|
end
|
119
|
-
|
120
|
-
result
|
121
122
|
end
|
123
|
+
# rubocop: enable Style/NegatedIfElseCondition
|
122
124
|
end # class
|
123
125
|
|
124
126
|
class SkmReal < SkmNumber
|
@@ -76,8 +76,7 @@ module Skeem
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def quasiquote(aRuntime)
|
79
|
-
|
80
|
-
result
|
79
|
+
evaluate(aRuntime)
|
81
80
|
end
|
82
81
|
|
83
82
|
protected
|
@@ -115,7 +114,10 @@ module Skeem
|
|
115
114
|
class SkmBindingBlock < SkmUnaryExpression
|
116
115
|
alias body child
|
117
116
|
|
117
|
+
# @return [Symbol] One of: :let, :let_star
|
118
118
|
attr_reader :kind
|
119
|
+
|
120
|
+
# @return [Array<SkmBinding>]
|
119
121
|
attr_reader :bindings
|
120
122
|
|
121
123
|
def initialize(theKind, theBindings, aBody)
|
@@ -126,14 +128,15 @@ module Skeem
|
|
126
128
|
|
127
129
|
def evaluate(aRuntime)
|
128
130
|
aRuntime.push(SkmFrame.new(aRuntime.environment))
|
129
|
-
|
131
|
+
case kind
|
132
|
+
when :let
|
130
133
|
locals = bindings.map do |bnd|
|
131
134
|
SkmBinding.new(bnd.variable, bnd.value.evaluate(aRuntime))
|
132
135
|
end
|
133
136
|
locals.each do |bnd|
|
134
137
|
aRuntime.add_binding(bnd.variable.evaluate(aRuntime), bnd.value)
|
135
138
|
end
|
136
|
-
|
139
|
+
when :let_star
|
137
140
|
bindings.each do |bnd|
|
138
141
|
val = bnd.value.evaluate(aRuntime)
|
139
142
|
aRuntime.add_binding(bnd.variable.evaluate(aRuntime), val)
|
@@ -186,18 +189,16 @@ module Skeem
|
|
186
189
|
def eval_pair(aRuntime)
|
187
190
|
result = nil
|
188
191
|
sequence.to_a.each do |cmd|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
result = cmd.evaluate(aRuntime)
|
194
|
-
end
|
195
|
-
rescue NoMethodError => e
|
196
|
-
$stderr.puts inspect
|
197
|
-
$stderr.puts sequence.inspect
|
198
|
-
$stderr.puts cmd.inspect
|
199
|
-
raise e
|
192
|
+
if cmd.kind_of?(SkmLambda)
|
193
|
+
result = cmd.dup_cond(aRuntime)
|
194
|
+
else
|
195
|
+
result = cmd.evaluate(aRuntime)
|
200
196
|
end
|
197
|
+
rescue NoMethodError => e
|
198
|
+
$stderr.puts inspect
|
199
|
+
$stderr.puts sequence.inspect
|
200
|
+
$stderr.puts cmd.inspect
|
201
|
+
raise e
|
201
202
|
end
|
202
203
|
|
203
204
|
result
|
@@ -215,18 +216,16 @@ module Skeem
|
|
215
216
|
|
216
217
|
if sequence[:sequence].kind_of?(SkmPair)
|
217
218
|
sequence[:sequence].to_a.each do |cmd|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
result = cmd.evaluate(aRuntime)
|
223
|
-
end
|
224
|
-
rescue NoMethodError => e
|
225
|
-
$stderr.puts inspect
|
226
|
-
$stderr.puts sequence[:sequence].inspect
|
227
|
-
$stderr.puts cmd.inspect
|
228
|
-
raise e
|
219
|
+
if cmd.kind_of?(SkmLambda)
|
220
|
+
result = cmd.dup_cond(aRuntime)
|
221
|
+
else
|
222
|
+
result = cmd.evaluate(aRuntime)
|
229
223
|
end
|
224
|
+
rescue NoMethodError => e
|
225
|
+
$stderr.puts inspect
|
226
|
+
$stderr.puts sequence[:sequence].inspect
|
227
|
+
$stderr.puts cmd.inspect
|
228
|
+
raise e
|
230
229
|
end
|
231
230
|
else
|
232
231
|
result = sequence.evaluate(aRuntime)
|
data/lib/skeem/tokenizer.rb
CHANGED
@@ -16,8 +16,13 @@ module Skeem
|
|
16
16
|
# Delimiters: parentheses '(', ')'
|
17
17
|
# Separators: comma
|
18
18
|
class Tokenizer
|
19
|
+
# @return [StringScanner]
|
19
20
|
attr_reader(:scanner)
|
21
|
+
|
22
|
+
# @return [Integer] Current line number
|
20
23
|
attr_reader(:lineno)
|
24
|
+
|
25
|
+
# @return [Integer] Offset of start of current line
|
21
26
|
attr_reader(:line_start)
|
22
27
|
|
23
28
|
@@lexeme2name = {
|
@@ -53,7 +58,7 @@ module Skeem
|
|
53
58
|
SYNTAX-RULES
|
54
59
|
UNQUOTE
|
55
60
|
UNQUOTE-SPLICING
|
56
|
-
].map { |x| [x, x] }.to_h
|
61
|
+
].map { |x| [x, x.sub(/\*$/, '_STAR')] }.to_h
|
57
62
|
|
58
63
|
class ScanError < StandardError; end
|
59
64
|
|
@@ -162,11 +167,10 @@ other literal data (section 2.4).
|
|
162
167
|
if (lexeme = scanner.scan(/#\\/))
|
163
168
|
if (lexeme = scanner.scan(/(?:alarm|backspace|delete|escape|newline|null|return|space|tab)/))
|
164
169
|
token = build_token('CHAR', lexeme, :name)
|
165
|
-
elsif (lexeme = scanner.scan(/[^x]/))
|
166
|
-
token = build_token('CHAR', lexeme, :escaped)
|
167
170
|
elsif (lexeme = scanner.scan(/x[0-9a-fA-F]+/))
|
168
171
|
token = build_token('CHAR', lexeme, :hex_value)
|
169
|
-
|
172
|
+
else
|
173
|
+
lexeme = scanner.getch
|
170
174
|
token = build_token('CHAR', lexeme, :escaped)
|
171
175
|
end
|
172
176
|
end
|
data/lib/skeem/version.rb
CHANGED
data/skeem.gemspec
CHANGED
@@ -24,7 +24,8 @@ module PkgExtending
|
|
24
24
|
'lib/**/*.rb',
|
25
25
|
'lib/**/*.skm',
|
26
26
|
'spec/**/*.rb',
|
27
|
-
'spec/**/*.skm'
|
27
|
+
'spec/**/*.skm',
|
28
|
+
'spec/**/*.yml'
|
28
29
|
]
|
29
30
|
aPackage.files = file_list
|
30
31
|
aPackage.test_files = Dir['spec/**/*_spec.rb']
|
@@ -53,7 +54,7 @@ DESCR
|
|
53
54
|
SUMMARY
|
54
55
|
spec.homepage = 'https://github.com/famished-tiger/Skeem'
|
55
56
|
spec.license = 'MIT'
|
56
|
-
spec.required_ruby_version = '>= 2.
|
57
|
+
spec.required_ruby_version = '>= 2.5.0'
|
57
58
|
|
58
59
|
spec.bindir = 'bin'
|
59
60
|
spec.executables << 'skeem'
|
@@ -61,7 +62,7 @@ SUMMARY
|
|
61
62
|
PkgExtending.pkg_files(spec)
|
62
63
|
PkgExtending.pkg_documentation(spec)
|
63
64
|
# Runtime dependencies
|
64
|
-
spec.add_dependency 'rley', '~> 0.
|
65
|
+
spec.add_dependency 'rley', '~> 0.8.03'
|
65
66
|
|
66
67
|
# Development dependencies
|
67
68
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
@@ -16,7 +16,7 @@ module Skeem
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'could be initialized with a block argument' do
|
19
|
-
expect { Interpreter.new
|
19
|
+
expect { Interpreter.new(&:runtime) }.not_to raise_error
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'should have a parser' do
|
@@ -67,6 +67,7 @@ module Skeem
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
# rubocop: disable Style/ExponentialNotation
|
70
71
|
it 'should evaluate isolated real numbers' do
|
71
72
|
samples = [
|
72
73
|
['0.0', 0.0],
|
@@ -80,6 +81,7 @@ module Skeem
|
|
80
81
|
expect(result).to eq(predicted)
|
81
82
|
end
|
82
83
|
end
|
84
|
+
# rubocop: enable Style/ExponentialNotation
|
83
85
|
|
84
86
|
it 'should evaluate isolated strings' do
|
85
87
|
samples = [
|
data/spec/skeem/lambda_spec.rb
CHANGED
@@ -31,7 +31,7 @@ SKEEM
|
|
31
31
|
|
32
32
|
context 'Defining compound procedures:' do
|
33
33
|
it 'should accept the definition of simple procedure with arity 1' do
|
34
|
-
source = definition_set
|
34
|
+
source = "#{definition_set}\nsquare"
|
35
35
|
result = subject.run(source)
|
36
36
|
|
37
37
|
square = result.last
|
@@ -41,7 +41,7 @@ SKEEM
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should accept the definition of simple procedure with arity 2' do
|
44
|
-
source = definition_set
|
44
|
+
source = "#{definition_set}\nsum-of-squares"
|
45
45
|
result = subject.run(source)
|
46
46
|
|
47
47
|
square = result.last
|
@@ -65,14 +65,14 @@ SKEEM
|
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'should support the call to a simple procedure with arity 2' do
|
68
|
-
source = definition_set
|
68
|
+
source = "#{definition_set}\n(sum-of-squares 3 4)"
|
69
69
|
result = subject.run(source)
|
70
70
|
|
71
71
|
expect(result.last).to eq(25)
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'should support the call to a nested lambda procedure' do
|
75
|
-
source = definition_set
|
75
|
+
source = "#{definition_set}\n(f 5)"
|
76
76
|
result = subject.run(source)
|
77
77
|
|
78
78
|
expect(result.last).to eq(136)
|
data/spec/skeem/parser_spec.rb
CHANGED
@@ -45,6 +45,7 @@ module Skeem
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
# rubocop: disable Style/ExponentialNotation
|
48
49
|
it 'should parse isolated real numbers' do
|
49
50
|
samples = [
|
50
51
|
['0.0', 0.0],
|
@@ -59,6 +60,7 @@ module Skeem
|
|
59
60
|
expect(ptree.root.value).to eq(predicted)
|
60
61
|
end
|
61
62
|
end
|
63
|
+
# rubocop: enable Style/ExponentialNotation
|
62
64
|
|
63
65
|
it 'should parse isolated strings' do
|
64
66
|
samples = [
|
@@ -654,8 +654,8 @@ SKEEM
|
|
654
654
|
["(append '(a b) '(c d))", array2list_ids(%w[a b c d])],
|
655
655
|
["(append '(a b) '(c) 'd)", array2list_ids(%w[a b c d])],
|
656
656
|
["(append '(a (b)) '((c)))", [SkmIdentifier.create('a'),
|
657
|
-
|
658
|
-
|
657
|
+
SkmPair.create_from_a(array2list_ids(['b'])),
|
658
|
+
SkmPair.create_from_a(array2list_ids(['c']))]],
|
659
659
|
["(append '() 'a)", SkmIdentifier.create('a')]
|
660
660
|
]
|
661
661
|
compare_to_predicted(checks) do |result, expectation|
|
@@ -919,8 +919,8 @@ SKEEM
|
|
919
919
|
result = subject.run(source)
|
920
920
|
expect(result).to be_kind_of(SkmVector)
|
921
921
|
expectation = [SkmInteger.create(0),
|
922
|
-
|
923
|
-
|
922
|
+
SkmPair.new(SkmString.create('Sue'), SkmPair.new(SkmString.create('Sue'), SkmEmptyList.instance)),
|
923
|
+
SkmString.create('Anna')]
|
924
924
|
expect(result).to eq(expectation)
|
925
925
|
|
926
926
|
source = <<-SKEEM
|
@@ -1010,7 +1010,7 @@ SKEEM
|
|
1010
1010
|
err = StandardError
|
1011
1011
|
msg1 = 'Error: assertion failed on line 3, column 4'
|
1012
1012
|
msg2 = 'with <Skeem::SkmBoolean: false>'
|
1013
|
-
expect { subject.run(source) }.to raise_error(err, msg1
|
1013
|
+
expect { subject.run(source) }.to raise_error(err, "#{msg1}, #{msg2}")
|
1014
1014
|
end
|
1015
1015
|
end # context
|
1016
1016
|
end # describe
|
@@ -149,7 +149,7 @@ module Skeem
|
|
149
149
|
expect(pproc.call(rtime, no_arg)).to eq(0)
|
150
150
|
|
151
151
|
many = [SkmString.create('foo'), SkmString.create('bar'),
|
152
|
-
|
152
|
+
SkmString.create('quux')]
|
153
153
|
expect(pproc.call(rtime, many)).to eq(3)
|
154
154
|
end
|
155
155
|
end # context
|
@@ -50,7 +50,7 @@ module Skeem
|
|
50
50
|
it 'should return its text representation' do
|
51
51
|
txt1 = '<Skeem::SkmCompoundDatum: <Skeem::SkmInteger: 1>,'
|
52
52
|
txt2 = '<Skeem::SkmInteger: 2>, <Skeem::SkmInteger: 3>>'
|
53
|
-
expect(subject.inspect).to eq(txt1
|
53
|
+
expect(subject.inspect).to eq("#{txt1} #{txt2}")
|
54
54
|
end
|
55
55
|
end # context
|
56
56
|
|
data/spec/skeem/skm_pair_spec.rb
CHANGED
@@ -37,7 +37,7 @@ module Skeem
|
|
37
37
|
|
38
38
|
context 'Provided services:' do
|
39
39
|
let(:runtime) { Runtime.new(SkmFrame.new) }
|
40
|
-
let(:
|
40
|
+
let(:list_length2) { SkmPair.new(integer(10), subject) }
|
41
41
|
let(:quirk_element) { double('three') }
|
42
42
|
let(:quirk_members) { [integer(10), quirk_element] }
|
43
43
|
|
@@ -71,7 +71,7 @@ module Skeem
|
|
71
71
|
expect(subject.length).to eq(1)
|
72
72
|
|
73
73
|
# Use a list of length 2
|
74
|
-
expect(
|
74
|
+
expect(list_length2.length).to eq(2)
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'should respond false to `eqv?` message' do
|
@@ -113,7 +113,7 @@ module Skeem
|
|
113
113
|
expect(subject.to_a).to eq([sample_car])
|
114
114
|
|
115
115
|
# Use a list of length 2
|
116
|
-
expect(
|
116
|
+
expect(list_length2.to_a).to eq([integer(10), sample_car])
|
117
117
|
end
|
118
118
|
|
119
119
|
it 'should return the last pair of a proper list' do
|
@@ -133,7 +133,7 @@ module Skeem
|
|
133
133
|
|
134
134
|
it 'should return the last element of a list' do
|
135
135
|
expect(subject.last).to eq(sample_car)
|
136
|
-
expect(
|
136
|
+
expect(list_length2.last).to eq(sample_car)
|
137
137
|
end
|
138
138
|
|
139
139
|
it 'should append a new element to a list' do
|
@@ -227,7 +227,7 @@ module Skeem
|
|
227
227
|
expect(subject.inspect).to eq(predicted)
|
228
228
|
|
229
229
|
predicted = '<Skeem::SkmPair: <Skeem::SkmInteger: 10>, <Skeem::SkmInteger: 3>>'
|
230
|
-
expect(
|
230
|
+
expect(list_length2.inspect).to eq(predicted)
|
231
231
|
end
|
232
232
|
end # context
|
233
233
|
end # describe
|