rus3 0.2.0 → 0.2.1

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