| 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 | |
|---|
| 10 | require 'prelude' |
|---|
| 11 | |
|---|
| 12 | class 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 |
|---|
|
|---|