skeem 0.2.14 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +451 -195
  3. data/.travis.yml +27 -0
  4. data/CHANGELOG.md +35 -1
  5. data/Gemfile +2 -0
  6. data/README.md +125 -56
  7. data/Rakefile +2 -0
  8. data/appveyor.yml +3 -4
  9. data/bin/cubic.skm +4 -0
  10. data/bin/hello-world.skm +1 -0
  11. data/bin/skeem +72 -0
  12. data/lib/skeem/datum_dsl.rb +40 -30
  13. data/lib/skeem/element_visitor.rb +5 -2
  14. data/lib/skeem/grammar.rb +88 -26
  15. data/lib/skeem/interpreter.rb +9 -7
  16. data/lib/skeem/parser.rb +6 -4
  17. data/lib/skeem/primitive/primitive_builder.rb +148 -122
  18. data/lib/skeem/primitive/primitive_procedure.rb +23 -25
  19. data/lib/skeem/runtime.rb +17 -15
  20. data/lib/skeem/s_expr_builder.rb +49 -117
  21. data/lib/skeem/s_expr_nodes.rb +147 -132
  22. data/lib/skeem/skeem_exception.rb +1 -0
  23. data/lib/skeem/skm_binding.rb +9 -11
  24. data/lib/skeem/skm_compound_datum.rb +9 -6
  25. data/lib/skeem/skm_element.rb +15 -13
  26. data/lib/skeem/skm_empty_list.rb +6 -4
  27. data/lib/skeem/skm_exception.rb +9 -0
  28. data/lib/skeem/skm_expression.rb +3 -1
  29. data/lib/skeem/skm_frame.rb +3 -2
  30. data/lib/skeem/skm_pair.rb +26 -18
  31. data/lib/skeem/skm_procedure_exec.rb +11 -6
  32. data/lib/skeem/skm_simple_datum.rb +23 -20
  33. data/lib/skeem/skm_unary_expression.rb +34 -37
  34. data/lib/skeem/standard/base.skm +4 -0
  35. data/lib/skeem/tokenizer.rb +38 -28
  36. data/lib/skeem/version.rb +3 -1
  37. data/lib/skeem.rb +2 -0
  38. data/skeem.gemspec +9 -6
  39. data/spec/skeem/add4.skm +4 -0
  40. data/spec/skeem/datum_dsl_spec.rb +13 -12
  41. data/spec/skeem/element_visitor_spec.rb +14 -10
  42. data/spec/skeem/interpreter_spec.rb +84 -44
  43. data/spec/skeem/lambda_spec.rb +13 -11
  44. data/spec/skeem/parser_spec.rb +23 -19
  45. data/spec/skeem/primitive/primitive_builder_spec.rb +65 -48
  46. data/spec/skeem/primitive/primitive_procedure_spec.rb +14 -12
  47. data/spec/skeem/runtime_spec.rb +20 -18
  48. data/spec/skeem/s_expr_nodes_spec.rb +8 -6
  49. data/spec/skeem/skm_compound_datum_spec.rb +12 -10
  50. data/spec/skeem/skm_element_spec.rb +7 -5
  51. data/spec/skeem/skm_empty_list_spec.rb +7 -5
  52. data/spec/skeem/skm_frame_spec.rb +5 -4
  53. data/spec/skeem/skm_pair_spec.rb +9 -8
  54. data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
  55. data/spec/skeem/skm_simple_datum_spec.rb +24 -22
  56. data/spec/skeem/skm_unary_expression_spec.rb +11 -9
  57. data/spec/skeem/tokenizer_spec.rb +54 -43
  58. data/spec/skeem_spec.rb +2 -0
  59. data/spec/spec_helper.rb +15 -10
  60. metadata +18 -10
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_element'
2
4
 
3
5
  module Skeem
4
-
5
6
  # An identifier that is not a syntactic keyword can be used as a variable.
6
7
  # A variable may give a name to value that is bound (i.e. associated)
