rus3 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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