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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -6
- data/exe/rus3 +26 -2
- data/lib/rus3.rb +3 -0
- data/lib/rus3/ast.rb +70 -0
- data/lib/rus3/ast/branch_node.rb +412 -0
- data/lib/rus3/ast/error.rb +8 -0
- data/lib/rus3/ast/leaf_node.rb +55 -0
- data/lib/rus3/error.rb +15 -1
- data/lib/rus3/evaluator.rb +38 -54
- data/lib/rus3/evaluator/environment.rb +25 -0
- data/lib/rus3/evaluator/scheme_evaluator.rb +79 -0
- data/lib/rus3/evaluator/translator.rb +337 -0
- data/lib/rus3/{parser/lexer.rb → lexer.rb} +22 -52
- data/lib/rus3/parser.rb +39 -23
- data/lib/rus3/parser/scheme_parser.rb +595 -306
- data/lib/rus3/procedure/char.rb +21 -17
- data/lib/rus3/procedure/control.rb +28 -24
- data/lib/rus3/procedure/list.rb +210 -207
- data/lib/rus3/procedure/predicate.rb +267 -264
- data/lib/rus3/procedure/utils.rb +20 -16
- data/lib/rus3/procedure/vector.rb +68 -65
- data/lib/rus3/procedure/write.rb +107 -103
- data/lib/rus3/repl.rb +57 -47
- data/lib/rus3/token.rb +35 -0
- data/lib/rus3/version.rb +2 -2
- metadata +11 -3
@@ -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] %
|
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
|
data/lib/rus3/evaluator.rb
CHANGED
@@ -2,76 +2,60 @@
|
|
2
2
|
|
3
3
|
module Rus3
|
4
4
|
|
5
|
-
|
5
|
+
module Evaluator
|
6
|
+
require_relative "evaluator/environment"
|
6
7
|
|
7
|
-
|
8
|
+
# Indicates the version of the evaluator module.
|
9
|
+
VERSION = "0.2.0"
|
8
10
|
|
9
|
-
#
|
10
|
-
|
11
|
+
# An evaluator.
|
12
|
+
class Evaluator
|
11
13
|
|
12
|
-
|
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
|
-
@
|
17
|
+
@verbose = false
|
27
18
|
end
|
28
19
|
|
29
|
-
|
20
|
+
def verbose=(verbose)
|
21
|
+
@verbose = verbose
|
22
|
+
end
|
30
23
|
|
31
|
-
|
24
|
+
def instance_eval(&proc)
|
25
|
+
super
|
26
|
+
end
|
32
27
|
|
33
|
-
|
28
|
+
def eval(ast); nil; end
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
47
|
-
|
48
|
-
end
|
36
|
+
class PassthroughEvaluator < Evaluator
|
37
|
+
EVALUATOR_VERSION = "0.1.0"
|
49
38
|
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|