rus3 0.2.0 → 0.2.1

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
  SHA256:
3
- metadata.gz: 8b1f3c9f79ba7f452ff3a2f6d7ec904ac3a1e0ffd836bafd4b4892a8cb0b12ac
4
- data.tar.gz: 8c65e739832e954d9ca16fac40e437ca73bb3cddf48c35fbd3eb2f86658d8fd6
3
+ metadata.gz: 5309fbc8e935c7fea460f7084c02e36d082c17ec4f61f6343e5c340aacfa8eec
4
+ data.tar.gz: 30ad12bdae593004cf1d23e7f82676ae5b5b4f7e7c92d51857de1bc916d61452
5
5
  SHA512:
6
- metadata.gz: 9b87669992f65b1279ceb003d2767d7ae6173374c6d810c646ee2914643050514c483aadb81cebafbd505fbbea41b89e297e6026f20749e571e84b423bc3cc8c
7
- data.tar.gz: fec0ac13faa9880b10f6245d660b3e95430bfcd6cf48a65787634a55fe32c32e4e5f2eeb8f9321467c6a8dede5c03d34d7ab23ef0a0045de698e8bdf821c5534
6
+ metadata.gz: fe695566d2706dc9121278a76589085b46de790c0b8b6bfae7f9befaabb53239ffe52f4aa77e8311eb5648388d35f51130c4056020b80cb1cc8a2318908192c2
7
+ data.tar.gz: e70a4aef0e3d336f9fde29aa4a6030c75d4c53bd04f2c0b901f2506aa629d3ea10eff29f6674574ad4bb7b587a9ce723965aab51a18b206b402dd2b36056e1ff
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
  ## [Unreleased]
8
8
  - (nothing to record here)
9
9
 
