root/misc/STD_red/std.rb

Revision 22374, 91.0 kB (checked in by putter, 4 months ago)

[elfish/on_sbcl] More work on Array, Hash, and oo. Parser.pm runs.
[STD_red] Postcircumfix methods now parse.
[elf] More backend neutrality.

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
Line 
1#!/usr/bin/env ruby
2# -*- encoding: utf-8 -*-
3# A ruby transliteration of src/perl6/STD.pm
4# See README.
5#
6# STD_red issues
7#  Some Match ruls are "foo__bar", where bar was a #= comment.  This is wrongish.
8#
9
10require 'prelude'
11
12class Perl < Grammar
13    attr_accessor :ws_from, :ws_to
14
15    def _TOP; _UNIT( $env_vars[:unitstopper] || "_EOS" ); end
16
17    def_precedence :hyper           ,{ :transparent=>1                         }
18    def_precedence :term            ,{ :prec=>"z="                             }
19    def_precedence :methodcall      ,{ :prec=>"y="                             }
20    def_precedence :autoincrement   ,{ :prec=>"x="                             }
21    def_precedence :exponentiation  ,{ :prec=>"w=", :assoc=>:right, :assign=>1 }
22    def_precedence :symbolic_unary  ,{ :prec=>"v="                             }
23    def_precedence :multiplicative  ,{ :prec=>"u=", :assoc=>:left,  :assign=>1 }
24    def_precedence :additive        ,{ :prec=>"t=", :assoc=>:left,  :assign=>1 }
25    def_precedence :replication     ,{ :prec=>"s=", :assoc=>:left,  :assign=>1 }
26    def_precedence :concatenation   ,{ :prec=>"r=", :assoc=>:left,  :assign=>1 }
27    def_precedence :junctive_and    ,{ :prec=>"q=", :assoc=>:list,  :assign=>1 }
28    def_precedence :junctive_or     ,{ :prec=>"p=", :assoc=>:list,  :assign=>1 }
29    def_precedence :named_unary     ,{ :prec=>"o=",                            }
30    def_precedence :nonchaining     ,{ :prec=>"n=", :assoc=>:non               }
31    def_precedence :chaining        ,{ :prec=>"m=", :assoc=>:chain, :bool=>1   }
32    def_precedence :tight_and       ,{ :prec=>"l=", :assoc=>:left,  :assign=>1 }
33    def_precedence :tight_or        ,{ :prec=>"k=", :assoc=>:left,  :assign=>1 }
34    def_precedence :conditional     ,{ :prec=>"j=", :assoc=>:right,            }
35    def_precedence :item_assignment ,{ :prec=>"i=", :assoc=>:right             }
36    def_precedence :loose_unary     ,{ :prec=>"h=",                            }
37    def_precedence :comma           ,{ :prec=>"g=", :assoc=>:list,             }
38    def_precedence :list_infix      ,{ :prec=>"f=", :assoc=>:list,  :assign=>1 }
39    def_precedence :list_assignment ,{ :prec=>"i=", :sub=>"e=", :assoc=>:right }
40    def_precedence :list_prefix     ,{ :prec=>"e=",                            }
41    def_precedence :loose_and       ,{ :prec=>"d=", :assoc=>:left,  :assign=>1 }
42    def_precedence :loose_or        ,{ :prec=>"c=", :assoc=>:left,  :assign=>1 }
43    def_precedence :LOOSEST         ,{ :prec=>"a=!",                           }
44    def_precedence :terminator      ,{ :prec=>"a=", :assoc=>:list              }
45    SLOOSEST = HLOOSEST[:prec]
46
47    #R role PrecOp
48    def precop_method(m,defaults)
49        if not defaults[:transparent]
50            mO = m[:O]
51            mO = m[:O] = {} if not mO
52            defaults.each{|k,v| mO[k] = v if not mO.key? k }
53        end
54        return m;
55    end
56    #R XXX I'm unsure what make() (in expect_term, and elsewhwere) should be doing.
57    def make(m,overwrite)
58        overwrite.each{|k,v| m[k] = v }
59    end
60
61    #R things like "class Term does PrecOp[|%term] {}" are folded into
62    #R def_precedence above.
63
64    $env_vars.scope_enter(:endsym,:unitstopper,:endstmt,:endargs)
65    $env_vars[:endsym] = "null"
66    $env_vars[:unitstopper] = "_EOS"
67    $env_vars[:endstmt] = -1
68    $env_vars[:endargs] = -1
69    #R helper
70    def scan_unitstopper
71        us = $env_vars[:unitstopper];
72        ((if us == '_EOS'; @scanner.eos?
73          else; raise "assert: known unitstopper: #{us}"
74          end) or
75         permit_partial_parse or
76         panic("Can't understand next input--giving up"))
77    end
78
79    #R XXX TODO - the non-simple constraints are not being applied.
80    token_category :category
81    token_category :sigil
82    token_category :twigil
83    token_category :special_variable
84    token_category :version
85    token_category :module_name
86    token_category :term
87    token_category :quote, 'nofat'
88    token_category :prefix
89    token_category :infix
90    token_category :postfix
91    # def_precedence_alias is what "is defequiv" means.
92    def_precedence_alias :prefix,  :symbolic_unary
93    def_precedence_alias :infix,   :additive
94    def_precedence_alias :postfix, :autoincrement
95    token_category :dotty,  'unspacey'
96    token_category :circumfix
97    token_category :postcircumfix
98    token_category :regex_metachar
99    token_category :regex_backslash
100    token_category :regex_assertion
101    token_category :regex_quantifier
102    token_category :regex_mod_internal
103    token_category :quote_mod
104    token_category :q_backslash
105    token_category :qq_backslash
106    token_category :trait_verb,        'nofat_space'
107    token_category :trait_auxiliary,   'nofat_space'
108    token_category :type_declarator,      'nofat'
109    token_category :scope_declarator,     'nofat'
110    token_category :package_declarator,   'nofat'
111    token_category :plurality_declarator, 'nofat'
112    token_category :routine_declarator,   'nofat'
113    token_category :regex_declarator,     'nofat'
114    token_category :statement_prefix,     'nofat'
115    token_category :statement_control, 'nofat_space'
116    token_category :statement_mod_cond,   'nofat'
117    token_category :statement_mod_loop,   'nofat'
118    token_category :infix_prefix_meta_operator
119    token_category :infix_postfix_meta_operator
120    token_category :infix_circumfixfix_meta_operator
121    token_category :postfix_prefix_meta_operator
122    token_category :prefix_postfix_meta_operator
123    token_category :prefix_circumfix_meta_operator
124    #R categories added:
125    token_category :terminator
126    token_category :infix_circumfix_meta_operator
127
128    def unspacey; unsp;true end
129    def nofat_space
130        before(/\s|\#/) and
131        nofat #R# before{nofat} # nofat is already a zero-length assertion.
132    end
133
134    # Lexical routines
135
136    def nofat
137        # make sure we're at end of a non-autoquoted identifier
138        # regex nofat { <!before » \h* <.unsp>? '=>' > <!before \w> }
139        (not before{ scan(/»/) and scan(/[ \t]*/) and (unsp;true) and scan(/=>/) } and
140         not before(/\w/u))
141    end
142
143
144    if RUBY_VERSION =~ /\A(1\.9|2\.)/ # have look-behind
145        $have_lookbehind = true
146        eval %q{ def wsp__after_and_before_ws; scan(/(?<=\w)(?=\w)/u) end }
147    else
148        $have_lookbehind = false
149        eval %q{ def wsp__after_and_before_ws; scan(/(?=\w)/u) and after(/\w/u)  end }
150    end
151
152    #R ws, renamed wsp to make life easier.
153    def wsp
154        pos == ws_to and return true
155        #R# || <?after \w> <?before \w> ::: <!>        # must \s+ between words
156        #R# after(/\w/u) and before(/\w/u) and return false
157        wsp__after_and_before_ws and return false
158        @ws_from = pos
159        starTOK{
160            unsp or
161            let_pos{ vws and heredoc } or
162            unv
163        }
164        @ws_to = pos
165        true
166    end
167    def unsp
168        scan(/\\(?=\s|\#)/) and starTOK{ vws or unv }
169    end
170    def unsp?; (unsp;true); end
171    def vws
172        scan(/[\r\n\f]/) and (moreinput;true)
173    end
174    def moreinput
175        send($env_vars[:moreinput]) if $env_vars.defined?(:moreinput);
176    end
177
178    def unv
179        let_pos{
180            scan(/[ \t]+/) or
181            (@scanner.bol? and pod_comment) or
182            let_pos{
183               scan(/\#/) and bracketed and
184               (not(@scanner.bol?) or panic("Can't use embedded comments in column 1"))
185            } or
186            (scan(/\#.*/u))
187        }
188    end
189
190    def ident; scan(/[[:alpha:]_]\w*/u); end
191   
192    def pod_comment
193        @scanner.bol? and scan(/=/) and unsp? and
194        (let_pos{
195             scan(/begin[ \t]*/) and
196             #wsp and #R XXX causes problems with "=begin\n=head...".
197             (id= ident;true) and
198             scan(/(?:.|\n)*?\n=end\b/u) and #R XXX doesn't accept unsp between '=' and 'end'.
199             (not(id) or (wsp and scan(/#{id}.*/u)))
200         } or
201         scan(/.*/u))
202    end
203
204    # Top-level rules
205   
206    def _UNIT (_unitstopper =nil)
207        $env_vars.scope_enter(:unitstopper)
208        $env_vars[:unitstopper] = _unitstopper || "_EOS"
209        # UNIT: do {
210        v = comp_unit()
211        $env_vars.scope_leave
212        v
213    end
214
215    def comp_unit
216        $env_vars.scope_enter(:begin_compunit,:endstmt,:endargs)
217        $env_vars[:begin_compunit] = 1
218        $env_vars[:endstmt] = -1
219        $env_vars[:endargs] = -1
220        b = pos
221        wsp
222        _sl = statementlist
223        wsp
224        scan_unitstopper #R panic() is in scan_unitstopper
225        wsp
226        $env_vars.scope_leave
227        _match_from(b,{:statementlist=>_sl},:comp_unit)
228    end
229
230    def pblock
231        b = pos
232        l=s=nil
233        quesTOK{ l= _lambda and s= signature }; bl= block or return false
234        h={:block=>bl};_hkv(h,:lambda,l);_hkv(h,:signature,s)
235        _match_from(b,h,:pblock)
236    end
237
238    def _lambda; scan(/->|<->/); end
239
240    def block
241        b=pos
242        let_pos{ scan(/\{/) and sl= statementlist and _block_rest and
243                 _match_from(b,{:statementlist=>sl},:block) }
244    end
245
246    #R QUESTION regexp_block lacks block's \h*.  Intentional?
247    def regex_block
248        let_pos{
249            b = pos
250            scan(/\{/) and r= regex('}') and _block_rest and
251            _match_from(b,{:regex=>r},:regex_block) }
252    end
253
254    def _block_rest
255        ( scan(/\}/) or panic("Missing right brace") ) and
256          #R QUESTION <?before < ,: >> typo?
257          ( let_pos{ scan(/[ \t]*/) and unsp? and before(/[,:]/) } or
258            let_pos{
259                unv; before(/\n/) and wsp and
260                #R XXX BAD should be let
261                ($env_vars[:endstmt] = ws_from;true)
262            } or
263            #R XXX BAD should be let
264            ($env_vars[:endargs] = pos) )
265    end
266
267
268    def statementlist
269        starRULE{ s= statement and eat_terminator and s }
270    end
271
272    def semilist
273        starRULE{ s= statement and eat_terminator and s }
274    end
275
276    def label
277        let_pos{ id = ident and scan(/:(?=\s)/) and wsp and id }
278        #R ...missing... bookkeeping - needed?
279    end
280
281
282    def _hkv(h,k,v)
283        h[k] = v if v and (v.instance_of?(Array) ? (not v.empty?) : true)
284        h
285    end
286
287    def statement
288        $env_vars.scope_enter(:endstmt)
289        $env_vars[:endstmt] = -1;
290        (label_ = control_ = expr_ = mod_loop_ = mod_cond_ =
291         loopx_ = condx_ = mod_condloop_ = modexpr_ = nil)
292        let_pos{
293            b = pos
294            wsp
295            label_= starTOK{ label }
296            (begin
297                 let_pos{
298                     (( control_= statement_control or
299                        before(/;/) )
300                      )
301                 }
302             end or
303             begin
304                 let_pos{
305                     b1 = nil
306                     endstmt = $env_vars[:endstmt]; endargs = $env_vars[:endargs]
307                     expr_= _EXPR and
308                     (b1 = pos;true) and
309                     (let_pos{
310                          before{ stdstopper_no_mod } #R XXX NONSPEC KLUDGE _no_mod - STD.pm bug? workaround.
311                      } or
312                      let_pos{
313                          $env_vars[:endstmt] = endstmt; $env_vars[:endargs] = endargs
314                          mod_loop_= statement_mod_loop #R XXX NONSPEC bug? workaround # and loopx= _EXPR
315                      } or
316                      let_pos{
317                          $env_vars[:endstmt] = endstmt; $env_vars[:endargs] = endargs
318                          endstmt1 = $env_vars[:endstmt]; endargs1 = $env_vars[:endargs]
319                          mod_cond_= statement_mod_cond and #R XXX NONSPEC bug? workaround # condx= _EXPR and
320                          (let_pos{
321                               before{ stdstopper_no_mod } #R XXX NONSPEC KLUDGE _no_mod - STD.pm bug? workaround.
322                           } or
323                           let_pos{
324                               $env_vars[:endstmt] = endstmt1; $env_vars[:endargs] = endargs1
325                               mod_condloop_= statement_mod_loop #R XXX NONSPEC bug? workaround # and loopx= _EXPR
326                           } or
327                           false)
328                      } or
329                      false)
330                     #R NONSPEC  modexpr missing
331                     #R# (modexpr_= b1 != pos ? _match_from(b1,{},:statement__modexpr) : nil; true)
332                 }
333             end) and
334            begin
335                h = {}
336                _hkv(h,:label,label_)
337                _hkv(h,:control,control_)
338                _hkv(h,:expr,expr_)
339                _hkv(h,:mod_loop,mod_loop_)
340                _hkv(h,:mod_cond,mod_cond_)
341                _hkv(h,:loopx,loopx_)
342                _hkv(h,:condx,condx_)
343                _hkv(h,:mod_condloop,mod_condloop_)
344                _hkv(h,:modexprp,modexpr_)
345                m = _match_from(b,h,:statement)
346            end
347        } || ($env_vars.scope_leave; false) #R XXX fails to reset endargs
348    end
349
350    def eat_terminator
351        ( scan(/;/) or
352          ($env_vars[:endstmt] == ws_from) or
353          before{ terminator } or
354          @scanner.eos? or @scanner.check(/\n/) or
355          panic("Statement not terminated properly"))
356    end
357
358    def_tokens_rest :statement_control,false,%w{ use no },%q{
359      e=nil
360      nofat_space and wsp and
361      mn = module_name and wsp and (e=_EXPR and wsp;true) and
362      (h={:module_name=>mn};_hkv(h,:EXPR,e);_match_from(start,h,:<sym>))
363    }
364    def_tokens_rest :statement_control,false,%w{ if }, %q{
365      nofat_space and wsp and
366      e=_EXPR and wsp and pb=pblock and wsp and
367      ei=starRULE{ b1=pos; scan(/elsif/) and nofat_space and wsp and
368                   e1=_EXPR and wsp and pb1=pblock and wsp and
369                   _match_from(b1,{:elsif_expr=>e1,:elsif_block=>pb1},:elsif) } and
370      el=quesRULE{ b1=pos; scan(/else/) and nofat_space and wsp and
371                   pb1=pblock and wsp and
372                   _match_from(b1,{:pblock=>pb1},:if__else) } and
373      (h={:if_expr=>e,:if_block=>pb,:elsif=>ei};_hkv(h,:else,el);
374       _match_from(start,h,:if))
375    }
376
377    def_tokens_rest :statement_control,false,%w{ unless while until  for given when },%q{
378      nofat_space and wsp and
379      e=_EXPR and wsp and pb=pblock and wsp and
380      _match_from(start,{:expr=>e,:block=>pb},:<sym>)
381    }
382    def_tokens_rest :statement_control,false,%w{ repeat },%q{
383      nofat_space and wsp and
384      ((wu= scan(/while|until/) and wsp and e=_EXPR and wsp and bk=block and wsp and
385        _match_from(start,{'0'=>wu,:wu_expr=>e,:wu_block=>bk},:repeat)) or
386       (bk=block and wsp and wu=scan(/while|until/) and wsp and e=_EXPR and wsp and
387        _match_from(start,{'0'=>wu,:expr_wu=>e,:block_wu=>bk},:repeat)))
388    }
389    def_tokens_rest :statement_control,false,%w{ loop },%q{
390      nofat_space and wsp and
391      ((scan(/\(/) and wsp and
392        e1= _EXPR and wsp and scan(/;/) and wsp and
393        e2= _EXPR and wsp and scan(/;/) and wsp and
394        e3= _EXPR and wsp and scan(/\)/) and wsp and
395        (h={};_hkv(h,:loop_e1,e1);_hkv(h,:loop_e2,e2);_hkv(h,:loop_e3,e3);
396         eee= _match_from(start,h,:loop__eee)
397       );true) and
398       bk= block and wsp and
399       (h={:loop_block=>bk};_hkv(h,:loop_eee,eee);
400        _match_from(start,h,:loop)))
401    }
402
403    def_tokens_rest :statement_control,false,%w{
404      default BEGIN CHECK INIT END START ENTER LEAVE KEEP UNDO FIRST NEXT LAST
405      PRE POST CATCH CONTROL },
406      %q{
407        nofat_space and wsp and
408        bk=block and wsp and
409        _match_from(start,{:block=>bk},:<sym>)
410      }
411
412    def_tokens_rest :term,false,%w{
413      BEGIN CHECK INIT START ENTER FIRST },
414      %q{
415        wsp and
416        bk=block and wsp and
417        _match_from(start,{:block=>bk},:<sym>)
418      }
419
420    def modifier_expr; wsp and e=_EXPR and wsp and e; end
421    def_tokens_rest :statement_mod_cond,false,%w{ if unless when },%q{
422      nofat and wsp and
423      me=modifier_expr and wsp and
424      _match_from(start,{:modifier_expr=>me},:<sym>) #R NONSPEC normalized name, ignored #= name.
425    }
426    def_tokens_rest :statement_mod_loop,false,%w{ while until for given },%q{
427      nofat and wsp and
428      me=modifier_expr and wsp and
429      _match_from(start,{:modifier_expr=>me},:<sym>) #R NONSPEC normalized name, ignored #= name.
430    }
431   
432    def role_name
433        b=pos
434        pc=nil
435        (mn= module_name and (before(/\[/) and pc= postcircumfix;true) and
436         (h={:module_name=>mn};_hkv(h,:postcircumfix,pc);
437          _match_from(b,h,:role_name)))
438    end
439
440    #R reordered.  depreciated needs to come first.
441    def_token_full :module_name,false,'depreciated',/(?=v6-alpha)/,%q{
442      scan(/v6-alpha/) and
443       _match_from(start,{},:depreciated)
444    }
445    def_token_full :module_name,false,'normal',/(?=\w)/u,%q{
446      (n=name and na= starTOK{ colonpair }) and
447      (h={:name=>n};_hkv(h,:colonpair,na)
448       _match_from(start,h,:normal))
449    }
450
451    def whatever; scan(/\*/); end
452
453    def_tokens_rest :version,false,%w{ v },%q{ scan(/ \d+ ( \. (\d+ | \*) )* \+?/x) }
454
455    ###################################################
456
457    def pre
458        precircum_ = prepost_ = nil
459        b = pos
460        let_pos{
461            ((prefix_= prefix) or
462             (precircum_= prefix_circumfix_meta_operator)
463             ) and
464            (prepost_= starTOK{ prefix_postfix_meta_operator }) and
465            wsp and
466            (o = (prefix_||precircum_)[:O];
467             h={:O=>o};
468             _hkv(h,:prefix,prefix_);
469             _hkv(h,:precircum,precircum_);
470             _hkv(h,:prepost,prepost_);
471             _match_from(b,h,:pre))
472        }
473    end
474
475    def expect_term
476        let_pos{
477            b = pos
478            pre_=adv=nil
479            return false if before{ stdstopper }
480            (noun_= noun or
481             (pre_= plusTOK{ pre } and noun_= noun)) and
482            # also queue up any postfixes, since adverbs could change things
483            post_= starTOK{ post } and
484            wsp and
485            (adv_= adverbs;true) and
486            (h={};
487             _hkv(h,:noun,noun_)
488             _hkv(h,:pre,pre_)
489             _hkv(h,:post,post_)
490             _hkv(h,:adverbs,adv_)
491             _match_from(b,h,:expect_term))
492        }
493    end
494
495    def adverbs
496        b = pos
497        colonpair_=nil
498        not before{ stdstopper } and
499        (plusTOK{ _cp = colonpair and (colonpair_ ||= []; colonpair_.push(_cp);true) and wsp } and
500         ( prop = $env_vars[:prevop] or
501           panic('No previous operator visible to adverbial pair ('+colonpair_.inspect+')');
502           prop.adverb(colonpair_); true ) and
503         (h={:colonpair=>colonpair_};_match_from(b,h,:adverbs)))
504    end
505
506    def noun
507        (fatarrow || package_declarator || scope_declarator || plurality_declarator ||
508         routine_declarator || regex_declarator || type_declarator || circumfix ||
509         dotty || subcall || variable || value || capterm || sigterm ||
510         statement_prefix || term ||  #R NONSPEC out of order
511         colonpair)
512    end
513   
514    def fatarrow
515        let_pos{
516            b = pos
517            (key= ident and scan(/[ \t]*/) and
518             scan(/\=>/) and wsp and
519             val = _EXPR(Hitem_assignment)) and
520            _match_from(b,{:key=>key,:val=>val},:fatarrow)
521        }
522    end
523
524    def colonpair
525        b = pos; id1=id2=pc1=pc2=si=tw=dsn=nil
526        let_pos{
527        (scan(/:/) and b1 = pos and
528         (let_pos{ scan(/!/) and id1= ident } or
529          ( id2= ident and (unsp; pc1= postcircumfix;true)) or
530          pc2= postcircumfix or
531          let_pos{ si= sigil and (tw= twigil;true) and dsn= desigilname }) and
532         (false_ = id1 ? _match_from(b1,{:ident=>id1},:colonpair__false) : nil;
533          value_ = id2 ? _match_from(b1,{:ident=>id2,:postcircumfix=>pc1},:colonpair__value) : nil;
534          structural_ = pc2;
535          varname_ = si ? _match_from(b1,{:sigil=>si,:twigil=>tw,:desigilname=>dsn},:colonpair__varname) : nil;
536          h={};
537          _hkv(h,:false,false_)
538          _hkv(h,:value,value_)
539          _hkv(h,:structural,structural_)
540          _hkv(h,:varname,varname_)
541          _match_from(b,h,:colonpair)))
542        }
543    end
544
545    def quotepair
546        b = pos; id1=id2=pc1=n=suf=nil
547        let_pos{
548            scan(/:/) and b1 = pos and
549            (let_pos{ scan(/!/) and id1= ident } or
550             (id2= ident and (unsp; before(/\(/) and pc1= postcircumfix;true)) or
551             #R NONSPEC spec doesn't have n and suffix named, so this is speculative.
552             (n= scan(/\d+/) and suf= scan(/[a-z]+/))) and
553            (h={}
554             _hkv(h,:ident,(id1 || id2))
555             _hkv(h,:postcircumfix,pc1)
556             _hkv(h,:n,n)
557             _hkv(h,:suffix,suf)
558             false_ = id1 ? _match_from(b1,h,:quotepair__false) : nil;
559             value_ = id2 ? _match_from(b1,h,:quotepair__value) : nil;
560             nth_ = suf ? _match_from(b1,h,:quotepair__nth) : nil;
561             h={};
562             _hkv(h,:false,false_)
563             _hkv(h,:value,value_)
564             _hkv(h,:nth,nth_)
565             _match_from(b,h,:quotepair))
566        }
567    end
568
569    def expect_tight_infix(loosest)
570        let_pos {
571            ((not before{ scan(/\{/) or _lambda }) and # presumably a statement control block
572             ei= expect_infix and
573             #R# { $<O> := $<expect_infix><O> }  #R not required as ei is passed on directly.
574             (ei[:O][:prec] > loosest) and
575             ei)
576        }
577    end
578
579    def expect_infix
580        b = pos; i=ipost=ipre=icirc=nil; op=nil
581        not(before{infixstopper}) and
582        ((let_pos{
583              i= infix and
584              ($env_vars.scope_enter(:opS)   # (used in infix_postfix_meta_operator)
585               $env_vars[:opS] = i
586               ipost= starTOK{ infix_postfix_meta_operator }) and # may modify $+op
587              (op = $env_vars[:opS])
588          } or
589          (ipre= infix_prefix_meta_operator) or
590          (icirc= infix_circumfix_meta_operator)) and
591         (h={};
592          _hkv(h,:infix,i)
593          _hkv(h,:infix_postfix_meta_operator,ipost)
594          _hkv(h,:infix_prefix_meta_operator,ipre)
595          _hkv(h,:infix_circumfix_meta_operator,icirc)
596          h[:O] = op ? op[:O] : (ipre || icirc)[:O]
597          h[:sym] = (i || ipre || icirc)[:sym]
598          _match_from(b,h,:expect_infix)))
599    end
600
601    def_tokens_rest :dotty,:methodcall,%w{ .+ .* .? .= .^ .: .:: .^!},%q{ #R NONSPEC ADDED .::
602      unspacey and
603      op= methodop and
604      _match_from(start,{:sym=>'<sym>',:methodop=>op,:O=>op[:O]},:'<sym>') #R NONSPEC name(s)?
605    }
606    def_tokens_rest :dotty,:methodcall,%w{ . },%q{
607      unspacey and
608      op= dottyop
609      #R XXX requires an elf update
610      #R# _match_from(start,{:sym=>'<sym>',:dottyop=>op,:O=>op[:O]},:'<sym>')
611    }
612    #R XXX NONSPEC Disabled ! to avoid conflict with prefix:<!> in '!foo()'.
613    #def_tokens_rest :dotty,:methodcall,%w{ ! },%q{
614    #  unspacey and
615    #  op= methodop and
616    #  _match_from(start,{:sym=>'<sym>',:methodop=>op,:O=>op[:O]},:'<sym>')
617    #}
618    def dottyop #R [:O] copying unnecessary as no Match is created.
619        methodop or postop
620    end
621
622    def post
623        let_pos{
624            b=pos
625            d=postop_=nil;ppmo=[]
626            not(before{stdstopper}) and
627            # last whitespace didn't end here (or was zero width)
628            (pos != ws_to or ws_to == ws_from) and
629            before{unspacey} and
630            starTOK{
631                let_pos{
632                    quesTOK{scan(/\./) and unsp?} and
633                    op= postfix_prefix_meta_operator and (ppmo.push op;true) and
634                    unsp?
635                }
636            } and
637            (d= dotty or postop_= postop) and
638            (h={};
639             h[:O] = (d || postop_)[:O]
640             _hkv(h,:postfix_prefix_meta_operator,ppmo)
641             _hkv(h,:dotty,d)
642             _hkv(h,:postop,postop_)
643             _match_from(b,h,:post))
644        }
645    end
646
647    #R XXX TODO I currently don't understand the [LIST] issue.  And so likely dont support it.
648
649    # Note: backtracks, or we'd never get to parse [LIST] on seeing [+ and such.
650    # (Also backtracks if on \op when no \op infix exists.)
651    def_token_full :prefix_circumfix_meta_operator,false,'reduce',/\[/,%q{
652       let_pos{
653           b = pos
654           scan(/(?=\S*\])/) or return false
655           ei=nil
656           (let_pos{ ei= expect_infix and scan(/\]/) } or
657            let_pos{ scan(/\\\\/) and ei= expect_infix and scan(/\]/) }) and
658           (o = ei[:O]
659            (not(o[:assoc] == :non) or
660             panic("Can't reduce a non-associative operator"))
661            (not(o[:prec] == Hconditional[:prec]) or
662             panic("Can't reduce a conditional operator"))
663            _match_from(b,{:expect_infix=>ei,:O=>o},:reduce))
664       }
665    }
666
667    def_tokens_simple :prefix_postfix_meta_operator,false,%w{ « }
668    def_tokens_simple :prefix_postfix_meta_operator,false,%w{ << }
669    def_tokens_simple :postfix_prefix_meta_operator,false,%w{ » }
670    def_tokens_simple :postfix_prefix_meta_operator,false,%w{ >> }
671
672    def_tokens_rest :infix_prefix_meta_operator,:chaining,%w{ ! },%q{
673      i=nil
674      lex1(:negation) and
675      let_pos{ (not before(/!/)) and i= infix } and
676      (o = i[:O]
677       (o[:assoc] == :chain or
678        o[:assoc] and o[:bool] or
679        panic("Only boolean infix operators may be negated"))
680       (o[:hyper] and
681        panic("Negation of hyper operator not allowed"))
682       _match_from(start,{:infix=>i,:O=>o},:<sym>))
683    }
684
685    def lex1(s)
686        false and #R XXX UNIMPLEMENTED - STD.pm being refactored
687        panic("Nested #{s} metaoperators not allowed")
688        true
689    end
690
691    def_token_full :infix_circumfix_meta_operator,:list_infix,'X X',/X/,%q{
692      lex1(:cross) and let_pos{ i= infix and scan(/X/) } and
693      _match_from(start,{:infix=>i,:O=>i[:O]},:'<sym>')
694    }
695
696    def_token_full :infix_circumfix_meta_operator,:hyper,'« »',/(?=«|»|<<|>>)/,%q{
697      i=nil
698      lex1(:hyper) and
699      (let_pos{ scan(/«|»/) and i= infix and scan(/«|»/) } or
700       let_pos{ scan(/<<|>>/) and i= infix and scan(/<<|>>/) }) and
701      _match_from(start,{:infix=>i,:O=>i[:O]},:'<sym>')
702    }
703
704    def_tokens_rest :infix_postfix_meta_operator,:item_assignment,%w{ = },%q{
705       lex1(:assignment) and
706       (op = $env_vars[:opS]
707        o = op[:O]
708        (o[:prec] > Hitem_assignment[:prec] or
709         panic("Can't make assignment op of operator looser than assignment"))
710        (not(o[:assoc] == :chain) or
711         panic("Can't make assignment op of boolean operator"))
712        (not(o[:assoc] == :non) or
713         panic("Can't make assignment op of non-associative operator"))
714        _match_from(start,{:O=>o},:'<sym>'))
715    }
716   
717    def_tokens_rest :postcircumfix,:methodcall,%w{ ( },%q{ sl=semilist and scan(/\)/) and sl }
718    def_tokens_rest :postcircumfix,:methodcall,%w{ [ },%q{ sl=semilist and scan(/\]/) and sl }
719    def_tokens_rest :postcircumfix,:methodcall,%w{ \{ },%q[ sl=semilist and scan(/\}/) and sl ]
720    def_tokens_rest :postcircumfix,:methodcall,%w{ < },%q{ w=anglewords('>') and scan(/>/) and w }
721    def_tokens_rest :postcircumfix,:methodcall,%w{ << },%q{ w=shellwords('>>') and scan(/>>/) and w }
722    def_tokens_rest :postcircumfix,:methodcall,%w{ « },%q{ w=shellwords('»') and scan(/»/) and w }
723   
724    def postop
725        #R We pass though, and so don't have to set [:O].
726        (( postfix ) or
727         ( postcircumfix ))
728    end
729
730    def methodop
731        b = pos; id=v=q=sl=al=nil
732        ((id= ident or
733          (before(/\$|\@/) and v= variable) or
734          (before(/[\'\"]/) and q= quote and (q =~ /\W/u or panic("Useless use of quotes")))) and
735         unsp? and
736         (let_pos{ scan(/\./); unsp; scan(/\(/) and sl= semilist and scan(/\)/) } or
737          let_pos{ scan(/\:/) and before(/\s/) and (not $env_vars[:inqoute]) and al= arglist } or
738          null) and
739         (h={};
740          _hkv(h,:ident,id)
741          _hkv(h,:variable,v)
742          _hkv(h,:quote,q)
743          _hkv(h,:semilist,sl)
744          _hkv(h,:arglist,al)
745          _match_from(b,h,:methodop)))
746    end
747
748    def arglist
749        $env_vars.scope_enter(:endargs)
750        $env_vars[:endargs] = false #R ??? XXX "0" or "false"?
751        wsp and
752        v = _EXPR(Hlist_prefix)
753        $env_vars.scope_leave
754        v
755    end
756
757    def anglewords(stop)
758        #wsp and starTOK{ (not before(/#{stop}/u)) and scan(/./u) } # XXX need to split
759        wsp and scan(/(?:(?!#{stop}).)*/u) #R# Modified, to get str, not array of char.
760    end
761
762    def shellwords(stop)
763        wsp and starTOK{ (not before(/#{stop}/)) and scan(/./u) } # XXX need to split
764    end
765
766    #R inlined lambda in re
767    def_token_full :circumfix,:term,'{ }',/(?=\{|->|<->)/,%q{ pblock }
768
769    def variable_decl
770        b = pos
771        e1=e2=nil
772        (var = variable and # ( xXXX[:sigil] = var[:sigil] ) and
773         quesTOK{
774             %w{ @ % }.member?(var[:sigil]) and
775             wsp and
776             before(/[\<\(\[\{]/) and
777             postcircumfix
778         } and
779         t= starTOK{trait} and
780         wsp and
781         #R XXX only first value is captured.
782         #R QUESTION spec rx would seem to not interleave the = and .= ?
783         quesTOK{
784             ((scan(/\=/) and wsp and e1=_EXPR(var[:sigil] == '$' ? Hitem_assignment : Hlist_prefix)) or
785              (scan(/\.\=/) and wsp and e2=_EXPR(Hitem_assignment)))
786         }) and
787         (h={};
788          _hkv(h,:variable,var)
789          _hkv(h,:default_value,e1) #R XXX speculative name
790          _hkv(h,:default_call,e2) #R XXX speculative name
791          _hkv(h,:traits,t)
792          _match_from(b,h,:variable_decl))
793    end
794
795    def scoped #rule
796        regex_declarator or package_declarator or
797            #R XXX not backtracking properly - don't know if it needs to yet
798            b=pos
799            ft=v=sig=ts=pd=rd=td=nil
800            (let_pos{
801                 ft= starRULE{fulltypename} and wsp and
802                 ( v= variable_decl or
803                   let_pos{ scan(/\(/) and wsp and sig= signature and wsp and scan(/\)/) and wsp and ts= starRULE{trait} } or
804                   pd= plurality_declarator or
805                   rd= routine_declarator or
806                   td= type_declarator)
807             }) and
808            (h={};
809             _hkv(h,:fulltypename,ft)
810             _hkv(h,:variable_decl,v)
811             _hkv(h,:signature,sig)
812             _hkv(h,:trait,ts)
813             _hkv(h,:plurality_declarator,pd)
814             _hkv(h,:routine_declarator,rd)
815             _hkv(h,:type_declarator,td)
816             _match_from(b,h,:scoped))
817    end
818    def_tokens_rest :scope_declarator,false,%w{ my our state constant has temp },%q{b=pos; s=scoped and _match_from(b,{:scoped=>s},:<sym>) } #R NONSPEC temp added.
819    def_tokens_rest :package_declarator,false,%w{ class grammar module role package },%q{b=pos; pd=package_def and _match_from(b,{:package_def=>pd},:<sym>) } #end;end
820    def_tokens_rest :package_declarator,false,%w{ require },%q{ module_name and (_EXPR;true) }
821    def_tokens_rest :package_declarator,false,%w{ trusts },%q{ module_name }
822
823    #R added a .ws between module_name and block, and before module_name. XXX
824    def package_def
825        let_pos{
826            b = pos
827            mn=traits_=bk=nil
828            (wsp and
829             (mn = quesRULE{ module_name } and wsp and
830              traits_= starRULE{ trait } and wsp and
831              (let_pos{ $env_vars[:begin_compunit] and
832                before(/;/) and # XXX NONSPEC Dont eat the ; , it's needed by the caller.
833                (mn.bool or panic("Compilation unit cannot be anonymous")) and
834                ($env_vars[:begin_compunit] = false
835                 true)
836               } or
837               (bk= block and wsp)
838               ))) and
839            (h={};
840             _hkv(h,:module_name,mn)
841             _hkv(h,:traits,traits_)
842             _hkv(h,:block,bk)
843             _match_from(b,h,:package_def))
844        }
845    end
846
847    def pluralized
848        let_pos {
849            wsp and
850            (variable_decl or
851             let_pos{
852                 scan(/\(/) and wsp and signature and wsp and
853                 scan(/\)/) and wsp and
854                 ruleSTAR{trait} } or
855             package_declarator or
856             routine_declarator or
857             regex_declarator or
858             type_declarator) }
859    end
860
861    def_tokens_rest :plurality_declarator,false,%w{ multi proto only },%q{
862       if not before{ wsp and scan(/sub\b|method\b/) } #R XXX NONSPEC ADDED
863         r= routine_def and _match_from(start,{:routine_def=>r},:<sym>)
864       else
865         p= pluralized and _match_from(start,{:pluralized=>p},:<sym>)
866       end
867    }
868    def_tokens_rest :routine_declarator,false,%w{ sub },%q{ routine_def }
869    def_tokens_rest :routine_declarator,false,%w{ method submethod },%q{ method_def }
870    def_tokens_rest :routine_declarator,false,%w{ macro },%q{ macro_def }
871    def_tokens_rest :regex_declarator,false,%w{ regex token rule },%q{ regex_def }
872
873
874    # Most of these special variable rules are there simply to catch old p5 brainos
875    #R so most are ignored here.
876    #R Ignore most of them for now.
877
878    def_tokens_simple :special_variable,false,%w{ $/ $! $_ }
879
880
881    # desigilname should only follow a sigil/twigil
882
883    def desigilname
884        ((before(/\$/) and variable) or
885         (name))
886    end
887   
888    def variable
889        b = pos
890        (special_variable or
891         let_pos{
892             sln=dsl=pc=nil
893             (si = sigil and (tw = twigil;true) and
894              ((si[:sym] == '&' and (sln = sublongname or return false;sln)) or
895               dsl= desigilname) and
896              ((tw and tw[:sym] == '.' and unsp? and before(/\(/) and pc= postcircumfix) or
897               null)) and
898             (h={:sigil=>si,:twigil=>tw};
899              _hkv(h,:sublongname,sln)
900              _hkv(h,:desigilname,dsl)
901              _hkv(h,:postcircumfix,pc)
902             _match_from(b,h,:variable))
903         } or
904         let_pos{ si= sigil and d= scan(/\d+/) and
905             (h={:sigil=>si};
906              _hkv(h,:desigilname,d) #R XXX non-spec
907             _match_from(b,h,:variable))
908         } or
909         # Note: $() can also parse as contextualizer in an expression; should have same effect
910         let_pos{ sigil and before(/[<\(]/) and postcircumfix } or
911         # Note: any ::() are handled within <name>, and subscript must be final part.
912         # A bare ::($foo) is not considered a variable, but ::($foo)::<$bar> is.
913         # (The point being that we want a sigil either first or last but not both.)
914         #= FOO::<$x>
915         let_pos{ name and scan(/::/) and before(/[\<\{«]/) and postcircumfix }
916         )
917    end
918
919    def_tokens_simple :sigil,false,%w{ $ @@ @ % & :: }
920    def_tokens_simple :twigil,false,%w{ . ! ^ : * + ? = }
921
922    def name
923        ident_ = morename_ = nil
924        b = pos
925        (let_pos{ ident_ = ident and nofat and morename_ = starTOK{morename} } or
926         morename_ = plusTOK{morename}) or return false
927        h = {}
928        _hkv(h,:ident,ident_)
929        _hkv(h,:morename,morename_)
930        _match_from(b,h,:name)
931    end
932
933    def morename
934        (scan(/::/) and
935         ((ident) or
936          (scan(/\(/) and _EXPR and scan(/\)/))))
937    end
938
939    def subshortname
940        b=pos
941        (let_pos{
942             c= category and cp= plusTOK{colonpair} and
943             _match_from(b,{:category=>c,:colonpair=>cp},:subshortname)
944         } or
945         (dsn= desigilname and
946          _match_from(b,{:desigilname=>dsn},:subshortname))
947         )
948    end
949    def subshortname_variant_for_method_def
950        #R# Late hack to parse method postcircumfix. 2008-Sep-25
951        b=pos
952        (let_pos{
953             c= category and cp= plusTOK{colonpair} and
954             _match_from(b,{:category=>c,:colonpair=>cp},:subshortname)
955         })
956    end
957   
958    def sublongname
959        subshortname and (sigterm;true)
960    end
961
962    def subcall
963        # XXX should this be sublongname?
964        let_pos{b=pos; n=subshortname and unsp? and (scan(/\./);true) and scan(/\(/) and l=semilist and scan(/\)/) and _match_from(b,{:subshortname=>n,:semilist=>l},:subcall) }
965    end
966
967    def value; quote || number || version || fulltypename; end
968
969    def typename
970        b=pos
971        let_pos{ n = name and is_type(n.str) and
972            # parametric type?
973            unsp? and
974            quesTOK{ before(/\[/) and postcircumfix } and
975            (h={};
976             _hkv(h,:name,n)
977             _match_from(b,h,:typename))
978        }
979    end
980
981    def fulltypename #R regex XXX
982        b = pos
983        tn= typename and
984            #R# quesRX{ wsp and scan(/of/) and wsp and fulltypename }
985            rest= quesRULE{ scan(/of/) and wsp and fulltypename } and
986            (a=[tn]
987             a += rest[0][:typename] if not rest.empty?
988             h={:typename=>a};
989             _match_from(b,h,:fulltypename))
990    end
991
992    def number; dec_number || integer || rad_number; end
993    def integer
994        _match_pat %r{
995            0 ( b [01]+           ( _ [01]+ )*
996              | o [0-7]+         ( _ [0-7]+ )*
997              | x [0-9a-fA-F]+ ( _ [0-9a-fA-F]+ )*
998              | d \d+               ( _ \d+)*
999              | \d+(_\d+)*
1000              )
1001            | \d+(_\d+)*
1002        }x,'integer'
1003    end
1004    def radint; integer or (let_pos{ r = rad_number and r[:intpart] and not r[:fracpart] }); end
1005    def dec_number; scan(/\d+(?:_\d+)*
1006                           (?: (?: \. \d+(?:_\d+)* (?: [Ee] [+\-]? \d+ )?)
1007                         |                         (?: [Ee] [+\-]? \d+ ))/x); end
1008    def rad_number
1009        let_pos{
1010            b=pos
1011            radix_=intpart=fracpart=base=exp=pc=nil
1012            scan(/:/) and radix_ = scan(/\d+/) and unsp? and
1013            ( ( scan(/</) and
1014                intpart = scan(/[0-9a-zA-Z_]+/) and #R XXX NONSPEC ADDED _
1015                (fracpart = scan(/\.[0-9a-zA-Z_]+/);true) and  #R XXX NONSPEC ADDED _
1016                (scan(/\*/) and base = radint and scan(/\*\*/) and exp = radint;true) and
1017                scan(/>/)) or
1018              ( before(/\[/) and pc= postcircumfix ) or
1019              ( before(/\(/) and pc= postcircumfix )) and
1020            (h={}
1021             _hkv(h,:radix,radix_)
1022             _hkv(h,:intpart,intpart)
1023             _hkv(h,:fracpart,fracpart)
1024             _hkv(h,:base,base)
1025             _hkv(h,:exp,exp)
1026             _hkv(h,:postcircumfix,pc)
1027             _match_from(b,h,:rad_number))
1028        }
1029    end
1030    def octint; scan(/[0-7]+/); end
1031    def hexint; scan(/[0-9a-fA-F]+/); end
1032
1033
1034
1035
1036    $herestub_queue = []
1037
1038    def q_herestub(lang)
1039        (xXXX[:delimstr] = quotesnabber() or  # force raw semantics on /END/ marker
1040         return false)
1041        hs = Herestub.new($xXXX[:delimstr][:delimited][:q][:text], # XXX or some such
1042                          xXXX,
1043                          lang);
1044        $herestub_queue.push hs
1045    end
1046
1047    class Herestub
1048        attr_accessor :delim,:orignode,:lang
1049        def initialize; @delim,@orignode,@lang=delim,orignode,lang; end
1050    end
1051
1052    def theredoc
1053        @scanner.bol? and scan(/[ \t]*?/) and eat($env_vars[:delim]) and scan(/[ \t]*$\n?/)
1054    end
1055
1056    # XXX be sure to temporize @herestub_queue on reentry to new line of heredocs
1057
1058    def heredoc()
1059        here = self
1060        while herestub = $herestub_queue.shift
1061            $env_vars.scope_enter(:delim)
1062            $env_vars[:delim] = herestub.delim
1063            lang = herestub.lang
1064            doc = nil
1065            wsS = ""
1066            here = here.q_unbalanced_rule(lang, method(:theredoc)).xMATCHIFY;
1067            if here.bool
1068                if wsS != ""
1069                    wsequiv = wsS;
1070                    wsequiv.gsub!(/\A( *)\t/,"$1        "); # per spec
1071                    here[:text][0].sub!(/\A/,"\n"); # so we don't match ^^ after escapes
1072                    here[:text].each{|s__|
1073                        s__.gsub!(/\n(#{wsS}||[ \t]*)/){
1074                            white = $1;
1075                            if white == wsS
1076                                '';
1077                            else
1078                                white.sub!(/\A(\t+)/){ #R QUESTION shouldn't it be ^ instead of \A?
1079                                    #R XXX TODO
1080                                    #R ' ' x ($0.chars * (COMPILING::<$?TABSTOP> // 8))
1081                                };
1082                                white.sub!(/\A#{wsequiv}/,'') ? white : '';
1083                            end
1084                        }
1085                    }
1086                    here[:text][0].sub!(/^\n/,'')
1087                end
1088                herestub.orignode[:doc] = here;
1089            else
1090                panic("Ending delimiter $delim not found");
1091            end
1092            $env_vars.scope_leave
1093        end
1094        return here;
1095    end
1096
1097
1098    def self.def_quote(name,args)
1099        left_sym, = name.split(/\s+/)
1100        def_token_full :quote,false,name,Regexp.new(Regexp.quote(left_sym))," quotesnabber(#{args})"
1101    end
1102    #R# XXX NONSPEC last "close" argument to quotesnabber is non-spec.
1103    def_quote "' '"  ,%q{':q',"'"}
1104    def_quote '" "'  ,%q{':qq','"'}
1105    def_quote '« »'  ,%q{':qq',':ww','»'}
1106    def_quote '<< >>',%q{':qq',':ww','>>'}
1107    def_quote '< >'  ,%q{':q',':w','>'}
1108    def_quote '/ /'  ,%q{':regex','/'}
1109
1110    # handle composite forms like qww
1111    def_tokens_rest :quote,false,%w{ qq q },%q{ nofat and  qm = quote_mod and quotesnabber(':<sym>',qm) }
1112
1113    def_tokens_simple :quote_mod,false,%w{ w ww x to s a h f c b }
1114
1115    def_tokens_rest :quote,false,%w{ rx m },%q{
1116      nofat and mod= starTOK{ quotepair } and q= quotesnabber(':regex') and
1117      (h={}
1118       _hkv(h,:quotepair,mod)
1119       _hkv(h,:quotesnabber,q)
1120       _match_from(start,h,:regex))
1121    }
1122    def_tokens_rest :quote,false,%w{ mm },%q{ nofat and quotesnabber(':regex', ':s') }
1123    def_tokens_rest :quote,false,%w{ s },%q{ nofat and pat=quotesnabber(':regex') and finish_subst(pat) }
1124    def_tokens_rest :quote,false,%w{ ss },%q{ nofat and pat=quotesnabber(':regex', ':s') and finish_subst(pat) }
1125    def_tokens_rest :quote,false,%w{ tr },%q{ nofat and pat=quotesnabber(':trans') and finish_subst(pat) }
1126
1127    def finish_subst(pat)
1128        $env_vars.scope_enter(:thisop)
1129        u =(
1130            # bracketed form
1131            (pat[:delim] == 2 and ((wsp and infix and
1132                                    ($env_vars[:thisop][:prec] == Hitem_assignment[:prec] or
1133                                     panic("Bracketed subst must use some form of assignment")) and
1134                                    repl=_EXPR(Hitem_assignment)) or :failed)) or
1135            # unbracketed form
1136            (repl=q_unbalanced(qlang('Q',':qq'), pat[:delim][0])))
1137        $env_vars.scope_leave
1138        u = false if u == :failed
1139        u
1140    end
1141
1142    def finish_trans(pat)
1143        u =(
1144            # bracketed form
1145            (pat[:delim] == 2 and ((wsp and
1146                                    repl==q_pickdelim(qlang('Q',':tr'))) or :failed)) or
1147            # unbracketed form
1148            (repl=q_unbalanced(qlang('Q',':tr'), pat[:delim][0])))
1149        u
1150    end
1151
1152    # The key observation here is that the inside of quoted constructs may
1153    # be any of a lot of different sublanguages, and we have to parameterize
1154    # which parse rule to use as well as what options to feed that parse rule.
1155
1156    $qlang = {}
1157    def qlang(*pedigreeA)
1158        pedigreeS = pedigreeA.inspect
1159        $qlang[pedigreeS] ||= QLang.create(pedigreeA)
1160    end
1161
1162    class QLang
1163        attr_accessor :option,:tweaker,:parser,:escrule
1164        def initialize(option,tweaker,parser,escrule)
1165            @option,@tweaker,@parser,@escrule=option,tweaker,parser,escrule
1166            initialize_escapes
1167        end
1168        attr_accessor :escapes
1169        def initialize_escapes(*a)
1170            # super(*a)
1171            @escapes = []
1172            if @option
1173                @escapes.push('\\') if @option[:b]
1174                @escapes.push('$') if @option[:s]
1175                @escapes.push('@') if @option[:a]
1176                @escapes.push('%') if @option[:h]
1177                @escapes.push('&') if @option[:f]
1178                @escapes.push('{') if @option[:c]
1179            end
1180        end
1181        def escset; @escapes end
1182        def self.create(pedigree)
1183            q = QLang.new(nil,nil,nil,nil)
1184            base = pedigree.shift
1185            eval("q.init_root_of_#{base}")
1186            pedigree.each{|mod|
1187                ma = mod.match(/^:(!)?(\w+)$/u) or raise "bug"
1188                all,neg,name = ma.to_a
1189                q.tweak(name => (neg ? false : 1))
1190            }
1191            q
1192        end
1193        def init_root_of_Q
1194            @option  = {}
1195            @tweaker = :the_Q_tweaker
1196            @parser  = :q_pickdelim
1197            @escrule = :quote_escapes
1198        end
1199        def tweak(opt)
1200            send(@tweaker,opt)
1201        end
1202       
1203        def the_Q_tweaker(opt)
1204            k,v = opt.to_a[0]
1205            ks = k.to_s
1206            if %w{ q }.member? ks
1207                v or panic("Can't turn :q back off");
1208                (not @option.empty?) and panic("Too late for :q");
1209                @option = {:b=>1, :s=>false, :a=>false, :h=>false, :f=>false, :c=>false};
1210            elsif %w{ qq }.member? ks
1211                v or panic("Can't turn :qq back off");
1212                (not @option.empty?) and panic("Too late for :qq");
1213                @option = {:b=>1, :s=>1, :a=>1, :h=>1, :f=>1, :c=>1};
1214            elsif %w{ b s a h f c  x w ww }.member? ks
1215                @option[k] = v
1216            elsif %w{ to }.member? ks
1217                @parser = :q_heredoc
1218                @option[k] = v
1219            elsif %w{ regex }.member? ks
1220                @tweaker = :the_RX_tweaker
1221                @parser = :rx_pickdelim
1222                @option = {}
1223                @escrule = :regex_metachar
1224            elsif %w{ trans }.member? ks
1225                @tweaker = :the_TR_tweaker
1226                @parser = :tr_pickdelim
1227                @option = {}
1228                @escrule = :trans_metachar
1229            elsif %w{ code }.member? ks
1230                @tweaker = :the_RX_tweaker