skeem 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|