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.
@@ -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
@@ -17,7 +17,12 @@
17
17
  along with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
  =end
19
19
 
20
- require 'rubygems'
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
- break if iv=="@data"
51
- result.push iv, instance_variable_get(iv)
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
- options.include? :newlines and Thread.current[:$RedParse_parsetree_newlines]=true
67
- options.include? :quirks and Thread.current[:$RedParse_parsetree_quirks]=true
68
-
69
- result=[parsetree]
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
- Thread.current[:$RedParse_parsetree_newlines]=false
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?; nil end
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 VarNameToken
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: return [:nth_ref,ident[1..-1].to_i]
109
- when ?&,?+,?`,?': return [:back_ref,ident[1].chr.to_sym] #`
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: :const
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
- when ?$: :gasgn
133
- when ?@:
134
- if ident[1]!=?@: :iasgn
135
- elsif in_def: :cvasgn
136
- else :cvdecl
137
- end
138
- when ?A..?Z: :cdecl
139
- else :lasgn
140
- case lvar_type
141
- when :local; :lasgn
142
- when :block; :dasgn
143
- when :current; :dasgn_curr
144
- else fail
145
- end
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 :line,:lvalue
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
- yield nil,nil,nil,self
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
- attr_accessor :line
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
- options.include? :newlines and Thread.current[:$RedParse_parsetree_newlines]=true
308
- options.include? :quirks and Thread.current[:$RedParse_parsetree_quirks]=true
309
-
310
- result=[parsetree]
485
+ o={}
486
+ [:newlines,:quirks,:ruby187].each{|opt|
487
+ o[opt]=true if options.include? opt
488
+ }
311
489
 
312
- Thread.current[:$RedParse_parsetree_newlines]=false
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
- def parsetree
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: datum.walk(self,i,&callback)
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? :line and line=node.line
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: true
417
- # when ParenedNode: x.size>1
418
- when CallSiteNode: x.params and !x.real_parens
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 ParenedNode===node and node.op? and assign=node.first and #ick
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
- ParenedNode.new(assign.right,nil,node[1][0].action)
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: false
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 ParenedNode:
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?; false end
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,VarNameToken
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 :@line rescue nil
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 '*': star=val.parsetree
633
- when '&': amp=val.parsetree
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?; nil end
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 /a-z_/i===op
1089
+ result+=" " if /\A(?:!|#{LCLETTER})/o===op
719
1090
  result+=op
720
- result+=" " if /a-z_/i===op or / \Z/===l
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
- attr_accessor :lvalue
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
- #VarNameToken| #why not this too?
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
- header=items.first
836
- (items[0,1] = *header[1..-1]) if header and header.first==:block
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.pred.downto(0){|i|
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)}.join("\n")
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(strs,str1,str2)
859
- if HereDocNode===strs
860
- hd,strs,str=strs,str1,str2
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 #not to appear in final tree?
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
- /^(!|not)$/===op and
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
- attr_accessor :lvalue
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 /^&/: [:block_arg, val.ident.to_sym]
984
- when "!","not": [:not, val.rescue_parsetree]
985
- when "defined?": [:defined, val.parsetree]
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 /[a-z_]/i===op
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 parsetree
1006
- [:splat, val.rescue_parsetree]
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
- def unparse o
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 VarNameToken===node and (?A..?Z)===node.ident[0]
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
- attr_accessor :lvalue
1477
+ attr_writer :lvalue
1478
+ identity_param :lvalue, nil, true
1095
1479
  end
1096
1480
  LookupNode=ConstantNode
1097
1481
 
1098
- class DoubleColonNode<ValueNode #dunno about this name... maybe ConstantNode?
1099
- #not used anymore
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 VarNameToken===val1 and /\A[A-Z]/===val1.ident
1106
- val2=val2.ident if VarNameToken===val2 and /\A[A-Z]/===val2.ident
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
- attr_accessor :lvalue
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
- attr_accessor :lvalue
1535
+ attr_writer :lvalue
1152
1536
  end
