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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d588cbeb0a65a6d0821ca4298fb15f577b873a0f
4
- data.tar.gz: b71fd66e1970299cef3e5802be3a8800cef3dd83
3
+ metadata.gz: ba107706c9483fb97e9a628b621ca7932c00f16d
4
+ data.tar.gz: 14ddf9ec1cebab58ae123ffbef3786f306824cb3
5
5
  SHA512:
6
- metadata.gz: e2aa7dec8f113fe704d859201f4176d7dcea1870a02d2fd7d6c89e96b1e2f3848d3e99c6283f95326a40a54af7c153834d8a213d6dcf8b3afd772bfbf2d28989
7
- data.tar.gz: 3f46e06c1c4b603b3b0af8d49bfd2180ffd4aba3906492ae845dc2e0d2c727286f8e63e09d9e8aeb1ca5dae7f6e47635f7364022e688d713086ec7ed63e2428f
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 retrieve its value
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 # => 42
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
- # Delimitersn, separators...
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
- # add_terminals('BEGIN', 'DEFINE')
22
- add_terminals('DEFINE')
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
@@ -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
@@ -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
@@ -28,6 +28,7 @@ module Skeem
28
28
  # Here are all the SRL keywords (in uppercase)
29
29
  @@keywords = %w[
30
30
  BEGIN
31
+ IF
31
32
  DEFINE
32
33
  ].map { |x| [x, x] } .to_h
33
34
 
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.0.12'.freeze
2
+ VERSION = '0.0.13'.freeze
3
3
  end
@@ -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.12
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-17 00:00:00.000000000 Z
11
+ date: 2018-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley