rus3 0.1.2 → 0.2.0

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.
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+ module AST
5
+ class Error < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+ module AST
5
+
6
+ class LeafNode < Node
7
+ def leaf?
8
+ true
9
+ end
10
+ end
11
+
12
+ class BooleanNode < LeafNode
13
+ def type
14
+ :boolean
15
+ end
16
+ end
17
+
18
+ class IdentifierNode < LeafNode
19
+ def type
20
+ :identifier
21
+ end
22
+ end
23
+
24
+ class PeculiarIdentifierNode < IdentifierNode
25
+ def type
26
+ :peculiar_identifier
27
+ end
28
+ end
29
+
30
+ class CharacterNode < LeafNode
31
+ def type
32
+ :character
33
+ end
34
+ end
35
+
36
+ class StringNode < LeafNode
37
+ def type
38
+ :string
39
+ end
40
+ end
41
+
42
+ class NumberNode < LeafNode
43
+ def type
44
+ :number
45
+ end
46
+ end
47
+
48
+ class DotNode < LeafNode
49
+ def type
50
+ :dot
51
+ end
52
+ end
53
+
54
+ end
55
+ end
data/lib/rus3/error.rb CHANGED
@@ -46,6 +46,8 @@ module Rus3
46
46
  :unsupported_method => "specified method does not work now.",
47
47
  :unsupported_feature => "specified feature (`%s`) does not support for %s",
48
48
  :cannot_find_file => "cannot find %s",
49
+ :not_implemented_yet => "not implemented yet (%s)",
50
+ :unknown_operator => "unknown operator: got=%s",
49
51
  }
50
52
 
51
53
  # :startdoc:
@@ -125,7 +127,7 @@ module Rus3
125
127
 
126
128
  class SchemeSyntaxError < Error
127
129
  def initialize(obj)
128
- super(EMSG[:scheme_syntax_error] % smart_error_value(obj))
130
+ super(EMSG[:scheme_syntax_error] % "#{obj[1]} as #{obj[0]}")
129
131
  end
130
132
  end
131
133
 
@@ -147,4 +149,16 @@ module Rus3
147
149
  end
148
150
  end
149
151
 
152
+ class NotImplementedYetError < Error
153
+ def initialize(feature)
154
+ super(EMSG[:not_implemented_yet] % feature)
155
+ end
156
+ end
157
+
158
+ class UknownOperatorError < Error
159
+ def initialize(operator)
160
+ super(EMSG[:unknown_operator] % operator)
161
+ end
162
+ end
163
+
150
164
  end
@@ -2,76 +2,60 @@
2
2
 
3
3
  module Rus3
4
4
 
5
- # An evaluator.
5
+ module Evaluator
6
+ require_relative "evaluator/environment"
6
7
 
7
- class Evaluator
8
+ # Indicates the version of the evaluator module.
9
+ VERSION = "0.2.0"
8
10
 
9
- # Indicates the version of the evaluator class.
10
- VERSION = "0.1.0"
11
+ # An evaluator.
12
+ class Evaluator
11
13
 
12
- include EmptyList
13
-
14
- class Environment
15
- include Rus3::Procedure::Control
16
- include Rus3::Procedure::Write
17
- include Rus3::Procedure::Vector
18
- include Rus3::Procedure::List
19
- include Rus3::Procedure::Char
20
- include Rus3::Procedure::Predicate
21
- include Rus3::EmptyList
22
-
23
- attr_reader :binding
14
+ attr_reader :verbose
24
15
 
25
16
  def initialize
26
- @binding = Kernel.binding
17
+ @verbose = false
27
18
  end
28
19
 
29
- end
20
+ def verbose=(verbose)
21
+ @verbose = verbose
22
+ end
30
23
 
31
- attr_accessor :verbose
24
+ def instance_eval(&proc)
25
+ super
26
+ end
32
27
 
33
- attr_reader :environment
28
+ def eval(ast); nil; end
34
29
 
35
- def initialize
36
- @verbose = false
37
- @env = Environment.new
38
- define_procs_for_infix_ops
39
- end
30
+ def version
31
+ "evaluator-module version: #{VERSION}"
32
+ end
40
33
 
41
- def eval(exp)
42
- pp exp if @verbose
43
- @env.binding.eval(exp)
44
34
  end
45
35
 
46
- def binding
47
- @env.binding
48
- end
36
+ class PassthroughEvaluator < Evaluator
37
+ EVALUATOR_VERSION = "0.1.0"
49
38
 