1153
1537
 
1154
- class ParenedNode<ValueNode
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= (ParenedNode===body and want_extra_begin? and body.after_equals)
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
- # def rescue_parsetree
1251
- # result=parsetree
1252
- # result.first==:begin and result=result.last
1253
- # result
1254
- # end
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
- attr_accessor :lvalue
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+="\n"
1659
+ result+=unparse_nl(rescues.first,o)
1284
1660
  rescues.each{|resc| result+=resc.unparse(o) }
1285
- result+="\nensure "+ensure_.unparse(o) if ensure_
1286
- result+="\nelse "+else_.unparse(o) if else_
1287
- result+="\nend"
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=ParenedNode.new(rescuee.val,op2,rescuer)
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
- if lhs.size==1 and !lhs.after_comma #look for () around lhs
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
- end
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: huh
1365
- when ConstantNode: huh
1366
- when BracketsGetNode: huh
1367
- when VarNameToken
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: huh
1391
- when ConstantNode:
1392
- left.lvalue_parsetree << right.parsetree
1393
-
1394
- when MultiAssign:
1395
- lhs=left.lvalue_parsetree
1396
- rhs= right.class==Array ? right : [right]
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
- lhs<< rhs
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 VarNameToken
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 VarNameToken:
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)+op+
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 VarNameToken===x
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&-{:size=>1}===datum
2215
+ if ParenedNode===datum
1571
2216
  first=datum.first
1572
2217
  list=case first
1573
- when CommaOpNode: Array.new(first)
1574
- when UnaryStarNode,ParenedNode: [first]
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 VarNameToken===x
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 VarNameToken===x
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, star.lvalue_parsetree]
1635
- elsif result.size==1 and !star and !(NestedAssign===data.first)
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 star.lvalue_parsetree if star and not DanglingCommaNode===star
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
- # def parsetree
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 and item.size==1
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
- unless @had_parens
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 "&&": op="and"
1731
- when "||": op="or"
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= !( ParenedNode===val1 and val1.size != 1 )
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= !( ParenedNode===val1 and (val1.size != 1 ))
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 !consequent.empty_else and
1862
- !consequent.ensure and !consequent.empty_ensure and consequent.rescues.empty?
1863
- ) if ParenedNode===consequent
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
- param_list[arrowrange]=[HashLiteralNode.new(nil,arrows,nil)]
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
- param_list=[HashLiteralNode.new(nil,param_list,nil)]
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&&params.map{|param| param.unparse(o)}.join(', '),
2645
+ params&&params.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
- attr_accessor :lvalue
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
- return [methodsym, singlearg.parsetree] if singlearg and "super"!=methodname
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": callsite=[:postexe]
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 VarNameToken===x
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 VarNameToken===old
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
- VarNameToken===x ? x.ident.to_sym : x.parsetree
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: stmts=Array.new(stmts)
2223
- when nil: stmts=[]
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": callsite=[:postexe]
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
- @open=token.open
2333
- @close=token.close
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='#' if %r{\A["`/\{]\Z} === @char #"
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
- substr.gsub! /\\+/ do
2382
- result=$&*2
2383
- result.chomp! '\\' if $&.size&1==1
2384
- result
2385
- end
2386
- substr.gsub! escapable do '\\'+$& end
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: token.elems
2416
- when HerePlaceholderToken: token.string.elems
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
- klass=Thread.current[:$RedParse_parser].class
2433
- data[i]=klass.new(tokens, "(string inclusion)").parse
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
- delete= frag.empty?
2442
- next if frag_i==last #and quirks
2443
- next if data[frag_i-1].line != data[frag_i+1].line #and quirks
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) if delete
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 line= line
3181
+ def endline= endline
2452
3182
  each{|frag|
2453
- frag.line||=line if frag.respond_to? :line
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
- first[/\A(?:\s|\v)+/]='' if /\A(?:\s|\v)/===first
2469
- each{|x|
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
- double_chunks=x.split(/((?:(?:[^\\]|\A)(?:\\\\)+)|(?:[^\\\s\v]|\A))(?:\s|\v)+/,-1)
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(double_chunks[i,2].to_s)#.gsub(/\\([\s\v\\])/){$1}
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| StringNode[chunk,{:@char=>'"'}]}
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,VarNameToken:
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]<<vals.delete_at(1).last
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
- [@char,(unparse_interior o,@char,@char),@char].to_s
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
- #val=eval(val[1..-1]).to_sym
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)/: val=val.oct
2718
- when /[.e]/i: val=val.to_f
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: s="-"+Inf
2744
- when /inf/i: s= Inf
2745
- when /nan/i: s= Nan
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 o}.join(', ')+"]"
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}\n"
2904
- result+="#{consequent.unparse(o)}\n" if consequent
2905
- result+=elsifs.map{|n| n.unparse(o)}.to_s if elsifs
2906
- result+="else "+else_.unparse(o)+"\n" if else_
2907
- result+="end"
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}\n#{consequent.unparse o}\n"
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), "\n",
3831
+ condition.unparse(o), unparse_nl(body||self,o),
3026
3832
  body&&body.unparse(o),
