44 "fmt"
55
66 "github.com/thiremani/pluto/ast"
7+ "github.com/thiremani/pluto/token"
78 "tinygo.org/x/go-llvm"
89)
910
@@ -401,10 +402,10 @@ func (c *Compiler) valuesHaveCondExpr(values []ast.Expression) bool {
401402}
402403
403404// hasCondExprInTree returns true if any node in the expression tree has
404- // CondScalar set (a scalar comparison in value position) .
405+ // conditional value lowering .
405406func (c * Compiler ) hasCondExprInTree (expr ast.Expression ) bool {
406407 info := c .ExprCache [key (c .FuncNameMangled , expr )]
407- if info != nil && info .HasCondScalar () {
408+ if info != nil && info .HasCondExpr () {
408409 return true
409410 }
410411 for _ , child := range ast .ExprChildren (expr ) {
@@ -415,6 +416,28 @@ func (c *Compiler) hasCondExprInTree(expr ast.Expression) bool {
415416 return false
416417}
417418
419+ func (c * Compiler ) logicalOrCondExpr (expr ast.Expression ) (* ast.InfixExpression , bool ) {
420+ infix , ok := expr .(* ast.InfixExpression )
421+ if ! ok || infix .Operator != token .SYM_LOGICAL_OR {
422+ return nil , false
423+ }
424+
425+ info := c .ExprCache [key (c .FuncNameMangled , expr )]
426+ return infix , info != nil && info .HasCondOr ()
427+ }
428+
429+ func (c * Compiler ) hasLogicalOrCondExprInTree (expr ast.Expression ) bool {
430+ if _ , ok := c .logicalOrCondExpr (expr ); ok {
431+ return true
432+ }
433+ for _ , child := range ast .ExprChildren (expr ) {
434+ if c .hasLogicalOrCondExprInTree (child ) {
435+ return true
436+ }
437+ }
438+ return false
439+ }
440+
418441// handleComparisons processes each slot of a multi-return comparison based on
419442// its CondMode. CondScalar slots are compared and ANDed into cond. CondArray
420443// slots are compiled as array filters (source freed, marked borrowed).
@@ -494,13 +517,23 @@ func (c *Compiler) cleanupCondExprElse(temps []condTemp) {
494517 }
495518}
496519
497- // compileCondExprValue extracts cond-expr predicates for expr, branches on the
498- // combined condition (AND with baseCond when provided), and compiles onTrue on
499- // the true path only. False path performs standard cond-expr cleanup.
520+ // compileCondExprValue extracts cond-expr predicates for expr, branches through
521+ // value-position conditions, and compiles onTrue on admitted paths only. Plain
522+ // comparisons compose as AND; value-position logical OR tries the left operand
523+ // first and falls back to the right operand only on the left false path.
500524func (c * Compiler ) compileCondExprValue (expr ast.Expression , baseCond llvm.Value , onTrue func ()) {
501525 c .pushCondLHSFrame ()
502526 defer c .popCondLHSFrame ()
503527
528+ c .compileCondExprValueInFrame (expr , baseCond , onTrue )
529+ }
530+
531+ func (c * Compiler ) compileCondExprValueInFrame (expr ast.Expression , baseCond llvm.Value , onTrue func ()) {
532+ if c .hasLogicalOrCondExprInTree (expr ) {
533+ c .compileCondExprAlternative (expr , baseCond , onTrue , func () {})
534+ return
535+ }
536+
504537 cond , temps := c .extractCondExprs (expr , baseCond , nil )
505538 c .compileCondExprBranch (cond , temps , onTrue )
506539}
@@ -512,6 +545,11 @@ func (c *Compiler) compileOperandCondExprValue(expr ast.Expression, baseCond llv
512545 c .pushCondLHSFrame ()
513546 defer c .popCondLHSFrame ()
514547
548+ if c .hasLogicalOrCondExprInTree (expr ) {
549+ c .compileCondExprChildrenInFrame (ast .ExprChildren (expr ), baseCond , onTrue , func () {})
550+ return
551+ }
552+
515553 cond := baseCond
516554 var temps []condTemp
517555 for _ , child := range ast .ExprChildren (expr ) {
@@ -521,6 +559,10 @@ func (c *Compiler) compileOperandCondExprValue(expr ast.Expression, baseCond llv
521559}
522560
523561func (c * Compiler ) compileCondExprBranch (cond llvm.Value , temps []condTemp , onTrue func ()) {
562+ c .compileCondExprBranchWithFailure (cond , temps , onTrue , func () {})
563+ }
564+
565+ func (c * Compiler ) compileCondExprBranchWithFailure (cond llvm.Value , temps []condTemp , onTrue func (), onFalse func ()) {
524566 if cond .IsNil () {
525567 onTrue ()
526568 return
@@ -534,11 +576,90 @@ func (c *Compiler) compileCondExprBranch(cond llvm.Value, temps []condTemp, onTr
534576
535577 c .builder .SetInsertPointAtEnd (elseBlock )
536578 c .cleanupCondExprElse (temps )
579+ onFalse ()
537580 c .builder .CreateBr (contBlock )
538581
539582 c .builder .SetInsertPointAtEnd (contBlock )
540583}
541584
585+ func (c * Compiler ) compileCondExprChildrenInFrame (children []ast.Expression , baseCond llvm.Value , onTrue func (), onFalse func ()) {
586+ if len (children ) == 0 {
587+ c .compileCondExprBranchWithFailure (baseCond , nil , onTrue , onFalse )
588+ return
589+ }
590+
591+ child := children [0 ]
592+ rest := children [1 :]
593+ if c .hasCondExprInTree (child ) {
594+ c .compileCondExprAlternative (child , baseCond , func () {
595+ c .compileCondExprChildrenInFrame (rest , llvm.Value {}, onTrue , onFalse )
596+ }, onFalse )
597+ return
598+ }
599+
600+ c .compileCondExprChildrenInFrame (rest , baseCond , onTrue , onFalse )
601+ }
602+
603+ func (c * Compiler ) compileCondExprAlternative (expr ast.Expression , baseCond llvm.Value , onTrue func (), onFalse func ()) {
604+ if logicalOr , ok := c .logicalOrCondExpr (expr ); ok {
605+ c .compileLogicalOrCondExprAlternative (logicalOr , baseCond , onTrue , onFalse )
606+ return
607+ }
608+
609+ if ! c .hasLogicalOrCondExprInTree (expr ) {
610+ cond , temps := c .extractCondExprs (expr , baseCond , nil )
611+ c .compileCondExprBranchWithFailure (cond , temps , onTrue , onFalse )
612+ return
613+ }
614+
615+ c .compileCondExprChildrenInFrame (ast .ExprChildren (expr ), baseCond , func () {
616+ if infix , ok := expr .(* ast.InfixExpression ); ok {
617+ info := c .ExprCache [key (c .FuncNameMangled , infix )]
618+ if info != nil && info .HasCondScalar () && len (c .pendingLoopRanges (info .Ranges )) == 0 {
619+ left := c .compileExpression (infix .Left , nil )
620+ right := c .compileExpression (infix .Right , nil )
621+
622+ lhsSyms , cond := c .handleComparisons (infix .Operator , left , right , info , llvm.Value {})
623+ c .requireCondLHSFrame ()[key (c .FuncNameMangled , expr )] = lhsSyms
624+ temps := []condTemp {{infix .Left , left }}
625+ c .freeTemporary (infix .Right , right )
626+ c .compileCondExprBranchWithFailure (cond , temps , onTrue , onFalse )
627+ return
628+ }
629+ }
630+
631+ onTrue ()
632+ }, onFalse )
633+ }
634+
635+ func (c * Compiler ) withCondLHS (expr ast.Expression , syms []* Symbol , body func ()) {
636+ frame := c .requireCondLHSFrame ()
637+ exprKey := key (c .FuncNameMangled , expr )
638+ old , hadOld := frame [exprKey ]
639+ frame [exprKey ] = syms
640+ body ()
641+ if hadOld {
642+ frame [exprKey ] = old
643+ return
644+ }
645+ delete (frame , exprKey )
646+ }
647+
648+ func (c * Compiler ) compileLogicalOrCondExprAlternative (expr * ast.InfixExpression , baseCond llvm.Value , onTrue func (), onFalse func ()) {
649+ leftTrue := func () {
650+ left := c .compileExpression (expr .Left , nil )
651+ c .withCondLHS (expr , left , onTrue )
652+ }
653+ rightTrue := func () {
654+ right := c .compileExpression (expr .Right , nil )
655+ c .withCondLHS (expr , right , onTrue )
656+ }
657+
658+ c .compileCondExprAlternative (expr .Left , baseCond , leftTrue , func () {
659+ c .compileCondExprAlternative (expr .Right , baseCond , rightTrue , onFalse )
660+ })
661+ }
662+
542663func (c * Compiler ) isRangeDriverCond (expr ast.Expression ) bool {
543664 info := c .ExprCache [key (c .FuncNameMangled , expr )]
544665 if len (info .OutTypes ) != 1 {
0 commit comments