50
- def version
51
- "Evaluator version: #{VERSION}"
52
- end
39
+ def version
40
+ super + " (pass-through-evaluator version: #{EVALUATOR_VERSION})"
41
+ end
42
+
43
+ def eval(ast)
44
+ if @verbose
45
+ ast.each { |node|
46
+ print " evaluator(pass-through): "
47
+ pp node
48
+ }
49
+ end
50
+ ast.to_s
51
+ end
53
52
 
54
- private
55
-
56
- INFIX_OPS = {
57
- :+ => :add,
58
- :- => :subtract,
59
- :* => :mul,
60
- :/ => :div,
61
- :% => :mod,
62
- :< => :lt?,
63
- :<= => :le?,
64
- :> => :gt?,
65
- :>= => :ge?,
66
- :== => :eqv?,
67
- }
68
-
69
- def define_procs_for_infix_ops
70
- r = @env.binding.receiver
71
- INFIX_OPS.each { |op, proc_name|
72
- r.instance_eval("def #{proc_name}(op1, op2); op1 #{op} op2; end")
73
- }
74
53
  end
75
54
 
55
+ require_relative "evaluator/scheme_evaluator"
56
+ require_relative "evaluator/translator"
57
+
58
+ DEFAULT_EVALUATOR = SchemeEvaluator # :nodoc:
59
+
76
60
  end
