@@ -36,6 +36,7 @@ import {
3636 FunctionCallNode ,
3737 UnaryOpNode ,
3838 BinaryOpNode ,
39+ TernaryNode ,
3940 BoolLiteralNode ,
4041 IntLiteralNode ,
4142 HexLiteralNode ,
@@ -806,6 +807,31 @@ export default class GenerateTargetTraversal extends AstTraversal {
806807 return node ;
807808 }
808809
810+ // A ternary `condition ? consequent : alternative` compiles to OP_IF <consequent> OP_ELSE <alternative> OP_ENDIF.
811+ // The condition is consumed by OP_IF; each branch leaves exactly one value, so the net effect mirrors any other
812+ // expression: one operand consumed, one result produced. We bump scopeDepth (so variable reads inside the branches
813+ // use OP_PICK rather than OP_ROLL, keeping the stack depth identical on both paths) and reset the symbolic stack
814+ // before the alternative so both branches are tracked from the same starting point.
815+ visitTernary ( node : TernaryNode ) : Node {
816+ node . condition = this . visit ( node . condition ) ;
817+ this . popFromStack ( ) ;
818+
819+ this . scopeDepth += 1 ;
820+
821+ this . emit ( Op . OP_IF , { location : node . consequent . location , positionHint : PositionHint . START } ) ;
822+ const stackCopy = [ ...this . stack ] ;
823+ node . consequent = this . visit ( node . consequent ) ;
824+
825+ this . emit ( Op . OP_ELSE , { location : node . alternative . location , positionHint : PositionHint . START } ) ;
826+ this . stack = [ ...stackCopy ] ;
827+ node . alternative = this . visit ( node . alternative ) ;
828+
829+ this . emit ( Op . OP_ENDIF , { location : node . location , positionHint : PositionHint . END } ) ;
830+ this . scopeDepth -= 1 ;
831+
832+ return node ;
833+ }
834+
809835 visitNullaryOp ( node : NullaryOpNode ) : Node {
810836 this . emit ( compileNullaryOp ( node . operator ) , { location : node . location , positionHint : PositionHint . START } ) ;
811837 this . pushToStack ( '(value)' ) ;
0 commit comments