1# Copyright (C) 2005-2009, Parrot Foundation. 2 3=head1 DESCRIPTION 4 5PGE::Exp - base class for expressions 6 7=cut 8 9.namespace [ 'PGE';'Exp' ] 10 11.include "interpinfo.pasm" 12.include "cclass.pasm" 13.const int PGE_INF = 2147483647 14.const int PGE_CUT_GROUP = -1 15.const int PGE_CUT_RULE = -2 16.const int PGE_CUT_MATCH = -3 17.const int PGE_CUT_CUT = -4 18.const int PGE_BACKTRACK_GREEDY = 1 19.const int PGE_BACKTRACK_EAGER = 2 20.const int PGE_BACKTRACK_NONE = 3 21 22.sub "__onload" :load 23 .local pmc optable 24 .local pmc term 25 26 .local pmc p6meta, expproto 27 p6meta = get_hll_global 'P6metaclass' 28 expproto = p6meta.'new_class'('PGE::Exp', 'parent'=>'PGE::Match') 29 p6meta.'new_class'('PGE::Exp::Literal', 'parent'=>expproto) 30 p6meta.'new_class'('PGE::Exp::Scalar', 'parent'=>expproto) 31 p6meta.'new_class'('PGE::Exp::CCShortcut', 'parent'=>expproto) 32 p6meta.'new_class'('PGE::Exp::Newline', 'parent'=>expproto) 33 p6meta.'new_class'('PGE::Exp::EnumCharList', 'parent'=>expproto) 34 p6meta.'new_class'('PGE::Exp::Anchor', 'parent'=>expproto) 35 p6meta.'new_class'('PGE::Exp::Concat', 'parent'=>expproto) 36 p6meta.'new_class'('PGE::Exp::Alt', 'parent'=>expproto) 37 p6meta.'new_class'('PGE::Exp::Conj', 'parent'=>expproto) 38 p6meta.'new_class'('PGE::Exp::Group', 'parent'=>expproto) 39 p6meta.'new_class'('PGE::Exp::CGroup', 'parent'=>'PGE::Exp::Group') 40 p6meta.'new_class'('PGE::Exp::Subrule', 'parent'=>expproto) 41 p6meta.'new_class'('PGE::Exp::Cut', 'parent'=>expproto) 42 p6meta.'new_class'('PGE::Exp::Quant', 'parent'=>expproto) 43 p6meta.'new_class'('PGE::Exp::Modifier', 'parent'=>expproto) 44 p6meta.'new_class'('PGE::Exp::Closure', 'parent'=>expproto) 45 p6meta.'new_class'('PGE::Exp::Action', 'parent'=>expproto) 46 47 load_bytecode 'PGE/Util.pbc' 48.end 49 50 51=over 4 52 53=item C<compile(PMC adverbs :slurpy :named)> 54 55Compile C<self> into PIR or a subroutine, according to the 56C<target> adverbs. 57 58=cut 59 60.sub 'compile' :method 61 .param pmc adverbs :slurpy :named 62 63 .local string target 64 target = adverbs['target'] 65 target = downcase target 66 if target == 'parse' goto return_exp 67 if target == 'pge::exp' goto return_exp 68 69 .local pmc code 70 code = new 'StringBuilder' 71 72 .local pmc ns 73 ns = adverbs['namespace'] 74 unless null ns goto ns_emit 75 ns_grammar: 76 .local string grammar 77 grammar = adverbs['grammar'] 78 ns = split '::', grammar 79 ns_emit: 80 $P1 = get_root_global ['parrot';'PGE';'Util'], 'pir_key_escape' 81 $P0 = $P1(ns :flat) 82 code.'append_format'(".namespace %0\n", $P0) 83 ns_done: 84 85 $P0 = self.'root_pir'(adverbs :flat :named) 86 code .= $P0 87 if target != 'pir' goto bytecode 88 .return (code) 89 90 bytecode: 91 $P0 = compreg 'PIR' 92 $P1 = $P0(code) 93 $P1 = $P1.'first_sub_in_const_table'() 94 make_grammar: 95 if grammar == '' goto end 96 .local pmc p6meta 97 p6meta = get_hll_global 'P6metaclass' 98 $P0 = p6meta.'get_proto'(grammar) 99 unless null $P0 goto end 100 $P0 = p6meta.'new_class'(grammar, 'parent'=>'PGE::Grammar') 101 end: 102 .return ($P1) 103 104 return_exp: 105 .return (self) 106.end 107 108 109=item C<root_pir(PMC adverbs)> 110 111Return a StringBuilder object containing the entire expression 112tree as a PIR code object that can be compiled. 113 114=cut 115 116.sub 'root_pir' :method 117 .param pmc adverbs :slurpy :named 118 119 .local pmc code 120 code = new 'StringBuilder' 121 122 .local string name, namecorou 123 name = adverbs['name'] 124 namecorou = concat name, '_corou' 125 if name > '' goto have_name 126 $P0 = get_root_global ['parrot';'PGE';'Util'], 'unique' 127 name = $P0('_regex') 128 namecorou = concat name, '_corou' 129 have_name: 130 .local pmc escape 131 escape = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 132 name = escape(name) 133 namecorou = escape(namecorou) 134 135 .local string pirflags 136 pirflags = adverbs['pirflags'] 137 138 $I0 = index pirflags, ':subid' 139 if $I0 >= 0 goto have_subid 140 $P0 = adverbs['subid'] 141 if null $P0 goto have_subid 142 $S0 = escape($P0) 143 pirflags = concat pirflags, ' :subid(' 144 pirflags = concat pirflags, $S0 145 pirflags = concat pirflags, ')' 146 have_subid: 147 148 ## Perform reduction/optimization on the 149 ## expression tree before generating PIR. 150 .local pmc exp 151 .local string explabel 152 exp = self 153 set_hll_global ['PGE';'Exp'], '$!group', exp 154 exp = exp.'reduce'(self) 155 156 ## we don't need a coroutine if :ratchet is set 157 .local int cutrule 158 $I0 = adverbs['ratchet'] 159 cutrule = isne $I0, 0 160 161 ## generate the PIR for the expression tree. 162 .local pmc expcode 163 expcode = new 'StringBuilder' 164 explabel = 'R' 165 exp.'pir'(expcode, explabel, 'succeed') 166 167 if cutrule goto code_cutrule 168 ## Generate the initial PIR code for a backtracking (uncut) rule. 169 .local string returnop 170 returnop = '.yield' 171 code.'append_format'(<<" CODE", name, pirflags, namecorou, .INTERPINFO_CURRENT_SUB) 172 .sub %0 :method :nsentry %1 173 .param pmc adverbs :slurpy :named 174 .local pmc mob 175 .const 'Sub' corou = %2 176 $P0 = corou 177 $P0 = clone $P0 178 mob = $P0(self, adverbs) 179 .return (mob) 180 .end 181 .sub '' :subid(%2) 182 .param pmc mob 183 .param pmc adverbs 184 .local string target 185 .local pmc mfrom, mpos 186 .local int cpos, iscont 187 $P0 = get_hll_global ['PGE'], '$!MATCH' 188 (mob, cpos, target, mfrom, mpos, iscont) = $P0.'new'(mob, adverbs :flat :named) 189 $P0 = interpinfo %3 190 setattribute mob, '&!corou', $P0 191 .local int lastpos 192 lastpos = length target 193 if cpos > lastpos goto fail_rule 194 CODE 195 goto code_body 196 197 code_cutrule: 198 ## Initial code for a rule that cannot be backtracked into. 199 returnop = '.return' 200 code.'append_format'(<<" CODE", name, pirflags) 201 .sub %0 :method :nsentry %1 202 .param pmc adverbs :slurpy :named 203 .local pmc mob 204 .local string target 205 .local pmc mfrom, mpos 206 .local int cpos, iscont 207 $P0 = get_hll_global ['PGE'], '$!MATCH' 208 (mob, cpos, target, mfrom, mpos, iscont) = $P0.'new'(self, adverbs :flat :named) 209 .local int lastpos 210 lastpos = length target 211 if cpos > lastpos goto fail_rule 212 CODE 213 214 code_body: 215 ## generate the ustack only if we need it 216 .local string expstr 217 expstr = expcode 218 code.'append_format'(" .local pmc cstack\n") 219 code.'append_format'(" cstack = root_new ['parrot';'ResizableIntegerArray']\n") 220 $I0 = index expstr, 'ustack' 221 if $I0 < 0 goto code_body_1 222 code.'append_format'(" .local pmc ustack\n") 223 code.'append_format'(" ustack = root_new ['parrot';'ResizablePMCArray']\n") 224 code_body_1: 225 ## generate the gpad only if we need it 226 $I0 = index expstr, 'gpad' 227 if $I0 < 0 goto code_body_2 228 code.'append_format'(" .local pmc gpad\n") 229 code.'append_format'(" gpad = root_new ['parrot';'ResizablePMCArray']\n") 230 code_body_2: 231 ## set the captscope if we need it 232 $I0 = index expstr, 'captscope' 233 if $I0 < 0 goto code_body_3 234 code.'append_format'(" .local pmc captscope, captob\n") 235 code.'append_format'(" captscope = mob\n") 236 code_body_3: 237 238 code.'append_format'(<<" CODE", PGE_CUT_RULE, returnop) 239 .local int pos, rep, cutmark 240 try_match: 241 if cpos > lastpos goto fail_rule 242 mfrom = cpos 243 pos = cpos 244 cutmark = 0 245 local_branch cstack, R 246 if cutmark <= %0 goto fail_cut 247 inc cpos 248 if iscont goto try_match 249 fail_rule: 250 cutmark = %0 251 fail_cut: 252 mob.'_failcut'(cutmark) 253 %1 (mob) 254 goto fail_cut 255 succeed: 256 mpos = pos 257 %1 (mob) 258 fail: 259 local_return cstack 260 CODE 261 262 ## add the "fail_match" target if we need it 263 $I0 = index expstr, 'fail_match' 264 if $I0 < 0 goto add_expcode 265 code.'append_format'(<<" CODE", PGE_CUT_MATCH) 266 fail_match: 267 cutmark = %0 268 goto fail_cut 269 CODE 270 271 add_expcode: 272 ## add the expression code, then close off the sub 273 code .= expcode 274 code.'append_format'(" .end\n") 275 .return (code) 276.end 277 278 279.sub 'getargs' :method 280 .param pmc label 281 .param pmc next 282 .param pmc hash :slurpy :named 283 hash['L'] = label # %L = node's label 284 hash['S'] = next # %S = success target 285 .local pmc quant 286 $I0 = exists hash['quant'] 287 if $I0 == 0 goto end 288 quant = hash['quant'] 289 $I0 = quant['min'] 290 $I1 = quant['max'] 291 $S2 = quant['backtrack'] 292 hash['m'] = $I0 # %m = min repetitions 293 hash['n'] = $I1 # %n = max repetitions 294 $S0 = $I0 295 $S0 .= '..' 296 $S1 = $I1 297 $S0 .= $S1 298 $S0 .= ' (' 299 $S0 .= $S2 300 $S0 .= ')' 301 hash['Q'] = $S0 # %Q = printable quant 302 hash['M'] = '' 303 hash['N'] = '' 304 quant_min: 305 if $I0 > 0 goto quant_max 306 hash['M'] = '### ' # %M = # if min==0 307 quant_max: 308 if $I1 != PGE_INF goto end 309 hash['N'] = '### ' # %N = # if max==INF 310 end: 311 .return (hash) 312.end 313 314 315.sub 'gencapture' :method 316 .param pmc label 317 .local string cname 318 .local pmc captgen, captsave, captback 319 .local int iscapture, isarray 320 cname = self['cname'] 321 iscapture = self['iscapture'] 322 isarray = self['isarray'] 323 captgen = new 'StringBuilder' 324 captsave = new 'StringBuilder' 325 captback = new 'StringBuilder' 326 if iscapture == 0 goto end 327 if isarray != 0 goto capt_array 328 push captsave, 'captscope[' 329 push captsave, cname 330 push captsave, "] = captob\n" 331 # TODO GH #1154 check for invalid cname index 332 push captback, '$I5 = exists captscope[' 333 push captback, cname 334 push captback, "]\n" 335 push captback, 'unless $I5, ' 336 push captback, label 337 push captback, "_nodel\n" 338 push captback, 'delete captscope[' 339 push captback, cname 340 push captback, "]\n" 341 push captback, label 342 push captback, "_nodel:\n" 343 goto end 344 capt_array: 345 push captsave, '$P2 = captscope[' 346 push captsave, cname 347 push captsave, "]\n" 348 push captsave, 'push $P2, captob' 349 push captback, '$P2 = captscope[' 350 push captback, cname 351 push captback, "]\n" 352 push captback, '$P2 = pop $P2' 353 push captgen, '$I0 = defined captscope[' 354 push captgen, cname 355 push captgen, "]\n" 356 push captgen, 'if $I0 goto ' 357 push captgen, label 358 push captgen, "_cgen\n" 359 push captgen, "$P0 = root_new ['parrot';'ResizablePMCArray']\n" 360 push captgen, 'captscope[' 361 push captgen, cname 362 push captgen, "] = $P0\n" 363 push captgen, 'local_branch cstack, ' 364 push captgen, label 365 push captgen, "_cgen\n" 366 push captgen, 'delete captscope[' 367 push captgen, cname 368 push captgen, "]\n" 369 push captgen, "goto fail\n" 370 push captgen, label 371 push captgen, "_cgen:\n" 372 end: 373 .return (captgen, captsave, captback) 374.end 375 376 377.namespace [ 'PGE';'Exp';'Literal' ] 378 379.sub 'reduce' :method 380 .param pmc next 381 .return (self) 382.end 383 384.sub 'pir' :method 385 .param pmc code 386 .param string label 387 .param string next 388 389 .local pmc args 390 args = self.'getargs'(label, next) 391 .local string literal 392 .local int litlen 393 literal = self.'ast'() 394 litlen = length literal 395 396 args['I'] = '' 397 $I0 = self['ignorecase'] 398 if $I0 == 0 goto ignorecase_end 399 args['I'] = '$S0 = downcase $S0' 400 literal = downcase literal 401 ignorecase_end: 402 403 $P0 = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 404 literal = $P0(literal) 405 406 code.'append_format'(<<" CODE", litlen, literal, args :named :flat) 407 %L: # literal 408 $I0 = pos + %0 409 if $I0 > lastpos goto fail 410 $S0 = substr target, pos, %0 411 %I 412 if $S0 != %1 goto fail 413 pos += %0 414 goto %S\n 415 CODE 416 .return () 417.end 418 419 420.namespace [ 'PGE';'Exp';'Concat' ] 421 422.sub 'reduce' :method 423 .param pmc next 424 425 .local pmc children, exp 426 .local int n 427 children = self.'list'() 428 n = elements children 429 reduce_loop: 430 if n <= 0 goto reduce_end 431 dec n 432 exp = self[n] 433 exp = exp.'reduce'(next) 434 self[n] = exp 435 next = exp 436 goto reduce_loop 437 reduce_end: 438 .local int i, j 439 .local pmc exp0, exp1 440 n = elements children 441 i = 0 442 j = 0 443 concat_lit_loop: 444 inc i 445 if i >= n goto concat_lit_end 446 exp1 = children[i] 447 $I1 = isa exp1, ['PGE';'Exp';'Literal'] 448 if $I1 == 0 goto concat_lit_shift 449 exp0 = children[j] 450 $I0 = isa exp0, ['PGE';'Exp';'Literal'] 451 if $I0 == 0 goto concat_lit_shift 452 $I0 = exp0['ignorecase'] 453 $I1 = exp1['ignorecase'] 454 if $I0 != $I1 goto concat_lit_shift 455 $S0 = exp0.'ast'() 456 $S1 = exp1.'ast'() 457 $S0 = concat $S0, $S1 458 exp0.'!make'($S0) 459 goto concat_lit_loop 460 concat_lit_shift: 461 inc j 462 if j >= i goto concat_lit_loop 463 children[j] = exp1 464 goto concat_lit_loop 465 concat_lit_end: 466 inc j 467 children = j 468 if j > 1 goto end 469 exp = self[0] 470 .return (exp) 471 end: 472 .return (self) 473.end 474 475 476.sub 'pir' :method 477 .param pmc code 478 .param string label 479 .param string next 480 .local pmc unique 481 unique = get_root_global ['parrot';'PGE';'Util'], 'unique' 482 483 .local pmc it, exp 484 code.'append_format'(" %0: # concat\n", label) 485 $P0 = self.'list'() 486 it = iter $P0 487 exp = shift it 488 $S0 = unique('R') 489 iter_loop: 490 unless it goto iter_end 491 $P1 = shift it 492 $S1 = unique('R') 493 exp.'pir'(code, $S0, $S1) 494 exp = $P1 495 $S0 = $S1 496 goto iter_loop 497 iter_end: 498 exp.'pir'(code, $S0, next) 499 .return () 500.end 501 502 503.namespace [ 'PGE';'Exp';'Quant' ] 504 505.sub 'reduce' :method 506 .param pmc next 507 .local pmc exp0, sep 508 exp0 = self[0] 509 sep = self['sep'] 510 511 .local int backtrack, min, max 512 backtrack = self['backtrack'] 513 min = self['min'] 514 max = self['max'] 515 if max != 1 goto reduce_exp0 516 if min != max goto reduce_max1 517 exp0['backtrack'] = backtrack 518 exp0 = exp0.'reduce'(next) 519 .return (exp0) 520 521 reduce_max1: 522 ## special case of 0..1?: node 523 if backtrack != PGE_BACKTRACK_NONE goto reduce_exp0 524 $I0 = exists exp0['backtrack'] 525 if $I0 goto reduce_exp0 526 exp0['backtrack'] = backtrack 527 528 reduce_exp0: 529 exp0 = exp0.'reduce'(next) 530 self[0] = exp0 531 if null sep goto reduce_exp0_1 532 sep = sep.'reduce'(next) 533 self['sep'] = sep 534 reduce_exp0_1: 535 .return (self) 536.end 537 538.sub 'pir' :method 539 .param pmc code 540 .param string label 541 .param string next 542 543 .local pmc unique 544 unique = get_root_global ['parrot';'PGE';'Util'], 'unique' 545 546 .local pmc exp, sep 547 .local string explabel, seplabel, replabel, nextlabel 548 exp = self[0] 549 sep = self['sep'] 550 551 unless null sep goto outer_quant 552 $I0 = can exp, 'pir_quant' 553 if $I0 == 0 goto outer_quant 554 $I0 = exp.'pir_quant'(code, label, next, self) 555 if $I0 == 0 goto outer_quant 556 .return () 557 558 outer_quant: 559 .local pmc args 560 args = self.'getargs'(label, next, 'quant' => self) 561 562 .local int backtrack 563 backtrack = self['backtrack'] 564 565 explabel = unique('R') 566 nextlabel = explabel 567 replabel = concat label, '_repeat' 568 if null sep goto outer_quant_1 569 seplabel = unique('R') 570 nextlabel = concat label, '_sep' 571 outer_quant_1: 572 573 if backtrack == PGE_BACKTRACK_EAGER goto bt_eager 574 if backtrack == PGE_BACKTRACK_NONE goto bt_none 575 576 bt_greedy: 577 args['c'] = 0 578 args['C'] = '### ' 579 ## handle 0..Inf as a special case 580 $I0 = self['min'] 581 if $I0 != 0 goto bt_greedy_none 582 $I0 = self['max'] 583 if $I0 != PGE_INF goto bt_greedy_none 584 code.'append_format'(<<" CODE", replabel, nextlabel, args :flat :named) 585 %L: # quant 0..Inf greedy 586 %0: 587 push ustack, pos 588 local_branch cstack, %1 589 pos = pop ustack 590 if cutmark != 0 goto fail 591 goto %S 592 CODE 593 goto end 594 595 bt_none: 596 $S0 = unique() 597 args['c'] = $S0 598 args['C'] = '' 599 ## handle 0..Inf as a special case 600 $I0 = self['min'] 601 if $I0 != 0 goto bt_greedy_none 602 $I0 = self['max'] 603 if $I0 != PGE_INF goto bt_greedy_none 604 code.'append_format'(<<" CODE", replabel, nextlabel, args :flat :named) 605 %L: # quant 0..Inf none 606 local_branch cstack, %0 607 if cutmark != %c goto fail 608 cutmark = 0 609 goto fail 610 %0: 611 push ustack, pos 612 local_branch cstack, %1 613 pos = pop ustack 614 if cutmark != 0 goto fail 615 local_branch cstack, %S 616 if cutmark != 0 goto fail 617 cutmark = %c 618 goto fail 619 CODE 620 goto end 621 622 bt_greedy_none: 623 ## handle greedy or none 624 code.'append_format'(<<" CODE", replabel, nextlabel, args :flat :named) 625 %L: # quant %Q greedy/none 626 push gpad, 0 627 local_branch cstack, %0 628 $I0 = pop gpad 629 %Cif cutmark != %c goto fail 630 %Ccutmark = 0 631 goto fail 632 %0: 633 rep = gpad[-1] 634 %Nif rep >= %n goto %L_1 635 inc rep 636 gpad[-1] = rep 637 push ustack, pos 638 push ustack, rep 639 local_branch cstack, %1 640 rep = pop ustack 641 pos = pop ustack 642 if cutmark != 0 goto fail 643 dec rep 644 %L_1: 645 %Mif rep < %m goto fail 646 $I0 = pop gpad 647 push ustack, rep 648 local_branch cstack, %S 649 rep = pop ustack 650 push gpad, rep 651 if cutmark != 0 goto fail 652 %Ccutmark = %c 653 goto fail\n 654 CODE 655 goto end 656 657 bt_eager: 658 ## handle eager backtracking 659 code.'append_format'(<<" CODE", replabel, nextlabel, args :flat :named) 660 %L: # quant %Q eager 661 push gpad, 0 662 local_branch cstack, %0 663 $I0 = pop gpad 664 goto fail 665 %0: 666 rep = gpad[-1] 667 %Mif rep < %m goto %L_1 668 $I0 = pop gpad 669 push ustack, pos 670 push ustack, rep 671 local_branch cstack, %S 672 rep = pop ustack 673 pos = pop ustack 674 push gpad, rep 675 %L_1: 676 %Nif rep >= %n goto fail 677 inc rep 678 gpad[-1] = rep 679 goto %1\n 680 CODE 681 682 end: 683 if null sep goto sep_done 684 code.'append_format'(<<" CODE", nextlabel, explabel, seplabel) 685 %0: 686 if rep == 1 goto %1 687 goto %2 688 CODE 689 sep.'pir'(code, seplabel, explabel) 690 sep_done: 691 exp.'pir'(code, explabel, replabel) 692 .return () 693.end 694 695 696.namespace [ 'PGE';'Exp';'Group' ] 697 698.sub 'reduce' :method 699 .param pmc next 700 .local pmc exp 701 702 $I0 = self['backtrack'] 703 if $I0 != PGE_BACKTRACK_NONE goto reduce_exp0 704 ## This group is non-backtracking, so concatenate a "cut group" 705 ## node (PGE::Exp::Cut) to its child. 706 exp = self[0] 707 $P0 = new ['PGE';'Exp';'Concat'] 708 $P0[0] = exp 709 $P1 = new ['PGE';'Exp';'Cut'] 710 $P0[1] = $P1 711 self[0] = $P0 712 713 reduce_exp0: 714 .local pmc group 715 ## Temporarily store this group as the current group. Any 716 ## cut nodes we encounter will set a cutmark into this group. 717 group = get_hll_global ['PGE';'Exp'], '$!group' 718 set_hll_global ['PGE';'Exp'], '$!group', self 719 exp = self[0] 720 exp = exp.'reduce'(next) 721 set_hll_global ['PGE';'Exp'], '$!group', group 722 $I0 = self['cutmark'] 723 if $I0 > 0 goto keep_group 724 $I0 = self['iscapture'] 725 if $I0 != 0 goto keep_group 726 .return (exp) 727 keep_group: 728 .return (self) 729.end 730 731.sub 'pir' :method 732 .param pmc code 733 .param string label 734 .param string next 735 736 .local pmc exp0 737 exp0 = self[0] 738 739 .local int cutmark 740 cutmark = self['cutmark'] 741 if cutmark > 0 goto has_cutmark 742 exp0.'pir'(code, label, next) 743 .return () 744 745 has_cutmark: 746 .local string exp0label 747 $P0 = get_root_global ['parrot';'PGE';'Util'], 'unique' 748 exp0label = $P0('R') 749 code.'append_format'(<<" CODE", label, exp0label, cutmark) 750 %0: # group %2 751 local_branch cstack, %1 752 if cutmark != %2 goto fail 753 cutmark = 0 754 goto fail\n 755 CODE 756 exp0.'pir'(code, exp0label, next) 757.end 758 759 760.namespace [ 'PGE';'Exp';'CGroup' ] 761 762.sub 'pir' :method :nsentry 763 .param pmc code 764 .param string label 765 .param string next 766 767 .local string explabel, expnext 768 $P0 = get_root_global ['parrot';'PGE';'Util'], 'unique' 769 explabel = $P0('R') 770 expnext = concat label, '_close' 771 772 .local pmc args 773 args = self.'getargs'(label, next) 774 775 .local string captgen, captsave, captback 776 (captgen, captsave, captback) = self.'gencapture'(label) 777 778 .local int cutmark 779 cutmark = self['cutmark'] 780 args['c'] = cutmark 781 args['C'] = '### ' 782 if cutmark == 0 goto cutmark_end 783 args['C'] = '' 784 cutmark_end: 785 786 .local int isscope 787 isscope = self['isscope'] 788 args['X'] = '' 789 if isscope != 0 goto isscope_end 790 args['X'] = '### ' 791 isscope_end: 792 793 code.'append_format'(<<" CODE", captgen, captsave, captback, 'E'=>explabel, args :flat :named) 794 %L: # capture 795 %0 796 captob = captscope.'new'(captscope, 'pos'=>pos) 797 push gpad, captscope 798 push gpad, captob 799 %Xcaptscope = captob 800 local_branch cstack, %E 801 captob = pop gpad 802 captscope = pop gpad 803 %Cif cutmark != %c goto fail 804 %Ccutmark = 0 805 goto fail 806 %L_close: 807 push ustack, captscope 808 captob = pop gpad 809 captscope = pop gpad 810 $P1 = getattribute captob, '$.pos' 811 $P1 = pos 812 %1 813 push ustack, captob 814 local_branch cstack, %S 815 captob = pop ustack 816 %2 817 push gpad, captscope 818 push gpad, captob 819 captscope = pop ustack 820 goto fail\n 821 CODE 822 .local pmc exp 823 exp = self[0] 824 exp.'pir'(code, explabel, expnext) 825 .return () 826.end 827 828 829.namespace [ 'PGE';'Exp';'Subrule' ] 830 831.sub 'reduce' :method 832 .param pmc next 833 .return (self) 834.end 835 836.sub 'pir' :method 837 .param pmc code 838 .param string label 839 .param string next 840 841 .local pmc args 842 args = self.'getargs'(label, next) 843 844 .local pmc escape 845 escape = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 846 847 .local string subarg 848 subarg = '' 849 $I0 = exists self['arg'] 850 if $I0 == 0 goto subarg_dba 851 subarg = self['arg'] 852 subarg = escape(subarg) 853 subarg = concat ', ', subarg 854 args['A'] = $S0 855 subarg_dba: 856 $I0 = exists self['dba'] 857 if $I0 == 0 goto subarg_end 858 $S0 = self['dba'] 859 $S0 = escape($S0) 860 subarg .= ", 'dba'=>" 861 subarg .= $S0 862 subarg_end: 863 864 .local string cname, captgen, captsave, captback 865 (captgen, captsave, captback) = self.'gencapture'(label) 866 867 .local string subname 868 subname = self['subname'] 869 subrule: 870 $I0 = 0 871 subrule_1: 872 $I1 = index subname, '::', $I0 873 if $I1 == -1 goto subrule_2 874 $I0 = $I1 + 2 875 goto subrule_1 876 subrule_2: 877 if $I0 == 0 goto subrule_simple_name 878 ## The subrule is of the form <Grammar::rule>, which means we need 879 ## to create a Match object of the appropriate grammar (class) for it. 880 .local string grammar, rname 881 rname = substr subname, $I0 882 $I0 -= 2 883 grammar = substr subname, 0, $I0 884 $P0 = split '::', grammar 885 $P1 = get_root_global ['parrot';'PGE';'Util'], 'pir_key_escape' 886 $P0 = $P1($P0 :flat) 887 code.'append_format'(<<" CODE", grammar, rname, $P0, args :flat :named) 888 %L: # grammar subrule %0::%1 889 captob = captscope.'new'(captscope, 'grammar'=>'%0') 890 captob.'to'(pos) 891 $P0 = get_hll_global %2, '%1' 892 CODE 893 goto subrule_match 894 895 subrule_simple_name: 896 ## The subrule is of the form <rule>, which means we first look 897 ## for a method on the current match object, otherwise we do a 898 ## normal name lookup. 899 code.'append_format'(<<" CODE", subname, args :flat :named) 900 %L: # subrule %0 901 captob = captscope 902 $P0 = getattribute captob, '$.pos' 903 $P0 = pos 904 $I0 = can mob, '%0' 905 if $I0 == 0 goto %L_1 906 $P0 = find_method mob, '%0' 907 goto %L_2 908 %L_1: 909 $P0 = find_name '%0' 910 unless null $P0 goto %L_2 911 die "Unable to find regex '%0'" 912 %L_2: 913 CODE 914 915 subrule_match: 916 $I0 = self['iszerowidth'] 917 if $I0 goto subrule_zerowidth 918 $S0 = concat label, '_3' 919 $I0 = self['backtrack'] 920 if $I0 != PGE_BACKTRACK_NONE goto subrule_match_1 921 $S0 = next 922 subrule_match_1: 923 ## Perform the subrule match, capturing the result as needed. 924 ## We either branch directly to the next node (PGE_BACKTRACK_NONE) 925 ## or to a small subroutine below that will keep backtracking into 926 ## the subrule until it no longer produces a match. 927 code.'append_format'(<<" CODE", PGE_CUT_MATCH, $S0, captgen, captsave, captback, subarg) 928 $P2 = adverbs['action'] 929 captob = $P0(captob%5, 'action'=>$P2) 930 $P1 = getattribute captob, '$.pos' 931 if $P1 <= %0 goto fail_match 932 if $P1 < 0 goto fail 933 %2 934 %3 935 pos = $P1 936 local_branch cstack, %1 937 %4 938 goto fail 939 CODE 940 if $I0 == PGE_BACKTRACK_NONE goto end 941 ## Repeatedly backtrack into the subrule until there are no matches. 942 code.'append_format'(<<" CODE", PGE_CUT_MATCH, $S0, next) 943 %1: 944 pos = $P1 945 $P1 = getattribute captob, '&!corou' 946 if null $P1 goto %2 947 push ustack, captob 948 local_branch cstack, %2 949 captob = pop ustack 950 if cutmark != 0 goto fail 951 captob.'next'() 952 $P1 = getattribute captob, '$.pos' 953 if $P1 >= 0 goto %1 954 if $P1 <= %0 goto fail_match 955 goto fail\n 956 CODE 957 goto end 958 .return() 959 960 subrule_zerowidth: 961 ## this handles zero-width subrule matches, either positive 962 ## or negative. 963 .local string test 964 test = 'if' 965 $I0 = self['isnegated'] 966 unless $I0 goto have_test 967 test = 'unless' 968 have_test: 969 code.'append_format'(<<" CODE", PGE_CUT_MATCH, test, next, subarg) 970 captob = $P0(captob%3) 971 $P1 = getattribute captob, '$.pos' 972 if $P1 <= %0 goto fail_match 973 %1 $P1 < 0 goto fail 974 $P1 = pos 975 $P1 = getattribute captob, '$.from' 976 $P1 = pos 977 goto %2 978 CODE 979 end: 980 .return() 981.end 982 983 984.namespace [ 'PGE';'Exp';'Alt' ] 985 986.sub 'reduce' :method 987 .param pmc next 988 .local pmc exp0, exp1 989 exp0 = self[0] 990 exp0 = exp0.'reduce'(next) 991 self[0] = exp0 992 exp1 = self[1] 993 exp1 = exp1.'reduce'(next) 994 self[1] = exp1 995 .return (self) 996.end 997 998 999.sub 'pir' :method 1000 .param pmc code 1001 .param string label 1002 .param string next 1003 .local pmc exp0, exp1 1004 .local string exp0label, exp1label 1005 $P0 = get_root_global ['parrot';'PGE';'Util'], 'unique' 1006 exp0label = $P0('R') 1007 exp1label = $P0('R') 1008 code.'append_format'(<<" CODE", label, exp0label, exp1label) 1009 %0: # alt %1, %2 1010 push ustack, pos 1011 local_branch cstack, %1 1012 pos = pop ustack 1013 if cutmark != 0 goto fail 1014 goto %2\n 1015 CODE 1016 exp0 = self[0] 1017 exp0.'pir'(code, exp0label, next) 1018 exp1 = self[1] 1019 exp1.'pir'(code, exp1label, next) 1020 .return () 1021.end 1022 1023 1024.namespace [ 'PGE';'Exp';'Anchor' ] 1025 1026.sub 'reduce' :method 1027 .param pmc next 1028 .return (self) 1029.end 1030 1031.sub 'pir' :method 1032 .param pmc code 1033 .param pmc label 1034 .param pmc next 1035 .local string token, test 1036 token = self.'ast'() 1037 1038 if token == '<?>' goto anchor_null 1039 if token == '^' goto anchor_bos 1040 if token == '$' goto anchor_eos 1041 if token == '^^' goto anchor_bol 1042 if token == '$$' goto anchor_eol 1043 if token == '<<' goto anchor_word_left 1044 if token == '>>' goto anchor_word_right 1045 if token == unicode:"\xab" goto anchor_word_left 1046 if token == unicode:"\xbb" goto anchor_word_right 1047 test = '!=' 1048 if token == '\b' goto anchor_word 1049 test = '==' 1050 if token == '\B' goto anchor_word 1051 1052 anchor_fail: 1053 code.'append_format'(" %0: # anchor fail %1\n", label, token) 1054 code.'append_format'(" goto fail\n") 1055 .return () 1056 1057 anchor_null: 1058 code.'append_format'(" %0: # anchor null %1\n", label, token) 1059 code.'append_format'(" goto %0\n", next) 1060 .return () 1061 1062 anchor_bos: 1063 code.'append_format'(" %0: # anchor bos\n", label) 1064 code.'append_format'(" if pos == 0 goto %0\n", next) 1065 code.'append_format'(" goto fail\n") 1066 .return () 1067 1068 anchor_eos: 1069 code.'append_format'(" %0: # anchor eos\n", label) 1070 code.'append_format'(" if pos == lastpos goto %0\n", next) 1071 code.'append_format'(" goto fail\n") 1072 .return () 1073 1074 anchor_bol: 1075 code.'append_format'(<<" CODE", label, next, .CCLASS_NEWLINE) 1076 %0: # anchor bol 1077 if pos == 0 goto %1 1078 if pos == lastpos goto fail 1079 $I0 = pos - 1 1080 $I1 = is_cclass %2, target, $I0 1081 if $I1 goto %1 1082 goto fail\n 1083 CODE 1084 .return () 1085 1086 anchor_eol: 1087 code.'append_format'(<<" CODE", label, next, .CCLASS_NEWLINE) 1088 %0: # anchor eol 1089 $I1 = is_cclass %2, target, pos 1090 if $I1 goto %1 1091 if pos != lastpos goto fail 1092 if pos < 1 goto %1 1093 $I0 = pos - 1 1094 $I1 = is_cclass %2, target, $I0 1095 if $I1 == 0 goto %1 1096 goto fail\n 1097 CODE 1098 .return () 1099 1100 anchor_word: 1101 code.'append_format'(<<" CODE", label, next, .CCLASS_WORD, test) 1102 %0: # anchor word 1103 $I0 = 0 1104 if pos == 0 goto %0_1 1105 $I2 = pos - 1 1106 $I0 = is_cclass %2, target, $I2 1107 %0_1: 1108 $I1 = 0 1109 if pos >= lastpos goto %0_2 1110 $I1 = is_cclass %2, target, pos 1111 %0_2: 1112 if $I0 %3 $I1 goto %1 1113 goto fail 1114 CODE 1115 .return () 1116 1117 anchor_word_left: 1118 code.'append_format'(<<" CODE", label, next, .CCLASS_WORD) 1119 %0: # left word boundary 1120 if pos >= lastpos goto fail 1121 $I0 = is_cclass %2, target, pos 1122 if $I0 == 0 goto fail 1123 if pos == 0 goto %1 1124 $I0 = pos - 1 1125 $I0 = is_cclass %2, target, $I0 1126 if $I0 goto fail 1127 goto %1 1128 CODE 1129 .return () 1130 1131 anchor_word_right: 1132 code.'append_format'(<<" CODE", label, next, .CCLASS_WORD) 1133 %0: # right word boundary 1134 if pos == 0 goto fail 1135 $I0 = pos - 1 1136 $I0 = is_cclass %2, target, $I0 1137 if $I0 == 0 goto fail 1138 if pos >= lastpos goto %1 1139 $I0 = is_cclass %2, target, pos 1140 if $I0 goto fail 1141 goto %1 1142 CODE 1143 .return () 1144 1145.end 1146 1147 1148.namespace [ 'PGE';'Exp';'CCShortcut' ] 1149 1150.sub 'reduce' :method 1151 .param pmc next 1152 1153 .local string token 1154 token = self.'ast'() 1155 self['negate'] = 1 1156 if token == '\D' goto digit 1157 if token == '\S' goto space 1158 if token == '\W' goto word 1159 if token == '\N' goto newline 1160 self['negate'] = 0 1161 if token == '\d' goto digit 1162 if token == '\s' goto space 1163 if token == '\w' goto word 1164 if token == '\n' goto newline 1165 self['cclass'] = .CCLASS_ANY 1166 goto end 1167 digit: 1168 self['cclass'] = .CCLASS_NUMERIC 1169 goto end 1170 space: 1171 self['cclass'] = .CCLASS_WHITESPACE 1172 goto end 1173 word: 1174 self['cclass'] = .CCLASS_WORD 1175 goto end 1176 newline: 1177 self['cclass'] = .CCLASS_NEWLINE 1178 end: 1179 .return (self) 1180.end 1181 1182 1183.sub 'pir' :method 1184 .param pmc code 1185 .param string label 1186 .param string next 1187 .local int cclass, negate 1188 1189 $S0 = self.'ast'() 1190 code.'append_format'(" %0: # cclass %1\n", label, $S0) 1191 code.'append_format'(" if pos >= lastpos goto fail\n") 1192 cclass = self['cclass'] 1193 negate = self['negate'] 1194 if cclass == .CCLASS_ANY goto end 1195 code.'append_format'(" $I0 = is_cclass %0, target, pos\n", cclass) 1196 code.'append_format'(" if $I0 == %0 goto fail\n", negate) 1197 end: 1198 code.'append_format'(" inc pos\n") 1199 code.'append_format'(" goto %0\n", next) 1200 .return () 1201.end 1202 1203 1204.sub 'pir_quant' :method 1205 .param pmc code 1206 .param string label 1207 .param string next 1208 .param pmc quant 1209 1210 .local pmc args 1211 .local int min, max, backtrack 1212 args = self.'getargs'(label, next, 'quant'=>quant) 1213 min = quant['min'] 1214 max = quant['max'] 1215 backtrack = quant['backtrack'] 1216 1217 ## output initial label 1218 code.'append_format'(" %L: # cclass %0 %Q\n", self, args :flat :named) 1219 1220 .local int cclass, negate 1221 cclass = self['cclass'] 1222 negate = self['negate'] 1223 if cclass == .CCLASS_ANY goto emit_dot 1224 .local string negstr 1225 negstr = '_not' 1226 if negate == 0 goto emit_find 1227 negstr = '' 1228 emit_find: 1229 code.'append_format'(<<" CODE", negstr, cclass) 1230 $I0 = find%0_cclass %1, target, pos, lastpos 1231 rep = $I0 - pos 1232 CODE 1233 goto emit_pir 1234 emit_dot: 1235 code.'append_format'(" rep = lastpos - pos\n") 1236 1237 emit_pir: 1238 code.'append_format'(<<" CODE", args :flat :named) 1239 %Mif rep < %m goto fail 1240 %Nif rep <= %n goto %L_1 1241 %Nrep = %n 1242 %L_1: 1243 CODE 1244 1245 if backtrack == PGE_BACKTRACK_NONE goto bt_none 1246 if backtrack == PGE_BACKTRACK_EAGER goto bt_eager 1247 1248 bt_greedy: 1249 code.'append_format'(<<" CODE", args :flat :named) 1250 pos += rep 1251 %L_2: 1252 if rep <= %m goto %S 1253 push ustack, pos 1254 push ustack, rep 1255 local_branch cstack, %S 1256 rep = pop ustack 1257 pos = pop ustack 1258 if cutmark != 0 goto fail 1259 dec pos 1260 dec rep 1261 goto %L_2 1262 CODE 1263 .return (1) 1264 1265 bt_none: 1266 code.'append_format'(" pos += rep\n goto %0\n", next) 1267 .return (1) 1268 1269 bt_eager: 1270 code.'append_format'(<<" CODE", args :flat :named) 1271 %Mpos += %m 1272 %Mrep -= %m 1273 %L_2: 1274 if rep == 0 goto %S 1275 push ustack, pos 1276 push ustack, rep 1277 local_branch cstack, %S 1278 rep = pop ustack 1279 pos = pop ustack 1280 if cutmark != 0 goto fail 1281 inc pos 1282 dec rep 1283 goto %L_2 1284 CODE 1285 .return (1) 1286 1287.end 1288 1289.namespace [ 'PGE';'Exp';'Cut' ] 1290 1291.sub 'reduce' :method 1292 .param pmc next 1293 .local pmc group 1294 .local int cutmark 1295 1296 cutmark = self['cutmark'] 1297 if cutmark <= PGE_CUT_RULE goto end 1298 ## This node is cutting a group. We need to 1299 ## get the current group's cutmark, or set 1300 ## one if it doesn't already have one. 1301 group = get_hll_global ['PGE';'Exp'], '$!group' 1302 cutmark = group['cutmark'] 1303 if cutmark > 0 goto has_cutmark 1304 $P1 = get_root_global ['parrot';'PGE';'Util'], 'unique' 1305 cutmark = $P1() 1306 group['cutmark'] = cutmark 1307 has_cutmark: 1308 self['cutmark'] = cutmark 1309 end: 1310 .return (self) 1311.end 1312 1313.sub 'pir' :method 1314 .param pmc code 1315 .param string label 1316 .param string next 1317 1318 .local int cutmark 1319 cutmark = self['cutmark'] 1320 1321 if cutmark > 0 goto group_cutmark 1322 code.'append_format'(<<" CODE", label, next, cutmark) 1323 %0: # cut rule or match 1324 local_branch cstack, %1 1325 cutmark = %2 1326 goto fail_cut\n 1327 CODE 1328 .return () 1329 1330 group_cutmark: 1331 code.'append_format'(<<" CODE", label, next, cutmark) 1332 %0: # cut %2 1333 local_branch cstack, %1 1334 cutmark = %2 1335 goto fail\n 1336 CODE 1337 .return () 1338.end 1339 1340 1341.namespace [ 'PGE';'Exp';'Scalar' ] 1342 1343.sub 'reduce' :method 1344 .param pmc next 1345 .return (self) 1346.end 1347 1348.sub 'pir' :method 1349 .param pmc code 1350 .param string label 1351 .param string next 1352 1353 .local string cname 1354 cname = self['cname'] 1355 code.'append_format'(<<" CODE", label, next, cname) 1356 %0: # scalar %2 1357 $P0 = mob[%2] 1358 $I0 = does $P0, 'array' 1359 if $I0 == 0 goto %0_1 1360 $P0 = $P0[-1] 1361 %0_1: 1362 $S1 = $P0 1363 $I1 = length $S1 1364 $I0 = pos + $I1 1365 if $I0 > lastpos goto fail 1366 $S0 = substr target, pos, $I1 1367 if $S0 != $S1 goto fail 1368 pos += $I1 1369 goto %1 1370 CODE 1371 .return () 1372.end 1373 1374 1375.namespace [ 'PGE';'Exp';'EnumCharList' ] 1376 1377.sub 'reduce' :method 1378 .param pmc next 1379 .return (self) 1380.end 1381 1382.sub 'pir' :method 1383 .param pmc code 1384 .param string label 1385 .param string next 1386 1387 .local pmc escape 1388 escape = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 1389 1390 .local string charlist 1391 $S0 = self.'ast'() 1392 charlist = escape($S0) 1393 1394 .local string test 1395 test = '<' 1396 $I0 = self['isnegated'] 1397 if $I0 == 0 goto negated_end 1398 test = '>=' 1399 negated_end: 1400 .local string incpos 1401 incpos = 'inc pos' 1402 $I0 = self['iszerowidth'] 1403 if $I0 == 0 goto zerowidth_end 1404 incpos = '### zero width' 1405 zerowidth_end: 1406 1407 code.'append_format'(<<" CODE", label, charlist, test, incpos, next) 1408 %0: # enumcharlist %1 1409 if pos >= lastpos goto fail 1410 $S0 = substr target, pos, 1 1411 $I0 = index %1, $S0 1412 if $I0 %2 0 goto fail 1413 %3 1414 goto %4 1415 CODE 1416 .return () 1417.end 1418 1419 1420.namespace [ 'PGE';'Exp';'Newline' ] 1421 1422.sub 'reduce' :method 1423 .param pmc next 1424 .return (self) 1425.end 1426 1427.sub 'pir' :method 1428 .param pmc code 1429 .param string label 1430 .param string next 1431 code.'append_format'(<<" CODE", label, next, .CCLASS_NEWLINE) 1432 %0: # newline 1433 $I0 = is_cclass %2, target, pos 1434 if $I0 == 0 goto fail 1435 $S0 = substr target, pos, 2 1436 inc pos 1437 if $S0 != "\\r\\n" goto %1 1438 inc pos 1439 goto %1 1440 CODE 1441 .return () 1442.end 1443 1444 1445.namespace [ 'PGE';'Exp';'Conj' ] 1446 1447.sub 'reduce' :method 1448 .param pmc next 1449 .local pmc exp0, exp1 1450 exp0 = self[0] 1451 exp0 = exp0.'reduce'(next) 1452 self[0] = exp0 1453 exp1 = self[1] 1454 exp1 = exp1.'reduce'(next) 1455 self[1] = exp1 1456 .return (self) 1457.end 1458 1459.sub 'pir' :method 1460 .param pmc code 1461 .param string label 1462 .param string next 1463 1464 .local string exp0label, exp1label, chk0label, chk1label 1465 $P0 = get_root_global ['parrot';'PGE';'Util'], 'unique' 1466 exp0label = $P0('R') 1467 exp1label = $P0('R') 1468 chk0label = concat label, '_chk0' 1469 chk1label = concat label, '_chk1' 1470 code.'append_format'(<<" CODE", label, next, exp0label, chk0label, exp1label, chk1label) 1471 %0: # conj %2, %4 1472 push gpad, pos 1473 push gpad, pos 1474 local_branch cstack, %2 1475 $I0 = pop gpad 1476 $I0 = pop gpad 1477 goto fail 1478 %3: 1479 gpad[-1] = pos 1480 pos = gpad[-2] 1481 goto %4 1482 %5: 1483 $I0 = gpad[-1] 1484 if $I0 != pos goto fail 1485 $I0 = pop gpad 1486 $I1 = pop gpad 1487 push ustack, $I1 1488 push ustack, $I0 1489 local_branch cstack, %1 1490 $I0 = pop ustack 1491 $I1 = pop ustack 1492 push gpad, $I1 1493 push gpad, $I0 1494 goto fail\n 1495 CODE 1496 .local pmc exp0, exp1 1497 exp0 = self[0] 1498 exp0.'pir'(code, exp0label, chk0label) 1499 exp1 = self[1] 1500 exp1.'pir'(code, exp1label, chk1label) 1501 .return () 1502.end 1503 1504.namespace [ 'PGE';'Exp';'Closure' ] 1505 1506.sub 'reduce' :method 1507 .param pmc next 1508 .return (self) 1509.end 1510 1511.sub 'pir' :method 1512 .param pmc code 1513 .param string label 1514 .param string next 1515 1516 .local pmc escape 1517 escape = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 1518 1519 .local string value, lang 1520 value = self.'ast'() 1521 lang = self['lang'] 1522 value = escape(value) 1523 lang = escape(lang) 1524 ## to prevent recompiling every execution, this code makes use of 1525 ## a global %!cache, keyed on the inline closure source. There 1526 ## could be a (unlikely) problem if the same source is sent to 1527 ## two different compilers. Also, if the sources can be lengthy 1528 ## we might be well served to use a hashed representation of 1529 ## the source. 1530 code.'append_format'(<<" CODE", label, lang, value) 1531 %0: # closure 1532 $S1 = %2 1533 $P0 = get_hll_global ['PGE';'Match'], '%!cache' 1534 $P1 = $P0[$S1] 1535 unless null $P1 goto %0_1 1536 $P1 = compreg %1 1537 $P1 = $P1($S1) 1538 $P1 = $P1.'first_sub_in_const_table'() 1539 $P0[$S1] = $P1 1540 %0_1: 1541 CODE 1542 $I0 = self['iszerowidth'] 1543 if $I0 goto closure_zerowidth 1544 code.'append_format'(<<" CODE", next) 1545 mpos = pos 1546 ($P0 :optional, $I0 :opt_flag) = $P1(mob) 1547 if $I0 == 0 goto %0 1548 mob.'!make'($P0) 1549 push ustack, pos 1550 local_branch cstack, succeed 1551 pos = pop ustack 1552 null $P0 1553 mob.'!make'($P0) 1554 goto fail 1555 CODE 1556 .return () 1557 closure_zerowidth: 1558 ## we're doing a <?{{ or <!{{ assertion. 1559 .local string test 1560 test = 'if' 1561 $I0 = self['isnegated'] 1562 unless $I0 goto have_test 1563 test = 'unless' 1564 have_test: 1565 code.'append_format'(<<" CODE", test, next) 1566 mpos = pos 1567 $P0 = $P1(mob) 1568 %0 $P0 goto %1 1569 goto fail 1570 CODE 1571 .return () 1572.end 1573 1574.namespace [ 'PGE';'Exp';'Action' ] 1575 1576.sub 'reduce' :method 1577 .param pmc next 1578 .return (self) 1579.end 1580 1581.sub 'pir' :method 1582 .param pmc code 1583 .param string label 1584 .param string next 1585 .local pmc escape 1586 escape = get_root_global ['parrot';'PGE';'Util'], 'pir_str_escape' 1587 .local string actionname, actionkey 1588 code.'append_format'(" %0: # action\n", label) 1589 actionname = self['actionname'] 1590 if actionname == '' goto end 1591 actionname = escape(actionname) 1592 actionkey = self['actionkey'] 1593 if actionkey == '' goto have_actionkey 1594 actionkey = escape(actionkey) 1595 actionkey = concat ', ', actionkey 1596 have_actionkey: 1597 code.'append_format'(<<" CODE", label, next, actionname, actionkey) 1598 $P1 = adverbs['action'] 1599 if null $P1 goto %1 1600 $I1 = can $P1, %2 1601 if $I1 == 0 goto %1 1602 mpos = pos 1603 $P1.%2(mob%3) 1604 goto %1 1605 CODE 1606 end: 1607 .return () 1608.end 1609 1610=back 1611 1612=cut 1613 1614# Local Variables: 1615# mode: pir 1616# fill-column: 100 1617# End: 1618# vim: expandtab shiftwidth=4 ft=pir: 1619