| 3513 | | $oldpos = $here.pos; |
| 3514 | | my @infix = $here.cursor_fresh.infixish(); |
| 3515 | | last unless @infix; |
| 3516 | | my $infix = @infix[0]; |
| 3517 | | last unless $infix.pos > $oldpos; |
| 3518 | | |
| 3519 | | # XXX might want to allow this in a declaration though |
| 3520 | | if not $infix { $here.panic("Can't have two terms in a row") } |
| 3521 | | |
| 3522 | | if not $infix<sym> { |
| 3523 | | die $infix.dump if $*DEBUG +& DEBUG::EXPR; |
| 3524 | | } |
| 3525 | | |
| 3526 | | my $inO = $infix<O>; |
| 3527 | | $prevop = $inO; |
| 3528 | | my Str $inprec = $inO<prec>; |
| 3529 | | if not defined $inprec { |
| 3530 | | self.deb("No prec given in infix!") if $*DEBUG +& DEBUG::EXPR; |
| 3531 | | die $infix.dump if $*DEBUG +& DEBUG::EXPR; |
| 3532 | | $inprec = %terminator<prec>; |
| 3533 | | } |
| 3534 | | |
| 3535 | | last unless $inprec gt $preclim; |
| 3536 | | |
| 3537 | | $here = $infix.cursor_fresh.ws(); |
| 3538 | | |
| 3539 | | |
| 3540 | | # substitute precedence for listops |
| 3541 | | $inO<prec> = $inO<sub> if $inO<sub>; |
| 3542 | | |
| 3543 | | # Does new infix (or terminator) force any reductions? |
| 3544 | | while @opstack[*-1]<O><prec> gt $inprec { |
| 3545 | | reduce(); |
| 3546 | | } |
| 3547 | | |
| 3548 | | # Not much point in reducing the sentinels... |
| 3549 | | last if $inprec lt $LOOSEST; |
| 3550 | | |
| 3551 | | # Equal precedence, so use associativity to decide. |
| 3552 | | if @opstack[*-1]<O><prec> eq $inprec { |
| 3553 | | given $inO<assoc> { |
| 3554 | | when 'non' { $here.panic("\"$infix\" is not associative") } |
| 3555 | | when 'left' { reduce() } # reduce immediately |
| 3556 | | when 'right' { } # just shift |
| 3557 | | when 'chain' { } # just shift |
| 3558 | | when 'list' { # if op differs reduce else shift |
| 3559 | | reduce() if $infix<sym> !eqv @opstack[*-1]<sym>; |
| | 3502 | |
| | 3503 | loop { # while we see adverbs |
| | 3504 | $oldpos = $here.pos; |
| | 3505 | my @infix = $here.cursor_fresh.infixish(); |
| | 3506 | last TERM unless @infix; |
| | 3507 | my $infix = @infix[0]; |
| | 3508 | last TERM unless $infix.pos > $oldpos; |
| | 3509 | |
| | 3510 | if not $infix<sym> { |
| | 3511 | die $infix.dump if $*DEBUG +& DEBUG::EXPR; |
| | 3512 | } |
| | 3513 | |
| | 3514 | my $inO = $infix<O>; |
| | 3515 | my Str $inprec = $inO<prec>; |
| | 3516 | if not defined $inprec { |
| | 3517 | self.deb("No prec given in infix!") if $*DEBUG +& DEBUG::EXPR; |
| | 3518 | die $infix.dump if $*DEBUG +& DEBUG::EXPR; |
| | 3519 | $inprec = %terminator<prec>; |
| | 3520 | } |
| | 3521 | |
| | 3522 | last TERM unless $inprec gt $preclim; |
| | 3523 | |
| | 3524 | $here = $infix.cursor_fresh.ws(); |
| | 3525 | |
| | 3526 | |
| | 3527 | # substitute precedence for listops |
| | 3528 | $inO<prec> = $inO<sub> if $inO<sub>; |
| | 3529 | |
| | 3530 | # Does new infix (or terminator) force any reductions? |
| | 3531 | while @opstack[*-1]<O><prec> gt $inprec { |
| | 3532 | reduce(); |
| | 3533 | } |
| | 3534 | |
| | 3535 | # Not much point in reducing the sentinels... |
| | 3536 | last if $inprec lt $LOOSEST; |
| | 3537 | |
| | 3538 | # Equal precedence, so use associativity to decide. |
| | 3539 | if @opstack[*-1]<O><prec> eq $inprec { |
| | 3540 | given $inO<assoc> { |
| | 3541 | when 'non' { $here.panic("\"$infix\" is not associative") } |
| | 3542 | when 'left' { reduce() } # reduce immediately |
| | 3543 | when 'right' { } # just shift |
| | 3544 | when 'chain' { } # just shift |
| | 3545 | when 'list' { # if op differs reduce else shift |
| | 3546 | reduce() if $infix<sym> !eqv @opstack[*-1]<sym>; |
| | 3547 | } |
| | 3548 | default { $here.panic("Unknown associativity \"$_\" for \"$infix\"") } |