77
61
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+
5
+ module Evaluator
6
+
7
+ class Environment
8
+ include Rus3::Procedure::Control
9
+ include Rus3::Procedure::Write
10
+ include Rus3::Procedure::Vector
11
+ include Rus3::Procedure::List
12
+ include Rus3::Procedure::Char
13
+ include Rus3::Procedure::Predicate
14
+ include Rus3::EmptyList
15
+
16
+ attr_reader :binding
17
+
18
+ def initialize
19
+ @binding = Kernel.binding
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+
5
+ module Evaluator
6
+
7
+ class SchemeEvaluator < Evaluator
8
+ EVALUATOR_VERSION = "0.2.0"
9
+
10
+ def version
11
+ vmsg = "(scheme-evaluator :version #{EVALUATOR_VERSION})"
12
+ if @translator
13
+ vmsg += " #{@translator.version}"
14
+ end
15
+ super + " (#{vmsg})"
16
+ end
17
+
18
+ def initialize
19
+ super
20
+
21
+ @env = Environment.new
22
+ define_procs_for_infix_ops
23
+
24
+ @translator = Translator.new
25
+ @translator.add_procedure_map(INFIX_OPS_MAP)
26
+ end
27
+
28
+ def verbose=(verbose)
29
+ super
30
+ @translator and @translator.verbose = verbose
31
+ end
32
+
33
+ def instance_variable_set(var, value)
34
+ @env.binding.receiver.instance_variable_set(var, value)
35
+ end
36
+
37
+ def instance_eval(&proc)
38
+ @env.binding.receiver.instance_eval(&proc)
39
+ end
40
+
41
+ def eval(ast)
42
+ ruby_source = translate_ast(ast)
43
+ pp ruby_source if @verbose
44
+ @env.binding.eval(ruby_source)
45
+ end
46
+
47
+ def binding
48
+ @env.binding
49
+ end
50
+
51
+ INFIX_OPS_MAP = {
52
+ "+" => "add",
53
+ "-" => "subtract",
54
+ "*" => "mul",
55
+ "/" => "div",
56
+ "%" => "mod",
57
+ "<" => "lt?",
58
+ "<=" => "le?",
59
+ ">" => "gt?",
60
+ ">=" => "ge?",
61
+ "==" => "eqv?",
62
+ }
63
+
64
+ private
65
+
66
+ def translate_ast(ast)
67
+ ast.map{|node| @translator.translate(node)}.join("\n")
68
+ end
69
+
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
+ end
78
+ end
79
+ end
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rus3
4
+
5
+ module Evaluator
6
+
7
+ # A class to translate an i-exp to r-exp.
8
+
9
+ class Translator
10
+ TRANSLATOR_VERSION = "0.1.0"
11
+
12
+ def version
13
+ "(scheme-ruby-translator :version #{TRANSLATOR_VERSION})"
14
+ end
15
+
16
+ def initialize
17
+ @verbose = false
18
+ @procedure_map = {}
19
+ end
20
+
21
+ def verbose=(verbose)
22
+ @verbose = verbose
23
+ end
24
+
25
+ def add_procedure_map(map)
26
+ @procedure_map.merge!(map)
27
+ end
28
+
29
+ # Translates an AST node into Ruby code.
30
+
31
+ def translate(ast_node)
32
+ return nil if ast_node.nil?
33
+
34
+ if @verbose
35
+ print "- translater ==> "
36
+ pp ast_node
37
+ end
38
+
39
+ method_name = "translate_#{ast_node.type}".intern
40
+ begin
41
+ m = method(method_name)
42
+ rescue
43
+ raise SchemeSyntaxError.new([ast_node.type, ast_node.to_s])
44
+ end
45
+ m.call(ast_node)
46
+ end
47
+
48
+ # :stopdoc:
49
+
50
+ private
51
+
52
+ def translate_boolean(ast_node)
53
+ case ast_node.literal[0..1]
54
+ when "#f"
55
+ "false"
56
+ when "#t"
57
+ "true"
58
+ else
59
+ raise SchemeSyntaxError.new([:boolean, ast_node.to_s])
60
+ end
61
+ end
62
+
63
+ def translate_identifier(ast_node)
64
+ replace_extended_char(ast_node.literal)
65
+ end
66
+
67
+ def translate_character(ast_node)
68
+ character = ast_node.literal[2..-1]
69
+ case character
70
+ when "space"
71
+ character = " "
72
+ when "newline"
73
+ character = "\n"
74
+ end
75
+ "Char.new(\"#{character}\")"
76
+ end
77
+
78
+ def translate_string(ast_node)
79
+ "#{ast_node.literal}"
80
+ end
81
+
82
+ def translate_number(ast_node)
83
+ converter = nil
84
+ case ast_node.literal
85
+ when /\A0\Z/
86
+ converter = "Integer"
87
+ when /\A[+-]?[1-9][0-9]*\Z/ # 123
88
+ converter = "Integer"
89
+ when /\A[+-]?([0-9]?|[1-9][0-9]*)\.[0-9]+\Z/ # 0.123 or 123.456
90
+ converter = "Float"
91
+ when /\A[+-]?[0-9]+\/[1-9][0-9]*\Z/ # 1/2
92
+ converter = "Rational"
93
+ else
94
+ converter = "Complex"
95
+ end
96
+ "#{converter}(\"#{ast_node.literal}\")"
97
+ end
98
+
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
+ def translate_list(ast_node)
107
+ elements = ast_node.map{|e| translate(e)}.join(", ")
108
+ "[#{elements}]"
109
+ end
110
+
111
+ def translate_vector(ast_node)
112
+ obj_src = ast_node.map{|e| translate(e)}.join(", ")
113
+ "vector(#{obj_src})"
114
+ end
115
+
116
+ def translate_procedure_call(ast_node)
117
+ operands = ast_node.operands.map{|e| translate(e)}.join(", ")
118
+ operator = translate(ast_node.operator)
119
+ if ast_node.operator.type == :lambda_expression
120
+ "#{operator}.call(#{operands})"
121
+ else
122
+ "#{operator}(#{operands})"
123
+ end
124
+ end
125
+
126
+ def translate_lambda_expression(ast_node)
127
+ formals = translate_formals(ast_node)
128
+ body = translate_body(ast_node)
129
+ "lambda{|#{formals}| #{body}}"
130
+ end
131
+
132
+ def translate_formals(ast_node)
133
+ ast_node.formals.map{|node| translate_identifier(node)}.join(", ")
134
+ end
135
+
136
+ def translate_body(ast_node)
137
+ ast_node.body.map{|node| translate(node)}.join("; ")
138
+ end
139
+
140
+ def translate_conditional(ast_node)
141
+ test = translate(ast_node.test)
142
+ consequent = translate(ast_node.consequent)
143
+ alternate = translate(ast_node.alternate)
144
+ rb_src = "if #{test}; #{consequent}"
145
+ if alternate
146
+ rb_src += "; else; #{alternate}"
147
+ end
148
+ rb_src += "; end"
149
+ rb_src
150
+ end
151
+
152
+ def translate_assignment(ast_node)
153
+ identifier = translate_identifier(ast_node.identifier)
154
+ expression = translate(ast_node.expression)
155
+ "#{identifier} = #{expression}"
156
+ end
157
+
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
+ def translate_identifier_definition(ast_node)
182
+ name = translate_identifier(ast_node.identifier)
183
+ if ast_node.expression.type == :lambda_expression
184
+ def_formals = translate_formals(ast_node.expression)
185
+ body = translate_body(ast_node.expression)
186
+ "def #{name}(#{def_formals}); #{body}; end"
187
+ else
188
+ rb_value = translate(ast_node.expression)
189
+ "#{name} = #{rb_value}"
190
+ end
191
+ end
192
+
193
+ def translate_cond(ast_node)
194
+ test_and_exps = ast_node.cond_clauses.map{|e| translate(e)}
195
+
196
+ first = intermediate = last = nil
197
+
198
+ first = test_and_exps[0]
199
+
200
+ if test_and_exps.size > 1
201
+ last = test_and_exps[-1]
202
+ end
203
+
204
+ if test_and_exps.size > 2
205
+ intermediate = test_and_exps[1..-2]
206
+ end
207
+
208
+ rb_src = []
209
+ rb_src << "if #{first}"
210
+
211
+ if intermediate
212
+ rb_src.concat(intermediate.map{|e| " elsif #{e}"})
213
+ end
214
+
215
+ if last
216
+ if /\Aelse/ === last
217
+ rb_src << " #{last}"
218
+ else
219
+ rb_src << " elsif #{last}"
220
+ end
221
+ end
222
+
223
+ rb_src.join(";") + "; end"
224
+ end
225
+
226
+ def translate_cond_clause(ast_node)
227
+ test_src = translate(ast_node.test)
228
+ exps_src = ast_node.sequence.map{|e| translate(e)}.join(";")
229
+ "#{test_src}; #{exps_src}"
230
+ end
231
+
232
+ def translate_let(ast_node)
233
+ formals = []
234
+ args = []
235
+
236
+ ast_node.bind_specs.each { |spec|
237
+ formals << translate_identifier(spec.identifier)
238
+ args << translate(spec.expression)
239
+ }
240
+
241
+ body = translate_body(ast_node)
242
+
243
+ "lambda{|#{formals.join(', ')}| #{body}}.call(#{args.join(', ')})"
244
+ end
245
+
246
+ RB_KEYWORDS_MAP = {
247
+ "BEGIN" => nil,
248
+ "END" => nil,
249
+ "alias" => nil,
250
+ "and" => nil,
251
+ "begin" => nil,
252
+ "break" => nil,
253
+ "case" => nil,
254
+ "class" => nil,
255
+ "def" => nil,
256
+ "defined?" => nil,
257
+ "do" => nil,
258
+ "else" => nil,
259
+ "elsif" => nil,
260
+ "end" => nil,
261
+ "ensure" => nil,
262
+ "false" => nil,
263
+ "for" => nil,
264
+ "if" => nil,
265
+ "in" => nil,
266
+ "module" => nil,
267
+ "next" => nil,
268
+ "nil" => nil,
269
+ "not" => nil,
270
+ "or" => nil,
271
+ "redo" => nil,
272
+ "rescue" => nil,
273
+ "retry" => nil,
274
+ "return" => nil,
275
+ "self" => nil,
276
+ "super" => nil,
277
+ "then" => nil,
278
+ "true" => nil,
279
+ "undef" => nil,
280
+ "unless" => nil,
281
+ "until" => nil,
282
+ "when" => nil,
283
+ "while" => nil,
284
+ "yield" => nil,
285
+ "__LINE__" => nil,
286
+ "__FILE__" => nil,
287
+ "__ENCODING__" => nil,
288
+ }
289
+
290
+ COMPARISON_OPS_MAP = {
291
+ "=" => "eq",
292
+ "<" => "lt",
293
+ ">" => "gt",
294
+ "<=" => "le",
295
+ ">=" => "ge",
296
+ }
297
+
298
+ EXTENDED_REGEXP = Regexp.new("[#{Rus3::Lexer::EXTENDED_CHARS}]")
299
+
300
+ EXTENDED_CHARS_MAP = {
301
+ "!" => "!", # no conversion
302
+ "$" => "$", # no conversion
303
+ "%" => "%", # no conversion
304
+ "&" => "&", # no conversion
305
+ "*" => "*", # no conversion
306
+ "+" => "+", # no conversion
307
+ "-" => "_",
308
+ "." => ".", # no conversion
309
+ "/" => "/", # no conversion
310
+ ":" => ":", # no conversion
311
+ "<" => "<", # no conversion
312
+ "=" => "=", # no conversion
313
+ ">" => "to_",
314
+ "?" => "?", # no conversion
315
+ "@" => "@", # no conversion
316
+ "^" => "^", # no conversion
317
+ "_" => "_", # no conversion
318
+ "~" => "~", # no conversion
319
+ }
320
+
321
+ 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)
332
+ end
333
+
334
+ # :startdoc:
335
+ end
336
+ end
337
+ end