10
+ ## [0.2.1] - 20201-05-20
11
+ ### Changed
12
+ - Use Rbscmlex instead of built-in lexer. (#6)
13
+ - Use Rubasteme instead of built-in AST and parser. (#6)
14
+
15
+ ### Fixed
16
+ - Fix #5: too old `required_ruby_version`.
17
+
10
18
  ## [0.2.0] - 2021-05-03
11
19
  ### Added
12
20
  - Re-write the parser and evaluator mechanism.
data/Gemfile.lock CHANGED
@@ -1,13 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rus3 (0.2.0)
4
+ rus3 (0.2.1)
5
+ rbscmlex (>= 0.1.3)
6
+ rubasteme (>= 0.1.3)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
8
10
  specs:
9
11
  minitest (5.14.4)
10
12
  rake (13.0.3)
13
+ rbscmlex (0.1.3)
14
+ rubasteme (0.1.3)
15
+ rbscmlex (>= 0.1.3)
11
16
 
12
17
  PLATFORMS
13
18
  x86_64-darwin-20
data/lib/rus3.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rbscmlex"
4
+ require "rubasteme"
5
+
3
6
  module Rus3
4
7
 
5
8
  # An empty list is a special object in Scheme language. The role
@@ -43,16 +46,14 @@ module Rus3
43
46
 
44
47
  require_relative "rus3/procedure/utils"
45
48
  require_relative "rus3/procedure/predicate"
49
+ require_relative "rus3/procedure/arithmetic"
50
+ require_relative "rus3/procedure/comparison"
46
51
  require_relative "rus3/procedure/char"
47
52
  require_relative "rus3/procedure/list"
48
53
  require_relative "rus3/procedure/vector"
49
54
  require_relative "rus3/procedure/control"
50
55
  require_relative "rus3/procedure/write"
51
56
 
52
- require_relative "rus3/ast"
53
- require_relative "rus3/token"
54
- require_relative "rus3/lexer"
55
- require_relative "rus3/parser"
56
57
  require_relative "rus3/evaluator"
57
58
  require_relative "rus3/printer"
58
59
  require_relative "rus3/repl"
@@ -11,6 +11,8 @@ module Rus3
11
11
  include Rus3::Procedure::List
12
12
  include Rus3::Procedure::Char
13
13
  include Rus3::Procedure::Predicate
14
+ include Rus3::Procedure::Comparison
15
+ include Rus3::Procedure::Arithmetic
14
16
  include Rus3::EmptyList
15
17
 
16
18
  attr_reader :binding
@@ -19,10 +19,9 @@ module Rus3
19
19
  super
20
20
 
21
21
  @env = Environment.new
22
- define_procs_for_infix_ops
23
-
24
22
  @translator = Translator.new
25
- @translator.add_procedure_map(INFIX_OPS_MAP)
23
+ @translator.add_procedure_map(ARITHMETIC_OPS_MAP)
24
+ @translator.add_procedure_map(COMPARISON_OPS_MAP)
26
25
  end
27
26
 
28
27
  def verbose=(verbose)
@@ -48,17 +47,20 @@ module Rus3
48
47
  @env.binding
49
48
  end
50
49
 
51
- INFIX_OPS_MAP = {
50
+ ARITHMETIC_OPS_MAP = {
52
51
  "+" => "add",
53
52
  "-" => "subtract",
54
53
  "*" => "mul",
55
54
  "/" => "div",
56
55
  "%" => "mod",
56
+ }
57
+
58
+ COMPARISON_OPS_MAP = {
57
59
  "<" => "lt?",
58
60
  "<=" => "le?",
59
61
  ">" => "gt?",
60
62
  ">=" => "ge?",
61
- "==" => "eqv?",
63
+ "=" => "same_value?",
62
64
  }
63
65
 
64
66
  private
@@ -67,13 +69,6 @@ module Rus3
67
69
  ast.map{|node| @translator.translate(node)}.join("\n")
68
70
  end
69
71
 
70
- def define_procs_for_infix_ops
71
- r = @env.binding.receiver
72
- INFIX_OPS_MAP.each { |op, proc_name|
73
- r.instance_eval("def #{proc_name}(op1, op2); op1 #{op} op2; end")
74
- }
75
- end
76
-
77
72
  end
78
73
  end
79
74
  end
@@ -36,7 +36,8 @@ module Rus3
36
36
  pp ast_node
37
37
  end
38
38
 
39
- method_name = "translate_#{ast_node.type}".intern
39
+ type = ast_node.type.to_s.delete_prefix("ast_")
40
+ method_name = "translate_#{type}".intern
40
41
  begin
41
42
  m = method(method_name)
42
43
  rescue
@@ -49,6 +50,10 @@ module Rus3
49
50
 
50
51
  private
51
52
 
53
+ def translate_empty_list(_)
54
+ EmptyList::EMPTY_LIST.to_s
55
+ end
56
+
52
57
  def translate_boolean(ast_node)
53
58
  case ast_node.literal[0..1]
54
59
  when "#f"
@@ -56,7 +61,7 @@ module Rus3
56
61
  when "#t"
57
62
  "true"
58
63
  else
59
- raise SchemeSyntaxError.new([:boolean, ast_node.to_s])
64
+ raise SchemeSyntaxError.new([:ast_boolean, ast_node.to_s])
60
65
  end
61
66
  end
62
67
 
@@ -96,13 +101,6 @@ module Rus3
96
101
  "#{converter}(\"#{ast_node.literal}\")"
97
102
  end
98
103
 
99
- def translate_peculiar_identifier(ast_node)
100
- op_literal = ast_node.literal == "=" ? "==" : ast_node.literal
101
- sym = @procedure_map[op_literal]
102
- raise Rus3::UnknownOperatorError, op_literal if sym.nil?
103
- sym.to_s
104
- end
105
-
106
104
  def translate_list(ast_node)
107
105
  elements = ast_node.map{|e| translate(e)}.join(", ")
108
106
  "[#{elements}]"
@@ -113,10 +111,33 @@ module Rus3
113
111
  "vector(#{obj_src})"
114
112
  end
115
113
 
114
+ def translate_quotation(ast_node)
115
+ propagate_quotation(ast_node[0])
116
+ end
117
+
118
+ def propagate_quotation(ast_node)
119
+ case ast_node.type
120
+ when :ast_list, :ast_procedure_call, :ast_lambda_expression, :ast_conditional, :ast_assignment
121
+ elements = ast_node.map{|child| propagate_quotation(child)}
122
+ "[" + elements.join(", ") + "]"
123
+ when :ast_vector
124
+ elements = ast_node.map{|child| propagate_quotation(child)}
125
+ "vector(" + elements.join(", ") + ")"
126
+ when :ast_boolean, :ast_character, :ast_string
127
+ translate(ast_node)
128
+ when :ast_number
129
+ translate_number(ast_node)
130
+ when :ast_identifier
131
+ ":#{ast_node.to_s}"
132
+ else
133
+ raise SchemeSyntaxError.new([ast_node.type, ast_node.to_s])
134
+ end
135
+ end
136
+
116
137
  def translate_procedure_call(ast_node)
117
138
  operands = ast_node.operands.map{|e| translate(e)}.join(", ")
118
139
  operator = translate(ast_node.operator)
119
- if ast_node.operator.type == :lambda_expression
140
+ if ast_node.operator.type == :ast_lambda_expression
120
141
  "#{operator}.call(#{operands})"
121
142
  else
122
143
  "#{operator}(#{operands})"
@@ -155,32 +176,9 @@ module Rus3
155
176
  "#{identifier} = #{expression}"
156
177
  end
157
178
 
158
- def translate_quotation(ast_node)
159
- propagate_quotation(ast_node[1])
160
- end
161
-
162
- def propagate_quotation(ast_node)
163
- case ast_node.type
164
- when :list, :procedure_call, :lambda_expression, :conditional, :assignment
165
- elements = ast_node.map{|child| propagate_quotation(child)}
166
- "[" + elements.join(", ") + "]"
167
- when :vector
168
- elements = ast_node.map{|child| propagate_quotation(child)}
169
- "vector(" + elements.join(", ") + ")"
170
- when :boolean, :character, :string
171
- translate(ast_node)
172
- when :number
173
- ast_node.to_s
174
- when :identifier, :peculiar_identifier
175
- ":#{ast_node.to_s}"
176
- else
177
- raise SchemeSyntaxError.new([ast_node.type, ast_node.to_s])
178
- end
179
- end
180
-
181
179
  def translate_identifier_definition(ast_node)
182
180
  name = translate_identifier(ast_node.identifier)
183
- if ast_node.expression.type == :lambda_expression
181
+ if ast_node.expression.type == :ast_lambda_expression
184
182
  def_formals = translate_formals(ast_node.expression)
185
183
  body = translate_body(ast_node.expression)
186
184
  "def #{name}(#{def_formals}); #{body}; end"
@@ -229,11 +227,31 @@ module Rus3
229
227
  "#{test_src}; #{exps_src}"
230
228
  end
231
229
 
230
+ def translate_case(ast_node)
231
+ "not implemented yet"
232
+ end
233
+
234
+ def translate_and(ast_node)
235
+ "not implemented yet"
236
+ end
237
+
238
+ def translate_or(ast_node)
239
+ "not implemented yet"
240
+ end
241
+
242
+ def translate_when(ast_node)
243
+ "not implemented yet"
244
+ end
245
+
246
+ def translate_unless(ast_node)
247
+ "not implemented yet"
248
+ end
249
+
232
250
  def translate_let(ast_node)
233
251
  formals = []
234
252
  args = []
235
253
 
236
- ast_node.bind_specs.each { |spec|
254
+ ast_node.bindings.each { |spec|
237
255
  formals << translate_identifier(spec.identifier)
238
256
  args << translate(spec.expression)
239
257
  }
@@ -243,6 +261,26 @@ module Rus3
243
261
  "lambda{|#{formals.join(', ')}| #{body}}.call(#{args.join(', ')})"
244
262
  end
245
263
 
264
+ def translate_let_star(ast_node)
265
+ "not implemented yet"
266
+ end
267
+
268
+ def translate_letrec(ast_node)
269
+ "not implemented yet"
270
+ end
271
+
272
+ def translate_letrec_star(ast_node)
273
+ "not implemented yet"
274
+ end
275
+
276
+ def translate_begin(ast_node)
277
+ "not implemented yet"
278
+ end
279
+
280
+ def translate_do(ast_node)
281
+ "not implemented yet"
282
+ end
283
+
246
284
  RB_KEYWORDS_MAP = {
247
285
  "BEGIN" => nil,
248
286
  "END" => nil,
@@ -295,7 +333,7 @@ module Rus3
295
333
  ">=" => "ge",
296
334
  }
297
335
 
298
- EXTENDED_REGEXP = Regexp.new("[#{Rus3::Lexer::EXTENDED_CHARS}]")
336
+ EXTENDED_REGEXP = Regexp.new("[!\\$%&\\*\\+\\-\\./:<=>\\?@\\^_~]")
299
337
 
300
338
  EXTENDED_CHARS_MAP = {
301
339
  "!" => "!", # no conversion
@@ -319,16 +357,21 @@ module Rus3
319
357
  }
320
358
 
321
359
  def replace_extended_char(literal)
322
- result = literal
323
-
324
- COMPARISON_OPS_MAP.each { |op, word|
325
- comparison_regexp = Regexp.new("#{op}\\?\\Z")
326
- if comparison_regexp === literal
327
- result = literal.sub(comparison_regexp, "_#{word}?")
328
- end
329
- }
330
-
331
- result.gsub(EXTENDED_REGEXP, EXTENDED_CHARS_MAP)
360
+ case literal
361
+ when /\A[+\-*\/%=]\Z/, /\A[<>]=?\Z/
362
+ md = Regexp.last_match
363
+ @procedure_map[md.to_s]
364
+ else
365
+ result = literal
366
+ COMPARISON_OPS_MAP.each { |op, word|
367
+ comparison_regexp = Regexp.new("#{op}\\?\\Z")
368
+ if comparison_regexp === literal
369
+ result = literal.sub(comparison_regexp, "_#{word}?")
370
+ end
371
+ }
372
+
373
+ result.gsub(EXTENDED_REGEXP, EXTENDED_CHARS_MAP)
374
+ end
332
375
  end
333
376
 
334
377
  # :startdoc:
data/lib/rus3/printer.rb CHANGED
@@ -4,23 +4,59 @@ module Rus3
4
4
  module Printer
5
5
 
6
6
  # Indicates the version of the printer module.
7
- VERSION = "0.1.0"
7
+ VERSION = "0.2.1"
8
8
 
9
9
  class Printer
10
- include Rus3::Procedure::Write
11
-
12
10
  attr_accessor :verbose
13
11
 
14
12
  def initialize
15
13
  @verbose = false
16
14
  end
17
15
 
16
+ def self.version
17
+ ""
18
+ end
19
+ end
20
+
21
+ class RubyPrinter < Printer
22
+ def print(obj)
23
+ prefix = "==> "
24
+ prefix += "[#{obj.class}]: " if @verbose
25
+ Kernel.print prefix
26
+ pp obj
27
+ end
28
+
29
+ def self.version
30
+ "ruby-object-printer :version #{VERSION}"
31
+ end
32
+ end
33
+
34
+ class SchemePrinter < Printer
35
+ include Rus3::Procedure::Write
36
+
18
37
  def print(obj)
19
38
  display(obj)
20
39
  end
21
40
 
22
- def version
23
- "Printer version #{VERSION}"
41
+ def self.version
42
+ "scheme-printer :version #{VERSION}"
43
+ end
44
+ end
45
+
46
+ class ChainPrinter < Printer
47
+ CHAIN = [RubyPrinter.new, SchemePrinter.new]
48
+
49
+ def self.version
50
+ chain_printers = CHAIN.map{|e| e.class}
51
+ "chain-printer :version #{VERSION} :chain (#{chain_printers})"
52
+ end
53
+
54
+ def verbose=(flag)
55
+ CHAIN.each{|printer| printer.verbose = flag}
56
+ end
57
+
58
+ def print(obj)
59
+ CHAIN.each{|printer| printer.print(obj)}
24
60
  end
25
61
  end
26
62
 
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+ module Procedure
5
+
6
+ # This module holds arithmetic operation procedures of Scheme.
7
+
8
+ module Arithmetic
9
+
10
+ def add(*args)
11
+ a_calc(:+, *args)
12
+ end
13
+
14
+ def subtract(*args)
15
+ a_calc(:-, *args)
16
+ end
17
+
18
+ def mul(*args)
19
+ a_calc(:*, *args)
20
+ end
21
+
22
+ def div(*args)
23
+ a_calc(:/, *args)
24
+ end
25
+
26
+ def mod(*args)
27
+ a_calc(:%, *args)
28
+ end
29
+
30
+ private
31
+
32
+ def a_calc(op, *args)
33
+ case args.size
34
+ when 0
35
+ 0
36
+ when 1
37
+ args[0]
38
+ else
39
+ a_calc(op, args[0].send(op, args[1]), *args[2..-1])
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end