skeem 0.0.11 → 0.0.12
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 +13 -0
- data/README.md +6 -3
- data/lib/skeem/convertible.rb +17 -0
- data/lib/skeem/grammar.rb +5 -5
- data/lib/skeem/primitive/primitive_builder.rb +2 -12
- data/lib/skeem/s_expr_builder.rb +32 -0
- data/lib/skeem/s_expr_nodes.rb +55 -6
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +25 -14
- data/spec/skeem/parser_spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d588cbeb0a65a6d0821ca4298fb15f577b873a0f
|
4
|
+
data.tar.gz: b71fd66e1970299cef3e5802be3a8800cef3dd83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2aa7dec8f113fe704d859201f4176d7dcea1870a02d2fd7d6c89e96b1e2f3848d3e99c6283f95326a40a54af7c153834d8a213d6dcf8b3afd772bfbf2d28989
|
7
|
+
data.tar.gz: 3f46e06c1c4b603b3b0af8d49bfd2180ffd4aba3906492ae845dc2e0d2c727286f8e63e09d9e8aeb1ca5dae7f6e47635f7364022e688d713086ec7ed63e2428f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## [0.0.12] - 2018-09-17
|
2
|
+
Added primitive `define` and variable reference
|
3
|
+
|
4
|
+
### Added
|
5
|
+
- Class `SkmDefinition` for representing a specific definition.
|
6
|
+
- Class `SkmVariableReference` for representing a variable reference (i.e. retrieving its value)
|
7
|
+
- Module `Convertible` implementing utility methods for converting "native" Ruby objects into their Skeem counterpart.
|
8
|
+
- Class `SkmBuilder`. Added methods to implement the semantic actions for `define` and variable reference.
|
9
|
+
- File `interpreter_spec.rb` added tests for `define` and variable reference.
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- File `README.md` Changed demo snippet with example of variable definition and variable reference.
|
13
|
+
|
1
14
|
## [0.0.11] - 2018-09-16
|
2
15
|
Added primitive procedures: `=`, `<`, `>`, `>=`, `<=`
|
3
16
|
|
data/README.md
CHANGED
@@ -32,11 +32,14 @@ At this stage, the gem consists of a bare-bones interpreter.
|
|
32
32
|
|
33
33
|
schemer = Skeem::Interpreter.new
|
34
34
|
scheme_code =<<-SKEEM
|
35
|
-
; Let's
|
36
|
-
(
|
35
|
+
; Let's define a Scheme variable
|
36
|
+
(define foobar (* 2 3 7))
|
37
|
+
|
38
|
+
; Now retrieve its value
|
39
|
+
foobar
|
37
40
|
SKEEM
|
38
41
|
result = schemer.run(scheme_code)
|
39
|
-
puts result.value # =>
|
42
|
+
puts result.value # => 42
|
40
43
|
```
|
41
44
|
|
42
45
|
Roadmap:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 's_expr_nodes'
|
2
|
+
|
3
|
+
module Skeem
|
4
|
+
module Convertible
|
5
|
+
# Convert Ruby object into its Skeem counterpart
|
6
|
+
def to_skm(native_obj)
|
7
|
+
case native_obj
|
8
|
+
when TrueClass, FalseClass
|
9
|
+
SkmBoolean.create(native_obj)
|
10
|
+
when Float
|
11
|
+
SkmReal.create(native_obj)
|
12
|
+
when Integer
|
13
|
+
SkmInteger.create(native_obj)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end # module
|
17
|
+
end # module
|
data/lib/skeem/grammar.rb
CHANGED
@@ -21,14 +21,14 @@ module Skeem
|
|
21
21
|
# add_terminals('BEGIN', 'DEFINE')
|
22
22
|
add_terminals('DEFINE')
|
23
23
|
|
24
|
-
rule
|
25
|
-
rule
|
26
|
-
rule
|
24
|
+
rule('program' => 'cmd_or_def_plus').as 'main'
|
25
|
+
rule('cmd_or_def_plus' => 'cmd_or_def_plus cmd_or_def').as 'multiple_cmd_def'
|
26
|
+
rule('cmd_or_def_plus' => 'cmd_or_def').as 'last_cmd_def'
|
27
27
|
rule 'cmd_or_def' => 'command'
|
28
28
|
rule 'cmd_or_def' => 'definition'
|
29
29
|
rule 'command' => 'expression'
|
30
|
-
rule
|
31
|
-
rule
|
30
|
+
rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN').as 'definition'
|
31
|
+
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
32
32
|
rule 'expression' => 'literal'
|
33
33
|
rule 'expression' => 'procedure_call'
|
34
34
|
rule 'literal' => 'self-evaluating'
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require_relative '../primitive_procedure'
|
2
|
+
require_relative '../convertible'
|
2
3
|
|
3
4
|
module Skeem
|
4
5
|
module Primitive
|
5
6
|
module PrimitiveBuilder
|
7
|
+
include Convertible
|
6
8
|
def add_primitives(aRuntime)
|
7
9
|
add_arithmetic(aRuntime)
|
8
10
|
add_comparison(aRuntime)
|
@@ -238,18 +240,6 @@ module Skeem
|
|
238
240
|
def define(aRuntime, aKey, anEntry)
|
239
241
|
aRuntime.define(aKey, anEntry)
|
240
242
|
end
|
241
|
-
|
242
|
-
# Convert Ruby object into its Skeem counterpart
|
243
|
-
def to_skm(native_obj)
|
244
|
-
case native_obj
|
245
|
-
when TrueClass, FalseClass
|
246
|
-
SkmBoolean.create(native_obj)
|
247
|
-
when Float
|
248
|
-
SkmReal.create(native_obj)
|
249
|
-
when Integer
|
250
|
-
SkmInteger.create(native_obj)
|
251
|
-
end
|
252
|
-
end
|
253
243
|
end # module
|
254
244
|
end # module
|
255
245
|
end # module
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -35,6 +35,38 @@ module Skeem
|
|
35
35
|
Terminal2NodeClass
|
36
36
|
end
|
37
37
|
|
38
|
+
# rule('program' => 'cmd_or_def_plus').as 'main'
|
39
|
+
def reduce_main(_production, _range, _tokens, theChildren)
|
40
|
+
last_child = theChildren.last
|
41
|
+
result = if last_child.members.size == 1
|
42
|
+
last_child.members[0]
|
43
|
+
else
|
44
|
+
last_child
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# rule('cmd_or_def_plus' => 'cmd_or_def_plus cmd_or_def').as 'multiple_cmd_def'
|
49
|
+
def reduce_multiple_cmd_def(_production, _range, _tokens, theChildren)
|
50
|
+
theChildren[0].members << theChildren[1]
|
51
|
+
theChildren[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
# rule('cmd_or_def_plus' => 'cmd_or_def').as 'last_cmd_def'
|
55
|
+
def reduce_last_cmd_def(_production, _range, _tokens, theChildren)
|
56
|
+
SkmList.new([theChildren.last])
|
57
|
+
end
|
58
|
+
|
59
|
+
# rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN')
|
60
|
+
# .as 'definition'
|
61
|
+
def reduce_definition(_production, aRange, _tokens, theChildren)
|
62
|
+
SkmDefinition.new(aRange, theChildren[2], theChildren[3])
|
63
|
+
end
|
64
|
+
|
65
|
+
# rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
66
|
+
def reduce_variable_reference(_production, aRange, _tokens, theChildren)
|
67
|
+
SkmVariableReference.new(aRange, theChildren[0])
|
68
|
+
end
|
69
|
+
|
38
70
|
# rule('proc_call_args' => 'LPAREN operator operand_plus RPAREN')
|
39
71
|
def reduce_proc_call_args(_production, aRange, _tokens, theChildren)
|
40
72
|
ProcedureCall.new(aRange, theChildren[1], theChildren[2])
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -199,25 +199,74 @@ module Skeem
|
|
199
199
|
alias subnodes members
|
200
200
|
end # class
|
201
201
|
|
202
|
+
class SkmDefinition < SkmElement
|
203
|
+
attr_reader :variable
|
204
|
+
attr_reader :expression
|
205
|
+
|
206
|
+
def initialize(aPosition, aVariable, theExpression)
|
207
|
+
super(aPosition)
|
208
|
+
@variable = aVariable
|
209
|
+
@expression = theExpression
|
210
|
+
end
|
211
|
+
|
212
|
+
def evaluate(aRuntime)
|
213
|
+
var_key = variable.evaluate(aRuntime)
|
214
|
+
aRuntime.define(var_key, self)
|
215
|
+
self
|
216
|
+
end
|
217
|
+
end # class
|
218
|
+
|
219
|
+
class SkmVariableReference < SkmElement
|
220
|
+
attr_reader :variable
|
221
|
+
|
222
|
+
def initialize(aPosition, aVariable)
|
223
|
+
super(aPosition)
|
224
|
+
@variable = aVariable
|
225
|
+
end
|
226
|
+
|
227
|
+
def evaluate(aRuntime)
|
228
|
+
var_key = variable.evaluate(aRuntime)
|
229
|
+
unless aRuntime.include?(var_key.value)
|
230
|
+
err = StandardError
|
231
|
+
key = var_key.kind_of?(SkmIdentifier) ? var_key.value : var_key
|
232
|
+
err_msg = "Unknown variable '#{key}'"
|
233
|
+
raise err, err_msg
|
234
|
+
end
|
235
|
+
definition = aRuntime.environment.bindings[var_key.value]
|
236
|
+
result = definition.expression.evaluate(aRuntime)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Confusing!
|
240
|
+
# Value, here, means the value of the identifier (the variable's name).
|
241
|
+
def value()
|
242
|
+
variable.value
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
202
246
|
class ProcedureCall < SkmElement
|
203
247
|
attr_reader :operator
|
204
248
|
attr_reader :operands
|
205
249
|
|
206
250
|
def initialize(aPosition, anOperator, theOperands)
|
207
251
|
super(aPosition)
|
208
|
-
|
252
|
+
if anOperator.kind_of?(SkmVariableReference)
|
253
|
+
# Kinky: variable names are procedure names, not variable reference
|
254
|
+
@operator = SkmIdentifier.create(anOperator.value)
|
255
|
+
else
|
256
|
+
@operator = anOperator
|
257
|
+
end
|
209
258
|
@operands = SkmList.new(theOperands)
|
210
259
|
end
|
211
260
|
|
212
261
|
def evaluate(aRuntime)
|
213
|
-
|
214
|
-
unless aRuntime.include?(
|
262
|
+
var_key = operator.evaluate(aRuntime)
|
263
|
+
unless aRuntime.include?(var_key.value)
|
215
264
|
err = StandardError
|
216
|
-
key =
|
217
|
-
err_msg = "Unknown
|
265
|
+
key = var_key.kind_of?(SkmIdentifier) ? var_key.value : var_key
|
266
|
+
err_msg = "Unknown procedure '#{key}'"
|
218
267
|
raise err, err_msg
|
219
268
|
end
|
220
|
-
procedure = aRuntime.environment.bindings[
|
269
|
+
procedure = aRuntime.environment.bindings[var_key.value]
|
221
270
|
result = procedure.call(aRuntime, self)
|
222
271
|
end
|
223
272
|
|
data/lib/skeem/version.rb
CHANGED
@@ -76,18 +76,24 @@ module Skeem
|
|
76
76
|
expect(result.value).to eq(predicted)
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
samples.each do |source, predicted|
|
86
|
-
result = subject.run(source)
|
87
|
-
expect(result).to be_kind_of(SkmIdentifier)
|
88
|
-
expect(result.value).to eq(predicted)
|
89
|
-
end
|
79
|
+
end # context
|
80
|
+
|
81
|
+
context 'Built-in primitives' do
|
82
|
+
it 'should implement variable definition' do
|
83
|
+
result = subject.run('(define x 28)')
|
84
|
+
expect(result).to be_kind_of(SkmDefinition)
|
90
85
|
end
|
86
|
+
|
87
|
+
it 'should implement variable reference' do
|
88
|
+
source = <<-SKEEM
|
89
|
+
; Example from R7RS section 4.1.1
|
90
|
+
(define x 28)
|
91
|
+
x
|
92
|
+
SKEEM
|
93
|
+
result = subject.run(source)
|
94
|
+
expect(result).to be_kind_of(SkmInteger)
|
95
|
+
expect(result.value).to eq(28)
|
96
|
+
end
|
91
97
|
end # context
|
92
98
|
|
93
99
|
context 'Built-in primitive procedures' do
|
@@ -120,9 +126,14 @@ module Skeem
|
|
120
126
|
end
|
121
127
|
|
122
128
|
it 'should implement the product of numbers' do
|
123
|
-
|
124
|
-
|
125
|
-
|
129
|
+
checks = [
|
130
|
+
['(* 5 8)', 40],
|
131
|
+
['(* 2 3 4)', 24]
|
132
|
+
]
|
133
|
+
checks.each do |(skeem_expr, expectation)|
|
134
|
+
result = subject.run(skeem_expr)
|
135
|
+
expect(result.value).to eq(expectation)
|
136
|
+
end
|
126
137
|
end
|
127
138
|
|
128
139
|
it 'should implement the division of numbers' do
|
data/spec/skeem/parser_spec.rb
CHANGED
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.12
|
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-09-
|
11
|
+
date: 2018-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- Rakefile
|
86
86
|
- appveyor.yml
|
87
87
|
- lib/skeem.rb
|
88
|
+
- lib/skeem/convertible.rb
|
88
89
|
- lib/skeem/environment.rb
|
89
90
|
- lib/skeem/grammar.rb
|
90
91
|
- lib/skeem/interpreter.rb
|