3027
- "\nend"
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)}\n"+
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)+"\n" if otherwise
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+="\n"
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_ and for_.size==1
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
- for #{iterator.lhs_unparse(o)[1...-1]} in #{enumerable.unparse o}
3165
- #{body&&body.unparse(o)}
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 VarNameToken===lval
3986
+ res=lval.parsetree(o)
3987
+ res[0]=lval.varname2assigntype if VarNode===lval
3184
3988
  res
3185
3989
  }
3186
3990
  ]]
3187
- when VarNameToken:
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: super()
3208
- when ArrowOpNode: super(contents.first,contents.last)
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=true unless open
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 body= x
3310
- self[3]=x
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 #{receiver&&receiver.unparse(o)+'.'}#{name}#{
3328
- args&&'('+args.map{|arg| arg.unparse o}.join(',')+')'
3329
- }
3330
- #{body&&body.unparse(o)}
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+="end"
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 VarNameToken:
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: body << elses;elses=nil
3402
- when nil: body=elses;elses=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 ParenedNode===body and body.size>1 and
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: node.ident
3440
- when VarNameToken: node
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: node.val
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 VarNameToken: str.ident
3455
- when String:
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 VarNameToken===to and to.ident[0]==?$
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(:moduleword_,:name,:semi_,:body,:endword_)
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}\n#{body&&body.unparse(o)}\nend"
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 VarNameToken===name
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
- body&&scope << body.parsetree
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
- super(name,parent,body)
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+="\n#{body&&body.unparse(o)}\nend"
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 VarNameToken===name
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
- body&&scope << body.parsetree
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 :classword_, :leftleft_, :val, :semi_, :body, :endword_
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}\n#{body&&body.unparse(o)}\nend"
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
- body&&scope << body.parsetree
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 VarNameToken:
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 VarNameToken===exvarname || exvarname.nil?
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
- "rescue #{xx} #{varname&&'=> '+varname.lhs_unparse(o)}\n#{action&&action.unparse(o)}\n"
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
- VarNameToken===varname and offset=varname.offset
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: Array.new params
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&&params.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.parsetree, :[], output]
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
- attr_accessor :lvalue
4615
+ attr_writer :lvalue
4616
+ identity_param :lvalue, nil, true
3761
4617
  end
3762
4618
 
3763
4619
 
3764
- class StartNode<Node #not to appear in final tree
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
- #pass the buck to child ErrorNodes until there's no one else
3780
- def blame
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
- def msg
3801
- "#@line: misparsed #{what}: #{middle.map{|node| node&&node.image}.join(' ')}"
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