7
8
  # to that variable.
@@ -16,10 +17,13 @@ module Skeem
16
17
  # @param anIdentifier [SkmIdentifier] The variable name
17
18
  # @param aValue [SkmElement] The value to bind to the variable.
18
19
  def initialize(anIdentifier, aValue)
20
+ super(nil)
19
21
  @variable = anIdentifier
20
22
  @value = aValue
21
23
  end
22
24
 
25
+ # rubocop: disable Style/NegatedIfElseCondition
26
+
23
27
  def evaluate(aRuntime)
24
28
  name = variable.evaluate(aRuntime)
25
29
 
@@ -41,6 +45,7 @@ module Skeem
41
45
  binding_action(aRuntime, name, result)
42
46
  result
43
47
  end
48
+ # rubocop: enable Style/NegatedIfElseCondition
44
49
 
45
50
  protected
46
51
 
@@ -56,26 +61,19 @@ module Skeem
56
61
 
57
62
  result
58
63
  end
59
-
60
64
  end # class
61
65
 
62
-
63
66
  class SkmUpdateBinding < SkmBinding
64
-
65
67
  protected
66
68
 
67
69
  def binding_action(aRuntime, anIdentifier, anExpression)
68
70
  aRuntime.update_binding(anIdentifier, anExpression)
69
71
  end
70
72
  end # class
71
-
73
+
72
74
  class SkmDelayedUpdateBinding < SkmBinding
73
75
  attr_reader :new_val
74
-
75
- def initialize(anIdentifier, aValue)
76
- super(anIdentifier, aValue)
77
- end
78
-
76
+
79
77
  def do_it!(aRuntime)
80
78
  aRuntime.update_binding(variable, new_val)
81
79
  end
@@ -85,5 +83,5 @@ module Skeem
85
83
  def binding_action(_runtime, _identifier, anExpression)
86
84
  @new_val = anExpression
87
85
  end
88
- end # class
86
+ end # class
89
87
  end # module
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
  require_relative 'skm_element'
3
5
 
@@ -18,10 +20,11 @@ module Skeem
18
20
  end
19
21
 
20
22
  def ==(other)
21
- return true if self.equal?(other)
22
- result = case other
23
+ return true if equal?(other)
24
+
25
+ case other
23
26
  when SkmCompoundDatum
24
- self.class == other.class && self.members == other.members
27
+ self.class == other.class && members == other.members
25
28
  when Array
26
29
  members == other
27
30
  end
@@ -65,8 +68,8 @@ module Skeem
65
68
  protected
66
69
 
67
70
  def inspect_specific
68
- result = ''
69
- members.each { |elem| result << elem.inspect + ', ' }
71
+ result = +''
72
+ members.each { |elem| result << "#{elem.inspect}, " }
70
73
  result.sub!(/, $/, '')
71
74
  result
72
75
  end
@@ -77,4 +80,4 @@ module Skeem
77
80
  true
78
81
  end
79
82
  end # class
80
- end # module
83
+ end # module
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Skeem
2
4
  # Abstract class. Generalization of any S-expr element.
3
5
  SkmElement = Struct.new(:position) do
4
6
  def initialize(aPosition)
5
7
  self.position = aPosition
6
8
  end
7
-
9
+
8
10
  def callable?
9
11
  false
10
12
  end
@@ -12,15 +14,15 @@ module Skeem
12
14
  def number?
13
15
  false
14
16
  end
15
-
17
+
16
18
  def complex?
17
19
  false
18
- end
20
+ end
19
21
 
20
22
  def real?
21
23
  false
22
24
  end
23
-
25
+
24
26
  def rational?
25
27
  false
26
28
  end
@@ -32,7 +34,7 @@ module Skeem
32
34
  def boolean?
33
35
  false
34
36
  end
35
-
37
+
36
38
  def char?
37
39
  false
38
40
  end
@@ -56,7 +58,7 @@ module Skeem
56
58
  def pair?
57
59
  false
