resyma 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +31 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +69 -0
- data/LICENSE +674 -0
- data/README.md +167 -0
- data/Rakefile +8 -0
- data/lib/resyma/core/algorithm/engine.rb +189 -0
- data/lib/resyma/core/algorithm/matcher.rb +48 -0
- data/lib/resyma/core/algorithm/tuple.rb +25 -0
- data/lib/resyma/core/algorithm.rb +5 -0
- data/lib/resyma/core/automaton/builder.rb +78 -0
- data/lib/resyma/core/automaton/definition.rb +32 -0
- data/lib/resyma/core/automaton/epsilon_NFA.rb +115 -0
- data/lib/resyma/core/automaton/matchable.rb +16 -0
- data/lib/resyma/core/automaton/regexp.rb +175 -0
- data/lib/resyma/core/automaton/state.rb +22 -0
- data/lib/resyma/core/automaton/transition.rb +58 -0
- data/lib/resyma/core/automaton/visualize.rb +23 -0
- data/lib/resyma/core/automaton.rb +9 -0
- data/lib/resyma/core/parsetree/builder.rb +89 -0
- data/lib/resyma/core/parsetree/converter.rb +61 -0
- data/lib/resyma/core/parsetree/default_converter.rb +331 -0
- data/lib/resyma/core/parsetree/definition.rb +77 -0
- data/lib/resyma/core/parsetree/source.rb +73 -0
- data/lib/resyma/core/parsetree/traversal.rb +26 -0
- data/lib/resyma/core/parsetree.rb +8 -0
- data/lib/resyma/core/utilities.rb +30 -0
- data/lib/resyma/language.rb +290 -0
- data/lib/resyma/nise/date.rb +53 -0
- data/lib/resyma/nise/rubymoji.rb +13 -0
- data/lib/resyma/nise/toml.rb +63 -0
- data/lib/resyma/parsetree.rb +163 -0
- data/lib/resyma/program/automaton.rb +84 -0
- data/lib/resyma/program/parsetree.rb +79 -0
- data/lib/resyma/program/traverse.rb +77 -0
- data/lib/resyma/version.rb +5 -0
- data/lib/resyma.rb +12 -0
- data/resyma.gemspec +47 -0
- data/sig/resyma.rbs +4 -0
- metadata +184 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
require "resyma/core/parsetree/definition"
|
2
|
+
require "resyma/core/parsetree/converter"
|
3
|
+
|
4
|
+
module Resyma
|
5
|
+
module Core
|
6
|
+
DEFAULT_CONVERTER = Converter.new
|
7
|
+
|
8
|
+
CONST_TOKEN_TABLE = {
|
9
|
+
"(" => :round_left,
|
10
|
+
")" => :round_right,
|
11
|
+
"begin" => :kwd_begin,
|
12
|
+
"end" => :kwd_end,
|
13
|
+
"," => :comma,
|
14
|
+
"[" => :square_left,
|
15
|
+
"]" => :square_right,
|
16
|
+
"*" => :star,
|
17
|
+
"**" => :star2,
|
18
|
+
":" => :colon,
|
19
|
+
"=>" => :arrow,
|
20
|
+
"{" => :curly_left,
|
21
|
+
"}" => :curly_right,
|
22
|
+
".." => :dot2,
|
23
|
+
"..." => :dot3,
|
24
|
+
"defined?" => :kwd_defined?,
|
25
|
+
"." => :dot,
|
26
|
+
"&." => :and_dot,
|
27
|
+
"do" => :kwd_do,
|
28
|
+
"&" => :ampersand,
|
29
|
+
"|" => :tube,
|
30
|
+
"=" => :eq,
|
31
|
+
"true" => :the_true,
|
32
|
+
"false" => :the_false,
|
33
|
+
"nil" => :the_nil
|
34
|
+
}.freeze
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Resyma::Core::DEFAULT_CONVERTER.instance_eval do
|
39
|
+
|
40
|
+
def make_token(type, value, parent, index, ast)
|
41
|
+
Resyma::Core::ParseTree.new(type, [value], parent, index, true, ast)
|
42
|
+
end
|
43
|
+
|
44
|
+
def_fallback do |ast, parent, index|
|
45
|
+
make_token(:any, ast.type.to_s, parent, index, ast)
|
46
|
+
end
|
47
|
+
|
48
|
+
simple_literal = {
|
49
|
+
true: :the_true,
|
50
|
+
false: :the_false,
|
51
|
+
nil: :the_nil,
|
52
|
+
complex: :complex,
|
53
|
+
rational: :rational,
|
54
|
+
str: :str,
|
55
|
+
regexp: :regexp,
|
56
|
+
sym: :sym,
|
57
|
+
self: :the_self,
|
58
|
+
lvar: :id,
|
59
|
+
ivar: :ivar,
|
60
|
+
cvar: :cvar,
|
61
|
+
gvar: :gvar,
|
62
|
+
nth_ref: :nth_ref,
|
63
|
+
back_ref: :back_ref
|
64
|
+
}
|
65
|
+
|
66
|
+
def_rule simple_literal.keys do |ast, parent, index|
|
67
|
+
make_token simple_literal[ast.type], ast.loc.expression.source,
|
68
|
+
parent, index, ast
|
69
|
+
end
|
70
|
+
|
71
|
+
number_regexp = /^\s*(\+|-)?\s*([0-9.]+)\s*$/
|
72
|
+
def_rule %i[int float] do |ast, parent, index|
|
73
|
+
m = number_regexp.match(ast.loc.expression.source)
|
74
|
+
if m.nil?
|
75
|
+
raise Resyma::Core::ConversionError,
|
76
|
+
"Internal error: Number pattern [#{ast.loc.expression}] is invalid"
|
77
|
+
end
|
78
|
+
Resyma::Core::ParseTreeBuilder.root(ast.type, nil, index, ast) do
|
79
|
+
leaf :numop, m[1] unless m[1].nil?
|
80
|
+
leaf :numbase, m[2]
|
81
|
+
end.build(parent)
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_boundary(boundary, pt_builder)
|
85
|
+
return if boundary.nil?
|
86
|
+
|
87
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
88
|
+
value = boundary.source
|
89
|
+
type = ctt[value]
|
90
|
+
if type.nil?
|
91
|
+
raise Resyma::Core::ConversionError,
|
92
|
+
"Unknwon boundary-token of AST with type <begin>: #{value}"
|
93
|
+
end
|
94
|
+
pt_builder.add_child!(type, nil, true, [value])
|
95
|
+
end
|
96
|
+
|
97
|
+
def_rule %i[begin kwbegin] do |ast, parent, index|
|
98
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(:begin, index, false, [], ast)
|
99
|
+
check_boundary ast.loc.begin, ptb
|
100
|
+
ast.children.each do |sub|
|
101
|
+
ptb.add_parsetree_child!(convert(sub), sub)
|
102
|
+
end
|
103
|
+
check_boundary ast.loc.end, ptb
|
104
|
+
ptb.build(parent)
|
105
|
+
end
|
106
|
+
|
107
|
+
def_rule %i[dstr dsym xstr] do |ast, parent, index|
|
108
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
109
|
+
ast.children.each do |sub|
|
110
|
+
ptb.add_parsetree_child!(convert(sub), sub)
|
111
|
+
end
|
112
|
+
ptb.build(parent)
|
113
|
+
end
|
114
|
+
|
115
|
+
def def_rule_for_seq(type, open, sep, close)
|
116
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
117
|
+
def_rule type do |ast, parent, index|
|
118
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
119
|
+
ptb.add_child!(ctt[open], nil, true, [open]) unless open.nil?
|
120
|
+
unless ast.children.empty?
|
121
|
+
first = ast.children.first
|
122
|
+
ptb.add_parsetree_child!(convert(first), first)
|
123
|
+
ast.children[1..].each do |sub|
|
124
|
+
ptb.add_child!(ctt[sep], nil, true, [sep]) unless sep.nil?
|
125
|
+
ptb.add_parsetree_child!(convert(sub), sub)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
ptb.add_child!(ctt[close], nil, true, [close]) unless close.nil?
|
129
|
+
ptb.build(parent)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def_rule_for_seq(:array, "[", ",", "]")
|
134
|
+
def_rule_for_seq(:hash, "{", ",", "}")
|
135
|
+
def_rule_for_seq(:kwargs, nil, ",", nil)
|
136
|
+
|
137
|
+
def_rule %i[splat kwsplat] do |ast, parent, index|
|
138
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
139
|
+
star = ast.loc.operator.source
|
140
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
141
|
+
ptb.add_child!(ctt[star], nil, true, [star])
|
142
|
+
first = ast.children.first
|
143
|
+
ptb.add_parsetree_child!(convert(first), first)
|
144
|
+
ptb.build(parent)
|
145
|
+
end
|
146
|
+
|
147
|
+
def_rule :pair do |ast, parent, index|
|
148
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
149
|
+
left, right = ast.children
|
150
|
+
op_value = ast.loc.operator.source
|
151
|
+
op_type = ctt[op_value]
|
152
|
+
if op_type.nil?
|
153
|
+
raise Resyma::Core::ConversionError,
|
154
|
+
"Unknown operator for hash pair: #{op_value}"
|
155
|
+
end
|
156
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
157
|
+
ptb.add_parsetree_child!(convert(left), left)
|
158
|
+
ptb.add_child!(op_type, nil, true, [op_value])
|
159
|
+
ptb.add_parsetree_child!(convert(right), right)
|
160
|
+
ptb.build(parent)
|
161
|
+
end
|
162
|
+
|
163
|
+
def_rule %i[erange irange] do |ast, parent, index|
|
164
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
165
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
166
|
+
left, right = ast.children
|
167
|
+
op_value = ast.loc.operator.source
|
168
|
+
ptb.add_parsetree_child!(convert(left), left) unless left.nil?
|
169
|
+
ptb.add_child!(ctt[op_value], nil, true, [op_value])
|
170
|
+
ptb.add_parsetree_child!(convert(right), right) unless right.nil?
|
171
|
+
ptb.build(parent)
|
172
|
+
end
|
173
|
+
|
174
|
+
def_rule :const do |ast, parent, index|
|
175
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
176
|
+
scope, sym = ast.children
|
177
|
+
maybe_colon = ast.loc.double_colon
|
178
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(:const, index, false, [], ast)
|
179
|
+
unless scope.nil? || scope.type == :cbase
|
180
|
+
ptb.add_parsetree_child!(convert(scope), scope)
|
181
|
+
end
|
182
|
+
unless maybe_colon.nil?
|
183
|
+
op_value = maybe_colon.source
|
184
|
+
ptb.add_child!(ctt[op_value], nil, true, [op_value])
|
185
|
+
end
|
186
|
+
ptb.add_child!(:id, nil, true, [sym.to_s])
|
187
|
+
ptb.build(parent)
|
188
|
+
end
|
189
|
+
|
190
|
+
def try_token!(ptb, optional_range)
|
191
|
+
ctt = Resyma::Core::CONST_TOKEN_TABLE
|
192
|
+
return if optional_range.nil?
|
193
|
+
|
194
|
+
token_value = if optional_range.is_a?(String)
|
195
|
+
optional_range
|
196
|
+
else
|
197
|
+
optional_range.source
|
198
|
+
end
|
199
|
+
ptb.add_child!(ctt[token_value], nil, true, [token_value])
|
200
|
+
end
|
201
|
+
|
202
|
+
def_rule :defined? do |ast, parent, index|
|
203
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(:defined?, index, false, [], ast)
|
204
|
+
try_token! ptb, ast.loc.source.keyword
|
205
|
+
try_token! ptb, ast.loc.source.begin
|
206
|
+
expr, = ast.children
|
207
|
+
ptb.add_parsetree_child!(convert(expr), expr)
|
208
|
+
try_token! ptb, ast.loc.source.end
|
209
|
+
ptb.build(parent)
|
210
|
+
end
|
211
|
+
|
212
|
+
asgn_table = {
|
213
|
+
lvasgn: :id,
|
214
|
+
ivasgn: :ivar,
|
215
|
+
cvasgn: :cvar,
|
216
|
+
gvasgn: :gvar
|
217
|
+
}
|
218
|
+
|
219
|
+
def_rule %i[lvasgn ivasgn cvasgn gvasgn] do |ast, parent, index|
|
220
|
+
name = ast.loc.name.source
|
221
|
+
value = ast.children[1]
|
222
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(ast.type, index, false, [], ast)
|
223
|
+
name_tkn = make_token(asgn_table[ast.type], name, nil, 0, nil)
|
224
|
+
ptb.add_parsetree_child!(name_tkn)
|
225
|
+
try_token!(ptb, ast.loc.operator)
|
226
|
+
ptb.add_parsetree_child!(convert(value), value)
|
227
|
+
ptb.build(parent)
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# @yieldparam [Resyma::Core::ParseTreeBuilder]
|
232
|
+
#
|
233
|
+
def with_ptb(ast, parent, index, type = ast.type)
|
234
|
+
ptb = Resyma::Core::ParseTreeBuilder.new(type, index, false, [], ast)
|
235
|
+
yield ptb
|
236
|
+
ptb.build(parent)
|
237
|
+
end
|
238
|
+
|
239
|
+
def add_ast!(ptb, ast)
|
240
|
+
ptb.add_parsetree_child!(convert(ast), ast) unless ast.nil?
|
241
|
+
end
|
242
|
+
|
243
|
+
def_rule :casgn do |ast, parent, index|
|
244
|
+
with_ptb ast, parent, index do |ptb|
|
245
|
+
base, sym, value_ast = ast.children
|
246
|
+
add_ast! ptb, base unless base.nil? || base.type == :cbase
|
247
|
+
try_token! ptb, ast.loc.double_colon
|
248
|
+
name = ast.loc.name.source
|
249
|
+
name_tkn = make_token(:id, name, nil, 0, nil)
|
250
|
+
ptb.add_parsetree_child!(name_tkn)
|
251
|
+
try_token! ptb, ast.loc.operator
|
252
|
+
add_ast! ptb, value_ast
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def add_id!(ptb, name)
|
257
|
+
tkn = make_token(:id, name.to_s, nil, 0, nil)
|
258
|
+
ptb.add_parsetree_child!(tkn)
|
259
|
+
end
|
260
|
+
|
261
|
+
def_rule %i[send csend] do |ast, parent, index|
|
262
|
+
with_ptb ast, parent, index do |ptb|
|
263
|
+
if ast.loc.respond_to? :operator
|
264
|
+
rec, _, rhs = ast.children
|
265
|
+
add_ast! ptb, rec
|
266
|
+
try_token! ptb, ast.loc.dot
|
267
|
+
selector = ast.loc.selector.source
|
268
|
+
add_id! ptb, selector
|
269
|
+
try_token! ptb, ast.loc.operator
|
270
|
+
add_ast! ptb, rhs
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def_rule :block do |ast, parent, index|
|
276
|
+
with_ptb ast, parent, index do |ptb|
|
277
|
+
send, args, block = ast.children
|
278
|
+
add_ast! ptb, send
|
279
|
+
try_token! ptb, ast.loc.begin
|
280
|
+
add_ast! ptb, args
|
281
|
+
add_ast! ptb, block
|
282
|
+
try_token! ptb, ast.loc.end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def_rule :args do |ast, parent, index|
|
287
|
+
with_ptb ast, parent, index do |ptb|
|
288
|
+
try_token! ptb, ast.loc.begin
|
289
|
+
unless ast.children.empty?
|
290
|
+
add_ast! ptb, ast.children.first
|
291
|
+
ast.children[1..].each do |arg|
|
292
|
+
try_token! ptb, ","
|
293
|
+
add_ast! ptb, arg
|
294
|
+
end
|
295
|
+
end
|
296
|
+
try_token! ptb, ast.loc.end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def_rule :arg do |ast, parent, index|
|
301
|
+
with_ptb ast, parent, index do |ptb|
|
302
|
+
add_id! ptb, ast.loc.name.source
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def_rule :optarg do |ast, parent, index|
|
307
|
+
with_ptb ast, parent, index do |ptb|
|
308
|
+
add_id! ptb, ast.loc.name.source
|
309
|
+
try_token! ptb, ast.loc.operator
|
310
|
+
add_ast! ptb, ast.children[1]
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def def_rule_with_ptb(types)
|
315
|
+
def_rule types do |ast, parent, index|
|
316
|
+
with_ptb ast, parent, index do |ptb|
|
317
|
+
yield ptb, ast, parent, index
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def_rule_with_ptb :restarg do |ptb, ast|
|
323
|
+
try_token! ptb, "*"
|
324
|
+
add_id! ptb, ast.loc.name.source unless ast.loc.name.nil?
|
325
|
+
end
|
326
|
+
|
327
|
+
def_rule_with_ptb :blockarg do |ptb, ast|
|
328
|
+
try_token! ptb, "&"
|
329
|
+
add_id! ptb, ast.loc.name.source unless ast.loc.name.nil?
|
330
|
+
end
|
331
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module Resyma
|
4
|
+
module Core
|
5
|
+
class Field
|
6
|
+
#
|
7
|
+
# Create an instance of Field, which is set and used by the matching
|
8
|
+
# algorithm
|
9
|
+
#
|
10
|
+
# @param [Integer] id ID of the node
|
11
|
+
# @param [Hash<Integer, Set<Resyma::Core::Tuple2>>] start Sets of 2
|
12
|
+
# tuples, corresponding to different automata
|
13
|
+
# @param [Hash<Integer, Set<Resyma::Core::Tuple4>>] trans Sets of 4
|
14
|
+
# tuples, corresponding to different automata
|
15
|
+
#
|
16
|
+
def initialize(id, start, trans)
|
17
|
+
@id = id
|
18
|
+
@start = start
|
19
|
+
@trans = trans
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :id, :start, :trans
|
23
|
+
|
24
|
+
def self.clean_field
|
25
|
+
start = Hash.new { |hash, key| hash[key] = Set[] }
|
26
|
+
trans = Hash.new { |hash, key| hash[key] = Set[] }
|
27
|
+
new(-1, start, trans)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Parse tree with fields used by the matching algorithm
|
33
|
+
#
|
34
|
+
class ParseTree
|
35
|
+
attr_accessor :symbol, :children, :parent, :index, :field, :ast, :cache
|
36
|
+
|
37
|
+
#
|
38
|
+
# Create an instance of parse tree
|
39
|
+
#
|
40
|
+
# @param [Symbol] symbol Symbol associating to the node
|
41
|
+
# @param [Array] children Subtrees of current node, or an array with a
|
42
|
+
# single element if it is a leaf
|
43
|
+
# @param [Resyma::Core::ParseTree, nil] parent Parent tree, or nil if the
|
44
|
+
# current node is the root
|
45
|
+
# @param [Integer] index There are `index` brother preceding to the
|
46
|
+
# current node
|
47
|
+
# @param [true,false] is_leaf Whether or not the current node is a leaf
|
48
|
+
# @param [Parser::AST::Node,nil] ast Its corresponding abstract syntax
|
49
|
+
# tree
|
50
|
+
#
|
51
|
+
def initialize(symbol, children, parent, index, is_leaf, ast = nil)
|
52
|
+
@symbol = symbol
|
53
|
+
@children = children
|
54
|
+
@parent = parent
|
55
|
+
@index = index
|
56
|
+
@field = Field.clean_field
|
57
|
+
@is_leaf = is_leaf
|
58
|
+
@ast = ast
|
59
|
+
@cache = {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear!
|
63
|
+
@field = Field.clean_field
|
64
|
+
@cache = {}
|
65
|
+
@children.each(&:clear!) unless leaf?
|
66
|
+
end
|
67
|
+
|
68
|
+
def root?
|
69
|
+
@parent.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def leaf?
|
73
|
+
@is_leaf
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "set"
|
2
|
+
require "parser/current"
|
3
|
+
|
4
|
+
module Resyma
|
5
|
+
module Core
|
6
|
+
SourceLocator = Struct.new("SourceDetector", :matcher, :locate)
|
7
|
+
|
8
|
+
SOURCE_LOCATORS = []
|
9
|
+
|
10
|
+
def self.def_source_locator(regexp, &block)
|
11
|
+
SOURCE_LOCATORS.unshift SourceLocator.new(regexp, block)
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Locate the AST of a callable object
|
16
|
+
#
|
17
|
+
# @param [#source_location] procedure A callable object, particular a
|
18
|
+
# instance of Proc or Method
|
19
|
+
#
|
20
|
+
# @return [nil, Parser::AST::Node] AST of the procedure, or nil if cannot
|
21
|
+
# locate its source
|
22
|
+
#
|
23
|
+
def self.locate(procedure)
|
24
|
+
if procedure.respond_to? :source_location
|
25
|
+
filename, lino = procedure.source_location
|
26
|
+
SOURCE_LOCATORS.each do |locator|
|
27
|
+
if locator.matcher.match?(filename)
|
28
|
+
return locator.locate.call(procedure, filename, lino)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
CALLABLE_TYPES = Set[:def, :defs, :block]
|
37
|
+
|
38
|
+
def self.line_number_of_callable(ast)
|
39
|
+
case ast.type
|
40
|
+
when Set[:def, :defs] then ast.loc.keyword.line
|
41
|
+
when :block then ast.loc.begin.line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.locate_possible_procedures(ast, lino)
|
46
|
+
return [] unless ast.is_a?(Parser::AST::Node)
|
47
|
+
|
48
|
+
procs = []
|
49
|
+
if CALLABLE_TYPES.include?(ast.type) &&
|
50
|
+
line_number_of_callable(ast) == lino
|
51
|
+
procs.push ast
|
52
|
+
end
|
53
|
+
ast.children.each do |sub|
|
54
|
+
procs += locate_possible_procedures(sub, lino)
|
55
|
+
end
|
56
|
+
procs
|
57
|
+
end
|
58
|
+
|
59
|
+
class MultipleProcedureError < Resyma::Error; end
|
60
|
+
|
61
|
+
def_source_locator(/^.*$/) do |_, filename, lino|
|
62
|
+
tree = Parser::CurrentRuby.parse_file(filename)
|
63
|
+
procs = locate_possible_procedures(tree, lino)
|
64
|
+
case procs.size
|
65
|
+
when 1 then procs[0]
|
66
|
+
when 0 then nil
|
67
|
+
else raise MultipleProcedureError,
|
68
|
+
"Detected multiple procedures in [#{filename}:#{lino}], " +
|
69
|
+
"which is unsupported currently"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "resyma/core/parsetree/definition"
|
2
|
+
|
3
|
+
module Resyma
|
4
|
+
module Core
|
5
|
+
class ParseTree
|
6
|
+
#
|
7
|
+
# Depth-firstly traverse the tree
|
8
|
+
#
|
9
|
+
# @yieldparam [Resyma::Core::ParseTree] A parse tree
|
10
|
+
#
|
11
|
+
# @return [nil] Nothing
|
12
|
+
#
|
13
|
+
def depth_first_each(&block)
|
14
|
+
yield self
|
15
|
+
|
16
|
+
return if leaf?
|
17
|
+
|
18
|
+
@children.each do |child|
|
19
|
+
child.depth_first_each(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require "resyma/core/parsetree/source"
|
2
|
+
require "resyma/core/parsetree/definition"
|
3
|
+
require "resyma/core/parsetree/traversal"
|
4
|
+
require "resyma/core/parsetree/builder"
|
5
|
+
require "resyma/core/parsetree/converter"
|
6
|
+
require "resyma/core/parsetree/default_converter"
|
7
|
+
|
8
|
+
__END__
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module Resyma
|
4
|
+
module Core
|
5
|
+
module Utils
|
6
|
+
def self.big_union(sets)
|
7
|
+
union = Set[]
|
8
|
+
sets.each { |set| union.merge(set) }
|
9
|
+
union
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Whether an automaton accepts the input
|
14
|
+
#
|
15
|
+
# @param [Resyma::Core::Automaton] automaton An well-formed automaton
|
16
|
+
# @param [Array] input_array A list of input tokens
|
17
|
+
#
|
18
|
+
# @return [true,false] Result
|
19
|
+
#
|
20
|
+
def self.automaton_accept?(automaton, input_array)
|
21
|
+
current_state = automaton.start
|
22
|
+
input_array.each do |word|
|
23
|
+
current_state = automaton.destination(current_state, word)
|
24
|
+
return false if current_state.nil?
|
25
|
+
end
|
26
|
+
automaton.accept? current_state
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|