redparse 0.8.1 → 0.8.2
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.
- data/History.txt +33 -2
- data/Manifest.txt +2 -3
- data/README.txt +157 -265
- data/Rakefile +13 -4
- data/bin/redparse +3 -2
- data/lib/redparse.rb +2423 -489
- data/lib/redparse/generate.rb +378 -0
- data/lib/redparse/node.rb +1497 -620
- data/lib/redparse/reg_more_sugar.rb +21 -0
- data/lib/redparse/version.rb +1 -1
- data/test/data/def_spec.rb +2 -0
- data/test/rp-locatetest.rb +2 -1
- data/test/test_redparse.rb +594 -61
- metadata +17 -8
- data/nurli/test_control.nurli +0 -261
- data/redparse.vpj +0 -92
- data/redparse.vpw +0 -8
@@ -0,0 +1,378 @@
|
|
1
|
+
class RedParse
|
2
|
+
=begin
|
3
|
+
3 LR-Parsing Mechanics
|
4
|
+
We briefly explain the fundamentals of shift-reduce parsing (which represents
|
5
|
+
the LR(1) family) without going into any more detail than necessary for
|
6
|
+
subsequent exposition. LALR(1) parsers like yacc simulate, either directly or
|
7
|
+
indirectly, a very simple automaton with a stack of automaton states [FL88].
|
8
|
+
(Parsers generated by yacc also maintain a semantic stack, but since that stack
|
9
|
+
grows in parallel with the state stack, we only describe the use of the state
|
10
|
+
stack here.) Simulating the automaton requires two mechanisms: one for
|
11
|
+
determining the action, which is determined by the current input symbol and the
|
12
|
+
state on the top of the stack, and one for determining state transitions based
|
13
|
+
on the current top of stack and a grammar symbol. At parser-generation time
|
14
|
+
LALR(1) grammar analysis builds these tables, called action and goto,
|
15
|
+
respectively. (The analysis is necessary regardless of whether a table-driven
|
16
|
+
or hard-coded parser is desired.) Functionally, these tables have the following
|
17
|
+
signatures.
|
18
|
+
|
19
|
+
goto: state x symbol -> state
|
20
|
+
action: state x token -> {shift,reduce_y,accept,error}
|
21
|
+
|
22
|
+
There are only four possible actions: reduce, shift, accept, and error. Reduce
|
23
|
+
actions are parameterized by the grammar production being reduced. Actions are
|
24
|
+
described below. let TOS be the state on the top of the stack, and let
|
25
|
+
la_identity be the current lookahead token.
|
26
|
+
|
27
|
+
shift A shift pushes goto[TOS,la_identity] onto the stack, and updates
|
28
|
+
la_identity by advancing the lexical analyzer.
|
29
|
+
|
30
|
+
reduce_y A reduction processes production Y : X -> x_1...x_n, which
|
31
|
+
requires popping n states off the stack, followed by pushing goto[TOS, X].
|
32
|
+
(The semantic action of the parser relating to this production would be
|
33
|
+
executed prior to popping states off the stack.)
|
34
|
+
|
35
|
+
accept An accept signals a successful parse.
|
36
|
+
|
37
|
+
error An error requires error reporting and/or recovery.
|
38
|
+
|
39
|
+
|
40
|
+
4 Simple Implementation
|
41
|
+
mule creates a single parsing routine, yyparse(), that simulates the LALR(1)
|
42
|
+
parser directly in ANSI C, without interpreting any tables. The routine has
|
43
|
+
five simple parts: initialization, automata states, reduction actions,
|
44
|
+
nonterminal transitions, and error recovery. Although very similar to the
|
45
|
+
inverted table structure in [Pfa90], this structure avoids the duplication
|
46
|
+
of semantic action routines. Another diverence is the yacc-compatible error
|
47
|
+
recovery. The structure is simple, with all code being generated from a tiny
|
48
|
+
set of small, well-defined templates that directly mirror the grammar or
|
49
|
+
LALR(1) automaton. Since both the state stack and the semantic stack grow in
|
50
|
+
unison, we wrap the stack entries into a single structure, StackType.
|
51
|
+
|
52
|
+
4.1 Initialization
|
53
|
+
The initalization phase simply sets up bookkeeping and data structures for
|
54
|
+
subsequent automata simulation. It is grammar-independent.
|
55
|
+
=end
|
56
|
+
|
57
|
+
def init_code
|
58
|
+
"
|
59
|
+
#define YYABORT do { \\
|
60
|
+
free(start_stack);return -1; \\
|
61
|
+
} while(0)
|
62
|
+
#define YYACCEPT do { \\
|
63
|
+
YYSTYPE result=SEMANTIC_STACK; \\
|
64
|
+
free(start_stack); \\
|
65
|
+
return result; \\
|
66
|
+
} while(0)
|
67
|
+
/*#define yyclearin_token = yylex(&la_token)*/
|
68
|
+
#define yyerrok yyerrorstatus = 3
|
69
|
+
#define YYERROR goto user_error_handler
|
70
|
+
#define YYRECOVERING() (yyerrorstatus <= 2)
|
71
|
+
|
72
|
+
|
73
|
+
typedef VALUE YYSTYPE;
|
74
|
+
|
75
|
+
#if 0
|
76
|
+
typedef struct stackType{
|
77
|
+
int state;// State stack element.
|
78
|
+
} StackType;
|
79
|
+
typedef struct {
|
80
|
+
VALUE semantic;
|
81
|
+
} SemanticStackType;
|
82
|
+
#else
|
83
|
+
typedef int StackType;
|
84
|
+
typedef VALUE SemanticStackType;
|
85
|
+
#end
|
86
|
+
int yyparse(void){
|
87
|
+
YYSTYPE la_token;// Semantic value computed by yylex().
|
88
|
+
int la_identity;
|
89
|
+
unsigned yyerrorstatus = 3;// Initialize error-recovery counter.
|
90
|
+
YYSTYPE yyredval;// Variable holds semantic value of$$.
|
91
|
+
VALUE semantic_stack; /*Array of Node|Token*/
|
92
|
+
// SemanticStackType *semantic_stack_start;
|
93
|
+
StackType *stack_start;// Stack.
|
94
|
+
unsigned i=0;
|
95
|
+
unsigned stack_size=64;
|
96
|
+
|
97
|
+
stack_start=realloc(NULL,sizeof(StackType)*stack_size);
|
98
|
+
if (stack_start==NULL) MALLOC_ERROR();
|
99
|
+
semantic_stack=rb_ary_new();
|
100
|
+
// semantic_stack_start=realloc(NULL,sizeof(SemanticStackType)*stack_size);
|
101
|
+
// if (semantic_stack_start==NULL) MALLOC_ERROR();
|
102
|
+
|
103
|
+
la_identity = yylex(&la_token); /* Get 1st token.*/
|
104
|
+
|
105
|
+
goto shift_state_#{str2cname all_states.first.name};/* Start state.*/
|
106
|
+
"
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def state_utils
|
111
|
+
"
|
112
|
+
#define MALLOC_ERROR() huh
|
113
|
+
#define RESERVE_STACK_SLOT() \\
|
114
|
+
if (++i >= stack_size){ \\
|
115
|
+
unsigned new_stack_size=stack_size*2; \\
|
116
|
+
stack_start=realloc(stack_start,sizeof(StackType)*new_stack_size); \\
|
117
|
+
if (stack_start==NULL) MALLOC_ERROR(); \\
|
118
|
+
//semantic_stack_start=realloc(semantic_stack_start,sizeof(SemanticStackType)*new_stack_size); \\
|
119
|
+
//if (semantic_stack_start==NULL) MALLOC_ERROR(); \\
|
120
|
+
stack_size=new_stack_size; \\
|
121
|
+
}
|
122
|
+
|
123
|
+
#define GET_TOKEN() \\
|
124
|
+
do { \\
|
125
|
+
SEMANTIC_STACK_SET(la_token); /*Put lexical semantic entry on stack.*/ \\
|
126
|
+
la_identity = yylex(&la_token); /* Advance lexical analysis.*/ \\
|
127
|
+
yyerrorstatus++; /* Update error-recovery counter.*/ \\
|
128
|
+
} while(0)
|
129
|
+
|
130
|
+
#define STACK stack_start[i]
|
131
|
+
#define SEMANTIC_STACK rb_ary_get(semantic_stack,rb_int2fixnum(i))
|
132
|
+
#define SEMANTIC_STACK_SET(x) rb_ary_set(semantic_stack,rb_int2fixnum(i),x)
|
133
|
+
#define OLDSTACK stack_start[i-1]
|
134
|
+
"
|
135
|
+
end
|
136
|
+
|
137
|
+
def action2c(action)
|
138
|
+
case action
|
139
|
+
when Rule; "goto reduce_#{str2cname action.name};"
|
140
|
+
when nil,:error; "goto error_handler;"
|
141
|
+
when ParserState; "goto shift_state_#{str2cname action.name};"
|
142
|
+
when :accept; "YYACCEPT;"
|
143
|
+
when MultiReduce; action.action2c
|
144
|
+
when MultiShift; action.action2c
|
145
|
+
# when StackMonkey; action.action2c
|
146
|
+
else fail "unexpected action type: #{action.class} = #{action}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
=begin
|
151
|
+
4.2 Hard-coded States
|
152
|
+
For each automata state, mule creates code responsible for simulating the action of that state based
|
153
|
+
on the current input token. All transitions
|
154
|
+
into
|
155
|
+
a given state are labeled with the same grammar
|
156
|
+
symbol. States labeled with a token are called
|
157
|
+
shift states
|
158
|
+
and they require extra code to advance
|
159
|
+
the lexical analyzer. The template of this code for state N is
|
160
|
+
=end
|
161
|
+
|
162
|
+
def state(state_n,n)
|
163
|
+
#n=state_n.small_int
|
164
|
+
name=state_n.name
|
165
|
+
"
|
166
|
+
shift_state_#{name}:
|
167
|
+
GET_TOKEN(); /*modifies token, la_token*/
|
168
|
+
state_#{name}: /*state_#{n}:*/
|
169
|
+
STACK = #{n};
|
170
|
+
|
171
|
+
RESERVE_STACK_SLOT();
|
172
|
+
state_action_#{name}: /* Error-recovery entry point.*/
|
173
|
+
/*state_action_#{n}:*/
|
174
|
+
switch (la_identity){
|
175
|
+
#{state_n.actions.map do |tok,action|
|
176
|
+
%[ case #{str2cname(tok)}: #{action2c action}]
|
177
|
+
end.join(%[\n])
|
178
|
+
}
|
179
|
+
default: #{action2c state_n.actions.default}
|
180
|
+
}
|
181
|
+
"
|
182
|
+
rescue Exception=>e
|
183
|
+
backtrace.unshift("exception in state #{name} #{e.class}:#{e}").join("\n")
|
184
|
+
end
|
185
|
+
|
186
|
+
=begin
|
187
|
+
The state number is stored in the stack, followed by possibly invoking the lexical analyzer. The
|
188
|
+
three optional lines store the semantic value of the current token, advance the lexical analyzer, and
|
189
|
+
do error-recovery bookkeeping. Incrementing the stack pointer completes the push. The case arms
|
190
|
+
of the switch are determined by the
|
191
|
+
action
|
192
|
+
table computed by the LALR(1) analysis; for each
|
193
|
+
condition met in the comments, a case arm must be generated. Default actions were developed for
|
194
|
+
compressing table-driven parsers, and can be similarly employed here for generating the switchs
|
195
|
+
default [FL88].
|
196
|
+
|
197
|
+
4.3 Reduction Actions
|
198
|
+
One piece of code is generated for each production. Its template is given below.
|
199
|
+
=end
|
200
|
+
|
201
|
+
def repl(rule,m)
|
202
|
+
repl=rule.replacement
|
203
|
+
case repl
|
204
|
+
when :shift,:accept #do nothing?
|
205
|
+
when Class
|
206
|
+
%[static VALUE repl_#{rule.name}=rb_const_lookup(rb_const_lookup(kNIL,"RedParse"),"#{repl.name});\n]
|
207
|
+
when StackMonkey
|
208
|
+
end
|
209
|
+
|
210
|
+
def reduce(rule,m)
|
211
|
+
repl=rule.replacement
|
212
|
+
pattern=rule.pattern
|
213
|
+
numpatterns=pattern.subregs.size
|
214
|
+
|
215
|
+
leader="\nreduce_#{rule.name}:\n/*reduce_#{m}:*/ /*Production #{m}: #{rule.to_s} */\n"
|
216
|
+
if StackMonkey===repl
|
217
|
+
userhook="
|
218
|
+
huh rb_proc_call(stack_monkey_#{rule.name},semantic_stack);
|
219
|
+
huh /*objects removed from semantic stack get pushed back onto lexer input*/
|
220
|
+
i -= #{repl.backup_count};
|
221
|
+
|
222
|
+
goto nonterminal_switcher_#{str2cname repl.huh};
|
223
|
+
// Compute transition on some old node from the (semantic) stack.
|
224
|
+
huh//need a node (or token?) number to goto address mapper (switch stmt) here
|
225
|
+
"
|
226
|
+
elsif :accept==repl
|
227
|
+
return leader+"YYACCEPT;"
|
228
|
+
end
|
229
|
+
%[
|
230
|
+
#{leader}#{userhook}
|
231
|
+
yyredval=huh rb_call(repl_#{rule.name},huh("create"),semantic_stack,huh2ruby(-#{numpatterns}));
|
232
|
+
|
233
|
+
i -= #{numpatterns}; /* Pop patterns from stack.*/
|
234
|
+
|
235
|
+
SEMANTIC_STACK_SET(yyredval); /* Copy ($$) onto semantic stack.*/
|
236
|
+
goto nonterminal_#{str2cname repl.name}; /* Compute transition on produced node type.*/
|
237
|
+
]
|
238
|
+
end
|
239
|
+
|
240
|
+
rescue Exception=>e
|
241
|
+
backtrace.unshift("exception in reduce of rule #{rule.name} #{e.class}:#{e}").join("\n")
|
242
|
+
end
|
243
|
+
|
244
|
+
=begin
|
245
|
+
User actions are associated with reductions, and the code corresponding to a given production
|
246
|
+
is expanded in-place. After the user code, the symbols associated with right-hand side of the
|
247
|
+
production are popped, followed by copying $$ onto the semantic stack. Finally, there is a jump to
|
248
|
+
the code that will compute the appropriate state given the left-hand side symbol of this production.
|
249
|
+
|
250
|
+
4.4 Nonterminal Transitions
|
251
|
+
For each nonterminal, code is produced to compute (and jump to) the appropriate state given the
|
252
|
+
current state. This simple switch statement is given below.
|
253
|
+
=end
|
254
|
+
|
255
|
+
def nonterminal(j)
|
256
|
+
"
|
257
|
+
nonterminal_#{str2cname j.name}: /*nonterminal_#{j.small_int}:*/
|
258
|
+
switch (OLDSTACK){ // Top of stack.
|
259
|
+
#{
|
260
|
+
all_states.map_with_index do|state,k|
|
261
|
+
%[ case #{k}: goto state_#{str2cname state.goto[j].name};\n]
|
262
|
+
end
|
263
|
+
}
|
264
|
+
}
|
265
|
+
"
|
266
|
+
rescue Exception=>e
|
267
|
+
backtrace.unshift("exception in node(nonterminal) #{j.name} #{e.class}:#{e}").join("\n")
|
268
|
+
end
|
269
|
+
|
270
|
+
=begin
|
271
|
+
The case arms of the switch statement are taken directly from the goto table
|
272
|
+
that was computed by the LALR(1) grammar analysis. Because this switch cannot
|
273
|
+
fail, no default entry is needed. However, making the most common case arm the
|
274
|
+
default is a trivial time and space optimization.
|
275
|
+
=end
|
276
|
+
|
277
|
+
def generate_c output
|
278
|
+
output<< init_code
|
279
|
+
output<< state_utils
|
280
|
+
(0...RULES().size).each_with_index{|i,m| output<< (reduce i,m) }
|
281
|
+
node_types.each{|nt| output<< (nonterminal nt) }
|
282
|
+
map_with_index(all_states){|st,i| output<< (state st,i) }
|
283
|
+
#output<< error_handler #disabled, i have rules for error recovery
|
284
|
+
output<< "}"
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
|
289
|
+
|
290
|
+
=begin
|
291
|
+
4.5 Error Recovery
|
292
|
+
yacc's error recovery mechanism is rather idiosyncratic. In fact, examining two books, [LMB92]
|
293
|
+
and [ASU86], and the output generated by yacc yields three dierent descriptions of the recovery
|
294
|
+
mechanism. We have tried to be faithful to the output of yacc.
|
295
|
+
Fortunately, the mechanism has few consequences to the generation of the rest of the hard-
|
296
|
+
coded parser. The only change to the parser is the maintenance of the variable, yyerrorstatus.
|
297
|
+
Although relatively short, the code below is very subtle, like the explanation of yacc's error
|
298
|
+
recovery mechanism. The code is given only for completeness.
|
299
|
+
=end
|
300
|
+
|
301
|
+
def error_handler
|
302
|
+
%[
|
303
|
+
error_handler:
|
304
|
+
if (yyerrorstatus > 2){
|
305
|
+
yyerror("syntax error");
|
306
|
+
}
|
307
|
+
user_error_handler:
|
308
|
+
if (yyerrorstatus == 0){
|
309
|
+
huh if (la_identity == 0) YYABORT;// End of input.
|
310
|
+
la_identity = yylex(&la_token);
|
311
|
+
switch (OLDSTACK){
|
312
|
+
#{@states.map{|state|
|
313
|
+
i=state.small_int
|
314
|
+
"case #{i}: goto state_action_#{str2cname state.name};\n"
|
315
|
+
}
|
316
|
+
}
|
317
|
+
}else{
|
318
|
+
yyerrorstatus = 0;
|
319
|
+
while (stack != stack_start){
|
320
|
+
switch (OLDSTACK){
|
321
|
+
case N: goto state_M;// iff M = goto[N,error].
|
322
|
+
.
|
323
|
+
.
|
324
|
+
.
|
325
|
+
}
|
326
|
+
stack--;
|
327
|
+
}
|
328
|
+
YYABORT;// Empty stack.
|
329
|
+
}
|
330
|
+
]
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
CHARMAPPINGS={
|
335
|
+
?`=>'bquote', ?~=>'tilde', ?!=>'bang', ?@=>'at',
|
336
|
+
?#=>'num', ?$=>'dollar', ?%=>'percent', ?^=>'caret',
|
337
|
+
?&=>'and', ?*=>'star', ?(=>'lparen', ?)=>'rparen',
|
338
|
+
?-=>'minus', ?+=>'plus', ?==>'equals',
|
339
|
+
?{=>'lbrace', ?}=>'rbrace', ?[=>'lbrack', ?]=>'rbrack',
|
340
|
+
?|=>'or', ?\\=>'bslash',?:=>'colon', ?;=>'semicolon',
|
341
|
+
?"=>'dquote', ?'=>'squote', ?,=>'comma', ?.=>'dot',
|
342
|
+
?<=>'less', ?>=>'more', ??=>'q', ?/=>'y',
|
343
|
+
?\s=>'space',
|
344
|
+
?X=>'x',
|
345
|
+
}
|
346
|
+
STRMAPPINGS={
|
347
|
+
'::'=>"XX",
|
348
|
+
'++'=>"Xeval",
|
349
|
+
'--'=>"Xsingleton",
|
350
|
+
'[]'=>"Xbrackets",
|
351
|
+
'->'=>"Xcalling",
|
352
|
+
}
|
353
|
+
STRMAP_REX=/#{STRMAPPINGS.keys.map{|x| Regexp.quote x}.join "|"}/
|
354
|
+
def self.str2cname str
|
355
|
+
str.gsub(STRMAP_REX){|str| STRMAPPINGS[str] } \
|
356
|
+
.gsub(/(?!#{LETTER_DIGIT}).|[X]/o){|ch|
|
357
|
+
"X"+ esc=CHARMAPPINGS[ch[0]] ? esc : ch[0].to_s(16)
|
358
|
+
}
|
359
|
+
end
|
360
|
+
def str2cname(str) RedParse.str2cname(str) end
|
361
|
+
|
362
|
+
|
363
|
+
=begin
|
364
|
+
The case arms are the only part of the code that depends on the automaton. Any state that has
|
365
|
+
an outgoing transition on yacc's special error symbol will have a case arm in the second switch
|
366
|
+
statement.
|
367
|
+
|
368
|
+
Our error recovery implementation assumes that at most
|
369
|
+
MAX UINT-3
|
370
|
+
tokens will ever be shifted between syntactic
|
371
|
+
errors | given that this number is 4,294,967,293 on a 32-bit machine, we feel this is safe. Even then, the mechanism
|
372
|
+
is only flawed for the last 3 tokens out of every
|
373
|
+
MAX UINT
|
374
|
+
tokens, and furthermore, the assumption cannot disturb
|
375
|
+
a correct parse, only error-recovery processing. Making it completely safe would be trivial, but would require a
|
376
|
+
conditional increment at each shift, which we consider too costly for the benefit.
|
377
|
+
=end
|
378
|
+
end
|
data/lib/redparse/node.rb
CHANGED
@@ -17,7 +17,12 @@
|
|
17
17
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
=end
|
19
19
|
|
20
|
-
|
20
|
+
begin
|
21
|
+
require 'rubygems'
|
22
|
+
rescue LoadError=>e
|
23
|
+
raise unless /rubygems/===e.message
|
24
|
+
#hope we don't need it
|
25
|
+
end
|
21
26
|
require 'tempfile'
|
22
27
|
require 'pp'
|
23
28
|
require "rubylexer"
|
@@ -35,20 +40,13 @@ class RedParse
|
|
35
40
|
self::const_set k,t if Module===t and RubyLexer::Token>=t
|
36
41
|
}
|
37
42
|
|
38
|
-
module SimpleToLisp
|
39
|
-
def to_lisp; to_s end
|
40
|
-
end
|
41
|
-
|
42
|
-
[NumberToken, SymbolToken, VarNameToken, MethNameToken].each{|tokclass|
|
43
|
-
tokclass.send :include, SimpleToLisp
|
44
|
-
}
|
45
|
-
|
46
43
|
module FlattenedIvars
|
47
44
|
def flattened_ivars
|
48
45
|
result=[]
|
49
46
|
instance_variables.sort.each{|iv|
|
50
|
-
|
51
|
-
|
47
|
+
if iv!="@data"
|
48
|
+
result.push iv, instance_variable_get(iv)
|
49
|
+
end
|
52
50
|
}
|
53
51
|
return result
|
54
52
|
end
|
@@ -59,28 +57,139 @@ class RedParse
|
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
60
|
+
module Stackable
|
61
|
+
module Meta
|
62
|
+
#declare name to be part of the identity of current class
|
63
|
+
#variations are the allowed values for name in this class
|
64
|
+
#keep variations simple: booleans, integers, symbols and strings only
|
65
|
+
def identity_param name, *variations
|
66
|
+
name=name.to_s
|
67
|
+
list=
|
68
|
+
if (variations-[true,false,nil]).empty?
|
69
|
+
#const_get("BOOLEAN_IDENTITY_PARAMS") rescue const_set("BOOLEAN_IDENTITY_PARAMS",{})
|
70
|
+
self.boolean_identity_params
|
71
|
+
else
|
72
|
+
#const_get("IDENTITY_PARAMS") rescue const_set("IDENTITY_PARAMS",{})
|
73
|
+
self.identity_params
|
74
|
+
end
|
75
|
+
list[name]=variations
|
76
|
+
return #old way to generate examplars below
|
77
|
+
=begin
|
78
|
+
old_exemplars=self.exemplars||=[allocate]
|
79
|
+
exemplars=[]
|
80
|
+
variations.each{|var| old_exemplars.each{|exm|
|
81
|
+
exemplars<< res=exm.dup
|
82
|
+
|
83
|
+
#res.send name+"=", var
|
84
|
+
#res.send :define_method, name do var end
|
85
|
+
Symbol|String|Integer|true|false|nil===var or fail #so inspect works as a quoting
|
86
|
+
eval "def res.#{name}; #{var.inspect} end"
|
87
|
+
}}
|
88
|
+
old_exemplars.replace exemplars
|
89
|
+
=end
|
90
|
+
end
|
91
|
+
def enumerate_exemplars
|
92
|
+
@exemplars||= build_exemplars
|
93
|
+
end
|
94
|
+
def build_exemplars
|
95
|
+
exemplars=[[self]]
|
96
|
+
|
97
|
+
(boolean_identity_params.merge identity_params).each{|name,variations|
|
98
|
+
todo=[]
|
99
|
+
variations=variations.dup
|
100
|
+
variations.each{|var|
|
101
|
+
exemplars.each{|exm|
|
102
|
+
res=exm.dup
|
103
|
+
|
104
|
+
#res.send name+"=", var
|
105
|
+
#res.send :define_method, name do var end
|
106
|
+
Symbol|String|Integer|true|false|nil===var or fail #so inspect works as a quoting
|
107
|
+
#eval "def res.#{name}; #{var.inspect} end"
|
108
|
+
res.push name, var
|
109
|
+
|
110
|
+
todo<<res #unless exemplars.include? res
|
111
|
+
}
|
112
|
+
}
|
113
|
+
exemplars=todo
|
114
|
+
}
|
115
|
+
#by now, may be some exemplars with identical identities...
|
116
|
+
#those duplicate identities should be culled
|
117
|
+
# identities_seen={}
|
118
|
+
# exemplars.delete_if{|ex|
|
119
|
+
# idn=ex.identity_name
|
120
|
+
# chuck_it=identities_seen[idn]
|
121
|
+
# identities_seen[idn]=true
|
122
|
+
# chuck_it
|
123
|
+
# }
|
124
|
+
|
125
|
+
return exemplars
|
126
|
+
end
|
127
|
+
attr_writer :boolean_identity_params, :identity_params
|
128
|
+
def identity_params
|
129
|
+
return @identity_params if defined?(@identity_params) and @identity_params
|
130
|
+
@identity_params=
|
131
|
+
if superclass.respond_to? :identity_params
|
132
|
+
superclass.identity_params.dup
|
133
|
+
else
|
134
|
+
{}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
def boolean_identity_params
|
138
|
+
return @boolean_identity_params if defined?(@boolean_identity_params) and @boolean_identity_params
|
139
|
+
@boolean_identity_params=
|
140
|
+
if superclass.respond_to? :boolean_identity_params
|
141
|
+
superclass.boolean_identity_params.dup
|
142
|
+
else
|
143
|
+
{}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end #of Meta
|
147
|
+
|
148
|
+
def identity_name
|
149
|
+
k=self.class
|
150
|
+
list=[k.name]
|
151
|
+
list.concat k.boolean_identity_params.map{|(bip,)| bip if send(bip) }.compact
|
152
|
+
list.concat k.identity_params.map{|(ip,variations)|
|
153
|
+
val=send(ip)
|
154
|
+
variations.include? val or fail "identity_param #{k}##{ip} unexpected value #{val.inspect}"
|
155
|
+
[ip,val]
|
156
|
+
}.flatten
|
157
|
+
result=list.join("_")
|
158
|
+
return result
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
62
162
|
class Token
|
163
|
+
include Stackable
|
164
|
+
extend Stackable::Meta
|
165
|
+
|
63
166
|
def image; "#{inspect}" end
|
64
167
|
|
65
|
-
def to_parsetree(*options)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
168
|
+
def to_parsetree(*options) #this shouldn't be needed anymore
|
169
|
+
o={}
|
170
|
+
[:newlines,:quirks,:ruby187].each{|opt|
|
171
|
+
o[opt]=true if options.include? opt
|
172
|
+
}
|
70
173
|
|
71
|
-
|
72
|
-
Thread.current[:$RedParse_parsetree_quirks]=false
|
174
|
+
result=[parsetree(o)]
|
73
175
|
|
74
176
|
result=[] if result==[[]]
|
75
177
|
|
76
178
|
return result
|
77
179
|
end
|
78
|
-
def lvalue
|
180
|
+
def lvalue; nil end
|
79
181
|
def data; [self] end
|
80
182
|
def unary; false end
|
81
|
-
def rescue_parsetree; parsetree end
|
82
|
-
def begin_parsetree; parsetree end
|
183
|
+
def rescue_parsetree(o); parsetree(o) end
|
184
|
+
def begin_parsetree(o); parsetree(o) end
|
83
185
|
|
186
|
+
attr :line
|
187
|
+
alias endline line
|
188
|
+
|
189
|
+
attr_writer :startline
|
190
|
+
def startline
|
191
|
+
@startline||=endline
|
192
|
+
end
|
84
193
|
end
|
85
194
|
|
86
195
|
class KeywordToken
|
@@ -92,30 +201,91 @@ class RedParse
|
|
92
201
|
@not_real if defined? @not_real
|
93
202
|
end
|
94
203
|
|
204
|
+
identity_param :ident, *%w<+@ -@ unary& unary* ! ~ not defined?>+ #should be unary ops
|
205
|
+
%w<end ( ) { } [ ] alias undef in>+
|
206
|
+
%w<? : ; !~ lhs, rhs, rescue3>+ #these should be ops
|
207
|
+
%w{*= **= <<= >>= &&= ||= |= &= ^= /= %= -= += = => ... .. . ::}+ #shouldn't be here, grrr
|
208
|
+
RubyLexer::FUNCLIKE_KEYWORDLIST+
|
209
|
+
RubyLexer::VARLIKE_KEYWORDLIST+
|
210
|
+
RubyLexer::INNERBOUNDINGWORDLIST+
|
211
|
+
RubyLexer::BINOPWORDLIST+
|
212
|
+
RubyLexer::BEGINWORDLIST
|
213
|
+
#identity_param :unary, true,false,nil
|
214
|
+
|
215
|
+
#identity_param :tag, :lhs,:rhs,:param,:call,:array,:block,:nested,nil
|
216
|
+
identity_param :callsite?, nil, true, false
|
217
|
+
identity_param :not_real?, nil, true, false
|
218
|
+
identity_param :infix, nil, true
|
95
219
|
alias image ident
|
220
|
+
|
221
|
+
|
222
|
+
#KeywordToken#as/infix should be in rubylexer
|
223
|
+
alias old_as as
|
224
|
+
def as
|
225
|
+
if tag and ident[/^[,*&]$/]
|
226
|
+
tag.to_s+ident
|
227
|
+
else old_as
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def infix
|
232
|
+
@infix if defined? @infix
|
233
|
+
end unless instance_methods.include? "infix"
|
96
234
|
end
|
97
235
|
|
98
|
-
class
|
236
|
+
class OperatorToken
|
237
|
+
identity_param :ident, *%w[+@ -@ unary& unary* lhs* ! ~ not defined? * ** + -
|
238
|
+
< << <= <=> > >= >> =~ == ===
|
239
|
+
% / & | ^ != !~ = => :: ? : , ; . .. ...
|
240
|
+
*= **= <<= >>= &&= ||= && ||
|
241
|
+
&= |= ^= %= /= -= += and or
|
242
|
+
]+RubyLexer::OPORBEGINWORDLIST+%w<; lhs, rhs, rescue3>
|
243
|
+
#identity_param :unary, true,false,nil
|
244
|
+
#identity_param :tag, :lhs,:rhs,:param,:call,:array,:block,:nested,nil
|
245
|
+
|
246
|
+
#this should be in rubylexer
|
247
|
+
def as
|
248
|
+
if tag and ident[/^[,*&]$/]
|
249
|
+
tag.to_s+ident
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
class NumberToken
|
255
|
+
alias to_lisp to_s
|
256
|
+
def negative; /\A-/ === ident end unless instance_methods.include? "negative"
|
257
|
+
|
258
|
+
identity_param :negative, true,false
|
259
|
+
end
|
260
|
+
|
261
|
+
class MethNameToken
|
262
|
+
alias to_lisp to_s
|
263
|
+
def has_equals; /#{LETTER_DIGIT}=$/o===ident end unless instance_methods.include? "has_equals"
|
264
|
+
|
265
|
+
identity_param :has_equals, true,false
|
266
|
+
end
|
267
|
+
|
268
|
+
class VarNameToken #none of this should be necessary now
|
99
269
|
include FlattenedIvars
|
100
270
|
alias image ident
|
101
271
|
|
102
272
|
alias == flattened_ivars_equal?
|
103
273
|
|
104
|
-
def parsetree
|
274
|
+
def parsetree(o)
|
105
275
|
type=case ident[0]
|
106
|
-
when
|
276
|
+
when ?$
|
107
277
|
case ident[1]
|
108
|
-
when ?1..?9
|
109
|
-
when ?&,?+,?`,?'
|
278
|
+
when ?1..?9; return [:nth_ref,ident[1..-1].to_i]
|
279
|
+
when ?&,?+,?`,?'; return [:back_ref,ident[1].chr.to_sym] #`
|
110
280
|
else :gvar
|
111
281
|
end
|
112
|
-
when
|
282
|
+
when ?@
|
113
283
|
if ident[1]==?@
|
114
284
|
:cvar
|
115
285
|
else
|
116
286
|
:ivar
|
117
287
|
end
|
118
|
-
when ?A..?Z
|
288
|
+
when ?A..?Z; :const
|
119
289
|
else
|
120
290
|
case lvar_type
|
121
291
|
when :local; :lvar
|
@@ -129,28 +299,28 @@ class RedParse
|
|
129
299
|
|
130
300
|
def varname2assigntype
|
131
301
|
case ident[0]
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
302
|
+
when ?$; :gasgn
|
303
|
+
when ?@;
|
304
|
+
if ident[1]!=?@; :iasgn
|
305
|
+
elsif in_def; :cvasgn
|
306
|
+
else :cvdecl
|
307
|
+
end
|
308
|
+
when ?A..?Z; :cdecl
|
309
|
+
else
|
310
|
+
case lvar_type
|
311
|
+
when :local; :lasgn
|
312
|
+
when :block; :dasgn
|
313
|
+
when :current; :dasgn_curr
|
314
|
+
else fail
|
315
|
+
end
|
146
316
|
end
|
147
317
|
end
|
148
318
|
|
149
|
-
def lvalue_parsetree
|
319
|
+
def lvalue_parsetree(o)
|
150
320
|
[varname2assigntype, ident.to_sym]
|
151
321
|
end
|
152
322
|
|
153
|
-
def lvalue
|
323
|
+
def lvalue
|
154
324
|
return @lvalue if defined? @lvalue
|
155
325
|
@lvalue=true
|
156
326
|
end
|
@@ -159,7 +329,7 @@ class RedParse
|
|
159
329
|
lvar_type==:current ? [ident] : []
|
160
330
|
end
|
161
331
|
|
162
|
-
attr_accessor :
|
332
|
+
attr_accessor :endline,:lvalue
|
163
333
|
|
164
334
|
def dup
|
165
335
|
result=super
|
@@ -169,7 +339,7 @@ class RedParse
|
|
169
339
|
|
170
340
|
public :remove_instance_variable
|
171
341
|
|
172
|
-
def unparse o; ident end
|
342
|
+
def unparse o=default_unparse_options; ident end
|
173
343
|
alias lhs_unparse unparse
|
174
344
|
|
175
345
|
def delete_extraneous_ivars!
|
@@ -177,21 +347,24 @@ class RedParse
|
|
177
347
|
end
|
178
348
|
|
179
349
|
def walk
|
180
|
-
|
350
|
+
yield nil,nil,nil,self
|
181
351
|
end
|
182
352
|
end
|
183
353
|
|
184
354
|
class StringToken
|
185
355
|
attr :char
|
186
356
|
end
|
187
|
-
|
357
|
+
|
188
358
|
class HerePlaceholderToken
|
189
359
|
attr_accessor :node
|
190
360
|
attr :string
|
191
361
|
end
|
192
362
|
|
193
363
|
class Node<Array
|
364
|
+
include Stackable
|
365
|
+
extend Stackable::Meta
|
194
366
|
include FlattenedIvars
|
367
|
+
|
195
368
|
def initialize(*data)
|
196
369
|
replace data
|
197
370
|
end
|
@@ -206,13 +379,14 @@ class RedParse
|
|
206
379
|
result
|
207
380
|
end
|
208
381
|
|
209
|
-
|
210
382
|
def ==(other)
|
211
383
|
super and flattened_ivars_equal?(other)
|
212
384
|
end
|
213
385
|
|
214
386
|
def image; "(#{inspect})" end
|
215
387
|
|
388
|
+
def error? x; false end
|
389
|
+
|
216
390
|
@@data_warned=nil
|
217
391
|
def data
|
218
392
|
unless @@data_warned
|
@@ -223,7 +397,11 @@ class RedParse
|
|
223
397
|
end
|
224
398
|
alias unwrap data
|
225
399
|
|
226
|
-
|
400
|
+
attr_writer :startline
|
401
|
+
def startline
|
402
|
+
@startline||=endline
|
403
|
+
end
|
404
|
+
attr_accessor :endline
|
227
405
|
attr_accessor :errors
|
228
406
|
|
229
407
|
def self.[](*data)
|
@@ -304,27 +482,32 @@ class RedParse
|
|
304
482
|
def lhs_unparse o; unparse(o) end
|
305
483
|
|
306
484
|
def to_parsetree(*options)
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
485
|
+
o={}
|
486
|
+
[:newlines,:quirks,:ruby187].each{|opt|
|
487
|
+
o[opt]=true if options.include? opt
|
488
|
+
}
|
311
489
|
|
312
|
-
|
313
|
-
Thread.current[:$RedParse_parsetree_quirks]=false
|
490
|
+
result=[parsetree(o)]
|
314
491
|
|
315
|
-
result=[] if result==[[]]
|
492
|
+
result=[] if result==[[]] || result==[nil]
|
316
493
|
|
317
494
|
return result
|
318
495
|
end
|
319
|
-
|
496
|
+
|
497
|
+
def to_parsetree_and_warnings(*options)
|
498
|
+
#for now, no warnings are ever output
|
499
|
+
return to_parsetree(*options),[]
|
500
|
+
end
|
501
|
+
|
502
|
+
def parsetree(o)
|
320
503
|
"wrong(#{inspect})"
|
321
504
|
end
|
322
505
|
|
323
|
-
def rescue_parsetree; parsetree end
|
324
|
-
def begin_parsetree; parsetree end
|
506
|
+
def rescue_parsetree(o); parsetree(o) end
|
507
|
+
def begin_parsetree(o); parsetree(o) end
|
325
508
|
|
326
|
-
def parsetrees list
|
327
|
-
!list.empty? and list.map{|node| node.parsetree}
|
509
|
+
def parsetrees list,o
|
510
|
+
!list.empty? and list.map{|node| node.parsetree(o)}
|
328
511
|
end
|
329
512
|
|
330
513
|
def negate(condition,offset=nil)
|
@@ -342,8 +525,8 @@ class RedParse
|
|
342
525
|
callback[ parent,index,subindex,self ] and
|
343
526
|
each_with_index{|datum,i|
|
344
527
|
case datum
|
345
|
-
when Node
|
346
|
-
when Array
|
528
|
+
when Node; datum.walk(self,i,&callback)
|
529
|
+
when Array;
|
347
530
|
datum.each_with_index{|x,j|
|
348
531
|
Node===x ? x.walk(self,i,j,&callback) : callback[self,i,j,x]
|
349
532
|
}
|
@@ -352,11 +535,65 @@ class RedParse
|
|
352
535
|
}
|
353
536
|
end
|
354
537
|
|
538
|
+
def depthwalk(parent=nil,index=nil,subindex=nil,&callback)
|
539
|
+
each_with_index{|datum,i|
|
540
|
+
case datum
|
541
|
+
when Node
|
542
|
+
datum.depthwalk(self,i,&callback)
|
543
|
+
when Array
|
544
|
+
datum.each_with_index{|x,j|
|
545
|
+
if Node===x
|
546
|
+
x.depthwalk(self,i,j,&callback)
|
547
|
+
else
|
548
|
+
callback[self,i,j,x]
|
549
|
+
end
|
550
|
+
}
|
551
|
+
else
|
552
|
+
callback[self, i, nil, datum]
|
553
|
+
end
|
554
|
+
}
|
555
|
+
callback[ parent,index,subindex,self ]
|
556
|
+
end
|
557
|
+
|
558
|
+
def add_parent_links!
|
559
|
+
walk{|parent,i,subi,o|
|
560
|
+
o.parent=parent if Node===o
|
561
|
+
}
|
562
|
+
end
|
563
|
+
|
564
|
+
attr_accessor :parent
|
565
|
+
|
566
|
+
def xform_tree!(xformer)
|
567
|
+
session={}
|
568
|
+
depthwalk{|parent,i,subi,o|
|
569
|
+
xformer.xform!(o,session) if o
|
570
|
+
}
|
571
|
+
session["final"]=true
|
572
|
+
depthwalk{|parent,i,subi,o|
|
573
|
+
if session.has_key? o.__id__
|
574
|
+
new= session[o.__id__]
|
575
|
+
if Reg::Formula===new
|
576
|
+
new=new.formula_value(o,session)
|
577
|
+
end
|
578
|
+
subi ? parent[i][subi]=new : parent[i]=new
|
579
|
+
end
|
580
|
+
}
|
581
|
+
if session.has_key? self.__id__
|
582
|
+
new= session[self.__id__]
|
583
|
+
if Reg::Formula===new
|
584
|
+
new=new.formula_value(self,session)
|
585
|
+
end
|
586
|
+
return new
|
587
|
+
else
|
588
|
+
return self
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
355
592
|
def linerange
|
356
593
|
min=9999999999999999999999999999999999999999999999999999
|
357
594
|
max=0
|
358
595
|
walk{|parent,i,subi,node|
|
359
|
-
if node.respond_to? :
|
596
|
+
if node.respond_to? :endline and line=node.endline
|
360
597
|
min=[min,line].min
|
361
598
|
max=[max,line].max
|
362
599
|
end
|
@@ -364,7 +601,7 @@ class RedParse
|
|
364
601
|
return min..max
|
365
602
|
end
|
366
603
|
|
367
|
-
def fixup_multiple_assignments!
|
604
|
+
def fixup_multiple_assignments! #dead code
|
368
605
|
result=self
|
369
606
|
walk{|parent,i,subi,node|
|
370
607
|
if CommaOpNode===node
|
@@ -413,18 +650,18 @@ class RedParse
|
|
413
650
|
|
414
651
|
def prohibit_fixup x
|
415
652
|
case x
|
416
|
-
when UnaryStarNode
|
417
|
-
# when ParenedNode
|
418
|
-
when CallSiteNode
|
653
|
+
when UnaryStarNode; true
|
654
|
+
# when ParenedNode; x.size>1
|
655
|
+
when CallSiteNode; x.params and !x.real_parens
|
419
656
|
else false
|
420
657
|
end
|
421
658
|
end
|
422
659
|
|
423
|
-
def fixup_rescue_assignments!
|
660
|
+
def fixup_rescue_assignments! #dead code
|
424
661
|
result=self
|
425
662
|
walk{|parent,i,subi,node|
|
426
663
|
#if a rescue op with a single assignment on the lhs
|
427
|
-
if
|
664
|
+
if RescueOpNode===node and assign=node.first and #ick
|
428
665
|
AssignNode===assign and assign.op.ident=="=" and
|
429
666
|
!(assign.multi? or
|
430
667
|
prohibit_fixup assign.right)
|
@@ -432,7 +669,7 @@ class RedParse
|
|
432
669
|
|
433
670
|
#re-hang the node with = at the top instead of rescue
|
434
671
|
node=AssignNode.new(assign.left, assign.op,
|
435
|
-
|
672
|
+
RescueOpNode.new(assign.right,nil,node[1][0].action)
|
436
673
|
)
|
437
674
|
|
438
675
|
#graft the new node back onto the old tree
|
@@ -461,7 +698,7 @@ class RedParse
|
|
461
698
|
result=[]
|
462
699
|
walk {|parent,i,subi,node|
|
463
700
|
case node
|
464
|
-
when MethodNode,ClassNode,ModuleNode,MetaClassNode
|
701
|
+
when MethodNode,ClassNode,ModuleNode,MetaClassNode; false
|
465
702
|
when CallSiteNode
|
466
703
|
Node===node.receiver and
|
467
704
|
result.concat node.receiver.lvars_defined_in
|
@@ -474,19 +711,17 @@ class RedParse
|
|
474
711
|
lvalue.respond_to? :all_current_lvars and
|
475
712
|
result.concat lvalue.all_current_lvars
|
476
713
|
true
|
477
|
-
when ForNode
|
714
|
+
when ForNode
|
478
715
|
lvalue=node.for
|
479
716
|
lvalue.respond_to? :all_current_lvars and
|
480
717
|
result.concat lvalue.all_current_lvars
|
481
718
|
true
|
482
|
-
when
|
483
|
-
if node.size>1
|
719
|
+
when RescueOpNode,BeginNode
|
484
720
|
rescues=node[1]
|
485
721
|
rescues.each{|resc|
|
486
722
|
name=resc.varname
|
487
723
|
name and result.push name.ident
|
488
724
|
}
|
489
|
-
end
|
490
725
|
true
|
491
726
|
else true
|
492
727
|
end
|
@@ -497,7 +732,7 @@ class RedParse
|
|
497
732
|
end
|
498
733
|
|
499
734
|
def unary; false end
|
500
|
-
def lvalue
|
735
|
+
def lvalue; nil end
|
501
736
|
|
502
737
|
def deep_copy transform={},&override
|
503
738
|
handler=proc{|child|
|
@@ -537,10 +772,11 @@ class RedParse
|
|
537
772
|
def delete_extraneous_ivars!
|
538
773
|
walk{|parent,i,subi,node|
|
539
774
|
case node
|
540
|
-
when Node
|
775
|
+
when Node
|
541
776
|
node.remove_instance_variable :@offset rescue nil
|
542
777
|
node.remove_instance_variable :@loopword_offset rescue nil
|
543
|
-
node.remove_instance_variable :@
|
778
|
+
node.remove_instance_variable :@endline rescue nil
|
779
|
+
node.remove_instance_variable :@lvalue rescue nil
|
544
780
|
if node.respond_to? :lvalue
|
545
781
|
node.lvalue or
|
546
782
|
node.remove_instance_variable :@lvalue rescue nil
|
@@ -554,6 +790,18 @@ class RedParse
|
|
554
790
|
return self
|
555
791
|
end
|
556
792
|
|
793
|
+
def delete_linenums!
|
794
|
+
walk{|parent,i,subi,node|
|
795
|
+
case node
|
796
|
+
when Node
|
797
|
+
node.remove_instance_variable :@endline rescue nil
|
798
|
+
node.remove_instance_variable :@startline rescue nil
|
799
|
+
end
|
800
|
+
true
|
801
|
+
}
|
802
|
+
return self
|
803
|
+
end
|
804
|
+
|
557
805
|
public :remove_instance_variable
|
558
806
|
|
559
807
|
#convert to a Reg::Array expression. subnodes are also converted.
|
@@ -575,9 +823,6 @@ class RedParse
|
|
575
823
|
end
|
576
824
|
|
577
825
|
private
|
578
|
-
def quirks
|
579
|
-
Thread.current[:$RedParse_parsetree_quirks]
|
580
|
-
end
|
581
826
|
|
582
827
|
#turn a list (array) of arrays into a linked list, in which each array
|
583
828
|
#has a reference to the next in turn as its last element.
|
@@ -620,25 +865,151 @@ class RedParse
|
|
620
865
|
handle_normals[]
|
621
866
|
end
|
622
867
|
|
623
|
-
def param_list_parse(param_list)
|
868
|
+
def param_list_parse(param_list,o)
|
624
869
|
output=[]
|
625
870
|
star=amp=nil
|
626
871
|
param_list_walk(param_list){|type,val,i|
|
627
872
|
case type
|
628
|
-
when ''
|
629
|
-
output.concat val.map{|param| param.rescue_parsetree}
|
630
|
-
when '=>'
|
631
|
-
output.push HashLiteralNode.new(nil,val,nil).parsetree
|
632
|
-
when '*'
|
633
|
-
when '&'
|
873
|
+
when ''
|
874
|
+
output.concat val.map{|param| param.rescue_parsetree(o)}
|
875
|
+
when '=>'
|
876
|
+
output.push HashLiteralNode.new(nil,val,nil).parsetree(o)
|
877
|
+
when '*'; star=val.parsetree(o)
|
878
|
+
when '&'; amp=val.parsetree(o)
|
634
879
|
end
|
635
880
|
}
|
636
881
|
return output,star,amp
|
637
882
|
end
|
883
|
+
|
884
|
+
def unparse_nl(token,o,alt=';',nl="\n")
|
885
|
+
|
886
|
+
#should really only emit newlines
|
887
|
+
#to bring line count up to startline, not endline.
|
888
|
+
|
889
|
+
linenum= Integer===token ? token : token.startline rescue (return alt)
|
890
|
+
shy=(linenum||0)-o[:linenum]
|
891
|
+
return alt if shy<=0
|
892
|
+
o[:linenum]=linenum
|
893
|
+
return nl*shy
|
894
|
+
end
|
895
|
+
|
896
|
+
def default_unparse_options
|
897
|
+
{:linenum=>1}
|
898
|
+
end
|
638
899
|
end
|
639
900
|
|
640
901
|
class ValueNode<Node
|
641
|
-
def lvalue
|
902
|
+
def lvalue; nil end
|
903
|
+
#identity_param :lvalue, nil, true
|
904
|
+
end
|
905
|
+
|
906
|
+
class VarNode<ValueNode
|
907
|
+
include FlattenedIvars
|
908
|
+
attr_accessor :endline
|
909
|
+
attr_reader :lvar_type,:in_def,:offset
|
910
|
+
attr_writer :lvalue
|
911
|
+
|
912
|
+
|
913
|
+
alias == flattened_ivars_equal?
|
914
|
+
|
915
|
+
def initialize(tok)
|
916
|
+
super(tok.ident)
|
917
|
+
@lvar_type=tok.lvar_type
|
918
|
+
@offset=tok.offset
|
919
|
+
@endline=tok.endline
|
920
|
+
@in_def=tok.in_def
|
921
|
+
end
|
922
|
+
|
923
|
+
def ident; first end
|
924
|
+
def ident=x; self[0]=x end
|
925
|
+
alias image ident
|
926
|
+
alias startline endline
|
927
|
+
|
928
|
+
def parsetree(o)
|
929
|
+
type=case ident[0]
|
930
|
+
when ?$:
|
931
|
+
case ident[1]
|
932
|
+
when ?1..?9; return [:nth_ref,ident[1..-1].to_i]
|
933
|
+
when ?&,?+,?`,?'; return [:back_ref,ident[1].chr.to_sym] #`
|
934
|
+
else :gvar
|
935
|
+
end
|
936
|
+
when ?@
|
937
|
+
if ident[1]==?@
|
938
|
+
:cvar
|
939
|
+
else
|
940
|
+
:ivar
|
941
|
+
end
|
942
|
+
when ?A..?Z; :const
|
943
|
+
else
|
944
|
+
case lvar_type
|
945
|
+
when :local; :lvar
|
946
|
+
when :block; :dvar
|
947
|
+
when :current; :dvar#_curr
|
948
|
+
else fail
|
949
|
+
end
|
950
|
+
end
|
951
|
+
return [type,ident.to_sym]
|
952
|
+
end
|
953
|
+
|
954
|
+
def varname2assigntype
|
955
|
+
case ident[0]
|
956
|
+
when ?$; :gasgn
|
957
|
+
when ?@
|
958
|
+
if ident[1]!=?@; :iasgn
|
959
|
+
elsif in_def; :cvasgn
|
960
|
+
else :cvdecl
|
961
|
+
end
|
962
|
+
when ?A..?Z; :cdecl
|
963
|
+
else
|
964
|
+
case lvar_type
|
965
|
+
when :local; :lasgn
|
966
|
+
when :block; :dasgn
|
967
|
+
when :current; :dasgn_curr
|
968
|
+
else fail
|
969
|
+
end
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
def lvalue_parsetree(o)
|
974
|
+
[varname2assigntype, ident.to_sym]
|
975
|
+
end
|
976
|
+
|
977
|
+
alias to_lisp to_s
|
978
|
+
|
979
|
+
def lvalue
|
980
|
+
return @lvalue if defined? @lvalue
|
981
|
+
@lvalue=true
|
982
|
+
end
|
983
|
+
|
984
|
+
identity_param :lvalue, nil, true
|
985
|
+
|
986
|
+
def all_current_lvars
|
987
|
+
lvar_type==:current ? [ident] : []
|
988
|
+
end
|
989
|
+
|
990
|
+
|
991
|
+
def dup
|
992
|
+
result=super
|
993
|
+
result.ident=@ident.dup if @ident
|
994
|
+
return result
|
995
|
+
end
|
996
|
+
|
997
|
+
public :remove_instance_variable
|
998
|
+
|
999
|
+
def unparse o=default_unparse_options; ident end
|
1000
|
+
alias lhs_unparse unparse
|
1001
|
+
|
1002
|
+
# def delete_extraneous_ivars!
|
1003
|
+
# remove_instance_variable :@lvalue
|
1004
|
+
# super
|
1005
|
+
# end
|
1006
|
+
|
1007
|
+
if false
|
1008
|
+
def walk #is this needed?
|
1009
|
+
yield nil,nil,nil,self
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
|
642
1013
|
end
|
643
1014
|
|
644
1015
|
#forward decls
|
@@ -704,34 +1075,34 @@ class RedParse
|
|
704
1075
|
"(#{op} #{left.to_lisp} #{right.to_lisp})"
|
705
1076
|
end
|
706
1077
|
|
707
|
-
def parsetree
|
1078
|
+
def parsetree(o)
|
708
1079
|
[:call,
|
709
|
-
left.rescue_parsetree,
|
1080
|
+
left.rescue_parsetree(o),
|
710
1081
|
op.to_sym,
|
711
|
-
[:array, right.rescue_parsetree]
|
1082
|
+
[:array, right.rescue_parsetree(o)]
|
712
1083
|
]
|
713
1084
|
end
|
714
1085
|
alias opnode_parsetree parsetree
|
715
1086
|
|
716
|
-
def unparse o
|
1087
|
+
def unparse o=default_unparse_options
|
717
1088
|
result=l=left.unparse(o)
|
718
|
-
result+=" " if /
|
1089
|
+
result+=" " if /\A(?:!|#{LCLETTER})/o===op
|
719
1090
|
result+=op
|
720
|
-
result+=" " if /
|
1091
|
+
result+=" " if /#{LETTER_DIGIT}\Z/o===op or / \Z/===l
|
721
1092
|
result+=right.unparse(o)
|
722
1093
|
end
|
723
1094
|
|
724
|
-
def unparse o; raw_unparse o end
|
1095
|
+
# def unparse o=default_unparse_options; raw_unparse o end
|
725
1096
|
end
|
726
1097
|
|
727
1098
|
module MatchNode
|
728
1099
|
include OpNode
|
729
1100
|
|
730
|
-
def parsetree
|
1101
|
+
def parsetree(o)
|
731
1102
|
if StringNode===left and left.char=='/'
|
732
|
-
[:match2, left.parsetree, right.parsetree]
|
1103
|
+
[:match2, left.parsetree(o), right.parsetree(o)]
|
733
1104
|
elsif StringNode===right and right.char=='/'
|
734
|
-
[:match3, right.parsetree, left.parsetree]
|
1105
|
+
[:match3, right.parsetree(o), left.parsetree(o)]
|
735
1106
|
else
|
736
1107
|
super
|
737
1108
|
end
|
@@ -742,8 +1113,8 @@ class RedParse
|
|
742
1113
|
module NotEqualNode
|
743
1114
|
include OpNode
|
744
1115
|
|
745
|
-
def parsetree
|
746
|
-
result=opnode_parsetree
|
1116
|
+
def parsetree(o)
|
1117
|
+
result=opnode_parsetree(o)
|
747
1118
|
result[2]="=#{op[1..1]}".to_sym
|
748
1119
|
result=[:not, result]
|
749
1120
|
return result
|
@@ -754,11 +1125,11 @@ class RedParse
|
|
754
1125
|
module NotMatchNode
|
755
1126
|
include NotEqualNode
|
756
1127
|
|
757
|
-
def parsetree
|
1128
|
+
def parsetree(o)
|
758
1129
|
if StringNode===left and left.char=="/"
|
759
|
-
[:not, [:match2, left.parsetree, right.parsetree]]
|
1130
|
+
[:not, [:match2, left.parsetree(o), right.parsetree(o)]]
|
760
1131
|
elsif StringNode===right and right.char=="/"
|
761
|
-
[:not, [:match3, right.parsetree, left.parsetree]]
|
1132
|
+
[:not, [:match3, right.parsetree(o), left.parsetree(o)]]
|
762
1133
|
else
|
763
1134
|
super
|
764
1135
|
end
|
@@ -775,11 +1146,11 @@ class RedParse
|
|
775
1146
|
[val1]
|
776
1147
|
end
|
777
1148
|
if self.class===val2
|
778
|
-
list.push *val2
|
1149
|
+
list.push( *val2 )
|
779
1150
|
elsif val2
|
780
1151
|
list.push val2
|
781
1152
|
end
|
782
|
-
super *list
|
1153
|
+
super( *list )
|
783
1154
|
end
|
784
1155
|
end
|
785
1156
|
|
@@ -788,11 +1159,12 @@ class RedParse
|
|
788
1159
|
def to_lisp
|
789
1160
|
"(#{map{|x| x.to_lisp}.join(" ")})"
|
790
1161
|
end
|
791
|
-
def lvalue
|
1162
|
+
def lvalue
|
792
1163
|
return @lvalue if defined? @lvalue
|
793
1164
|
@lvalue=true
|
794
1165
|
end
|
795
|
-
|
1166
|
+
attr_writer :lvalue
|
1167
|
+
identity_param :lvalue, nil, true
|
796
1168
|
end
|
797
1169
|
|
798
1170
|
class LiteralNode<ValueNode; end
|
@@ -818,24 +1190,26 @@ class RedParse
|
|
818
1190
|
#class<<LITCAT; alias === call; end
|
819
1191
|
LITCAT=StringCatNode& item_that.grep(~LITSTR).empty? #+[LITSTR.+]
|
820
1192
|
LITNODE=LiteralNode|NopNode|LITSTR|LITCAT|LITRANGE|(VarLikeNode&-{:name=>/^__/})
|
821
|
-
#
|
822
|
-
def parsetree
|
1193
|
+
#VarNode| #why not this too?
|
1194
|
+
def parsetree(o)
|
823
1195
|
data=compact
|
824
1196
|
data.empty? and return
|
825
1197
|
items=Array.new(data[0...-1])
|
826
|
-
if quirks
|
1198
|
+
if o[:quirks]
|
827
1199
|
items.shift while LITNODE===items.first
|
828
1200
|
else
|
829
1201
|
items.reject!{|expr| LITNODE===expr }
|
830
1202
|
end
|
831
|
-
items.map!{|expr| expr.rescue_parsetree}.push last.parsetree
|
832
|
-
# items=map{|expr| expr.parsetree}
|
1203
|
+
items.map!{|expr| expr.rescue_parsetree(o)}.push last.parsetree(o)
|
1204
|
+
# items=map{|expr| expr.parsetree(o)}
|
833
1205
|
items.reject!{|expr| []==expr }
|
834
|
-
if quirks
|
835
|
-
|
836
|
-
|
1206
|
+
if o[:quirks]
|
1207
|
+
unless BeginNode===data[0]
|
1208
|
+
header=items.first
|
1209
|
+
(items[0,1] = *header[1..-1]) if header and header.first==:block
|
1210
|
+
end
|
837
1211
|
else
|
838
|
-
items.size.
|
1212
|
+
(items.size-1).downto(0){|i|
|
839
1213
|
header=items[i]
|
840
1214
|
(items[i,1] = *header[1..-1]) if header and header.first==:block
|
841
1215
|
}
|
@@ -849,25 +1223,21 @@ class RedParse
|
|
849
1223
|
end
|
850
1224
|
end
|
851
1225
|
|
852
|
-
def unparse o
|
853
|
-
map{|expr| expr.unparse(o)}.
|
1226
|
+
def unparse o=default_unparse_options
|
1227
|
+
map{|expr| unparse_nl(expr,o)+expr.unparse(o)}.to_s
|
854
1228
|
end
|
855
1229
|
end
|
856
1230
|
|
857
1231
|
class StringCatNode < ValueNode
|
858
|
-
def initialize(
|
859
|
-
|
860
|
-
|
861
|
-
strs.push str
|
862
|
-
else
|
863
|
-
strs.push str1,str2
|
864
|
-
end
|
1232
|
+
def initialize(*strses)
|
1233
|
+
strs=strses.pop.unshift( *strses )
|
1234
|
+
hd=strs.shift if HereDocNode===strs.first
|
865
1235
|
strs.map!{|str| StringNode.new(str)}
|
866
1236
|
strs.unshift hd if hd
|
867
|
-
super *strs
|
1237
|
+
super( *strs )
|
868
1238
|
end
|
869
|
-
def parsetree
|
870
|
-
result=map{|str| str.parsetree}
|
1239
|
+
def parsetree(o)
|
1240
|
+
result=map{|str| str.parsetree(o)}
|
871
1241
|
sum=''
|
872
1242
|
type=:str
|
873
1243
|
tree=i=nil
|
@@ -885,6 +1255,8 @@ class RedParse
|
|
885
1255
|
x[0]=[:str,x0]
|
886
1256
|
end
|
887
1257
|
cat+x
|
1258
|
+
elsif x.last.empty?
|
1259
|
+
cat
|
888
1260
|
else
|
889
1261
|
cat+[x]
|
890
1262
|
end
|
@@ -892,7 +1264,7 @@ class RedParse
|
|
892
1264
|
]
|
893
1265
|
end
|
894
1266
|
|
895
|
-
def unparse o
|
1267
|
+
def unparse o=default_unparse_options
|
896
1268
|
map{|ss| ss.unparse(o)}.join ' '
|
897
1269
|
end
|
898
1270
|
end
|
@@ -900,10 +1272,14 @@ class RedParse
|
|
900
1272
|
# class ArrowOpNode<ValueNode
|
901
1273
|
# param_names(:left,:arrow_,:right)
|
902
1274
|
# end
|
903
|
-
module ArrowOpNode
|
1275
|
+
module ArrowOpNode
|
904
1276
|
def initialize(*args)
|
905
1277
|
@module=ArrowOpNode
|
906
1278
|
end
|
1279
|
+
|
1280
|
+
def unparse(o=default_unparse_options)
|
1281
|
+
left.unparse(o)+" => "+right.unparse(o)
|
1282
|
+
end
|
907
1283
|
end
|
908
1284
|
|
909
1285
|
# class RangeNode<ValueNode
|
@@ -921,9 +1297,9 @@ class RedParse
|
|
921
1297
|
def last; right end
|
922
1298
|
def exclude_end?; @exclude_end end
|
923
1299
|
|
924
|
-
def parsetree
|
925
|
-
first=first().parsetree
|
926
|
-
last=last().parsetree
|
1300
|
+
def parsetree(o)
|
1301
|
+
first=first().parsetree(o)
|
1302
|
+
last=last().parsetree(o)
|
927
1303
|
if :lit==first.first and :lit==last.first and
|
928
1304
|
Fixnum===first.last and Fixnum===last.last
|
929
1305
|
return [:lit, Range.new(first.last,last.last,@exclude_end)]
|
@@ -938,7 +1314,7 @@ class RedParse
|
|
938
1314
|
@as_flow_control=true
|
939
1315
|
end
|
940
1316
|
|
941
|
-
def unparse(o)
|
1317
|
+
def unparse(o=default_unparse_options)
|
942
1318
|
result=left.unparse(o)+'..'
|
943
1319
|
result+='.' if exclude_end?
|
944
1320
|
result << right.unparse(o)
|
@@ -949,9 +1325,9 @@ class RedParse
|
|
949
1325
|
class UnOpNode<ValueNode
|
950
1326
|
param_names(:op,:val)
|
951
1327
|
def initialize(op,val)
|
952
|
-
# /^[&*+-]$/===op.ident and op.ident+="@"
|
953
1328
|
op=op.ident
|
954
|
-
|
1329
|
+
/([&*])$/===op and op=$1+"@"
|
1330
|
+
/^(?:!|not)$/===op and
|
955
1331
|
val.respond_to? :special_conditions! and
|
956
1332
|
val.special_conditions!
|
957
1333
|
super(op,val)
|
@@ -961,49 +1337,54 @@ class RedParse
|
|
961
1337
|
|
962
1338
|
def image; "(#{op})" end
|
963
1339
|
|
964
|
-
def lvalue
|
1340
|
+
def lvalue
|
965
1341
|
# return nil unless op=="*@"
|
966
1342
|
|
967
1343
|
return @lvalue if defined? @lvalue
|
968
1344
|
@lvalue=true
|
969
1345
|
end
|
970
|
-
|
1346
|
+
attr_writer :lvalue
|
971
1347
|
|
972
1348
|
def to_lisp
|
973
1349
|
"(#{op} #{val.to_lisp})"
|
974
1350
|
end
|
975
1351
|
|
976
|
-
def parsetree
|
1352
|
+
def parsetree(o)
|
977
1353
|
node=self
|
978
1354
|
node=node.val while UnOpNode===node and node.op=="+@"
|
979
|
-
return node.parsetree if LiteralNode&-{:val=>Integer|Float|Symbol}===node
|
980
|
-
return node.parsetree if StringNode&-{:char=>'/', :size=>1}===node
|
1355
|
+
return node.parsetree(o) if LiteralNode&-{:val=>Integer|Float|Symbol}===node
|
1356
|
+
return node.parsetree(o) if StringNode&-{:char=>'/', :size=>1}===node
|
981
1357
|
|
982
1358
|
case op
|
983
|
-
when
|
984
|
-
when "!","not"
|
985
|
-
when "defined?"
|
1359
|
+
when /^&/; [:block_arg, val.ident.to_sym]
|
1360
|
+
when "!","not"; [:not, val.rescue_parsetree(o)]
|
1361
|
+
when "defined?"; [:defined, val.parsetree(o)]
|
986
1362
|
else
|
987
|
-
[:call, val.rescue_parsetree, op.to_sym]
|
1363
|
+
[:call, val.rescue_parsetree(o), op.to_sym]
|
988
1364
|
end
|
989
1365
|
end
|
990
1366
|
|
991
|
-
def lvalue_parsetree
|
992
|
-
parsetree
|
1367
|
+
def lvalue_parsetree(o)
|
1368
|
+
parsetree(o)
|
993
1369
|
end
|
994
1370
|
|
995
|
-
def unparse o
|
1371
|
+
def unparse o=default_unparse_options
|
996
1372
|
op=op()
|
997
1373
|
op=op.chomp "@"
|
998
1374
|
result=op
|
999
|
-
result+=" " if /[
|
1375
|
+
result+=" " if /#{LETTER}/o===op or /^[+-]/===op && LiteralNode===val
|
1000
1376
|
result+=val.unparse(o)
|
1001
1377
|
end
|
1002
1378
|
end
|
1003
1379
|
|
1004
1380
|
class UnaryStarNode<UnOpNode
|
1005
|
-
def
|
1006
|
-
|
1381
|
+
def initialize(op,val)
|
1382
|
+
op.ident="*@"
|
1383
|
+
super(op,val)
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
def parsetree(o)
|
1387
|
+
[:splat, val.rescue_parsetree(o)]
|
1007
1388
|
end
|
1008
1389
|
|
1009
1390
|
def all_current_lvars
|
@@ -1012,11 +1393,13 @@ class RedParse
|
|
1012
1393
|
end
|
1013
1394
|
attr_accessor :after_comma
|
1014
1395
|
|
1015
|
-
def lvalue_parsetree
|
1016
|
-
val.lvalue_parsetree
|
1396
|
+
def lvalue_parsetree o
|
1397
|
+
val.lvalue_parsetree(o)
|
1017
1398
|
end
|
1018
1399
|
|
1019
|
-
|
1400
|
+
identity_param :lvalue, nil, true
|
1401
|
+
|
1402
|
+
def unparse o=default_unparse_options
|
1020
1403
|
"*"+val.unparse(o)
|
1021
1404
|
end
|
1022
1405
|
end
|
@@ -1025,14 +1408,14 @@ class RedParse
|
|
1025
1408
|
#param_names :op,:val
|
1026
1409
|
def initialize(star)
|
1027
1410
|
@offset= star.offset
|
1028
|
-
replace ['*@',VarNameToken.new('',offset)]
|
1411
|
+
replace ['*@',VarNode.new(VarNameToken.new('',offset))]
|
1029
1412
|
end
|
1030
1413
|
attr :offset
|
1031
1414
|
def lvars_defined_in; [] end
|
1032
|
-
def parsetree; [:splat] end
|
1415
|
+
def parsetree(o); [:splat] end
|
1033
1416
|
alias lvalue_parsetree parsetree
|
1034
1417
|
|
1035
|
-
def unparse(o); "* "; end
|
1418
|
+
def unparse(o=nil); "* "; end
|
1036
1419
|
end
|
1037
1420
|
|
1038
1421
|
class DanglingCommaNode<DanglingStarNode
|
@@ -1041,26 +1424,26 @@ class RedParse
|
|
1041
1424
|
end
|
1042
1425
|
attr_accessor :offset
|
1043
1426
|
|
1044
|
-
def lvalue_parsetree
|
1427
|
+
def lvalue_parsetree o
|
1045
1428
|
:dangle_comma
|
1046
1429
|
end
|
1047
1430
|
alias parsetree lvalue_parsetree
|
1048
1431
|
|
1049
|
-
def unparse o; ""; end
|
1432
|
+
def unparse o=default_unparse_options; ""; end
|
1050
1433
|
end
|
1051
1434
|
|
1052
1435
|
class ConstantNode<ListOpNode
|
1053
1436
|
def initialize(*args)
|
1054
1437
|
args.unshift nil if args.size==2
|
1055
1438
|
args.map!{|node|
|
1056
|
-
if
|
1439
|
+
if VarNode===node and (?A..?Z)===node.ident[0]
|
1057
1440
|
then node.ident
|
1058
1441
|
else node
|
1059
1442
|
end
|
1060
1443
|
}
|
1061
1444
|
super(*args)
|
1062
1445
|
end
|
1063
|
-
def unparse(o)
|
1446
|
+
def unparse(o=default_unparse_options)
|
1064
1447
|
if Node===first
|
1065
1448
|
result=dup
|
1066
1449
|
result[0]= first.unparse(o)#.gsub(/\s+\Z/,'')
|
@@ -1069,16 +1452,16 @@ class RedParse
|
|
1069
1452
|
end
|
1070
1453
|
end
|
1071
1454
|
alias image unparse
|
1072
|
-
def lvalue_parsetree
|
1073
|
-
[:cdecl,parsetree]
|
1455
|
+
def lvalue_parsetree(o)
|
1456
|
+
[:cdecl,parsetree(o)]
|
1074
1457
|
end
|
1075
|
-
def parsetree
|
1458
|
+
def parsetree(o)
|
1076
1459
|
if !first
|
1077
1460
|
result=[:colon3, self[1].to_sym]
|
1078
1461
|
i=2
|
1079
1462
|
else
|
1080
1463
|
result=first.respond_to?(:parsetree) ?
|
1081
|
-
first.parsetree :
|
1464
|
+
first.parsetree(o) :
|
1082
1465
|
[:const,first.to_sym]
|
1083
1466
|
i=1
|
1084
1467
|
end
|
@@ -1087,46 +1470,47 @@ class RedParse
|
|
1087
1470
|
}
|
1088
1471
|
end
|
1089
1472
|
|
1090
|
-
def lvalue
|
1473
|
+
def lvalue
|
1091
1474
|
return @lvalue if defined? @lvalue
|
1092
1475
|
@lvalue=true
|
1093
1476
|
end
|
1094
|
-
|
1477
|
+
attr_writer :lvalue
|
1478
|
+
identity_param :lvalue, nil, true
|
1095
1479
|
end
|
1096
1480
|
LookupNode=ConstantNode
|
1097
1481
|
|
1098
|
-
class DoubleColonNode<ValueNode
|
1099
|
-
|
1482
|
+
class DoubleColonNode<ValueNode #obsolete
|
1483
|
+
#dunno about this name... maybe ConstantNode?
|
1100
1484
|
param_names :namespace, :constant
|
1101
1485
|
alias left namespace
|
1102
1486
|
alias right constant
|
1103
1487
|
def initialize(val1,op,val2=nil)
|
1104
1488
|
val1,op,val2=nil,val1,op unless val2
|
1105
|
-
val1=val1.ident if
|
1106
|
-
val2=val2.ident if
|
1489
|
+
val1=val1.ident if VarNode===val1 and /\A#{UCLETTER}/o===val1.ident
|
1490
|
+
val2=val2.ident if VarNode===val1 and /\A#{UCLETTER}/o===val2.ident
|
1107
1491
|
replace [val1,val2]
|
1108
1492
|
end
|
1109
1493
|
|
1110
1494
|
def image; '(::)' end
|
1111
1495
|
|
1112
1496
|
|
1113
|
-
def parsetree
|
1497
|
+
def parsetree(o)
|
1114
1498
|
if namespace
|
1115
|
-
ns= (String===namespace) ? [:const,namespace.to_sym] : namespace.parsetree
|
1499
|
+
ns= (String===namespace) ? [:const,namespace.to_sym] : namespace.parsetree(o)
|
1116
1500
|
[:colon2, ns, constant.to_sym]
|
1117
1501
|
else
|
1118
1502
|
[:colon3, constant.to_sym]
|
1119
1503
|
end
|
1120
1504
|
end
|
1121
|
-
def lvalue_parsetree
|
1122
|
-
[:cdecl,parsetree]
|
1505
|
+
def lvalue_parsetree(o)
|
1506
|
+
[:cdecl,parsetree(o)]
|
1123
1507
|
end
|
1124
1508
|
|
1125
|
-
def lvalue
|
1509
|
+
def lvalue
|
1126
1510
|
return @lvalue if defined? @lvalue
|
1127
1511
|
@lvalue=true
|
1128
1512
|
end
|
1129
|
-
|
1513
|
+
attr_writer :lvalue
|
1130
1514
|
end
|
1131
1515
|
|
1132
1516
|
class DotCallNode<ValueNode #obsolete
|
@@ -1138,20 +1522,21 @@ class RedParse
|
|
1138
1522
|
"(#{receiver.to_lisp} #{@data.last.to_lisp[1...-1]})"
|
1139
1523
|
end
|
1140
1524
|
|
1141
|
-
def parsetree
|
1525
|
+
def parsetree(o)
|
1142
1526
|
cs=self[1]
|
1143
|
-
cs &&= cs.parsetree
|
1527
|
+
cs &&= cs.parsetree(o)
|
1144
1528
|
cs.shift if cs.first==:vcall or cs.first==:fcall
|
1145
|
-
[:call, @data.first.parsetree, *cs]
|
1529
|
+
[:call, @data.first.parsetree(o), *cs]
|
1146
1530
|
end
|
1147
|
-
def lvalue
|
1531
|
+
def lvalue
|
1148
1532
|
return @lvalue if defined? @lvalue
|
1149
1533
|
@lvalue=true
|
1150
1534
|
end
|
1151
|
-
|
1535
|
+
attr_writer :lvalue
|
1152
1536
|
end
|
1153
1537
|
|
1154
|
-
|
1538
|
+
=begin
|
1539
|
+
class OldParenedNode<ValueNode
|
1155
1540
|
param_names :body, :rescues, :else!, :ensure!
|
1156
1541
|
def initialize(*args)
|
1157
1542
|
@empty_ensure=@op_rescue=nil
|
@@ -1197,20 +1582,10 @@ class RedParse
|
|
1197
1582
|
huh #what about rescues, else, ensure?
|
1198
1583
|
body.to_lisp
|
1199
1584
|
end
|
1200
|
-
|
1201
|
-
def self.want_extra_begin!(x=true)
|
1202
|
-
@@want_extra_begin=x
|
1203
|
-
end
|
1204
|
-
def want_extra_begin?
|
1205
|
-
return @@want_extra_begin if defined? @@want_extra_begin
|
1206
|
-
@@want_extra_begin =
|
1207
|
-
defined?(::ParseTree) and
|
1208
|
-
::ParseTree.new.parse_tree_for_string("begin; a; end")==[[:begin, [:vcall, :a]]]
|
1209
|
-
end
|
1210
1585
|
|
1211
|
-
def parsetree
|
1586
|
+
def parsetree(o)
|
1212
1587
|
if size==1
|
1213
|
-
body.parsetree
|
1588
|
+
body.parsetree(o)
|
1214
1589
|
else
|
1215
1590
|
body=body()
|
1216
1591
|
target=result=[] #was: [:begin, ]
|
@@ -1218,7 +1593,7 @@ class RedParse
|
|
1218
1593
|
#body,rescues,else_,ensure_=*self
|
1219
1594
|
target.push target=[:ensure, ] if ensure_ or @empty_ensure
|
1220
1595
|
|
1221
|
-
rescues=rescues().map{|resc| resc.parsetree}
|
1596
|
+
rescues=rescues().map{|resc| resc.parsetree(o)}
|
1222
1597
|
if rescues.empty?
|
1223
1598
|
else_ and
|
1224
1599
|
body=SequenceNode.new(body,nil,else_)
|
@@ -1228,66 +1603,309 @@ class RedParse
|
|
1228
1603
|
else_=else_()
|
1229
1604
|
end
|
1230
1605
|
if body
|
1231
|
-
needbegin= (
|
1232
|
-
body=body.parsetree
|
1233
|
-
body=[:begin, body] if needbegin and body.first!=:begin
|
1606
|
+
needbegin= (BeginNode===body and body.after_equals)
|
1607
|
+
body=body.parsetree(o)
|
1608
|
+
body=[:begin, body] if needbegin and body.first!=:begin and !o[:ruby187]
|
1234
1609
|
(newtarget||target).push body if body
|
1235
1610
|
end
|
1236
|
-
target.push ensure_.parsetree if ensure_
|
1611
|
+
target.push ensure_.parsetree(o) if ensure_
|
1237
1612
|
target.push [:nil] if @empty_ensure
|
1238
1613
|
target=newtarget if newtarget
|
1239
1614
|
|
1240
1615
|
unless rescues.empty?
|
1241
1616
|
target.push linked_list(rescues)
|
1242
1617
|
end
|
1243
|
-
target.push else_.parsetree if else_ #and !body
|
1618
|
+
target.push else_.parsetree(o) if else_ #and !body
|
1244
1619
|
result.size==0 and result=[[:nil]]
|
1245
1620
|
result=result.last #if @op_rescue
|
1621
|
+
result=[:begin,result] unless o[:ruby187]||op?||result==[:nil]#||result.first==:begin
|
1246
1622
|
result
|
1247
1623
|
end
|
1248
1624
|
end
|
1249
1625
|
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1626
|
+
def rescue_parsetree o
|
1627
|
+
result=parsetree o
|
1628
|
+
result.first==:begin and result=result.last unless o[:ruby187]
|
1629
|
+
result
|
1630
|
+
end
|
1255
1631
|
|
1256
|
-
def begin_parsetree
|
1632
|
+
def begin_parsetree(o)
|
1257
1633
|
body,rescues,else_,ensure_=*self
|
1258
1634
|
needbegin=(rescues&&!rescues.empty?) || ensure_ || @empty_ensure
|
1259
|
-
result=parsetree
|
1260
|
-
needbegin and result=[:begin, result]
|
1635
|
+
result=parsetree(o)
|
1636
|
+
needbegin and result=[:begin, result] unless result.first==:begin
|
1261
1637
|
result
|
1262
1638
|
end
|
1263
1639
|
|
1264
|
-
def lvalue
|
1640
|
+
def lvalue
|
1265
1641
|
return nil unless size==1
|
1266
1642
|
# case first
|
1267
1643
|
# when CommaOpNode,UnaryStarNode: #do nothing
|
1268
|
-
# when ParenedNode: return first.lvalue
|
1644
|
+
# when ParenedNode: return first.lvalue
|
1269
1645
|
# else return nil
|
1270
1646
|
# end
|
1271
1647
|
|
1272
1648
|
return @lvalue if defined? @lvalue
|
1273
1649
|
@lvalue=true
|
1274
1650
|
end
|
1275
|
-
|
1651
|
+
attr_writer :lvalue
|
1276
1652
|
|
1277
|
-
def unparse(o)
|
1653
|
+
def unparse(o=default_unparse_options)
|
1278
1654
|
if size==1
|
1279
1655
|
"("+(body&&body.unparse(o))+")"
|
1280
1656
|
else
|
1281
1657
|
result="begin "
|
1282
1658
|
body&&result+= body.unparse(o)
|
1283
|
-
result+=
|
1659
|
+
result+=unparse_nl(rescues.first,o)
|
1284
1660
|
rescues.each{|resc| result+=resc.unparse(o) }
|
1285
|
-
result+="
|
1286
|
-
result+="
|
1287
|
-
result+="
|
1661
|
+
result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse(o) if ensure_
|
1662
|
+
result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
|
1663
|
+
result+=";end"
|
1288
1664
|
end
|
1289
1665
|
end
|
1290
1666
|
end
|
1667
|
+
=end
|
1668
|
+
|
1669
|
+
class ParenedNode<ValueNode
|
1670
|
+
param_names :body #, :rescues, :else!, :ensure!
|
1671
|
+
def initialize(lparen,body,rparen)
|
1672
|
+
self[0]=body
|
1673
|
+
end
|
1674
|
+
|
1675
|
+
attr_accessor :after_comma, :after_equals
|
1676
|
+
|
1677
|
+
def image; "(#{body.image})" end
|
1678
|
+
|
1679
|
+
def special_conditions!
|
1680
|
+
node=body
|
1681
|
+
node.special_conditions! if node.respond_to? :special_conditions!
|
1682
|
+
end
|
1683
|
+
|
1684
|
+
def to_lisp
|
1685
|
+
huh #what about rescues, else, ensure?
|
1686
|
+
body.to_lisp
|
1687
|
+
end
|
1688
|
+
|
1689
|
+
def op?; false end
|
1690
|
+
|
1691
|
+
def parsetree(o)
|
1692
|
+
body.parsetree(o)
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
def rescue_parsetree o
|
1696
|
+
body.rescue_parsetree o
|
1697
|
+
# result.first==:begin and result=result.last unless o[:ruby187]
|
1698
|
+
# result
|
1699
|
+
end
|
1700
|
+
|
1701
|
+
alias begin_parsetree parsetree
|
1702
|
+
|
1703
|
+
def lvalue
|
1704
|
+
return @lvalue if defined? @lvalue
|
1705
|
+
@lvalue=true
|
1706
|
+
end
|
1707
|
+
attr_writer :lvalue
|
1708
|
+
|
1709
|
+
identity_param :lvalue, nil, true
|
1710
|
+
|
1711
|
+
def unparse(o=default_unparse_options)
|
1712
|
+
"("+(body&&body.unparse(o))+")"
|
1713
|
+
end
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
module HasRescue
|
1717
|
+
def parsetree_and_rescues(o)
|
1718
|
+
body=body()
|
1719
|
+
target=result=[] #was: [:begin, ]
|
1720
|
+
|
1721
|
+
#body,rescues,else_,ensure_=*self
|
1722
|
+
target.push target=[:ensure, ] if ensure_ or @empty_ensure
|
1723
|
+
|
1724
|
+
rescues=rescues().map{|resc| resc.parsetree(o)}
|
1725
|
+
if rescues.empty?
|
1726
|
+
else_ and
|
1727
|
+
body=SequenceNode.new(body,nil,else_)
|
1728
|
+
else_=nil
|
1729
|
+
else
|
1730
|
+
target.push newtarget=[:rescue, ]
|
1731
|
+
else_=else_()
|
1732
|
+
end
|
1733
|
+
if body
|
1734
|
+
# needbegin= (BeginNode===body and body.after_equals)
|
1735
|
+
body=body.parsetree(o)
|
1736
|
+
# body=[:begin, body] if needbegin and body.first!=:begin and !o[:ruby187]
|
1737
|
+
(newtarget||target).push body if body
|
1738
|
+
end
|
1739
|
+
target.push ensure_.parsetree(o) if ensure_
|
1740
|
+
target.push [:nil] if @empty_ensure
|
1741
|
+
target=newtarget if newtarget
|
1742
|
+
|
1743
|
+
unless rescues.empty?
|
1744
|
+
target.push linked_list(rescues)
|
1745
|
+
end
|
1746
|
+
target.push else_.parsetree(o) if else_ #and !body
|
1747
|
+
result.size==0 and result=[[:nil]]
|
1748
|
+
result=result.last #if @op_rescue
|
1749
|
+
result
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
def unparse_and_rescues(o)
|
1753
|
+
result=" "
|
1754
|
+
result+= body.unparse(o) if body
|
1755
|
+
result+=unparse_nl(rescues.first,o)
|
1756
|
+
rescues.each{|resc| result+=resc.unparse(o) }
|
1757
|
+
result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
|
1758
|
+
result+=";else" if @empty_else
|
1759
|
+
result+=unparse_nl(ensure_,o)+"ensure "+ensure_.unparse(o) if ensure_
|
1760
|
+
result+=";ensure" if @empty_ensure
|
1761
|
+
return result
|
1762
|
+
end
|
1763
|
+
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
class BeginNode<ValueNode
|
1767
|
+
include HasRescue
|
1768
|
+
param_names :body, :rescues, :else!, :ensure!
|
1769
|
+
def initialize(*args)
|
1770
|
+
@empty_ensure=@empty_else=@op_rescue=nil
|
1771
|
+
body,rescues,else_,ensure_=*args[1...-1]
|
1772
|
+
if else_
|
1773
|
+
else_=else_.val or @empty_else=true
|
1774
|
+
end
|
1775
|
+
if ensure_
|
1776
|
+
ensure_=ensure_.val or @empty_ensure=true
|
1777
|
+
end
|
1778
|
+
replace [body,rescues,else_,ensure_]
|
1779
|
+
end
|
1780
|
+
|
1781
|
+
def op?; false end
|
1782
|
+
|
1783
|
+
alias ensure_ ensure
|
1784
|
+
alias else_ else
|
1785
|
+
|
1786
|
+
attr_reader :empty_ensure, :empty_else
|
1787
|
+
attr_accessor :after_comma, :after_equals
|
1788
|
+
|
1789
|
+
identity_param :after_equals, nil, true
|
1790
|
+
|
1791
|
+
def image; '(begin)' end
|
1792
|
+
|
1793
|
+
def special_conditions!; nil end
|
1794
|
+
|
1795
|
+
def non_empty
|
1796
|
+
body.size+rescues.size > 0 or !!ensures
|
1797
|
+
end
|
1798
|
+
|
1799
|
+
identity_param :non_empty, false, true
|
1800
|
+
|
1801
|
+
def to_lisp
|
1802
|
+
huh #what about rescues, else, ensure?
|
1803
|
+
body.to_lisp
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
def parsetree(o)
|
1807
|
+
result=parsetree_and_rescues(o)
|
1808
|
+
result=[:begin,result] unless o[:ruby187]||result==[:nil]#||result.first==:begin
|
1809
|
+
return result
|
1810
|
+
end
|
1811
|
+
|
1812
|
+
def rescue_parsetree o
|
1813
|
+
result=parsetree o
|
1814
|
+
result.first==:begin and result=result.last unless o[:ruby187]
|
1815
|
+
result
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
def begin_parsetree(o)
|
1819
|
+
body,rescues,else_,ensure_=*self
|
1820
|
+
needbegin=(rescues&&!rescues.empty?) || ensure_ || @empty_ensure
|
1821
|
+
result=parsetree(o)
|
1822
|
+
needbegin and result=[:begin, result] unless result.first==:begin
|
1823
|
+
result
|
1824
|
+
end
|
1825
|
+
|
1826
|
+
def lvalue
|
1827
|
+
return nil
|
1828
|
+
end
|
1829
|
+
# attr_accessor :lvalue
|
1830
|
+
|
1831
|
+
def unparse(o=default_unparse_options)
|
1832
|
+
result="begin "
|
1833
|
+
result+=unparse_and_rescues(o)
|
1834
|
+
result+=";end"
|
1835
|
+
end
|
1836
|
+
end
|
1837
|
+
|
1838
|
+
class RescueOpNode<ValueNode
|
1839
|
+
# include OpNode
|
1840
|
+
param_names :body, :rescues #, :else!, :ensure!
|
1841
|
+
def initialize(expr,rescueword,backup)
|
1842
|
+
replace [expr,[RescueNode[[],nil,backup]]]
|
1843
|
+
end
|
1844
|
+
|
1845
|
+
def else; nil end
|
1846
|
+
def ensure; nil end
|
1847
|
+
|
1848
|
+
def left; body end
|
1849
|
+
def right; rescues.action end
|
1850
|
+
|
1851
|
+
alias ensure_ ensure
|
1852
|
+
alias else_ else
|
1853
|
+
alias empty_ensure ensure
|
1854
|
+
alias empty_else else
|
1855
|
+
|
1856
|
+
attr_accessor :after_equals
|
1857
|
+
def op?; true end
|
1858
|
+
|
1859
|
+
def special_conditions!
|
1860
|
+
nil
|
1861
|
+
end
|
1862
|
+
|
1863
|
+
def to_lisp
|
1864
|
+
huh #what about rescues
|
1865
|
+
body.to_lisp
|
1866
|
+
end
|
1867
|
+
|
1868
|
+
def parsetree(o)
|
1869
|
+
body=body()
|
1870
|
+
target=result=[] #was: [:begin, ]
|
1871
|
+
|
1872
|
+
#body,rescues,else_,ensure_=*self
|
1873
|
+
|
1874
|
+
rescues=rescues().map{|resc| resc.parsetree(o)}
|
1875
|
+
target.push newtarget=[:rescue, ]
|
1876
|
+
else_=nil
|
1877
|
+
needbegin= (BeginNode===body and body.after_equals)
|
1878
|
+
huh if needbegin and RescueOpNode===body #need test case for this
|
1879
|
+
huh if needbegin and ParenedNode===body #need test case for this
|
1880
|
+
body=body.parsetree(o)
|
1881
|
+
body=[:begin, body] if needbegin and body.first!=:begin and !o[:ruby187]
|
1882
|
+
newtarget.push body if body
|
1883
|
+
|
1884
|
+
newtarget.push linked_list(rescues)
|
1885
|
+
result=result.last if result.size==1
|
1886
|
+
# result=[:begin,result]
|
1887
|
+
result
|
1888
|
+
end
|
1889
|
+
|
1890
|
+
def old_rescue_parsetree o
|
1891
|
+
result=parsetree o
|
1892
|
+
result=result.last unless o[:ruby187]
|
1893
|
+
result
|
1894
|
+
end
|
1895
|
+
|
1896
|
+
alias begin_parsetree parsetree
|
1897
|
+
alias rescue_parsetree parsetree
|
1898
|
+
|
1899
|
+
def lvalue
|
1900
|
+
return nil
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
def unparse(o=default_unparse_options)
|
1904
|
+
result= body.unparse(o)
|
1905
|
+
result+=" rescue "
|
1906
|
+
result+=rescues.first.action.unparse(o)
|
1907
|
+
end
|
1908
|
+
end
|
1291
1909
|
|
1292
1910
|
class AssignmentRhsNode < Node #not to appear in final parse tree
|
1293
1911
|
param_names :open_, :val, :close_
|
@@ -1296,6 +1914,19 @@ class RedParse
|
|
1296
1914
|
else super args[1]
|
1297
1915
|
end
|
1298
1916
|
end
|
1917
|
+
#WITHCOMMAS=UnaryStarNode|CommaOpNode|(CallSiteNode&-{:with_commas=>true})
|
1918
|
+
def is_list
|
1919
|
+
|
1920
|
+
return !(WITHCOMMAS===val)
|
1921
|
+
=begin
|
1922
|
+
#this should be equivalent, why doesn't it work?
|
1923
|
+
!(UnaryStarNode===val or
|
1924
|
+
CommaOpNode===val or
|
1925
|
+
CallSiteNode===val && val.with_commas==true)
|
1926
|
+
# CallSiteNode===val && !val.real_parens && val.args.size>0
|
1927
|
+
=end
|
1928
|
+
end
|
1929
|
+
identity_param :is_list, true, false
|
1299
1930
|
end
|
1300
1931
|
|
1301
1932
|
class AssignNode<ValueNode
|
@@ -1307,7 +1938,7 @@ class RedParse
|
|
1307
1938
|
if args.size==5
|
1308
1939
|
if args[3].ident=="rescue3"
|
1309
1940
|
lhs,op,rescuee,op2,rescuer=*args
|
1310
|
-
rhs=
|
1941
|
+
rhs=RescueOpNode.new(rescuee.val,op2,rescuer)
|
1311
1942
|
else
|
1312
1943
|
lhs,op,bogus1,rhs,bogus2=*args
|
1313
1944
|
end
|
@@ -1319,14 +1950,14 @@ class RedParse
|
|
1319
1950
|
when UnaryStarNode #look for star on lhs
|
1320
1951
|
lhs=MultiAssign.new([lhs]) unless lhs.after_comma
|
1321
1952
|
when ParenedNode
|
1322
|
-
|
1953
|
+
if !lhs.after_comma #look for () around lhs
|
1323
1954
|
if CommaOpNode===lhs.first
|
1324
1955
|
lhs=MultiAssign.new(Array.new(lhs.first))
|
1325
1956
|
else
|
1326
1957
|
lhs=MultiAssign.new([lhs.first])
|
1327
1958
|
end
|
1328
1959
|
@lhs_parens=true
|
1329
|
-
|
1960
|
+
end
|
1330
1961
|
when CommaOpNode:
|
1331
1962
|
lhs=MultiAssign.new lhs
|
1332
1963
|
#rhs=Array.new(rhs) if CommaOpNode===rhs
|
@@ -1361,10 +1992,12 @@ class RedParse
|
|
1361
1992
|
|
1362
1993
|
def to_lisp
|
1363
1994
|
case left
|
1364
|
-
when ParenedNode
|
1365
|
-
when
|
1366
|
-
when
|
1367
|
-
when
|
1995
|
+
when ParenedNode; huh
|
1996
|
+
when BeginNode; huh
|
1997
|
+
when RescueOpNode; huh
|
1998
|
+
when ConstantNode; huh
|
1999
|
+
when BracketsGetNode; huh
|
2000
|
+
when VarNode
|
1368
2001
|
"(set #{left.to_lisp} (#{op.chomp('=')} #{left.to_lisp} #{right.to_lisp}))"
|
1369
2002
|
when CallSiteNode
|
1370
2003
|
if op=='='
|
@@ -1385,26 +2018,28 @@ class RedParse
|
|
1385
2018
|
left.all_current_lvars : []
|
1386
2019
|
end
|
1387
2020
|
|
1388
|
-
def parsetree
|
2021
|
+
def parsetree(o)
|
1389
2022
|
case left
|
1390
|
-
when ParenedNode
|
1391
|
-
when
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
2023
|
+
when ParenedNode; huh
|
2024
|
+
when RescueOpNode; huh
|
2025
|
+
when BeginNode; huh
|
2026
|
+
when ConstantNode;
|
2027
|
+
left.lvalue_parsetree(o) << right.parsetree(o)
|
2028
|
+
|
2029
|
+
when MultiAssign;
|
2030
|
+
lhs=left.lvalue_parsetree(o)
|
2031
|
+
rhs= right.class==Array ? right.dup : [right]
|
1397
2032
|
star=rhs.pop if UnaryStarNode===rhs.last
|
1398
|
-
rhs=rhs.map{|x| x.rescue_parsetree}
|
2033
|
+
rhs=rhs.map{|x| x.rescue_parsetree(o)}
|
1399
2034
|
if rhs.size==0
|
1400
2035
|
star or fail
|
1401
|
-
rhs= star.parsetree
|
2036
|
+
rhs= star.parsetree(o)
|
1402
2037
|
elsif rhs.size==1 and !star and !(UnaryStarNode===left.first)
|
1403
2038
|
rhs.unshift :to_ary
|
1404
2039
|
else
|
1405
2040
|
rhs.unshift(:array)
|
1406
2041
|
if star
|
1407
|
-
splat=star.val.rescue_parsetree
|
2042
|
+
splat=star.val.rescue_parsetree(o)
|
1408
2043
|
#if splat.first==:call #I don't see how this can be right....
|
1409
2044
|
# splat[0]=:attrasgn
|
1410
2045
|
# splat[2]="#{splat[2]}=".to_sym
|
@@ -1413,15 +2048,23 @@ class RedParse
|
|
1413
2048
|
end
|
1414
2049
|
if left.size==1 and !(UnaryStarNode===left.first) and !(NestedAssign===left.first)
|
1415
2050
|
rhs=[:svalue, rhs]
|
2051
|
+
if CallNode===left.first
|
2052
|
+
rhs=[:array, rhs]
|
2053
|
+
end
|
1416
2054
|
end
|
1417
2055
|
end
|
1418
|
-
|
2056
|
+
if left.size==1 and BracketsGetNode===left.first and right.class==Array #hack
|
2057
|
+
lhs.last<<rhs
|
2058
|
+
lhs
|
2059
|
+
else
|
2060
|
+
lhs<< rhs
|
2061
|
+
end
|
1419
2062
|
|
1420
2063
|
when CallSiteNode
|
1421
2064
|
op=op().chomp('=')
|
1422
|
-
rcvr=left.receiver.parsetree
|
2065
|
+
rcvr=left.receiver.parsetree(o)
|
1423
2066
|
prop=left.name.+('=').to_sym
|
1424
|
-
args=right.rescue_parsetree
|
2067
|
+
args=right.rescue_parsetree(o)
|
1425
2068
|
UnaryStarNode===right and args=[:svalue, args]
|
1426
2069
|
if op.empty?
|
1427
2070
|
[:attrasgn, rcvr, prop, [:array, args] ]
|
@@ -1432,9 +2075,9 @@ class RedParse
|
|
1432
2075
|
when BracketsGetNode
|
1433
2076
|
args=left.params
|
1434
2077
|
if op()=='='
|
1435
|
-
result=left.lvalue_parsetree #[:attrasgn, left[0].parsetree, :[]=]
|
2078
|
+
result=left.lvalue_parsetree(o) #[:attrasgn, left[0].parsetree(o), :[]=]
|
1436
2079
|
result.size==3 and result.push [:array]
|
1437
|
-
rhs=right.rescue_parsetree
|
2080
|
+
rhs=right.rescue_parsetree(o)
|
1438
2081
|
UnaryStarNode===right and rhs=[:svalue, rhs]
|
1439
2082
|
if args
|
1440
2083
|
result[-1]=[:argspush,result[-1]] if UnaryStarNode===args.last
|
@@ -1445,7 +2088,7 @@ class RedParse
|
|
1445
2088
|
|
1446
2089
|
else
|
1447
2090
|
=begin
|
1448
|
-
args&&=args.map{|x| x.parsetree}.unshift(:array)
|
2091
|
+
args&&=args.map{|x| x.parsetree(o)}.unshift(:array)
|
1449
2092
|
splat=args.pop if :splat==args.last.first
|
1450
2093
|
if splat and left.params.size==1
|
1451
2094
|
args=splat
|
@@ -1453,7 +2096,7 @@ class RedParse
|
|
1453
2096
|
args=[:argscat, args, splat.last]
|
1454
2097
|
end
|
1455
2098
|
=end
|
1456
|
-
lhs=left.parsetree
|
2099
|
+
lhs=left.parsetree(o)
|
1457
2100
|
if lhs.first==:fcall
|
1458
2101
|
rcvr=[:self]
|
1459
2102
|
args=lhs[2]
|
@@ -1465,37 +2108,37 @@ class RedParse
|
|
1465
2108
|
result=[
|
1466
2109
|
:op_asgn1, rcvr, args,
|
1467
2110
|
op().chomp('=').to_sym,
|
1468
|
-
right.rescue_parsetree
|
2111
|
+
right.rescue_parsetree(o)
|
1469
2112
|
]
|
1470
2113
|
end
|
1471
2114
|
|
1472
|
-
when
|
2115
|
+
when VarNode
|
1473
2116
|
node_type=left.varname2assigntype
|
1474
2117
|
if /^(&&|\|\|)=$/===op()
|
1475
2118
|
|
1476
2119
|
return ["op_asgn_#{$1[0]==?& ? "and" : "or"}".to_sym,
|
1477
|
-
left.parsetree,
|
2120
|
+
left.parsetree(o),
|
1478
2121
|
[node_type, left.ident.to_sym,
|
1479
|
-
right.rescue_parsetree]
|
2122
|
+
right.rescue_parsetree(o)]
|
1480
2123
|
]
|
1481
2124
|
end
|
1482
2125
|
|
1483
2126
|
if op()=='='
|
1484
|
-
rhs=right.rescue_parsetree
|
2127
|
+
rhs=right.rescue_parsetree(o)
|
1485
2128
|
UnaryStarNode===right and rhs=[:svalue, rhs]
|
1486
2129
|
|
1487
2130
|
# case left
|
1488
|
-
# when
|
2131
|
+
# when VarNode:
|
1489
2132
|
[node_type, left.ident.to_sym, rhs]
|
1490
|
-
# else [node_type, left.data[0].parsetree, left.data[1].data[0].ident.+('=').to_sym ,[:array, rhs]]
|
2133
|
+
# else [node_type, left.data[0].parsetree(o), left.data[1].data[0].ident.+('=').to_sym ,[:array, rhs]]
|
1491
2134
|
# end
|
1492
2135
|
|
1493
2136
|
=begin these branches shouldn't be necessary now
|
1494
2137
|
elsif node_type==:op_asgn2
|
1495
|
-
[node_type, @data[0].data[0].parsetree,
|
2138
|
+
[node_type, @data[0].data[0].parsetree(o),
|
1496
2139
|
@data[0].data[1].data[0].ident.+('=').to_sym,
|
1497
2140
|
op().ident.chomp('=').to_sym,
|
1498
|
-
@data[2].parsetree
|
2141
|
+
@data[2].parsetree(o)
|
1499
2142
|
]
|
1500
2143
|
elsif node_type==:attrasgn
|
1501
2144
|
[node_type]
|
@@ -1503,9 +2146,9 @@ class RedParse
|
|
1503
2146
|
else
|
1504
2147
|
[node_type, left.ident.to_sym,
|
1505
2148
|
[:call,
|
1506
|
-
left.parsetree,
|
2149
|
+
left.parsetree(o),
|
1507
2150
|
op().chomp('=').to_sym,
|
1508
|
-
[:array, right.rescue_parsetree]
|
2151
|
+
[:array, right.rescue_parsetree(o)]
|
1509
2152
|
]
|
1510
2153
|
]
|
1511
2154
|
end
|
@@ -1514,8 +2157,10 @@ class RedParse
|
|
1514
2157
|
end
|
1515
2158
|
end
|
1516
2159
|
|
1517
|
-
def unparse(o)
|
1518
|
-
lhs.lhs_unparse(o)
|
2160
|
+
def unparse(o=default_unparse_options)
|
2161
|
+
result=lhs.lhs_unparse(o)
|
2162
|
+
result="(#{result})" if defined? @lhs_parens
|
2163
|
+
result+op+
|
1519
2164
|
(rhs.class==Array ?
|
1520
2165
|
rhs.map{|rv| rv.unparse o}.join(',') :
|
1521
2166
|
rhs.unparse(o)
|
@@ -1528,18 +2173,18 @@ class RedParse
|
|
1528
2173
|
|
1529
2174
|
#not called from parse table
|
1530
2175
|
|
1531
|
-
def parsetree
|
2176
|
+
def parsetree(o)
|
1532
2177
|
lhs=left.dup
|
1533
2178
|
if UnaryStarNode===lhs.last
|
1534
2179
|
lstar=lhs.pop
|
1535
2180
|
end
|
1536
2181
|
lhs.map!{|x|
|
1537
|
-
res=x.parsetree
|
1538
|
-
res[0]=x.varname2assigntype if
|
2182
|
+
res=x.parsetree(o)
|
2183
|
+
res[0]=x.varname2assigntype if VarNode===x
|
1539
2184
|
res
|
1540
2185
|
}
|
1541
2186
|
lhs.unshift(:array) if lhs.size>1 or lstar
|
1542
|
-
rhs=right.map{|x| x.parsetree}
|
2187
|
+
rhs=right.map{|x| x.parsetree(o)}
|
1543
2188
|
if rhs.size==1
|
1544
2189
|
if rhs.first.first==:splat
|
1545
2190
|
rhs=rhs.first
|
@@ -1558,7 +2203,7 @@ class RedParse
|
|
1558
2203
|
end
|
1559
2204
|
end
|
1560
2205
|
result=[:masgn, lhs, rhs]
|
1561
|
-
result.insert(2,lstar.data.last.parsetree) if lstar
|
2206
|
+
result.insert(2,lstar.data.last.parsetree(o)) if lstar
|
1562
2207
|
result
|
1563
2208
|
|
1564
2209
|
end
|
@@ -1567,11 +2212,11 @@ class RedParse
|
|
1567
2212
|
class AssigneeList< ValueNode #abstract
|
1568
2213
|
def initialize(data)
|
1569
2214
|
data.each_with_index{|datum,i|
|
1570
|
-
if ParenedNode
|
2215
|
+
if ParenedNode===datum
|
1571
2216
|
first=datum.first
|
1572
2217
|
list=case first
|
1573
|
-
when CommaOpNode
|
1574
|
-
when UnaryStarNode,ParenedNode
|
2218
|
+
when CommaOpNode; Array.new(first)
|
2219
|
+
when UnaryStarNode,ParenedNode; [first]
|
1575
2220
|
end
|
1576
2221
|
data[i]=NestedAssign.new(list) if list
|
1577
2222
|
end
|
@@ -1579,18 +2224,18 @@ class RedParse
|
|
1579
2224
|
replace data
|
1580
2225
|
end
|
1581
2226
|
|
1582
|
-
def unparse o
|
2227
|
+
def unparse o=default_unparse_options
|
1583
2228
|
map{|lval| lval.lhs_unparse o}.join(', ')
|
1584
2229
|
end
|
1585
2230
|
|
1586
|
-
def old_parsetree
|
2231
|
+
def old_parsetree o
|
1587
2232
|
lhs=data.dup
|
1588
2233
|
if UnaryStarNode===lhs.last
|
1589
2234
|
lstar=lhs.pop.val
|
1590
2235
|
end
|
1591
2236
|
lhs.map!{|x|
|
1592
|
-
res=x.parsetree
|
1593
|
-
res[0]=x.varname2assigntype if
|
2237
|
+
res=x.parsetree(o)
|
2238
|
+
res[0]=x.varname2assigntype if VarNode===x
|
1594
2239
|
res
|
1595
2240
|
}
|
1596
2241
|
lhs.unshift(:array) if lhs.size>1 or lstar
|
@@ -1605,22 +2250,22 @@ class RedParse
|
|
1605
2250
|
|
1606
2251
|
end
|
1607
2252
|
|
1608
|
-
def parsetree
|
2253
|
+
def parsetree(o)
|
1609
2254
|
data=self
|
1610
2255
|
data.empty? and return nil
|
1611
2256
|
# data=data.first if data.size==1 and ParenedNode===data.first and data.first.size==1
|
1612
2257
|
data=Array.new(data)
|
1613
2258
|
star=data.pop if UnaryStarNode===data.last
|
1614
|
-
result=data.map{|x| x.lvalue_parsetree }
|
2259
|
+
result=data.map{|x| x.lvalue_parsetree(o) }
|
1615
2260
|
=begin
|
1616
2261
|
{
|
1617
|
-
if
|
2262
|
+
if VarNode===x
|
1618
2263
|
ident=x.ident
|
1619
2264
|
ty=x.varname2assigntype
|
1620
2265
|
# ty==:lasgn and ty=:dasgn_curr
|
1621
2266
|
[ty, ident.to_sym]
|
1622
2267
|
else
|
1623
|
-
x=x.parsetree
|
2268
|
+
x=x.parsetree(o)
|
1624
2269
|
if x[0]==:call
|
1625
2270
|
x[0]=:attrasgn
|
1626
2271
|
x[2]="#{x[2]}=".to_sym
|
@@ -1629,14 +2274,17 @@ class RedParse
|
|
1629
2274
|
end
|
1630
2275
|
}
|
1631
2276
|
=end
|
1632
|
-
if result.size==0
|
2277
|
+
if result.size==0 #just star on lhs
|
1633
2278
|
star or fail
|
1634
|
-
result=[:masgn
|
1635
|
-
|
2279
|
+
result=[:masgn]
|
2280
|
+
result.push nil #why??? #if o[:ruby187]
|
2281
|
+
result.push star.lvalue_parsetree(o)
|
2282
|
+
elsif result.size==1 and !star and !(NestedAssign===data.first) #simple lhs, not multi
|
1636
2283
|
result=result.first
|
1637
2284
|
else
|
1638
2285
|
result=[:masgn, [:array, *result]]
|
1639
|
-
result.push
|
2286
|
+
result.push nil if (!star or DanglingCommaNode===star) #and o[:ruby187]
|
2287
|
+
result.push star.lvalue_parsetree(o) if star and not DanglingCommaNode===star
|
1640
2288
|
end
|
1641
2289
|
result
|
1642
2290
|
end
|
@@ -1652,13 +2300,18 @@ class RedParse
|
|
1652
2300
|
return result
|
1653
2301
|
end
|
1654
2302
|
|
1655
|
-
def lvalue_parsetree; parsetree end
|
2303
|
+
def lvalue_parsetree(o); parsetree(o) end
|
1656
2304
|
end
|
1657
2305
|
class NestedAssign<AssigneeList
|
1658
|
-
|
2306
|
+
def parsetree(o)
|
2307
|
+
result=super
|
2308
|
+
result<<nil #why???!! #if o[:ruby187]
|
2309
|
+
result
|
2310
|
+
end
|
2311
|
+
# def parsetree(o)
|
1659
2312
|
# [:masgn, *super]
|
1660
2313
|
# end
|
1661
|
-
def unparse o
|
2314
|
+
def unparse o=default_unparse_options
|
1662
2315
|
"("+super+")"
|
1663
2316
|
|
1664
2317
|
end
|
@@ -1670,7 +2323,7 @@ class RedParse
|
|
1670
2323
|
def initialize(data)
|
1671
2324
|
item=data.first if data.size==1
|
1672
2325
|
#elide 1 layer of parens if present
|
1673
|
-
if ParenedNode===item
|
2326
|
+
if ParenedNode===item
|
1674
2327
|
item=item.first
|
1675
2328
|
data=CommaOpNode===item ? Array.new(item) : [item]
|
1676
2329
|
@had_parens=true
|
@@ -1679,13 +2332,19 @@ class RedParse
|
|
1679
2332
|
super(data)
|
1680
2333
|
end
|
1681
2334
|
|
1682
|
-
def unparse o
|
1683
|
-
|
1684
|
-
"|"+super+"|"
|
1685
|
-
else
|
2335
|
+
def unparse o=default_unparse_options
|
2336
|
+
if defined? @had_parens
|
1686
2337
|
"|("+super+")|"
|
2338
|
+
else
|
2339
|
+
"|"+super+"|"
|
1687
2340
|
end
|
1688
2341
|
end
|
2342
|
+
|
2343
|
+
def parsetree o
|
2344
|
+
result=super
|
2345
|
+
result.push nil if UnaryStarNode===self.last || size>1 #and o[:ruby187]
|
2346
|
+
result
|
2347
|
+
end
|
1689
2348
|
end
|
1690
2349
|
|
1691
2350
|
class AccessorAssignNode < ValueNode #obsolete
|
@@ -1703,11 +2362,11 @@ class RedParse
|
|
1703
2362
|
end
|
1704
2363
|
end
|
1705
2364
|
|
1706
|
-
def parsetree
|
2365
|
+
def parsetree(o)
|
1707
2366
|
op=op().ident.chomp('=')
|
1708
|
-
rcvr=left.parsetree
|
2367
|
+
rcvr=left.parsetree(o)
|
1709
2368
|
prop=property.ident.<<(?=).to_sym
|
1710
|
-
rhs=right.parsetree
|
2369
|
+
rhs=right.parsetree(o)
|
1711
2370
|
if op.empty?
|
1712
2371
|
[:attrasgn, rcvr, prop, [:array, args] ]
|
1713
2372
|
else
|
@@ -1717,7 +2376,7 @@ class RedParse
|
|
1717
2376
|
end
|
1718
2377
|
|
1719
2378
|
module KeywordOpNode
|
1720
|
-
def unparse o
|
2379
|
+
def unparse o=default_unparse_options
|
1721
2380
|
[left.unparse(o),' ',op,' ',right.unparse(o)].to_s
|
1722
2381
|
end
|
1723
2382
|
end
|
@@ -1727,8 +2386,8 @@ class RedParse
|
|
1727
2386
|
def initialize(left,op,right)
|
1728
2387
|
@opmap=op[0,1]
|
1729
2388
|
case op
|
1730
|
-
when "&&"
|
1731
|
-
when "||"
|
2389
|
+
when "&&"; op="and"
|
2390
|
+
when "||"; op="or"
|
1732
2391
|
end
|
1733
2392
|
#@reverse= op=="or"
|
1734
2393
|
#@op=op
|
@@ -1756,7 +2415,7 @@ class RedParse
|
|
1756
2415
|
|
1757
2416
|
#these 3 methods are defined in RawOpNode too, hence these
|
1758
2417
|
#definitions are ignored. grrrrrrr.
|
1759
|
-
def unparse o
|
2418
|
+
def unparse o=default_unparse_options
|
1760
2419
|
result=''
|
1761
2420
|
|
1762
2421
|
each_with_index{|expr,i|
|
@@ -1774,14 +2433,14 @@ class RedParse
|
|
1774
2433
|
method_missing(:right,*args,&block)
|
1775
2434
|
end
|
1776
2435
|
|
1777
|
-
def parsetree
|
2436
|
+
def parsetree(o)
|
1778
2437
|
result=[].replace(self).reverse
|
1779
|
-
last=result.shift.begin_parsetree
|
2438
|
+
last=result.shift.begin_parsetree(o)
|
1780
2439
|
first=result.pop
|
1781
2440
|
result=result.inject(last){|sum,x|
|
1782
|
-
[op.to_sym, x.begin_parsetree, sum]
|
2441
|
+
[op.to_sym, x.begin_parsetree(o), sum]
|
1783
2442
|
}
|
1784
|
-
[op.to_sym, first.rescue_parsetree, result]
|
2443
|
+
[op.to_sym, first.rescue_parsetree(o), result]
|
1785
2444
|
end
|
1786
2445
|
|
1787
2446
|
def special_conditions!
|
@@ -1802,16 +2461,16 @@ class RedParse
|
|
1802
2461
|
@reverse=false
|
1803
2462
|
@module=WhileOpNode
|
1804
2463
|
@loop=true
|
1805
|
-
@test_first= !(
|
2464
|
+
@test_first= !( BeginNode===val1 )
|
1806
2465
|
condition.special_conditions! if condition.respond_to? :special_conditions!
|
1807
2466
|
end
|
1808
2467
|
|
1809
2468
|
def while; condition end
|
1810
2469
|
def do; consequent end
|
1811
2470
|
|
1812
|
-
def parsetree
|
1813
|
-
cond=condition.rescue_parsetree
|
1814
|
-
body=consequent.parsetree
|
2471
|
+
def parsetree(o)
|
2472
|
+
cond=condition.rescue_parsetree(o)
|
2473
|
+
body=consequent.parsetree(o)
|
1815
2474
|
!@test_first and
|
1816
2475
|
body.size == 2 and
|
1817
2476
|
body.first == :begin and
|
@@ -1836,7 +2495,7 @@ class RedParse
|
|
1836
2495
|
self[1]=op
|
1837
2496
|
@reverse=true
|
1838
2497
|
@loop=true
|
1839
|
-
@test_first= !(
|
2498
|
+
@test_first= !( BeginNode===val1 )
|
1840
2499
|
@module=UntilOpNode
|
1841
2500
|
condition.special_conditions! if condition.respond_to? :special_conditions!
|
1842
2501
|
end
|
@@ -1844,9 +2503,9 @@ class RedParse
|
|
1844
2503
|
def while; negate condition end
|
1845
2504
|
def do; consequent end
|
1846
2505
|
|
1847
|
-
def parsetree
|
1848
|
-
cond=condition.rescue_parsetree
|
1849
|
-
body=consequent.parsetree
|
2506
|
+
def parsetree(o)
|
2507
|
+
cond=condition.rescue_parsetree(o)
|
2508
|
+
body=consequent.parsetree(o)
|
1850
2509
|
!@test_first and
|
1851
2510
|
body.size == 2 and
|
1852
2511
|
body.first == :begin and
|
@@ -1857,10 +2516,10 @@ class RedParse
|
|
1857
2516
|
else
|
1858
2517
|
kw=:until
|
1859
2518
|
end
|
1860
|
-
tf=@test_first
|
1861
|
-
tf||= (!consequent.body and !consequent.else and
|
1862
|
-
!consequent.ensure and !consequent.empty_ensure and consequent.rescues.empty?
|
1863
|
-
) if
|
2519
|
+
tf=@test_first||body==[:nil]
|
2520
|
+
# tf||= (!consequent.body and !consequent.else and #!consequent.empty_else and
|
2521
|
+
# !consequent.ensure and !consequent.empty_ensure and consequent.rescues.empty?
|
2522
|
+
# ) if BeginNode===consequent
|
1864
2523
|
[kw, cond, body, tf]
|
1865
2524
|
end
|
1866
2525
|
end
|
@@ -1882,9 +2541,9 @@ class RedParse
|
|
1882
2541
|
def else; consequent end
|
1883
2542
|
def elsifs; [] end
|
1884
2543
|
|
1885
|
-
def parsetree
|
1886
|
-
cond=condition.rescue_parsetree
|
1887
|
-
actions=[nil, consequent.parsetree]
|
2544
|
+
def parsetree(o)
|
2545
|
+
cond=condition.rescue_parsetree(o)
|
2546
|
+
actions=[nil, consequent.parsetree(o)]
|
1888
2547
|
if cond.first==:not
|
1889
2548
|
actions.reverse!
|
1890
2549
|
cond=cond.last
|
@@ -1910,9 +2569,9 @@ class RedParse
|
|
1910
2569
|
def else; nil end
|
1911
2570
|
def elsifs; [] end
|
1912
2571
|
|
1913
|
-
def parsetree
|
1914
|
-
cond=condition.rescue_parsetree
|
1915
|
-
actions=[consequent.parsetree, nil]
|
2572
|
+
def parsetree(o)
|
2573
|
+
cond=condition.rescue_parsetree(o)
|
2574
|
+
actions=[consequent.parsetree(o), nil]
|
1916
2575
|
if cond.first==:not
|
1917
2576
|
actions.reverse!
|
1918
2577
|
cond=cond.last
|
@@ -1946,11 +2605,17 @@ class RedParse
|
|
1946
2605
|
if first
|
1947
2606
|
arrowrange=first..last
|
1948
2607
|
arrows=param_list[arrowrange]
|
1949
|
-
|
2608
|
+
h=HashLiteralNode.new(nil,arrows,nil)
|
2609
|
+
h.startline=arrows.first.startline
|
2610
|
+
h.endline=arrows.last.endline
|
2611
|
+
param_list[arrowrange]=[h]
|
1950
2612
|
end
|
1951
2613
|
|
1952
|
-
when ArrowOpNode
|
1953
|
-
|
2614
|
+
when ArrowOpNode
|
2615
|
+
h=HashLiteralNode.new(nil,param_list,nil)
|
2616
|
+
h.startline=param_list.startline
|
2617
|
+
h.endline=param_list.endline
|
2618
|
+
param_list=[h]
|
1954
2619
|
# when KeywordOpNode
|
1955
2620
|
# fail "didn't expect '#{param_list.inspect}' inside actual parameter list"
|
1956
2621
|
when nil
|
@@ -1972,12 +2637,12 @@ class RedParse
|
|
1972
2637
|
|
1973
2638
|
def real_parens; !@not_real_parens end
|
1974
2639
|
|
1975
|
-
def unparse o
|
2640
|
+
def unparse o=default_unparse_options
|
1976
2641
|
fail if block==false
|
1977
2642
|
result=[
|
1978
2643
|
receiver&&receiver.unparse(o)+'.',name,
|
1979
2644
|
real_parens ? '(' : (' ' if params),
|
1980
|
-
params&¶ms.map{|param|
|
2645
|
+
params&¶ms.map{|param| unparse_nl(param,o,'',"\\\n")+param.unparse(o) }.join(', '),
|
1981
2646
|
real_parens ? ')' : nil,
|
1982
2647
|
|
1983
2648
|
block&&[
|
@@ -1994,19 +2659,27 @@ class RedParse
|
|
1994
2659
|
def image
|
1995
2660
|
result="(#{receiver.image if receiver}.#{name})"
|
1996
2661
|
end
|
2662
|
+
|
2663
|
+
def with_commas
|
2664
|
+
!real_parens and args.size>0
|
2665
|
+
end
|
2666
|
+
|
2667
|
+
# identity_param :with_commas, false, true
|
1997
2668
|
|
1998
|
-
def lvalue_parsetree
|
1999
|
-
result=parsetree
|
2669
|
+
def lvalue_parsetree(o)
|
2670
|
+
result=parsetree(o)
|
2000
2671
|
result[0]=:attrasgn
|
2001
2672
|
result[2]="#{result[2]}=".to_sym
|
2002
2673
|
result
|
2003
2674
|
end
|
2004
2675
|
|
2005
|
-
def lvalue
|
2676
|
+
def lvalue
|
2006
2677
|
return @lvalue if defined? @lvalue
|
2007
2678
|
@lvalue=true
|
2008
2679
|
end
|
2009
|
-
|
2680
|
+
attr_writer :lvalue
|
2681
|
+
|
2682
|
+
identity_param :lvalue, nil, true
|
2010
2683
|
|
2011
2684
|
def to_lisp
|
2012
2685
|
"(#{receiver.to_lisp} #{self[1..-1].map{|x| x.to_lisp}.join(' ')})"
|
@@ -2019,7 +2692,7 @@ class RedParse
|
|
2019
2692
|
self[0]=expr
|
2020
2693
|
end
|
2021
2694
|
|
2022
|
-
def parsetree_with_params
|
2695
|
+
def parsetree_with_params o
|
2023
2696
|
args=args()||[]
|
2024
2697
|
if (UnOpNode===args.last and args.last.ident=="&@")
|
2025
2698
|
lasti=args.size-2
|
@@ -2038,26 +2711,30 @@ class RedParse
|
|
2038
2711
|
]
|
2039
2712
|
elsif (UnaryStarNode===args[lasti])
|
2040
2713
|
if lasti.zero?
|
2041
|
-
[:fcall, methodsym, args.first.rescue_parsetree]
|
2714
|
+
[:fcall, methodsym, args.first.rescue_parsetree(o)]
|
2042
2715
|
else
|
2043
2716
|
[:fcall, methodsym,
|
2044
2717
|
[:argscat,
|
2045
|
-
[:array, *args[0...lasti].map{|x| x.rescue_parsetree } ],
|
2046
|
-
args[lasti].val.rescue_parsetree
|
2718
|
+
[:array, *args[0...lasti].map{|x| x.rescue_parsetree(o) } ],
|
2719
|
+
args[lasti].val.rescue_parsetree(o)
|
2047
2720
|
]
|
2048
2721
|
]
|
2049
2722
|
end
|
2050
2723
|
else
|
2051
2724
|
singlearg= lasti.zero?&&args.first
|
2052
2725
|
[:fcall, methodsym,
|
2053
|
-
[:array, *args[0..lasti].map{|x| x.rescue_parsetree } ]
|
2726
|
+
[:array, *args[0..lasti].map{|x| x.rescue_parsetree(o) } ]
|
2054
2727
|
]
|
2055
2728
|
end
|
2056
2729
|
|
2057
2730
|
result[0]=:vcall if block #and /\Af?call\Z/===result[0].to_s
|
2058
2731
|
|
2059
2732
|
if is_kw and !receiver
|
2060
|
-
|
2733
|
+
if singlearg and "super"!=methodname
|
2734
|
+
result=[methodsym, singlearg.parsetree(o)]
|
2735
|
+
result.push(true) if methodname=="yield" and ArrayLiteralNode===singlearg #why???!!
|
2736
|
+
return result
|
2737
|
+
end
|
2061
2738
|
breaklike= /^(break|next|return)$/===methodname
|
2062
2739
|
if @not_real_parens
|
2063
2740
|
return [:zsuper] if "super"==methodname and !args()
|
@@ -2071,31 +2748,31 @@ class RedParse
|
|
2071
2748
|
|
2072
2749
|
if receiver
|
2073
2750
|
result.shift if result.first==:vcall or result.first==:fcall #if not kw
|
2074
|
-
result=[:call, receiver.rescue_parsetree, *result]
|
2751
|
+
result=[:call, receiver.rescue_parsetree(o), *result]
|
2075
2752
|
end
|
2076
2753
|
|
2077
2754
|
if unamp_expr
|
2078
2755
|
# result[0]=:fcall if lasti.zero?
|
2079
|
-
result=[:block_pass, unamp_expr.rescue_parsetree, result]
|
2756
|
+
result=[:block_pass, unamp_expr.rescue_parsetree(o), result]
|
2080
2757
|
end
|
2081
2758
|
|
2082
2759
|
return result
|
2083
2760
|
end
|
2084
2761
|
|
2085
|
-
def parsetree
|
2086
|
-
callsite=parsetree_with_params
|
2762
|
+
def parsetree(o)
|
2763
|
+
callsite=parsetree_with_params o
|
2087
2764
|
return callsite unless blockparams or block
|
2088
2765
|
call=name
|
2089
2766
|
callsite[0]=:fcall if callsite[0]==:call or callsite[0]==:vcall
|
2090
2767
|
unless receiver
|
2091
2768
|
case call
|
2092
|
-
when "BEGIN"
|
2093
|
-
if quirks
|
2769
|
+
when "BEGIN"
|
2770
|
+
if o[:quirks]
|
2094
2771
|
return []
|
2095
2772
|
else
|
2096
2773
|
callsite=[:preexe]
|
2097
2774
|
end
|
2098
|
-
when "END"
|
2775
|
+
when "END"; callsite=[:postexe]
|
2099
2776
|
end
|
2100
2777
|
else
|
2101
2778
|
callsite[0]=:call if callsite[0]==:fcall
|
@@ -2105,17 +2782,17 @@ class RedParse
|
|
2105
2782
|
bparams=blockparams.dup
|
2106
2783
|
lastparam=bparams.last
|
2107
2784
|
amped=bparams.pop.val if UnOpNode===lastparam and lastparam.op=="&@"
|
2108
|
-
bparams=bparams.parsetree||0
|
2785
|
+
bparams=bparams.parsetree(o)||0
|
2109
2786
|
if amped
|
2110
2787
|
bparams=[:masgn, [:array, bparams]] unless bparams==0 or bparams.first==:masgn
|
2111
|
-
bparams=[:block_pass, amped.lvalue_parsetree, bparams]
|
2788
|
+
bparams=[:block_pass, amped.lvalue_parsetree(o), bparams]
|
2112
2789
|
end
|
2113
2790
|
else
|
2114
2791
|
bparams=nil
|
2115
2792
|
end
|
2116
2793
|
result=[:iter, callsite, bparams]
|
2117
2794
|
unless block.empty?
|
2118
|
-
body=block.parsetree
|
2795
|
+
body=block.parsetree(o)
|
2119
2796
|
if curr_vars=block.lvars_defined_in
|
2120
2797
|
curr_vars-=blockparams.all_current_lvars if blockparams
|
2121
2798
|
if curr_vars.empty?
|
@@ -2133,19 +2810,19 @@ class RedParse
|
|
2133
2810
|
result
|
2134
2811
|
end
|
2135
2812
|
|
2136
|
-
def blockformals_parsetree data
|
2813
|
+
def blockformals_parsetree data,o #dead code?
|
2137
2814
|
data.empty? and return nil
|
2138
2815
|
data=data.dup
|
2139
2816
|
star=data.pop if UnaryStarNode===data.last
|
2140
|
-
result=data.map{|x| x.parsetree }
|
2817
|
+
result=data.map{|x| x.parsetree(o) }
|
2141
2818
|
=begin
|
2142
|
-
{ if
|
2819
|
+
{ if VarNode===x
|
2143
2820
|
ident=x.ident
|
2144
2821
|
ty=x.varname2assigntype
|
2145
2822
|
# ty==:lasgn and ty=:dasgn_curr
|
2146
2823
|
[ty, ident.to_sym]
|
2147
2824
|
else
|
2148
|
-
x=x.parsetree
|
2825
|
+
x=x.parsetree(o)
|
2149
2826
|
if x[0]==:call
|
2150
2827
|
x[0]=:attrasgn
|
2151
2828
|
x[2]="#{x[2]}=".to_sym
|
@@ -2156,20 +2833,20 @@ class RedParse
|
|
2156
2833
|
=end
|
2157
2834
|
if result.size==0
|
2158
2835
|
star or fail
|
2159
|
-
result=[:masgn, star.parsetree.last]
|
2836
|
+
result=[:masgn, star.parsetree(o).last]
|
2160
2837
|
elsif result.size==1 and !star
|
2161
2838
|
result=result.first
|
2162
2839
|
else
|
2163
2840
|
result=[:masgn, [:array, *result]]
|
2164
2841
|
if star
|
2165
2842
|
old=star= star.val
|
2166
|
-
star=star.parsetree
|
2843
|
+
star=star.parsetree(o)
|
2167
2844
|
if star[0]==:call
|
2168
2845
|
star[0]=:attrasgn
|
2169
2846
|
star[2]="#{star[2]}=".to_sym
|
2170
2847
|
end
|
2171
2848
|
|
2172
|
-
if
|
2849
|
+
if VarNode===old
|
2173
2850
|
ty=old.varname2assigntype
|
2174
2851
|
# ty==:lasgn and ty=:dasgn_curr
|
2175
2852
|
star[0]=ty
|
@@ -2205,11 +2882,11 @@ class RedParse
|
|
2205
2882
|
"(#{data.join' '})"
|
2206
2883
|
end
|
2207
2884
|
|
2208
|
-
def parsetree
|
2885
|
+
def parsetree(o)
|
2209
2886
|
empty? ? nil :
|
2210
2887
|
[:dasgn_curr,
|
2211
2888
|
*map{|x|
|
2212
|
-
|
2889
|
+
(VarNode===x) ? x.ident.to_sym : x.parsetree(o)
|
2213
2890
|
}
|
2214
2891
|
]
|
2215
2892
|
end
|
@@ -2219,8 +2896,8 @@ class RedParse
|
|
2219
2896
|
param_names :params,:body
|
2220
2897
|
def initialize(open_brace,formals,stmts,close_brace)
|
2221
2898
|
case stmts
|
2222
|
-
when SequenceNode
|
2223
|
-
when nil
|
2899
|
+
when SequenceNode; stmts=Array.new(stmts)
|
2900
|
+
when nil; stmts=[]
|
2224
2901
|
else stmts=[stmts]
|
2225
2902
|
end
|
2226
2903
|
|
@@ -2235,23 +2912,23 @@ class RedParse
|
|
2235
2912
|
"(#{params.to_lisp} #{body.to_lisp})"
|
2236
2913
|
end
|
2237
2914
|
|
2238
|
-
def parsetree #obsolete
|
2239
|
-
callsite=@data[0].parsetree
|
2915
|
+
def parsetree(o) #obsolete
|
2916
|
+
callsite=@data[0].parsetree(o)
|
2240
2917
|
call=@data[0].data[0]
|
2241
2918
|
callsite[0]=:fcall if call.respond_to? :ident
|
2242
2919
|
if call.respond_to? :ident
|
2243
2920
|
case call.ident
|
2244
|
-
when "BEGIN"
|
2245
|
-
if quirks
|
2921
|
+
when "BEGIN"
|
2922
|
+
if o[:quirks]
|
2246
2923
|
return []
|
2247
2924
|
else
|
2248
2925
|
callsite=[:preexe]
|
2249
2926
|
end
|
2250
|
-
when "END"
|
2927
|
+
when "END"; callsite=[:postexe]
|
2251
2928
|
end
|
2252
2929
|
end
|
2253
|
-
result=[:iter, callsite, @data[1].parsetree]
|
2254
|
-
result.push @data[2].parsetree if @data[2]
|
2930
|
+
result=[:iter, callsite, @data[1].parsetree(o)]
|
2931
|
+
result.push @data[2].parsetree(o) if @data[2]
|
2255
2932
|
result
|
2256
2933
|
end
|
2257
2934
|
end
|
@@ -2261,7 +2938,7 @@ class RedParse
|
|
2261
2938
|
super()
|
2262
2939
|
end
|
2263
2940
|
|
2264
|
-
def unparse o
|
2941
|
+
def unparse o=default_unparse_options
|
2265
2942
|
''
|
2266
2943
|
end
|
2267
2944
|
|
@@ -2285,7 +2962,7 @@ class RedParse
|
|
2285
2962
|
"Object"
|
2286
2963
|
end
|
2287
2964
|
|
2288
|
-
def parsetree
|
2965
|
+
def parsetree(o)
|
2289
2966
|
:Object
|
2290
2967
|
end
|
2291
2968
|
end
|
@@ -2313,15 +2990,25 @@ class RedParse
|
|
2313
2990
|
@char=str.char
|
2314
2991
|
end
|
2315
2992
|
@modifiers=str.modifiers #if str.modifiers
|
2316
|
-
super *with_string_data(str)
|
2993
|
+
super( *with_string_data(str) )
|
2994
|
+
|
2995
|
+
@open=token.open
|
2996
|
+
@close=token.close
|
2997
|
+
@bs_handler=str.bs_handler
|
2317
2998
|
|
2318
2999
|
if /[\[{]/===@char
|
2319
3000
|
@parses_like=split_into_words(str)
|
2320
3001
|
end
|
2321
3002
|
|
3003
|
+
return
|
3004
|
+
|
3005
|
+
=begin
|
3006
|
+
#this should have been taken care of by with_string_data
|
2322
3007
|
first=shift
|
2323
3008
|
delete_if{|x| ''==x }
|
2324
3009
|
unshift(first)
|
3010
|
+
|
3011
|
+
#escape translation now done later on
|
2325
3012
|
map!{|strfrag|
|
2326
3013
|
if String===strfrag
|
2327
3014
|
str.translate_escapes strfrag
|
@@ -2329,8 +3016,25 @@ class RedParse
|
|
2329
3016
|
strfrag
|
2330
3017
|
end
|
2331
3018
|
}
|
2332
|
-
|
2333
|
-
|
3019
|
+
=end
|
3020
|
+
end
|
3021
|
+
|
3022
|
+
def translate_escapes(str)
|
3023
|
+
rl=RubyLexer.new("(string escape translation hack...)",'')
|
3024
|
+
result=str.dup
|
3025
|
+
seq=result.to_sequence
|
3026
|
+
rl.instance_eval{@file=seq}
|
3027
|
+
repls=[]
|
3028
|
+
i=0
|
3029
|
+
#ugly ugly ugly... all so I can call @bs_handler
|
3030
|
+
while i<result.size and bs_at=result.index(/\\./m,i)
|
3031
|
+
seq.pos=$~.end(0)-1
|
3032
|
+
ch=rl.send(@bs_handler,"\\",@open[-1,1],@close)
|
3033
|
+
result[bs_at...seq.pos]=ch
|
3034
|
+
i=bs_at+ch.size
|
3035
|
+
end
|
3036
|
+
|
3037
|
+
return result
|
2334
3038
|
end
|
2335
3039
|
|
2336
3040
|
def old_cat_initialize(*tokens) #not needed anymore?
|
@@ -2359,45 +3063,59 @@ class RedParse
|
|
2359
3063
|
|
2360
3064
|
ESCAPABLES={}
|
2361
3065
|
EVEN_NUM_BSLASHES=/(^|[^\\])((?:\\\\)*)/
|
2362
|
-
def unparse o
|
2363
|
-
|
2364
|
-
[@open,unparse_interior(o),@close,@modifiers].to_s
|
3066
|
+
def unparse o=default_unparse_options
|
3067
|
+
o[:linenum]+=@open.count("\n")
|
3068
|
+
result=[@open,unparse_interior(o),@close,@modifiers].to_s
|
3069
|
+
o[:linenum]+=@close.count("\n")
|
3070
|
+
return result
|
2365
3071
|
end
|
2366
3072
|
|
2367
3073
|
def escapable open=@open,close=@close
|
2368
3074
|
unless escapable=ESCAPABLES[open]
|
2369
|
-
maybe_crunch='
|
3075
|
+
maybe_crunch='\\#' if %r{\A["`/\{]\Z} === @char and open[1] != ?q and open != "'" #"
|
2370
3076
|
#crunch (#) might need to be escaped too, depending on what @char is
|
2371
3077
|
escapable=ESCAPABLES[open]=
|
2372
|
-
/[#{open[-1,1]+close}#{maybe_crunch}]/
|
3078
|
+
/[#{Regexp.quote open[-1,1]+close}#{maybe_crunch}]/
|
2373
3079
|
end
|
2374
3080
|
escapable
|
2375
3081
|
end
|
2376
3082
|
|
2377
|
-
def unparse_interior o,open=@open,close=@close
|
3083
|
+
def unparse_interior o,open=@open,close=@close,escape=nil
|
2378
3084
|
escapable=escapable(open,close)
|
2379
|
-
map{|substr|
|
3085
|
+
result=map{|substr|
|
2380
3086
|
if String===substr
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
substr.
|
3087
|
+
|
3088
|
+
#hack: this is needed for here documents only, because their
|
3089
|
+
#delimiter is changing.
|
3090
|
+
substr.gsub!(escape){|ch| ch[0...-1]+"\\"+ch[-1,1]} if escape
|
3091
|
+
|
3092
|
+
o[:linenum]+=substr.count("\n") if o[:linenum]
|
3093
|
+
|
2387
3094
|
substr
|
2388
3095
|
else
|
2389
3096
|
['#{',substr.unparse(o),'}']
|
2390
3097
|
end
|
2391
3098
|
}
|
3099
|
+
result
|
2392
3100
|
end
|
2393
3101
|
|
2394
3102
|
def image; '(#@char)' end
|
2395
3103
|
|
2396
3104
|
def delete_extraneous_ivars!
|
2397
|
-
@parses_like.delete_extraneous_ivars! if @parses_like
|
3105
|
+
@parses_like.delete_extraneous_ivars! if defined? @parses_like
|
2398
3106
|
return super
|
2399
3107
|
end
|
2400
3108
|
|
3109
|
+
def walk(*args,&callback)
|
3110
|
+
return @parses_like.walk(*args,&callback) if defined? @parses_like
|
3111
|
+
super
|
3112
|
+
end
|
3113
|
+
|
3114
|
+
def depthwalk(*args,&callback)
|
3115
|
+
return @parses_like.depthwalk(*args,&callback) if defined? @parses_like
|
3116
|
+
super
|
3117
|
+
end
|
3118
|
+
|
2401
3119
|
def special_conditions!
|
2402
3120
|
@implicit_match= @char=="/"
|
2403
3121
|
end
|
@@ -2412,45 +3130,57 @@ class RedParse
|
|
2412
3130
|
# data=elems=token.string.elems
|
2413
3131
|
data=elems=
|
2414
3132
|
case token
|
2415
|
-
when StringToken
|
2416
|
-
when HerePlaceholderToken
|
3133
|
+
when StringToken; token.elems
|
3134
|
+
when HerePlaceholderToken; token.string.elems
|
2417
3135
|
else raise "unknown string token type: #{token}:#{token.class}"
|
2418
3136
|
end
|
2419
3137
|
# sum.size%2==1 and sum.last<<elems.shift
|
2420
3138
|
# sum+elems
|
2421
3139
|
# }
|
3140
|
+
# endline=@endline
|
2422
3141
|
1.step(data.length-1,2){|i|
|
2423
3142
|
tokens=data[i].ident.dup
|
3143
|
+
line=data[i].linenum
|
3144
|
+
|
3145
|
+
#replace trailing } with EoiToken
|
2424
3146
|
(tokens.size-1).downto(0){|j|
|
2425
3147
|
tok=tokens[j]
|
2426
3148
|
break(tokens[j..-1]=[EoiToken.new('',nil,tokens[j].offset)]) if tok.ident=='}'
|
2427
3149
|
}
|
3150
|
+
#remove leading {
|
2428
3151
|
tokens.each_with_index{|tok,j| break(tokens.delete_at j) if tok.ident=='{' }
|
3152
|
+
|
2429
3153
|
if tokens.size==1 and VarNameToken===tokens.first
|
2430
|
-
data[i]=tokens.first
|
3154
|
+
data[i]=VarNode.new tokens.first
|
3155
|
+
data[i].endline=token.endline
|
2431
3156
|
else
|
2432
|
-
|
2433
|
-
|
3157
|
+
#parse the token list in the string inclusion
|
3158
|
+
parser=Thread.current[:$RedParse_parser]
|
3159
|
+
klass=parser.class
|
3160
|
+
data[i]=klass.new(tokens, "(string inclusion)",1,[],{:rubyversion=>parser.rubyversion}).parse
|
2434
3161
|
end
|
2435
3162
|
} #if data
|
2436
|
-
# was_nul_header= (String===data.first and data.first.empty?) #and quirks
|
3163
|
+
# was_nul_header= (String===data.first and data.first.empty?) #and o[:quirks]
|
2437
3164
|
last=data.size-1
|
3165
|
+
|
3166
|
+
#remove (most) empty string fragments
|
2438
3167
|
last.downto(1){|frag_i|
|
2439
3168
|
frag=data[frag_i]
|
2440
3169
|
String===frag or next
|
2441
|
-
|
2442
|
-
next if frag_i==last #and quirks
|
2443
|
-
next if data[frag_i-1].
|
3170
|
+
next unless frag.empty?
|
3171
|
+
next if frag_i==last #and o[:quirks]
|
3172
|
+
next if data[frag_i-1].endline != data[frag_i+1].endline #and o[:quirks]
|
2444
3173
|
#prev and next inclusions on different lines
|
2445
|
-
data.slice!(frag_i)
|
3174
|
+
data.slice!(frag_i)
|
2446
3175
|
}
|
2447
3176
|
# data.unshift '' if was_nul_header
|
3177
|
+
|
2448
3178
|
return data
|
2449
3179
|
end
|
2450
3180
|
|
2451
|
-
def
|
3181
|
+
def endline= endline
|
2452
3182
|
each{|frag|
|
2453
|
-
frag.
|
3183
|
+
frag.endline||=endline if frag.respond_to? :endline
|
2454
3184
|
}
|
2455
3185
|
|
2456
3186
|
super
|
@@ -2461,18 +3191,63 @@ class RedParse
|
|
2461
3191
|
huh
|
2462
3192
|
end
|
2463
3193
|
|
3194
|
+
EVEN_BSS=/(?:[^\\\s\v]|\G)(?:\\\\)*/
|
3195
|
+
|
3196
|
+
DQ_ESC=/(?>\\(?>[CM]-|c)?)/
|
3197
|
+
DQ_EVEN=%r[
|
3198
|
+
(?:
|
3199
|
+
\A |
|
3200
|
+
[^\\c-] |
|
3201
|
+
(?>\A|[^\\])c |
|
3202
|
+
(?> [^CM] | (?>\A|[^\\])[CM] )-
|
3203
|
+
) #not esc
|
3204
|
+
#{DQ_ESC}{2}* #an even number of esc
|
3205
|
+
]omx
|
3206
|
+
DQ_ODD=/#{DQ_EVEN}#{DQ_ESC}/omx
|
3207
|
+
SQ_ESC=/\\/
|
3208
|
+
SQ_EVEN=%r[
|
3209
|
+
(?: \A | [^\\] ) #not esc
|
3210
|
+
#{SQ_ESC}{2}* #an even number of esc
|
3211
|
+
]omx
|
3212
|
+
SQ_ODD=/#{SQ_EVEN}#{SQ_ESC}/omx
|
2464
3213
|
def split_into_words strtok
|
2465
3214
|
return unless /[{\[]/===@char
|
2466
3215
|
result=ArrayLiteralNode[]
|
2467
|
-
result << StringNode['',{:@char=>'"'}]
|
2468
|
-
|
2469
|
-
|
3216
|
+
result << StringNode['',{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}]
|
3217
|
+
proxy=dup
|
3218
|
+
proxy[0]=proxy[0][/\A(?:\s|\v)+(.*)\Z/m,1] if /\A(?:\s|\v)/===proxy[0]
|
3219
|
+
# first[/\A(?:\s|\v)+/]='' if /\A(?:\s|\v)/===first #uh-oh, changes first
|
3220
|
+
proxy.each{|x|
|
2470
3221
|
if String===x
|
2471
|
-
|
3222
|
+
# x=x[/\A(?:\s|\v)+(.*)\Z/,1] if /\A[\s\v]/===x
|
3223
|
+
if false
|
3224
|
+
#split on ws preceded by an even # of backslashes or a non-backslash, non-ws char
|
3225
|
+
#this ignores backslashed ws
|
3226
|
+
#save the thing that preceded the ws, it goes back on the token preceding split
|
3227
|
+
double_chunks=x.split(/( #{EVEN_BSS} | (?:[^\\\s\v]|\A|#{EVEN_BSS}\\[\s\v]) )(?:\s|\v)+/xo,-1)
|
2472
3228
|
chunks=[]
|
2473
3229
|
(0..double_chunks.size).step(2){|i|
|
2474
|
-
chunks << strtok.translate_escapes
|
3230
|
+
chunks << #strtok.translate_escapes \
|
3231
|
+
double_chunks[i,2].to_s #.gsub(/\\([\s\v\\])/){$1}
|
2475
3232
|
}
|
3233
|
+
else
|
3234
|
+
#split on ws, then ignore ws preceded by an odd number of esc's
|
3235
|
+
#esc is \ in squote word array, \ or \c or \C- or \M- in dquote
|
3236
|
+
chunks_and_ws=x.split(/([\s\v]+)/,-1)
|
3237
|
+
start=chunks_and_ws.size; start-=1 if start&1==1
|
3238
|
+
chunks=[]
|
3239
|
+
i=start+2;
|
3240
|
+
while (i-=2)>=0
|
3241
|
+
ch=chunks_and_ws[i]||""
|
3242
|
+
if i<chunks_and_ws.size and ch.match(@char=="[" ? /#{SQ_ODD}\Z/omx : /#{DQ_ODD}\Z/omx)
|
3243
|
+
ch<< chunks_and_ws[i+1][0,1]
|
3244
|
+
if chunks_and_ws[i+1].size==1
|
3245
|
+
ch<< chunks.shift
|
3246
|
+
end
|
3247
|
+
end
|
3248
|
+
chunks.unshift ch
|
3249
|
+
end
|
3250
|
+
end
|
2476
3251
|
|
2477
3252
|
chunk1= chunks.shift
|
2478
3253
|
if chunk1.empty?
|
@@ -2483,9 +3258,16 @@ class RedParse
|
|
2483
3258
|
result.last.push chunk1
|
2484
3259
|
end
|
2485
3260
|
# result.last.last.empty? and result.last.pop
|
2486
|
-
result.concat chunks.map{|chunk|
|
3261
|
+
result.concat chunks.map{|chunk|
|
3262
|
+
StringNode[chunk,{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}]
|
3263
|
+
}
|
2487
3264
|
else
|
2488
|
-
result.last << x
|
3265
|
+
#result.last << x
|
3266
|
+
unless String===result.last.last
|
3267
|
+
result.push StringNode["",{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}]
|
3268
|
+
end
|
3269
|
+
result.last.push x
|
3270
|
+
# result.push StringNode["",x,{:@char=>'"',:@open=>@open,:@close=>@close,:@bs_handler=>@bs_handler}]
|
2489
3271
|
end
|
2490
3272
|
}
|
2491
3273
|
result.shift if StringNode&-{:size=>1, :first=>''}===result.first
|
@@ -2514,9 +3296,9 @@ class RedParse
|
|
2514
3296
|
:dstr=>:str,
|
2515
3297
|
:dxstr=>:xstr,
|
2516
3298
|
}
|
2517
|
-
def parsetree
|
3299
|
+
def parsetree(o)
|
2518
3300
|
if size==1
|
2519
|
-
val=first
|
3301
|
+
val=translate_escapes first
|
2520
3302
|
type=case @char
|
2521
3303
|
when '"',"'"; :str
|
2522
3304
|
when '/'
|
@@ -2535,8 +3317,8 @@ class RedParse
|
|
2535
3317
|
val=Regexp.new val,numopts|charset
|
2536
3318
|
:lit
|
2537
3319
|
when '[','{'
|
2538
|
-
return @parses_like.parsetree
|
2539
|
-
|
3320
|
+
return @parses_like.parsetree(o)
|
3321
|
+
=begin
|
2540
3322
|
double_chunks=val.split(/([^\\]|\A)(?:\s|\v)/,-1)
|
2541
3323
|
chunks=[]
|
2542
3324
|
(0..double_chunks.size).step(2){|i|
|
@@ -2550,6 +3332,7 @@ class RedParse
|
|
2550
3332
|
words.pop if words.last.empty? unless words.empty?
|
2551
3333
|
return [:zarray] if words.empty?
|
2552
3334
|
return words.map{|word| [:str,word]}.unshift(:array)
|
3335
|
+
=end
|
2553
3336
|
when '`'; :xstr
|
2554
3337
|
else raise "dunno what to do with #@char<StringToken"
|
2555
3338
|
end
|
@@ -2559,7 +3342,8 @@ class RedParse
|
|
2559
3342
|
vals=[]
|
2560
3343
|
each{|elem|
|
2561
3344
|
case elem
|
2562
|
-
when String
|
3345
|
+
when String
|
3346
|
+
elem=translate_escapes elem
|
2563
3347
|
if saw_string
|
2564
3348
|
result=[:str, elem]
|
2565
3349
|
else
|
@@ -2567,10 +3351,10 @@ class RedParse
|
|
2567
3351
|
result=elem
|
2568
3352
|
end
|
2569
3353
|
vals.push result
|
2570
|
-
when NopNode
|
3354
|
+
when NopNode
|
2571
3355
|
vals.push [:evstr]
|
2572
|
-
when Node
|
2573
|
-
res=elem.parsetree
|
3356
|
+
when Node #,VarNameToken
|
3357
|
+
res=elem.parsetree(o)
|
2574
3358
|
if res.first==:str and @char != '{'
|
2575
3359
|
vals.push res
|
2576
3360
|
elsif res.first==:dstr and @char != '{'
|
@@ -2582,7 +3366,7 @@ class RedParse
|
|
2582
3366
|
end
|
2583
3367
|
}
|
2584
3368
|
while vals.size>1 and vals[1].first==:str
|
2585
|
-
vals[0]
|
3369
|
+
vals[0]+=vals.delete_at(1).last
|
2586
3370
|
end
|
2587
3371
|
#vals.pop if vals.last==[:str, ""]
|
2588
3372
|
|
@@ -2603,8 +3387,9 @@ class RedParse
|
|
2603
3387
|
vals.push numopts|charset unless numopts|charset==0
|
2604
3388
|
val=/#{val}/
|
2605
3389
|
type
|
2606
|
-
when '{'
|
2607
|
-
return @parses_like.parsetree
|
3390
|
+
when '{'
|
3391
|
+
return @parses_like.parsetree(o)
|
3392
|
+
=begin
|
2608
3393
|
vals[0]=vals[0].sub(/\A(\s|\v)+/,'') if /\A(\s|\v)/===vals.first
|
2609
3394
|
merged=Array.new(vals)
|
2610
3395
|
result=[]
|
@@ -2620,7 +3405,7 @@ class RedParse
|
|
2620
3405
|
if !result.empty? and frag=words.shift and !frag.last.empty?
|
2621
3406
|
result[-1]+=frag
|
2622
3407
|
end
|
2623
|
-
result.push *words
|
3408
|
+
result.push( *words )
|
2624
3409
|
else
|
2625
3410
|
result.push [:str,""] if result.empty?
|
2626
3411
|
if i.first==:evstr and i.size>1 and i.last.first==:str
|
@@ -2637,6 +3422,7 @@ class RedParse
|
|
2637
3422
|
end
|
2638
3423
|
}
|
2639
3424
|
return result.unshift(:array)
|
3425
|
+
=end
|
2640
3426
|
when '`'; :dxstr
|
2641
3427
|
else raise "dunno what to do with #@char<StringToken"
|
2642
3428
|
end
|
@@ -2657,6 +3443,7 @@ class RedParse
|
|
2657
3443
|
def initialize(token)
|
2658
3444
|
token.node=self
|
2659
3445
|
super(token)
|
3446
|
+
@startline=token.string.startline
|
2660
3447
|
end
|
2661
3448
|
attr_accessor :list_to_append
|
2662
3449
|
# attr :token
|
@@ -2666,18 +3453,35 @@ class RedParse
|
|
2666
3453
|
@char=token.quote
|
2667
3454
|
if @list_to_append
|
2668
3455
|
size%2==1 and token << @list_to_append.shift
|
2669
|
-
push *@list_to_append
|
3456
|
+
push( *@list_to_append )
|
2670
3457
|
remove_instance_variable :@list_to_append
|
2671
3458
|
end
|
2672
3459
|
end
|
2673
3460
|
|
3461
|
+
def translate_escapes x
|
3462
|
+
return x if @char=="'"
|
3463
|
+
super
|
3464
|
+
end
|
3465
|
+
|
2674
3466
|
|
2675
3467
|
def flattened_ivars_equal?(other)
|
2676
3468
|
StringNode===other
|
2677
3469
|
end
|
2678
3470
|
|
2679
|
-
def unparse o
|
2680
|
-
|
3471
|
+
def unparse o=default_unparse_options
|
3472
|
+
lead=unparse_nl(self,o,'',"\\\n")
|
3473
|
+
inner=unparse_interior o,@char,@char,
|
3474
|
+
case @char
|
3475
|
+
when "'" #single-quoted here doc is a special case;
|
3476
|
+
#\ and ' are not special within it
|
3477
|
+
#(and therefore always escaped if converted to normal squote str)
|
3478
|
+
/['\\]/
|
3479
|
+
when '"'; /#{DQ_EVEN}"/
|
3480
|
+
when "`"; /#{DQ_EVEN}`/
|
3481
|
+
else fail
|
3482
|
+
end
|
3483
|
+
|
3484
|
+
[lead,@char, inner, @char].to_s
|
2681
3485
|
end
|
2682
3486
|
end
|
2683
3487
|
|
@@ -2688,22 +3492,16 @@ class RedParse
|
|
2688
3492
|
@offset=old_val.offset
|
2689
3493
|
val=old_val.ident
|
2690
3494
|
case old_val
|
2691
|
-
when SymbolToken
|
3495
|
+
when SymbolToken
|
2692
3496
|
case val[1]
|
2693
|
-
when ?'
|
3497
|
+
when ?' #'
|
2694
3498
|
assert !old_val.raw.has_str_inc?
|
2695
3499
|
val=old_val.raw.translate_escapes(old_val.raw.elems.first).to_sym
|
2696
|
-
|
2697
|
-
#eval here is cheating!!!!
|
2698
|
-
#too lazy to do it right just now
|
2699
|
-
when ?": #"
|
3500
|
+
when ?" #"
|
2700
3501
|
if old_val.raw.has_str_inc?
|
2701
3502
|
val=StringNode.new(old_val.raw) #ugly hack: this isn't literal
|
2702
3503
|
else
|
2703
3504
|
val=old_val.raw.translate_escapes(old_val.raw.elems.first).to_sym
|
2704
|
-
#val=eval(val[1..-1]).to_sym
|
2705
|
-
#eval here is cheating!!!!
|
2706
|
-
#too lazy to do it right just now
|
2707
3505
|
end
|
2708
3506
|
else #val=val[1..-1].to_sym
|
2709
3507
|
if StringToken===old_val.raw
|
@@ -2712,16 +3510,22 @@ class RedParse
|
|
2712
3510
|
val=old_val.raw.to_sym
|
2713
3511
|
end
|
2714
3512
|
end
|
2715
|
-
when NumberToken
|
3513
|
+
when NumberToken
|
2716
3514
|
case val
|
2717
|
-
when /\A-?0([^.]|\Z)
|
2718
|
-
when /[.e]/i
|
3515
|
+
when /\A-?0([^.]|\Z)/; val=val.oct
|
3516
|
+
when /[.e]/i; val=val.to_f
|
2719
3517
|
else val=val.to_i
|
2720
3518
|
end
|
2721
3519
|
end
|
2722
3520
|
super(val)
|
2723
3521
|
end
|
2724
3522
|
|
3523
|
+
def bare_method
|
3524
|
+
Symbol===val || StringNode===val
|
3525
|
+
end
|
3526
|
+
|
3527
|
+
identity_param :bare_method, nil, false, true
|
3528
|
+
|
2725
3529
|
def image; "(#{':' if Symbol===val}#{val})" end
|
2726
3530
|
|
2727
3531
|
def to_lisp
|
@@ -2731,18 +3535,18 @@ class RedParse
|
|
2731
3535
|
Inf="999999999999999999999999999999999.9e999999999999999999999999999999999999"
|
2732
3536
|
Nan="****shouldnt ever happen****"
|
2733
3537
|
|
2734
|
-
def unparse o
|
3538
|
+
def unparse o=default_unparse_options
|
2735
3539
|
val=val()
|
2736
3540
|
case val
|
2737
3541
|
when StringNode #ugly hack
|
2738
3542
|
":"+
|
2739
3543
|
val.unparse(o)
|
2740
3544
|
when Float
|
2741
|
-
s= "%#{Float::DIG}.#{Float::DIG}f"%val
|
3545
|
+
s= "%#{Float::DIG+1}.#{Float::DIG+1}f"%val
|
2742
3546
|
case s
|
2743
|
-
when /-inf/i
|
2744
|
-
when /inf/i
|
2745
|
-
when /nan/i
|
3547
|
+
when /-inf/i; s="-"+Inf
|
3548
|
+
when /inf/i; s= Inf
|
3549
|
+
when /nan/i; s= Nan
|
2746
3550
|
else
|
2747
3551
|
fail unless [s.to_f].pack("d")==[val].pack("d")
|
2748
3552
|
end
|
@@ -2751,11 +3555,11 @@ class RedParse
|
|
2751
3555
|
end
|
2752
3556
|
end
|
2753
3557
|
|
2754
|
-
def parsetree
|
3558
|
+
def parsetree(o)
|
2755
3559
|
val=val()
|
2756
3560
|
case val
|
2757
3561
|
when StringNode #ugly hack
|
2758
|
-
result= val.parsetree
|
3562
|
+
result= val.parsetree(o)
|
2759
3563
|
result[0]=:dsym
|
2760
3564
|
return result
|
2761
3565
|
=begin
|
@@ -2786,6 +3590,7 @@ class RedParse
|
|
2786
3590
|
if name.ident=='('
|
2787
3591
|
#simulate nil
|
2788
3592
|
replace ['nil']
|
3593
|
+
@value=false
|
2789
3594
|
else
|
2790
3595
|
replace [name.ident]
|
2791
3596
|
@value=name.respond_to?(:value) && name.value
|
@@ -2800,12 +3605,12 @@ class RedParse
|
|
2800
3605
|
name
|
2801
3606
|
end
|
2802
3607
|
|
2803
|
-
def unparse o
|
3608
|
+
def unparse o=default_unparse_options
|
2804
3609
|
name
|
2805
3610
|
end
|
2806
3611
|
|
2807
|
-
def parsetree
|
2808
|
-
if @value
|
3612
|
+
def parsetree(o)
|
3613
|
+
if (defined? @value) and @value
|
2809
3614
|
type=:lit
|
2810
3615
|
val=@value
|
2811
3616
|
if name=="__FILE__"
|
@@ -2823,7 +3628,7 @@ class RedParse
|
|
2823
3628
|
def initialize(lbrack,contents,rbrack)
|
2824
3629
|
contents or return super()
|
2825
3630
|
if CommaOpNode===contents
|
2826
|
-
super *contents
|
3631
|
+
super( *contents )
|
2827
3632
|
else
|
2828
3633
|
super contents
|
2829
3634
|
end
|
@@ -2831,13 +3636,13 @@ class RedParse
|
|
2831
3636
|
|
2832
3637
|
def image; "([])" end
|
2833
3638
|
|
2834
|
-
def unparse o
|
2835
|
-
"["+map{|item| item.unparse
|
3639
|
+
def unparse o=default_unparse_options
|
3640
|
+
"["+map{|item| unparse_nl(item,o,'')+item.unparse(o)}.join(', ')+"]"
|
2836
3641
|
end
|
2837
3642
|
|
2838
|
-
def parsetree
|
3643
|
+
def parsetree(o)
|
2839
3644
|
size.zero? and return [:zarray]
|
2840
|
-
normals,star,amp=param_list_parse(self)
|
3645
|
+
normals,star,amp=param_list_parse(self,o)
|
2841
3646
|
result=normals.unshift :array
|
2842
3647
|
if star
|
2843
3648
|
if size==1
|
@@ -2854,9 +3659,9 @@ class RedParse
|
|
2854
3659
|
|
2855
3660
|
class BracketsSetNode < ValueNode #obsolete
|
2856
3661
|
param_names :left,:assign_,:right
|
2857
|
-
def parsetree
|
2858
|
-
[:attrasgn, left.data[0].parsetree, :[]=,
|
2859
|
-
[:array]+Array(left.data[1]).map{|x| x.parsetree}<< right.parsetree
|
3662
|
+
def parsetree(o)
|
3663
|
+
[:attrasgn, left.data[0].parsetree(o), :[]=,
|
3664
|
+
[:array]+Array(left.data[1]).map{|x| x.parsetree(o)}<< right.parsetree(o)
|
2860
3665
|
]
|
2861
3666
|
end
|
2862
3667
|
end
|
@@ -2867,11 +3672,11 @@ class RedParse
|
|
2867
3672
|
super
|
2868
3673
|
end
|
2869
3674
|
|
2870
|
-
def parsetree
|
3675
|
+
def parsetree(o)
|
2871
3676
|
bracketargs=@data[0].data[1]
|
2872
|
-
bracketargs=bracketargs ? bracketargs.map{|x| x.parsetree}.unshift(:array) : [:zarray]
|
2873
|
-
[:op_asgn1, @data[0].data[0].parsetree, bracketargs,
|
2874
|
-
data[1].ident.chomp('=').to_sym, data[2].parsetree]
|
3677
|
+
bracketargs=bracketargs ? bracketargs.map{|x| x.parsetree(o)}.unshift(:array) : [:zarray]
|
3678
|
+
[:op_asgn1, @data[0].data[0].parsetree(o), bracketargs,
|
3679
|
+
data[1].ident.chomp('=').to_sym, data[2].parsetree(o)]
|
2875
3680
|
end
|
2876
3681
|
end
|
2877
3682
|
|
@@ -2898,13 +3703,14 @@ class RedParse
|
|
2898
3703
|
|
2899
3704
|
attr_reader :empty_else
|
2900
3705
|
|
2901
|
-
def unparse o
|
3706
|
+
def unparse o=default_unparse_options
|
2902
3707
|
result=@reverse ? "unless " : "if "
|
2903
|
-
result+="#{condition.unparse o}
|
2904
|
-
result+="#{consequent.unparse(o)}
|
2905
|
-
result+=elsifs.map{|n| n.unparse(o)}.to_s if elsifs
|
2906
|
-
result+="else "+else_.unparse(o)
|
2907
|
-
result+="
|
3708
|
+
result+="#{condition.unparse o}"
|
3709
|
+
result+=unparse_nl(consequent,o)+"#{consequent.unparse(o)}" if consequent
|
3710
|
+
result+=unparse_nl(elsifs.first,o)+elsifs.map{|n| n.unparse(o)}.to_s if elsifs
|
3711
|
+
result+=unparse_nl(else_,o)+"else "+else_.unparse(o) if else_
|
3712
|
+
result+=";else " if defined? @empty_else
|
3713
|
+
result+=";end"
|
2908
3714
|
return result
|
2909
3715
|
end
|
2910
3716
|
|
@@ -2938,14 +3744,14 @@ class RedParse
|
|
2938
3744
|
end
|
2939
3745
|
end
|
2940
3746
|
|
2941
|
-
def parsetree
|
2942
|
-
elsepart=otherwise.parsetree if otherwise
|
3747
|
+
def parsetree(o)
|
3748
|
+
elsepart=otherwise.parsetree(o) if otherwise
|
2943
3749
|
elsifs.reverse_each{|elsifnode|
|
2944
|
-
elsepart=elsifnode.parsetree << elsepart
|
3750
|
+
elsepart=elsifnode.parsetree(o) << elsepart
|
2945
3751
|
}
|
2946
|
-
cond=condition.rescue_parsetree
|
3752
|
+
cond=condition.rescue_parsetree(o)
|
2947
3753
|
actions=[
|
2948
|
-
consequent&&consequent.parsetree,
|
3754
|
+
consequent&&consequent.parsetree(o),
|
2949
3755
|
elsepart
|
2950
3756
|
]
|
2951
3757
|
if cond.first==:not
|
@@ -2975,8 +3781,8 @@ class RedParse
|
|
2975
3781
|
param_names :ensureword_, :val
|
2976
3782
|
alias body val
|
2977
3783
|
def image; "(ensure)" end
|
2978
|
-
def parsetree #obsolete?
|
2979
|
-
(body=body()) ? body.parsetree : [:nil]
|
3784
|
+
def parsetree(o) #obsolete?
|
3785
|
+
(body=body()) ? body.parsetree(o) : [:nil]
|
2980
3786
|
end
|
2981
3787
|
end
|
2982
3788
|
|
@@ -2993,16 +3799,16 @@ class RedParse
|
|
2993
3799
|
|
2994
3800
|
def image; "(elsif)" end
|
2995
3801
|
|
2996
|
-
def unparse o
|
2997
|
-
"elsif #{condition.unparse o}
|
3802
|
+
def unparse o=default_unparse_options
|
3803
|
+
"elsif #{condition.unparse o}#{unparse_nl(consequent,o)}#{consequent.unparse o};"
|
2998
3804
|
end
|
2999
3805
|
|
3000
3806
|
def to_lisp
|
3001
3807
|
"("+condition.to_lisp+" "+consequent.to_lisp+")"
|
3002
3808
|
end
|
3003
3809
|
|
3004
|
-
def parsetree #obsolete?
|
3005
|
-
[:if, condition.rescue_parsetree, consequent&&consequent.parsetree, ]
|
3810
|
+
def parsetree(o) #obsolete?
|
3811
|
+
[:if, condition.rescue_parsetree(o), consequent&&consequent.parsetree(o), ]
|
3006
3812
|
end
|
3007
3813
|
end
|
3008
3814
|
|
@@ -3020,11 +3826,11 @@ class RedParse
|
|
3020
3826
|
|
3021
3827
|
def image; "(#{loopword})" end
|
3022
3828
|
|
3023
|
-
def unparse o
|
3829
|
+
def unparse o=default_unparse_options
|
3024
3830
|
[@reverse? "until " : "while ",
|
3025
|
-
condition.unparse(o),
|
3831
|
+
condition.unparse(o), unparse_nl(body||self,o),
|
3026
3832
|
body&&body.unparse(o),
|
3027
|
-
"
|
3833
|
+
";end"
|
3028
3834
|
].to_s
|
3029
3835
|
end
|
3030
3836
|
|
@@ -3041,15 +3847,15 @@ class RedParse
|
|
3041
3847
|
"(#{@reverse ? :until : :while} #{condition.to_lisp}\n#{body.to_lisp})"
|
3042
3848
|
end
|
3043
3849
|
|
3044
|
-
def parsetree
|
3045
|
-
cond=condition.rescue_parsetree
|
3850
|
+
def parsetree(o)
|
3851
|
+
cond=condition.rescue_parsetree(o)
|
3046
3852
|
if cond.first==:not
|
3047
3853
|
reverse=!@reverse
|
3048
3854
|
cond=cond.last
|
3049
3855
|
else
|
3050
3856
|
reverse=@reverse
|
3051
3857
|
end
|
3052
|
-
[reverse ? :until : :while, cond, body&&body.parsetree, true]
|
3858
|
+
[reverse ? :until : :while, cond, body&&body.parsetree(o), true]
|
3053
3859
|
end
|
3054
3860
|
end
|
3055
3861
|
|
@@ -3067,12 +3873,12 @@ class RedParse
|
|
3067
3873
|
|
3068
3874
|
attr_reader :empty_else
|
3069
3875
|
|
3070
|
-
def unparse o
|
3071
|
-
result="case #{condition&&condition.unparse(o)}
|
3876
|
+
def unparse o=default_unparse_options
|
3877
|
+
result="case #{condition&&condition.unparse(o)}"+
|
3072
3878
|
whens.map{|wh| wh.unparse o}.to_s
|
3073
3879
|
|
3074
|
-
result += "else "+otherwise.unparse(o)
|
3075
|
-
result += "end"
|
3880
|
+
result += unparse_nl(otherwise,o)+"else "+otherwise.unparse(o) if otherwise
|
3881
|
+
result += ";end"
|
3076
3882
|
|
3077
3883
|
return result
|
3078
3884
|
end
|
@@ -3086,10 +3892,10 @@ class RedParse
|
|
3086
3892
|
"\n)"
|
3087
3893
|
end
|
3088
3894
|
|
3089
|
-
def parsetree
|
3090
|
-
[:case, condition&&condition.parsetree]+
|
3091
|
-
whens.map{|whennode| whennode.parsetree}+
|
3092
|
-
[otherwise&&otherwise.parsetree]
|
3895
|
+
def parsetree(o)
|
3896
|
+
[:case, condition&&condition.parsetree(o)]+
|
3897
|
+
whens.map{|whennode| whennode.parsetree(o)}+
|
3898
|
+
[otherwise&&otherwise.parsetree(o)]
|
3093
3899
|
end
|
3094
3900
|
end
|
3095
3901
|
|
@@ -3105,13 +3911,12 @@ class RedParse
|
|
3105
3911
|
|
3106
3912
|
def image; "(when)" end
|
3107
3913
|
|
3108
|
-
def unparse o
|
3109
|
-
result="when "
|
3914
|
+
def unparse o=default_unparse_options
|
3915
|
+
result=unparse_nl(self,o)+"when "
|
3110
3916
|
result+=condition.class==Array ?
|
3111
3917
|
condition.map{|cond| cond.unparse(o)}.join(',') :
|
3112
3918
|
condition.unparse(o)
|
3113
|
-
result+=
|
3114
|
-
result+=consequent.unparse(o)+"\n" if consequent
|
3919
|
+
result+=unparse_nl(consequent,o)+consequent.unparse(o) if consequent
|
3115
3920
|
result
|
3116
3921
|
end
|
3117
3922
|
|
@@ -3127,19 +3932,19 @@ class RedParse
|
|
3127
3932
|
|
3128
3933
|
end
|
3129
3934
|
|
3130
|
-
def parsetree
|
3935
|
+
def parsetree(o)
|
3131
3936
|
conds=
|
3132
3937
|
if Node|Token===condition
|
3133
|
-
[condition.rescue_parsetree]
|
3938
|
+
[condition.rescue_parsetree(o)]
|
3134
3939
|
else
|
3135
|
-
condition.map{|cond| cond.rescue_parsetree}
|
3940
|
+
condition.map{|cond| cond.rescue_parsetree(o)}
|
3136
3941
|
end
|
3137
3942
|
if conds.last[0]==:splat
|
3138
3943
|
conds.last[0]=:when
|
3139
3944
|
conds.last.push nil
|
3140
3945
|
end
|
3141
3946
|
[:when, [:array, *conds],
|
3142
|
-
consequent&&consequent.parsetree
|
3947
|
+
consequent&&consequent.parsetree(o)
|
3143
3948
|
]
|
3144
3949
|
end
|
3145
3950
|
end
|
@@ -3148,7 +3953,7 @@ class RedParse
|
|
3148
3953
|
param_names(:forword_,:for!,:inword_,:in!,:doword_,:do!,:endword_)
|
3149
3954
|
def initialize(forword,for_,inword,in_,doword,do_,endword)
|
3150
3955
|
#elide 1 layer of parens if present
|
3151
|
-
for_=for_.first if ParenedNode===for_
|
3956
|
+
for_=for_.first if ParenedNode===for_
|
3152
3957
|
for_=CommaOpNode===for_ ? Array.new(for_) : [for_]
|
3153
3958
|
super(BlockParams.new(for_),in_,do_)
|
3154
3959
|
end
|
@@ -3159,18 +3964,17 @@ class RedParse
|
|
3159
3964
|
|
3160
3965
|
def image; "(for)" end
|
3161
3966
|
|
3162
|
-
def unparse o
|
3163
|
-
"
|
3164
|
-
|
3165
|
-
|
3166
|
-
end"
|
3967
|
+
def unparse o=default_unparse_options
|
3968
|
+
result=unparse_nl(self,o)+" for #{iterator.lhs_unparse(o)[1...-1]} in #{enumerable.unparse o}"
|
3969
|
+
result+=unparse_nl(body,o)+" #{body.unparse(o)}" if body
|
3970
|
+
result+=";end"
|
3167
3971
|
end
|
3168
3972
|
|
3169
|
-
def parsetree
|
3973
|
+
def parsetree(o)
|
3170
3974
|
=begin
|
3171
3975
|
case vars=@data[0]
|
3172
3976
|
when Node:
|
3173
|
-
vars=vars.parsetree
|
3977
|
+
vars=vars.parsetree(o)
|
3174
3978
|
if vars.first==:call
|
3175
3979
|
vars[0]=:attrasgn
|
3176
3980
|
vars[2]="#{vars[2]}=".to_sym
|
@@ -3179,22 +3983,22 @@ class RedParse
|
|
3179
3983
|
when Array:
|
3180
3984
|
vars=[:masgn, [:array,
|
3181
3985
|
*vars.map{|lval|
|
3182
|
-
res=lval.parsetree
|
3183
|
-
res[0]=lval.varname2assigntype if
|
3986
|
+
res=lval.parsetree(o)
|
3987
|
+
res[0]=lval.varname2assigntype if VarNode===lval
|
3184
3988
|
res
|
3185
3989
|
}
|
3186
3990
|
]]
|
3187
|
-
when
|
3991
|
+
when VarNode
|
3188
3992
|
ident=vars.ident
|
3189
|
-
vars=vars.parsetree
|
3993
|
+
vars=vars.parsetree(o)
|
3190
3994
|
(vars[0]=vars.varname2assigntype) rescue nil
|
3191
3995
|
else fail
|
3192
3996
|
end
|
3193
3997
|
=end
|
3194
3998
|
|
3195
|
-
vars=self.for.lvalue_parsetree
|
3196
|
-
result=[:for, self.in.begin_parsetree, vars]
|
3197
|
-
result.push self.do.parsetree if self.do
|
3999
|
+
vars=self.for.lvalue_parsetree(o)
|
4000
|
+
result=[:for, self.in.begin_parsetree(o), vars]
|
4001
|
+
result.push self.do.parsetree(o) if self.do
|
3198
4002
|
result
|
3199
4003
|
end
|
3200
4004
|
|
@@ -3204,8 +4008,8 @@ class RedParse
|
|
3204
4008
|
class HashLiteralNode<ValueNode
|
3205
4009
|
def initialize(open,contents,close)
|
3206
4010
|
case contents
|
3207
|
-
when nil
|
3208
|
-
when ArrowOpNode
|
4011
|
+
when nil; super()
|
4012
|
+
when ArrowOpNode; super(contents.first,contents.last)
|
3209
4013
|
when CommaOpNode,Array
|
3210
4014
|
if ArrowOpNode===contents.first
|
3211
4015
|
data=[]
|
@@ -3214,21 +4018,25 @@ class RedParse
|
|
3214
4018
|
data.push pair.first,pair.last
|
3215
4019
|
}
|
3216
4020
|
else
|
4021
|
+
@no_arrows=true
|
3217
4022
|
data=Array[*contents]
|
3218
4023
|
end
|
3219
4024
|
super(*data)
|
3220
4025
|
end
|
3221
|
-
@no_braces
|
4026
|
+
@no_braces=!open
|
3222
4027
|
end
|
3223
4028
|
|
4029
|
+
attr :no_arrows
|
4030
|
+
|
3224
4031
|
def image; "({})" end
|
3225
4032
|
|
3226
|
-
def unparse o
|
4033
|
+
def unparse o=default_unparse_options
|
3227
4034
|
result=''
|
3228
4035
|
result << "{" unless @no_braces
|
4036
|
+
arrow= defined?(@no_arrows) ? " , " : " => "
|
3229
4037
|
(0...size).step(2){|i|
|
3230
|
-
result<<
|
3231
|
-
self[i].unparse(o)+
|
4038
|
+
result<< unparse_nl(self[i],o,'')+
|
4039
|
+
self[i].unparse(o)+arrow+
|
3232
4040
|
self[i+1].unparse(o)+', '
|
3233
4041
|
}
|
3234
4042
|
result.chomp! ', '
|
@@ -3236,8 +4044,13 @@ class RedParse
|
|
3236
4044
|
return result
|
3237
4045
|
end
|
3238
4046
|
|
3239
|
-
def parsetree
|
3240
|
-
map{|elem| elem.rescue_parsetree}.unshift :hash
|
4047
|
+
def parsetree(o)
|
4048
|
+
map{|elem| elem.rescue_parsetree(o)}.unshift :hash
|
4049
|
+
end
|
4050
|
+
|
4051
|
+
def error? rubyversion=1.8
|
4052
|
+
return true if @no_arrows and rubyversion>=1.9
|
4053
|
+
return super
|
3241
4054
|
end
|
3242
4055
|
end
|
3243
4056
|
|
@@ -3253,20 +4066,21 @@ class RedParse
|
|
3253
4066
|
|
3254
4067
|
def image; "(?:)" end
|
3255
4068
|
|
3256
|
-
def unparse o
|
4069
|
+
def unparse o=default_unparse_options
|
3257
4070
|
"#{condition.unparse o} ? #{consequent.unparse o} : #{otherwise.unparse o}"
|
3258
4071
|
end
|
3259
4072
|
|
3260
4073
|
def elsifs; [] end
|
3261
4074
|
|
3262
|
-
def parsetree
|
3263
|
-
cond=condition.rescue_parsetree
|
4075
|
+
def parsetree(o)
|
4076
|
+
cond=condition.rescue_parsetree(o)
|
3264
4077
|
cond[0]=:fcall if cond[0]==:vcall and cond[1].to_s[/[?!]$/]
|
3265
|
-
[:if, cond, consequent.begin_parsetree, otherwise.begin_parsetree]
|
4078
|
+
[:if, cond, consequent.begin_parsetree(o), otherwise.begin_parsetree(o)]
|
3266
4079
|
end
|
3267
4080
|
end
|
3268
4081
|
|
3269
4082
|
class MethodNode<ValueNode
|
4083
|
+
include HasRescue
|
3270
4084
|
param_names(:defword_,:receiver,:name,:maybe_eq_,:args,:semi_,:body,:rescues,:elses,:ensures,:endword_)
|
3271
4085
|
alias ensure_ ensures
|
3272
4086
|
alias else_ elses
|
@@ -3276,7 +4090,7 @@ class RedParse
|
|
3276
4090
|
|
3277
4091
|
def initialize(defword_,header,maybe_eq_,semi_,
|
3278
4092
|
body,rescues,else_,ensure_,endword_)
|
3279
|
-
@empty_ensure=nil
|
4093
|
+
@empty_else=@empty_ensure=nil
|
3280
4094
|
# if DotCallNode===header
|
3281
4095
|
# header=header.data[1]
|
3282
4096
|
# end
|
@@ -3302,13 +4116,14 @@ class RedParse
|
|
3302
4116
|
|
3303
4117
|
attr_reader :empty_ensure, :empty_else
|
3304
4118
|
|
3305
|
-
def receiver= x
|
3306
|
-
self[0]=x
|
3307
|
-
end
|
3308
4119
|
|
3309
|
-
def
|
3310
|
-
self[
|
3311
|
-
end
|
4120
|
+
# def receiver= x
|
4121
|
+
# self[0]=x
|
4122
|
+
# end
|
4123
|
+
#
|
4124
|
+
# def body= x
|
4125
|
+
# self[3]=x
|
4126
|
+
# end
|
3312
4127
|
|
3313
4128
|
def ensure_= x
|
3314
4129
|
self[5]=x
|
@@ -3322,17 +4137,23 @@ class RedParse
|
|
3322
4137
|
"(def #{receiver.image.+('.') if receiver}#{name})"
|
3323
4138
|
end
|
3324
4139
|
|
3325
|
-
def unparse o
|
3326
|
-
result=
|
3327
|
-
def
|
3328
|
-
args
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
4140
|
+
def unparse o=default_unparse_options
|
4141
|
+
result=[
|
4142
|
+
"def ",receiver&&receiver.unparse(o)+'.',name,
|
4143
|
+
args ? '('+args.map{|arg| arg.unparse o}.join(',')+')' : unparse_nl(body||self,o)
|
4144
|
+
]
|
4145
|
+
result<<unparse_and_rescues(o)
|
4146
|
+
=begin
|
4147
|
+
body&&result+=body.unparse(o)
|
4148
|
+
|
3332
4149
|
result+=rescues.map{|resc| resc.unparse o}.to_s
|
3333
4150
|
result+="else #{else_.unparse o}\n" if else_
|
4151
|
+
result+="else\n" if @empty_else
|
3334
4152
|
result+="ensure #{ensure_.unparse o}\n" if ensure_
|
3335
|
-
result+="
|
4153
|
+
result+="ensure\n" if @empty_ensure
|
4154
|
+
=end
|
4155
|
+
result<<unparse_nl(endline,o)+"end"
|
4156
|
+
result.to_s
|
3336
4157
|
end
|
3337
4158
|
|
3338
4159
|
def to_lisp
|
@@ -3340,12 +4161,12 @@ class RedParse
|
|
3340
4161
|
#no receiver, args, rescues, else_ or ensure_...
|
3341
4162
|
end
|
3342
4163
|
|
3343
|
-
def parsetree
|
4164
|
+
def parsetree(o)
|
3344
4165
|
name=name().to_sym
|
3345
4166
|
|
3346
4167
|
result=[name, target=[:scope, [:block, ]] ]
|
3347
4168
|
if receiver
|
3348
|
-
result.unshift :defs, receiver.rescue_parsetree
|
4169
|
+
result.unshift :defs, receiver.rescue_parsetree(o)
|
3349
4170
|
else
|
3350
4171
|
result.unshift :defn
|
3351
4172
|
end
|
@@ -3365,21 +4186,21 @@ class RedParse
|
|
3365
4186
|
end
|
3366
4187
|
|
3367
4188
|
target.push args=[:args,]
|
3368
|
-
target.push unamp.parsetree if unamp
|
4189
|
+
target.push unamp.parsetree(o) if unamp
|
3369
4190
|
|
3370
4191
|
if args()
|
3371
4192
|
initvals=[]
|
3372
4193
|
args().each{|arg|
|
3373
4194
|
case arg
|
3374
|
-
when
|
4195
|
+
when VarNode
|
3375
4196
|
args.push arg.ident.to_sym
|
3376
4197
|
when UnaryStarNode:
|
3377
4198
|
args.push "*#{arg.val.ident}".to_sym
|
3378
4199
|
when UnOpNode:
|
3379
4200
|
nil
|
3380
4201
|
when AssignNode:
|
3381
|
-
initvals << arg.parsetree
|
3382
|
-
initvals[-1][-1]=arg.right.rescue_parsetree #ugly
|
4202
|
+
initvals << arg.parsetree(o)
|
4203
|
+
initvals[-1][-1]=arg.right.rescue_parsetree(o) #ugly
|
3383
4204
|
args.push arg[0].ident.to_sym
|
3384
4205
|
else
|
3385
4206
|
fail "unsupported node type in method param list: #{arg}"
|
@@ -3388,18 +4209,22 @@ class RedParse
|
|
3388
4209
|
unless initvals.empty?
|
3389
4210
|
initvals.unshift(:block)
|
3390
4211
|
args << initvals
|
3391
|
-
args[-2][0]==:block_arg and target.push args.delete_at(-2)
|
4212
|
+
#args[-2][0]==:block_arg and target.push args.delete_at(-2)
|
3392
4213
|
end
|
3393
4214
|
end
|
3394
4215
|
target.push [:nil] if !goodies && !receiver
|
4216
|
+
|
4217
|
+
#it would be better to use parsetree_and_rescues for the rest of this method,
|
4218
|
+
#just to be DRYer
|
4219
|
+
|
3395
4220
|
target.push ensuretarget=target=[:ensure, ] if ensures or @empty_ensure
|
3396
4221
|
#simple dup won't work... won't copy extend'd modules
|
3397
4222
|
body=Marshal.load(Marshal.dump(body())) if body()
|
3398
4223
|
elses=elses()
|
3399
4224
|
if rescues.empty?
|
3400
4225
|
case body
|
3401
|
-
when SequenceNode
|
3402
|
-
when nil
|
4226
|
+
when SequenceNode; body << elses;elses=nil
|
4227
|
+
when nil; body=elses;elses=nil
|
3403
4228
|
else nil
|
3404
4229
|
end if elses
|
3405
4230
|
else
|
@@ -3407,11 +4232,11 @@ class RedParse
|
|
3407
4232
|
elses=elses()
|
3408
4233
|
end
|
3409
4234
|
if body
|
3410
|
-
if
|
4235
|
+
if BeginNode===body||RescueOpNode===body and
|
3411
4236
|
body.rescues.empty? and !body.ensure and !body.empty_ensure and body.body and body.body.size>1
|
3412
4237
|
wantblock=true
|
3413
4238
|
end
|
3414
|
-
body=body.parsetree
|
4239
|
+
body=body.parsetree(o)
|
3415
4240
|
if body.first==:block and rescues.empty? and not ensures||@empty_ensure
|
3416
4241
|
if wantblock
|
3417
4242
|
target.push body
|
@@ -3420,13 +4245,13 @@ class RedParse
|
|
3420
4245
|
target.concat body
|
3421
4246
|
end
|
3422
4247
|
else
|
3423
|
-
body=[:block, *body] if wantblock
|
4248
|
+
#body=[:block, *body] if wantblock
|
3424
4249
|
target.push body
|
3425
4250
|
end
|
3426
4251
|
end
|
3427
|
-
target.push linked_list(rescues.map{|rescue_| rescue_.parsetree }) unless rescues.empty?
|
3428
|
-
target.push elses.parsetree if elses
|
3429
|
-
ensuretarget.push ensures.parsetree if ensures
|
4252
|
+
target.push linked_list(rescues.map{|rescue_| rescue_.parsetree(o) }) unless rescues.empty?
|
4253
|
+
target.push elses.parsetree(o) if elses
|
4254
|
+
ensuretarget.push ensures.parsetree(o) if ensures
|
3430
4255
|
ensuretarget.push [:nil] if @empty_ensure
|
3431
4256
|
|
3432
4257
|
return result
|
@@ -3436,13 +4261,13 @@ class RedParse
|
|
3436
4261
|
module BareSymbolUtils
|
3437
4262
|
def baresym2str(node)
|
3438
4263
|
case node
|
3439
|
-
when MethNameToken
|
3440
|
-
when
|
3441
|
-
when LiteralNode
|
4264
|
+
when MethNameToken; node.ident
|
4265
|
+
when VarNode; node
|
4266
|
+
when LiteralNode
|
3442
4267
|
case node.val
|
3443
|
-
when Symbol
|
4268
|
+
when Symbol
|
3444
4269
|
node.val.to_s
|
3445
|
-
when StringNode
|
4270
|
+
when StringNode; node.val
|
3446
4271
|
# when StringToken: StringNode.new(node.val)
|
3447
4272
|
else fail
|
3448
4273
|
end
|
@@ -3451,20 +4276,21 @@ class RedParse
|
|
3451
4276
|
|
3452
4277
|
def str_unparse(str,o)
|
3453
4278
|
case str
|
3454
|
-
when
|
3455
|
-
when
|
4279
|
+
when VarNode; str.ident
|
4280
|
+
when "~@"; str
|
4281
|
+
when String
|
3456
4282
|
str.to_sym.inspect
|
3457
4283
|
#what if str isn't a valid method or operator name? should be quoted
|
3458
|
-
when StringNode
|
4284
|
+
when StringNode
|
3459
4285
|
":"+str.unparse(o)
|
3460
4286
|
else fail
|
3461
4287
|
end
|
3462
4288
|
end
|
3463
4289
|
|
3464
|
-
def str2parsetree(str)
|
4290
|
+
def str2parsetree(str,o)
|
3465
4291
|
if String===str then [:lit, str.to_sym]
|
3466
4292
|
else
|
3467
|
-
result=str.parsetree
|
4293
|
+
result=str.parsetree(o)
|
3468
4294
|
result[0]=:dsym
|
3469
4295
|
result
|
3470
4296
|
end
|
@@ -3480,16 +4306,16 @@ class RedParse
|
|
3480
4306
|
super(to,from)
|
3481
4307
|
end
|
3482
4308
|
|
3483
|
-
def unparse o
|
4309
|
+
def unparse o=default_unparse_options
|
3484
4310
|
"alias #{str_unparse to,o} #{str_unparse from,o}"
|
3485
4311
|
end
|
3486
4312
|
|
3487
4313
|
def image; "(alias)" end
|
3488
|
-
def parsetree
|
3489
|
-
if
|
4314
|
+
def parsetree(o)
|
4315
|
+
if VarNode===to and to.ident[0]==?$
|
3490
4316
|
[:valias, to.ident.to_sym, from.ident.to_sym]
|
3491
4317
|
else
|
3492
|
-
[:alias, str2parsetree(to), str2parsetree(from)]
|
4318
|
+
[:alias, str2parsetree(to,o), str2parsetree(from,o)]
|
3493
4319
|
end
|
3494
4320
|
end
|
3495
4321
|
end
|
@@ -3507,12 +4333,12 @@ class RedParse
|
|
3507
4333
|
|
3508
4334
|
def image; "(undef)" end
|
3509
4335
|
|
3510
|
-
def unparse o
|
4336
|
+
def unparse o=default_unparse_options
|
3511
4337
|
"undef #{map{|name| str_unparse name,o}.join(', ')}"
|
3512
4338
|
end
|
3513
4339
|
|
3514
|
-
def parsetree
|
3515
|
-
result=map{|name| [:undef, str2parsetree(name)] }
|
4340
|
+
def parsetree(o)
|
4341
|
+
result=map{|name| [:undef, str2parsetree(name,o)] }
|
3516
4342
|
if result.size==1
|
3517
4343
|
result.first
|
3518
4344
|
else
|
@@ -3522,15 +4348,29 @@ class RedParse
|
|
3522
4348
|
end
|
3523
4349
|
|
3524
4350
|
class NamespaceNode<ValueNode
|
4351
|
+
include HasRescue
|
4352
|
+
def initialize(*args)
|
4353
|
+
@empty_ensure=@empty_else=nil
|
4354
|
+
super
|
4355
|
+
end
|
3525
4356
|
end
|
3526
4357
|
|
3527
4358
|
class ModuleNode<NamespaceNode
|
3528
|
-
param_names(:
|
4359
|
+
param_names(:name,:body,:rescues,:else!,:ensure!)
|
4360
|
+
|
4361
|
+
def initialize moduleword,name,semiword,body,rescues,else_,ensure_,endword
|
4362
|
+
else_=else_.val if else_
|
4363
|
+
ensure_=ensure_.val if ensure_
|
4364
|
+
super(name,body,rescues,else_,ensure_)
|
4365
|
+
end
|
4366
|
+
|
4367
|
+
alias else_ else
|
4368
|
+
alias ensure_ ensure
|
3529
4369
|
|
3530
4370
|
def image; "(module #{name})" end
|
3531
4371
|
|
3532
|
-
def unparse o
|
3533
|
-
"module #{name.unparse o}
|
4372
|
+
def unparse o=default_unparse_options
|
4373
|
+
"module #{name.unparse o}#{unparse_nl(body||self,o)}#{unparse_and_rescues(o)};end"
|
3534
4374
|
end
|
3535
4375
|
|
3536
4376
|
def parent; nil end
|
@@ -3543,38 +4383,43 @@ class RedParse
|
|
3543
4383
|
return result
|
3544
4384
|
end
|
3545
4385
|
|
3546
|
-
def parsetree
|
4386
|
+
def parsetree(o)
|
3547
4387
|
name=name()
|
3548
|
-
if
|
4388
|
+
if VarNode===name
|
3549
4389
|
name=name.ident.to_sym
|
3550
4390
|
elsif name.nil? #do nothing
|
3551
|
-
# elsif quirks
|
4391
|
+
# elsif o[:quirks]
|
3552
4392
|
# name=name.constant.ident.to_sym
|
3553
4393
|
else
|
3554
|
-
name=name.parsetree
|
4394
|
+
name=name.parsetree(o)
|
3555
4395
|
end
|
3556
4396
|
result=[:module, name, scope=[:scope, ]]
|
3557
|
-
|
4397
|
+
scope << parsetree_and_rescues(o) if body
|
3558
4398
|
return result
|
3559
4399
|
end
|
3560
4400
|
end
|
3561
4401
|
|
3562
4402
|
class ClassNode<NamespaceNode
|
3563
|
-
param_names(:name,:parent,:body)
|
3564
|
-
def initialize(classword,name,semi,body,endword)
|
4403
|
+
param_names(:name,:parent,:body,:rescues,:else!,:ensure!)
|
4404
|
+
def initialize(classword,name,semi,body,rescues, else_, ensure_, endword)
|
3565
4405
|
if OpNode===name
|
3566
4406
|
name,op,parent=*name
|
3567
4407
|
op=="<" or fail "invalid superclass expression: #{name}"
|
3568
4408
|
end
|
3569
|
-
|
4409
|
+
else_=else_.val if else_
|
4410
|
+
ensure_=ensure_.val if ensure_
|
4411
|
+
super(name,parent,body,rescues,else_,ensure_)
|
3570
4412
|
end
|
3571
4413
|
|
4414
|
+
alias else_ else
|
4415
|
+
alias ensure_ ensure
|
4416
|
+
|
3572
4417
|
def image; "(class #{name})" end
|
3573
4418
|
|
3574
|
-
def unparse o
|
4419
|
+
def unparse o=default_unparse_options
|
3575
4420
|
result="class #{name.unparse o}"
|
3576
4421
|
result+=" < #{parent.unparse o}" if parent
|
3577
|
-
result+="
|
4422
|
+
result+=unparse_nl(body||self,o)+"#{unparse_and_rescues(o)};end"
|
3578
4423
|
return result
|
3579
4424
|
end
|
3580
4425
|
|
@@ -3586,39 +4431,48 @@ class RedParse
|
|
3586
4431
|
return result
|
3587
4432
|
end
|
3588
4433
|
|
3589
|
-
def parsetree
|
4434
|
+
def parsetree(o)
|
3590
4435
|
name=name()
|
3591
|
-
if
|
4436
|
+
if VarNode===name
|
3592
4437
|
name=name.ident.to_sym
|
3593
4438
|
elsif name.nil? #do nothing
|
3594
|
-
# elsif quirks
|
4439
|
+
# elsif o[:quirks]
|
3595
4440
|
# name=name.constant.ident.to_sym
|
3596
4441
|
else
|
3597
|
-
name=name.parsetree
|
4442
|
+
name=name.parsetree(o)
|
3598
4443
|
end
|
3599
|
-
result=[:class, name, parent&&parent.parsetree, scope=[:scope,]]
|
3600
|
-
|
4444
|
+
result=[:class, name, parent&&parent.parsetree(o), scope=[:scope,]]
|
4445
|
+
scope << parsetree_and_rescues(o) if body
|
3601
4446
|
return result
|
3602
4447
|
end
|
3603
4448
|
end
|
3604
4449
|
|
3605
4450
|
class MetaClassNode<NamespaceNode
|
3606
|
-
param_names :
|
4451
|
+
param_names :val, :body, :rescues,:else!,:ensure!
|
4452
|
+
def initialize classword, leftleftword, val, semiword, body, rescues,else_,ensure_, endword
|
4453
|
+
else_=else_.val if else_
|
4454
|
+
ensure_=ensure_.val if ensure_
|
4455
|
+
super(val,body,rescues,else_,ensure_)
|
4456
|
+
end
|
4457
|
+
|
3607
4458
|
alias expr val
|
3608
4459
|
alias object val
|
3609
4460
|
alias obj val
|
3610
4461
|
alias receiver val
|
3611
4462
|
alias name val
|
3612
4463
|
|
4464
|
+
alias ensure_ ensure
|
4465
|
+
alias else_ else
|
4466
|
+
|
3613
4467
|
def image; "(class<<)" end
|
3614
4468
|
|
3615
|
-
def unparse o
|
3616
|
-
"class << #{obj.unparse o}
|
4469
|
+
def unparse o=default_unparse_options
|
4470
|
+
"class << #{obj.unparse o}#{unparse_nl(body||self,o)}#{unparse_and_rescues(o)};end"
|
3617
4471
|
end
|
3618
4472
|
|
3619
|
-
def parsetree
|
3620
|
-
result=[:sclass, expr.parsetree, scope=[:scope]]
|
3621
|
-
|
4473
|
+
def parsetree(o)
|
4474
|
+
result=[:sclass, expr.parsetree(o), scope=[:scope]]
|
4475
|
+
scope << parsetree_and_rescues(o) if body
|
3622
4476
|
return result
|
3623
4477
|
end
|
3624
4478
|
end
|
@@ -3628,7 +4482,7 @@ class RedParse
|
|
3628
4482
|
def initialize(rescueword,arrowword,exceptions,thenword)
|
3629
4483
|
case exceptions
|
3630
4484
|
when nil
|
3631
|
-
when
|
4485
|
+
when VarNode:
|
3632
4486
|
if arrowword
|
3633
4487
|
exvarname=exceptions
|
3634
4488
|
exceptions=nil
|
@@ -3646,7 +4500,7 @@ class RedParse
|
|
3646
4500
|
exceptions=Array.new(exceptions)
|
3647
4501
|
end
|
3648
4502
|
fail if arrowword
|
3649
|
-
# fail unless
|
4503
|
+
# fail unless VarNode===exvarname || exvarname.nil?
|
3650
4504
|
super(exceptions,exvarname)
|
3651
4505
|
end
|
3652
4506
|
|
@@ -3662,17 +4516,18 @@ class RedParse
|
|
3662
4516
|
super(exlist,rescuehdr.varname,action)
|
3663
4517
|
end
|
3664
4518
|
|
3665
|
-
def unparse o
|
4519
|
+
def unparse o=default_unparse_options
|
3666
4520
|
xx=exceptions.map{|exc| exc.unparse o}.join(',')
|
3667
|
-
|
4521
|
+
unparse_nl(self,o)+
|
4522
|
+
"rescue #{xx} #{varname&&'=> '+varname.lhs_unparse(o)}#{unparse_nl(action||self,o)}#{action&&action.unparse(o)}"
|
3668
4523
|
end
|
3669
4524
|
|
3670
|
-
def parsetree
|
4525
|
+
def parsetree(o)
|
3671
4526
|
result=[:resbody, nil]
|
3672
4527
|
fail unless exceptions.class==Array
|
3673
|
-
ex=#if Node===exceptions; [exceptions.rescue_parsetree]
|
4528
|
+
ex=#if Node===exceptions; [exceptions.rescue_parsetree(o)]
|
3674
4529
|
#elsif exceptions
|
3675
|
-
exceptions.map{|exc| exc.rescue_parsetree}
|
4530
|
+
exceptions.map{|exc| exc.rescue_parsetree(o)}
|
3676
4531
|
#end
|
3677
4532
|
if !ex or ex.empty? #do nothing
|
3678
4533
|
elsif ex.last.first!=:splat
|
@@ -3682,19 +4537,19 @@ class RedParse
|
|
3682
4537
|
else
|
3683
4538
|
result[1]= [:argscat, ex[0...-1].unshift(:array), ex.last[1]]
|
3684
4539
|
end
|
3685
|
-
|
4540
|
+
VarNode===varname and offset=varname.offset
|
3686
4541
|
action=if varname
|
3687
4542
|
SequenceNode.new(
|
3688
4543
|
AssignNode.new(
|
3689
4544
|
varname,
|
3690
4545
|
KeywordToken.new("=",offset),
|
3691
|
-
VarNameToken.new("$!",offset)
|
4546
|
+
VarNode.new(VarNameToken.new("$!",offset))
|
3692
4547
|
),nil,action()
|
3693
4548
|
)
|
3694
4549
|
else
|
3695
4550
|
action()
|
3696
4551
|
end
|
3697
|
-
result.push action.parsetree if action
|
4552
|
+
result.push action.parsetree(o) if action
|
3698
4553
|
result
|
3699
4554
|
end
|
3700
4555
|
|
@@ -3705,8 +4560,8 @@ class RedParse
|
|
3705
4560
|
param_names(:receiver,:lbrack_,:params,:rbrack_)
|
3706
4561
|
def initialize(receiver,lbrack,params,rbrack)
|
3707
4562
|
params=case params
|
3708
|
-
when CommaOpNode
|
3709
|
-
when nil
|
4563
|
+
when CommaOpNode; Array.new params
|
4564
|
+
when nil
|
3710
4565
|
else [params]
|
3711
4566
|
end
|
3712
4567
|
super(receiver,params)
|
@@ -3714,7 +4569,7 @@ class RedParse
|
|
3714
4569
|
|
3715
4570
|
def image; "(#{receiver.image}.[])" end
|
3716
4571
|
|
3717
|
-
def unparse o
|
4572
|
+
def unparse o=default_unparse_options
|
3718
4573
|
[ receiver.unparse(o).sub(/\s+\Z/,''),
|
3719
4574
|
'[',
|
3720
4575
|
params&¶ms.map{|param| param.unparse o}.join(','),
|
@@ -3722,18 +4577,18 @@ class RedParse
|
|
3722
4577
|
].to_s
|
3723
4578
|
end
|
3724
4579
|
|
3725
|
-
def parsetree
|
3726
|
-
result=parsetree_no_fcall
|
3727
|
-
quirks and VarLikeNode===receiver and receiver.name=='self' and
|
4580
|
+
def parsetree(o)
|
4581
|
+
result=parsetree_no_fcall o
|
4582
|
+
o[:quirks] and VarLikeNode===receiver and receiver.name=='self' and
|
3728
4583
|
result[0..2]=[:fcall,:[]]
|
3729
4584
|
return result
|
3730
4585
|
end
|
3731
4586
|
|
3732
|
-
def parsetree_no_fcall
|
4587
|
+
def parsetree_no_fcall o
|
3733
4588
|
params=params()
|
3734
|
-
output,star,amp=param_list_parse(params)
|
3735
|
-
# receiver=receiver.parsetree
|
3736
|
-
result=[:call, receiver.
|
4589
|
+
output,star,amp=param_list_parse(params,o)
|
4590
|
+
# receiver=receiver.parsetree(o)
|
4591
|
+
result=[:call, receiver.rescue_parsetree(o), :[], output]
|
3737
4592
|
if params
|
3738
4593
|
if star and params.size==1
|
3739
4594
|
output.concat star
|
@@ -3746,27 +4601,47 @@ class RedParse
|
|
3746
4601
|
end
|
3747
4602
|
return result
|
3748
4603
|
end
|
3749
|
-
def lvalue_parsetree
|
3750
|
-
result=parsetree_no_fcall
|
4604
|
+
def lvalue_parsetree(o)
|
4605
|
+
result=parsetree_no_fcall o
|
3751
4606
|
result[0]=:attrasgn
|
3752
4607
|
result[2]=:[]=
|
3753
4608
|
result
|
3754
4609
|
end
|
3755
4610
|
|
3756
|
-
def lvalue
|
4611
|
+
def lvalue
|
3757
4612
|
return @lvalue if defined? @lvalue
|
3758
4613
|
@lvalue=true
|
3759
4614
|
end
|
3760
|
-
|
4615
|
+
attr_writer :lvalue
|
4616
|
+
identity_param :lvalue, nil, true
|
3761
4617
|
end
|
3762
4618
|
|
3763
4619
|
|
3764
|
-
class
|
4620
|
+
class StartToken<Token #not to appear in final tree
|
3765
4621
|
def initialize; end
|
3766
4622
|
|
3767
4623
|
def image; "(START)" end
|
4624
|
+
alias to_s image
|
4625
|
+
|
4626
|
+
|
3768
4627
|
end #beginning of input marker
|
3769
4628
|
|
4629
|
+
class EoiToken
|
4630
|
+
#hack hack: normally, this should never
|
4631
|
+
#be called, but it may be when input is empty now.
|
4632
|
+
def to_parsetree(*options)
|
4633
|
+
[]
|
4634
|
+
end
|
4635
|
+
end
|
4636
|
+
|
4637
|
+
class GoalPostToken<Token #not to appear in final tree
|
4638
|
+
def initialize(offset); @offset=offset end
|
4639
|
+
def ident; "|" end
|
4640
|
+
attr :offset
|
4641
|
+
|
4642
|
+
def image; "|" end
|
4643
|
+
end
|
4644
|
+
|
3770
4645
|
class GoalPostNode<Node #not to appear in final tree
|
3771
4646
|
def initialize(offset); @offset=offset end
|
3772
4647
|
def ident; "|" end
|
@@ -3776,16 +4651,8 @@ class RedParse
|
|
3776
4651
|
end
|
3777
4652
|
|
3778
4653
|
module ErrorNode
|
3779
|
-
|
3780
|
-
|
3781
|
-
middle.each{|node|
|
3782
|
-
node.respond_to? :blame and return node.blame
|
3783
|
-
}
|
3784
|
-
return self
|
3785
|
-
end
|
3786
|
-
|
3787
|
-
|
3788
|
-
#def msg; ... end
|
4654
|
+
def error?(x=nil) @error end
|
4655
|
+
alias msg error?
|
3789
4656
|
end
|
3790
4657
|
|
3791
4658
|
|
@@ -3797,9 +4664,19 @@ class RedParse
|
|
3797
4664
|
|
3798
4665
|
def image; "misparsed #{what}" end
|
3799
4666
|
|
3800
|
-
|
3801
|
-
|
4667
|
+
#pass the buck to child ErrorNodes until there's no one else
|
4668
|
+
def blame
|
4669
|
+
middle.each{|node|
|
4670
|
+
node.respond_to? :blame and return node.blame
|
4671
|
+
}
|
4672
|
+
return self
|
4673
|
+
end
|
4674
|
+
|
4675
|
+
def error? x=nil
|
4676
|
+
inner=middle.grep(MisparsedNode).first and return inner.error?( x )
|
4677
|
+
"#@endline: misparsed #{what}: #{middle.map{|node| node&&node.image}.join(' ')}"
|
3802
4678
|
end
|
4679
|
+
alias msg error?
|
3803
4680
|
end
|
3804
4681
|
|
3805
4682
|
# end
|