58
60
  end
59
-
61
+
60
62
  def procedure?
61
63
  false
62
64
  end
@@ -73,11 +75,11 @@ module Skeem
73
75
  msg = "Missing implementation of method #{self.class.name}##{__method__}"
74
76
  raise NotImplementedError, msg
75
77
  end
76
-
78
+
77
79
  def skm_eq?(other)
78
80
  # Default implementation, to override when necessary
79
- self.eqv?(other)
80
- end
81
+ eqv?(other)
82
+ end
81
83
 
82
84
  # @return [TrueClass, FalseClass] true if quoted element is identical to itself
83
85
  def verbatim?
@@ -117,8 +119,8 @@ module Skeem
117
119
  # Do nothing
118
120
  end
119
121
 
120
- def inspect
121
- result = inspect_prefix
122
+ def inspect
123
+ result = inspect_prefix.dup
122
124
  result << inspect_specific
123
125
  result << inspect_suffix
124
126
 
@@ -136,7 +138,7 @@ module Skeem
136
138
  end
137
139
 
138
140
  def inspect_specific
139
- raise NotImplementedError, "Missing #{self.class.to_s + '#' + 'inspect_specific'}"
141
+ raise NotImplementedError, "Missing #{self.class}#inspect_specific"
140
142
  end
141
143
  end # struct
142
- end # module
144
+ end # module
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
  require_relative 'skm_element'
3
5
 
@@ -42,7 +44,7 @@ module Skeem
42
44
  def klone
43
45
  self
44
46
  end
45
-
47
+
46
48
  def append_list(aList)
47
49
  aList
48
50
  end
@@ -64,14 +66,14 @@ module Skeem
64
66
  protected
65
67
 
66
68
  def inspect_specific
67
- '()'
69
+ +'()'
68
70
  end
69
71
 
70
72
  private
71
73
 
72
- def initialize()
74
+ def initialize
73
75
  super(0)
74
- self.freeze
76
+ freeze
75
77
  end
76
78
  end # class
77
79
  end # module
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skeem
4
+ class SkmException < RuntimeError
5
+ end # class
6
+
7
+ class SkmError < SkmException
8
+ end # class
9
+ end # module
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_element'
2
4
 
3
5
  module Skeem
4
6
  # Abstract class.
5
7
  class SkmExpression < SkmElement
6
8
  end # class
7
- end # module
9
+ end # module
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_simple_datum'
2
4
 
3
5
  module Skeem
@@ -139,6 +141,5 @@ module Skeem
139
141
  # Notify the value that it is bound to a variable from this frame.
140
142
  anExpression.bound!(self)
141
143
  end
142
-
143
144
  end # class
144
- end # module
145
+ end # module
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_empty_list'
2
4
 
3
5
  module Skeem
4
6
  class SkmPair < SkmElement
7
+ # @return [SkmElement]
5
8
  attr_accessor :car
9
+
10
+ # @return [SkmElement]
6
11
  attr_accessor :cdr
7
12
 
8
13
  alias first car
@@ -41,11 +46,12 @@ module Skeem
41
46
  def self.create_from_a(anArray)
42
47
  current = nil
43
48
  return SkmEmptyList.instance if anArray.empty?
49
+
44
50
  anArray.reverse_each do |elem|
45
51
  if current.nil?
46
- current = self.new(elem, SkmEmptyList.instance)
52
+ current = new(elem, SkmEmptyList.instance)
47
53
  else
48
- current = self.new(elem, current)
54
+ current = new(elem, current)
49
55
  end
50
56
  end
51
57
 
@@ -54,6 +60,7 @@ module Skeem
54
60
 
55
61
  def empty?
56
62
  return false if car
63
+
57
64
  if [SkmPair, SkmEmptyList].include? cdr.class
58
65
  cdr.empty?
59
66
  else
@@ -92,20 +99,20 @@ module Skeem
92
99
  end
93
100
 
94
101
  def last_pair
