skeem 0.0.12 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +13 -3
- data/lib/skeem/grammar.rb +10 -5
- data/lib/skeem/s_expr_builder.rb +5 -0
- data/lib/skeem/s_expr_nodes.rb +31 -0
- data/lib/skeem/tokenizer.rb +1 -0
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +31 -1
- 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: ba107706c9483fb97e9a628b621ca7932c00f16d
|
4
|
+
data.tar.gz: 14ddf9ec1cebab58ae123ffbef3786f306824cb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfb3e078734b6e7ed68161f095c5c5c3287afd8c4fd1583b7a0e7f1d79c112aead08dd4e95d804ee68d7bfc7c1da73841252ef8eb8acdf88700d929682a2dc35
|
7
|
+
data.tar.gz: 5fd3ed354914cb9af65fd0e7836d3a474c45f980fcbf4a0535162d08d8944f14e72f8168e723ea024f46b8861292d47ae0e53ba419250f38e4a2a5fd1df2aaf3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## [0.0.13] - 2018-09-18
|
2
|
+
Added primitive `if` (conditional form)
|
3
|
+
|
4
|
+
### Added
|
5
|
+
- Class `SkmCondition` for representing a specific conditional.
|
6
|
+
|
7
|
+
### Changed
|
8
|
+
- File `grammar.rb` Added syntax rules for conditional expression.
|
9
|
+
- Class `SkmBuilder`. Added method to implement the semantic action for `if`.
|
10
|
+
- File `interpreter_spec.rb` added tests for `if`.
|
11
|
+
- File `README.md` Changed demo snippet with example of conditional expression.
|
12
|
+
|
1
13
|
## [0.0.12] - 2018-09-17
|
2
14
|
Added primitive `define` and variable reference
|
3
15
|
|
data/README.md
CHANGED
@@ -31,15 +31,25 @@ At this stage, the gem consists of a bare-bones interpreter.
|
|
31
31
|
require 'skeem'
|
32
32
|
|
33
33
|
schemer = Skeem::Interpreter.new
|
34
|
+
|
34
35
|
scheme_code =<<-SKEEM
|
36
|
+
; This heredoc consists of Scheme code...
|
35
37
|
; Let's define a Scheme variable
|
36
38
|
(define foobar (* 2 3 7))
|
37
39
|
|
38
|
-
; Now
|
39
|
-
foobar
|
40
|
+
; Now test its value against a lower value
|
41
|
+
(if (> foobar 40) #true #false)
|
40
42
|
SKEEM
|
43
|
+
|
44
|
+
# Ask Ruby to execute Scheme code
|
45
|
+
result = schemer.run(scheme_code)
|
46
|
+
puts result.value # => true
|
47
|
+
|
48
|
+
# The interpreter object keeps the bindings of variable
|
49
|
+
# Let's test that...
|
50
|
+
scheme_code = '(* foobar foobar)'
|
41
51
|
result = schemer.run(scheme_code)
|
42
|
-
puts result.value # =>
|
52
|
+
puts result.value # => 1764
|
43
53
|
```
|
44
54
|
|
45
55
|
Roadmap:
|
data/lib/skeem/grammar.rb
CHANGED
@@ -8,8 +8,8 @@ module Skeem
|
|
8
8
|
# https://bitbucket.org/cowan/r7rs/src/draft-10/rnrs/r7rs.pdf
|
9
9
|
# Names of grammar elements are based on the R7RS documentation
|
10
10
|
builder = Rley::Syntax::GrammarBuilder.new do
|
11
|
-
#
|
12
|
-
# add_terminals('APOSTROPHE', 'BACKQUOTE')
|
11
|
+
# Delimiters, separators...
|
12
|
+
# add_terminals('APOSTROPHE', 'BACKQUOTE')
|
13
13
|
add_terminals('LPAREN', 'RPAREN')
|
14
14
|
# add_terminals('PERIOD')
|
15
15
|
|
@@ -18,9 +18,8 @@ module Skeem
|
|
18
18
|
add_terminals('STRING_LIT', 'IDENTIFIER')
|
19
19
|
|
20
20
|
# Keywords...
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
add_terminals('DEFINE', 'IF')
|
22
|
+
|
24
23
|
rule('program' => 'cmd_or_def_plus').as 'main'
|
25
24
|
rule('cmd_or_def_plus' => 'cmd_or_def_plus cmd_or_def').as 'multiple_cmd_def'
|
26
25
|
rule('cmd_or_def_plus' => 'cmd_or_def').as 'last_cmd_def'
|
@@ -31,6 +30,7 @@ module Skeem
|
|
31
30
|
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
32
31
|
rule 'expression' => 'literal'
|
33
32
|
rule 'expression' => 'procedure_call'
|
33
|
+
rule 'expression' => 'conditional'
|
34
34
|
rule 'literal' => 'self-evaluating'
|
35
35
|
rule 'self-evaluating' => 'BOOLEAN'
|
36
36
|
rule 'self-evaluating' => 'number'
|
@@ -41,6 +41,11 @@ module Skeem
|
|
41
41
|
rule('operand_plus' => 'operand').as 'last_operand'
|
42
42
|
rule 'operator' => 'expression'
|
43
43
|
rule 'operand' => 'expression'
|
44
|
+
rule('conditional' => 'LPAREN IF test consequent alternate RPAREN').as 'conditional'
|
45
|
+
rule 'test' => 'expression'
|
46
|
+
rule 'consequent' => 'expression'
|
47
|
+
rule 'alternate' => 'expression'
|
48
|
+
rule 'alternate' => []
|
44
49
|
rule 'number' => 'INTEGER'
|
45
50
|
rule 'number' => 'REAL'
|
46
51
|
end
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -81,6 +81,11 @@ module Skeem
|
|
81
81
|
def reduce_last_operand(_production, _range, _tokens, theChildren)
|
82
82
|
[theChildren.last]
|
83
83
|
end
|
84
|
+
|
85
|
+
# rule('conditional' => 'LPAREN IF test consequent alternate RPAREN').as 'conditional'
|
86
|
+
def reduce_conditional(_production, aRange, _tokens, theChildren)
|
87
|
+
SkmCondition.new(aRange, theChildren[2], theChildren[3], theChildren[4])
|
88
|
+
end
|
84
89
|
end # class
|
85
90
|
end # module
|
86
91
|
# End of file
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -4,6 +4,13 @@
|
|
4
4
|
require 'forwardable'
|
5
5
|
|
6
6
|
module Skeem
|
7
|
+
class SkmUndefined
|
8
|
+
def value
|
9
|
+
:UNDEFINED
|
10
|
+
end
|
11
|
+
end # class
|
12
|
+
|
13
|
+
|
7
14
|
# Abstract class. Generalization of any S-expr element.
|
8
15
|
SkmElement = Struct.new(:position) do
|
9
16
|
def initialize(aPosition)
|
@@ -272,5 +279,29 @@ module Skeem
|
|
272
279
|
|
273
280
|
alias children operands
|
274
281
|
end # class
|
282
|
+
|
283
|
+
class SkmCondition < SkmElement
|
284
|
+
attr_reader :test
|
285
|
+
attr_reader :consequent
|
286
|
+
attr_reader :alternate
|
287
|
+
|
288
|
+
def initialize(aPosition, aTest, aConsequent, anAlternate)
|
289
|
+
super(aPosition)
|
290
|
+
@test = aTest
|
291
|
+
@consequent = aConsequent
|
292
|
+
@alternate = anAlternate
|
293
|
+
end
|
294
|
+
|
295
|
+
def evaluate(aRuntime)
|
296
|
+
test_result = test.evaluate(aRuntime)
|
297
|
+
condition_result = nil
|
298
|
+
if test_result.boolean? && test_result.value == false
|
299
|
+
# Only #f is considered as false, everything else is true
|
300
|
+
condition_result = alternate ? alternate.evaluate(aRuntime) : SkmUndefined.new
|
301
|
+
else
|
302
|
+
condition_result = consequent.evaluate(aRuntime)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end # class
|
275
306
|
end # module
|
276
307
|
# End of file
|
data/lib/skeem/tokenizer.rb
CHANGED
data/lib/skeem/version.rb
CHANGED
@@ -93,7 +93,37 @@ SKEEM
|
|
93
93
|
result = subject.run(source)
|
94
94
|
expect(result).to be_kind_of(SkmInteger)
|
95
95
|
expect(result.value).to eq(28)
|
96
|
-
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should implement the simple conditional form' do
|
99
|
+
checks = [
|
100
|
+
['(if (> 3 2) "yes")', 'yes'],
|
101
|
+
['(if (> 2 3) "yes")', :UNDEFINED]
|
102
|
+
]
|
103
|
+
checks.each do |(skeem_expr, expectation)|
|
104
|
+
result = subject.run(skeem_expr)
|
105
|
+
expect(result.value).to eq(expectation)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should implement the complete conditional form' do
|
110
|
+
checks = [
|
111
|
+
['(if (> 3 2) "yes" "no")', 'yes'],
|
112
|
+
['(if (> 2 3) "yes" "no")', 'no']
|
113
|
+
]
|
114
|
+
checks.each do |(skeem_expr, expectation)|
|
115
|
+
result = subject.run(skeem_expr)
|
116
|
+
expect(result.value).to eq(expectation)
|
117
|
+
end
|
118
|
+
source = <<-SKEEM
|
119
|
+
; Example from R7RS section 4.1.5
|
120
|
+
(if (> 3 2)
|
121
|
+
(- 3 2)
|
122
|
+
(+ 3 2))
|
123
|
+
SKEEM
|
124
|
+
result = subject.run(source)
|
125
|
+
expect(result.value).to eq(1)
|
126
|
+
end
|
97
127
|
end # context
|
98
128
|
|
99
129
|
context 'Built-in primitive procedures' do
|
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.13
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|