skeem 0.0.12 → 0.0.13

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 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