95
- if cdr.nil? || (cdr == SkmEmptyList.instance) || (!cdr.kind_of?(SkmPair))
102
+ if cdr.nil? || (cdr == SkmEmptyList.instance) || !cdr.kind_of?(SkmPair)
96
103
  self
97
104
  else
98
105
  cdr.last_pair
99
106
  end
100
107
  end
101
-
108
+
102
109
  def proper?
103
- last_node = self.last_pair
110
+ last_node = last_pair
104
111
  last_node.cdr.nil? || (last_node.cdr == SkmEmptyList.instance)
105
112
  end
106
113
 
107
114
  def last
108
- self.to_a.last
115
+ to_a.last
109
116
  end
110
117
 
111
118
  def eqv?(_other)
@@ -138,7 +145,7 @@ module Skeem
138
145
  end
139
146
 
140
147
  def append(anElement)
141
- last_one = self.last_pair
148
+ last_one = last_pair
142
149
  if last_one.cdr.nil? || last_one.cdr.kind_of?(SkmEmptyList)
143
150
  last_one.cdr = SkmPair.new(anElement, SkmEmptyList.instance)
144
151
  else
@@ -147,7 +154,7 @@ module Skeem
147
154
  end
148
155
 
149
156
  def append_list(aList)
150
- last_one = self.last_pair
157
+ last_one = last_pair
151
158
  if last_one.cdr.nil? || last_one.cdr.kind_of?(SkmEmptyList)
152
159
  last_one.cdr = aList
153
160
  else
@@ -157,22 +164,23 @@ module Skeem
157
164
 
158
165
  def evaluate(aRuntime)
159
166
  return SkmEmptyList.instance if empty?
167
+
160
168
  if car.kind_of?(SkmIdentifier) && car.is_var_name
161
169
  result = aRuntime.evaluate_form(self)
162
170
  else
163
171
  begin
164
172
  result = clone_evaluate(aRuntime)
165
- rescue NoMethodError => exc
166
- $stderr.puts 'SkmPair#evaluate: ' + self.inspect
167
- $stderr.puts 'SkmPair as Array: ' + self.to_a.inspect
168
- raise exc
173
+ rescue NoMethodError => e
174
+ $stderr.puts "SkmPair#evaluate: #{inspect}"
175
+ $stderr.puts "SkmPair as Array: #{to_a.inspect}"
176
+ raise e
169
177
  end
170
178
  end
171
179
  result
172
180
  end
173
181
 
174
182
  def quasiquote(aRuntime)
175
- members_eval = self.to_a.map { |elem| elem.quasiquote(aRuntime) }
183
+ members_eval = to_a.map { |elem| elem.quasiquote(aRuntime) }
176
184
  self.class.create_from_a(members_eval)
177
185
  end
178
186
 
@@ -184,16 +192,17 @@ module Skeem
184
192
 
185
193
  def quoted!
186
194
  car.quoted!
187
- cdr.quoted! if cdr
195
+ cdr&.quoted!
188
196
  end
189
197
 
190
198
  def unquoted!
191
199
  car.unquoted!
192
- cdr.unquoted! if cdr
200
+ cdr&.unquoted!
193
201
  end
194
202
 
195
- def verbatim?()
203
+ def verbatim?
196
204
  return false unless car.verbatim?
205
+
197
206
  if cdr.nil?
198
207
  true
199
208
  else
@@ -211,6 +220,5 @@ module Skeem
211
220
 
212
221
  result
213
222
  end
214
-
215
223
  end # class
216
- end # module
224
+ end # module
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'runtime'
2
4
 
3
5
  module Skeem
4
6
  class SkmProcedureExec
7
+ # @return [SkmFrame]
5
8
  attr_reader :frame
9
+
10
+ # @return [SkmLambda]
6
11
  attr_reader :definition
7
12
 
8
13
  def initialize(aLambda)
@@ -27,18 +32,18 @@ module Skeem
27
32
  result = definition.evaluate_sequence(runtime)
28
33
  runtime.pop
29
34
  # $stderr.puts "Lambda result: #{result.object_id.to_s(16)}" if result.kind_of?(SkmLambda)
30
-
35
+
31
36
  result
32
37
  end
33
-
38
+
34
39
  private
35
-
40
+
36
41
  def evaluate_defs(aRuntime)
37
42
  definition.definitions.each do |bndng|
38
- val = bndng.value.evaluate(aRuntime)
43
+ val = bndng.value.evaluate(aRuntime)
39
44
  var = bndng.variable.evaluate(aRuntime)
40
45
  frame.add_binding(var, val)
41
- end
46
+ end
42
47
  end
43
48
  end # class
44
- end # module
49
+ end # module
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_element'
2
4
 
3
5
  module Skeem
4
6
  # Abstract class. Root of class hierarchy needed for Interpreter
5
7
  # design pattern
6
8
  class SkmSimpleDatum < SkmElement
9
+ # @return [Rley::Syntax::Token] token object corresponding to Skeem element
7
10
  attr_reader :token
11
+
12
+ # @return [Object]
8
13
  attr_reader :value
9
14
 
10
15
  def initialize(aToken, aPosition)
@@ -14,7 +19,7 @@ module Skeem
14
19
  end
15
20
 
16
21
  def self.create(aValue)
17
- lightweight = self.allocate
22
+ lightweight = allocate
18
23
  lightweight.init_value(aValue)
19
24
  return lightweight
20
25
  end
@@ -33,15 +38,13 @@ module Skeem
33
38
  # @param other [SkmSimpleDatum, Object] object to compare with.
34
39
  # @return [TrueClass, FalseClass]
35
40
  def ==(other)
36
- return true if self.equal?(other)
37
-
38
- result = if other.kind_of?(SkmSimpleDatum)
39
- self.value == other.value
40
- else
41
- self.value == other
42
- end
41
+ return true if equal?(other)
43
42
 
44
- result
43
+ if other.kind_of?(SkmSimpleDatum)
44
+ value == other.value
45
+ else
46
+ value == other
47
+ end
45
48
  end
46
49
 
47
50
  alias eqv? ==
@@ -51,7 +54,7 @@ module Skeem
51
54
  true
52
55
  end
53
56
 
54
- def done!()
57
+ def done!
55
58
  # Do nothing
56
59
  end
57
60
 
@@ -102,21 +105,22 @@ module Skeem
102
105
  false
103
106
  end
104
107
 
108
+ # rubocop: disable Style/NegatedIfElseCondition
109
+
105
110
  def eqv?(other)
106
- return true if self.equal?(other)
111
+ return true if equal?(other)
107
112
 
108
- result = if other.kind_of?(SkmNumber)
109
- if self.exact? != other.exact?
113
+ if other.kind_of?(SkmNumber)
114
+ if exact? != other.exact?
110
115
  false
111
116
  else
112
- self.value == other.value
117
+ value == other.value
113
118
  end
114
119
  else
115
- self.value == other
120
+ value == other
116
121
  end
117
-
118
- result
119
122
  end
123
+ # rubocop: enable Style/NegatedIfElseCondition
120
124
  end # class
121
125
 
122
126
  class SkmReal < SkmNumber
@@ -159,7 +163,6 @@ module Skeem
159
163
  char_value = int_value < 0xff ? int_value.chr : [int_value].pack('U')
160
164
  create(char_value)
161
165
  end
162
-
163
166
  end # class
164
167
 
165
168
  class SkmString < SkmSimpleDatum
@@ -199,7 +202,7 @@ module Skeem
199
202
  end
200
203
 
201
204
  def verbatim?
202
- not is_var_name
205
+ !is_var_name
203
206
  end
204
207
 
205
208
  def quoted!
@@ -213,4 +216,4 @@ module Skeem
213
216
 
214
217
  class SkmReserved < SkmIdentifier
215
218
  end # class
216
- end # module
219
+ end # module