package core import ( "fmt" "git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/expression" ) // CompileCondition inserts code to jump to the start label or end label depending on the truth of the condition. func (f *Function) CompileCondition(condition *expression.Expression, successLabel string, failLabel string) error { switch condition.Token.Text() { case "||": f.count.subBranch++ leftFailLabel := fmt.Sprintf("%s_false_%d", f.Name, f.count.subBranch) // Left left := condition.Children[0] err := f.CompileCondition(left, successLabel, leftFailLabel) if err != nil { return err } f.JumpIfTrue(left.Token.Text(), successLabel) // Right f.AddLabel(leftFailLabel) right := condition.Children[1] err = f.CompileCondition(right, successLabel, failLabel) if condition.Parent != nil && condition.Parent.Token.Text() == "||" && condition != condition.Parent.LastChild() { f.JumpIfTrue(right.Token.Text(), successLabel) } else { f.JumpIfFalse(right.Token.Text(), failLabel) } return err case "&&": f.count.subBranch++ leftSuccessLabel := fmt.Sprintf("%s_true_%d", f.Name, f.count.subBranch) // Left left := condition.Children[0] err := f.CompileCondition(left, leftSuccessLabel, failLabel) if err != nil { return err } f.JumpIfFalse(left.Token.Text(), failLabel) // Right f.AddLabel(leftSuccessLabel) right := condition.Children[1] err = f.CompileCondition(right, successLabel, failLabel) if condition.Parent != nil && condition.Parent.Token.Text() == "||" && condition != condition.Parent.LastChild() { f.JumpIfTrue(right.Token.Text(), successLabel) } else { f.JumpIfFalse(right.Token.Text(), failLabel) } return err default: err := f.Compare(condition) if condition.Parent == nil { f.JumpIfFalse(condition.Token.Text(), failLabel) } return err } } // JumpIfFalse jumps to the label if the previous comparison was false. func (f *Function) JumpIfFalse(operator string, label string) { switch operator { case "==": f.Jump(asm.JNE, label) case "!=": f.Jump(asm.JE, label) case ">": f.Jump(asm.JLE, label) case "<": f.Jump(asm.JGE, label) case ">=": f.Jump(asm.JL, label) case "<=": f.Jump(asm.JG, label) } } // JumpIfTrue jumps to the label if the previous comparison was true. func (f *Function) JumpIfTrue(operator string, label string) { switch operator { case "==": f.Jump(asm.JE, label) case "!=": f.Jump(asm.JNE, label) case ">": f.Jump(asm.JG, label) case "<": f.Jump(asm.JL, label) case ">=": f.Jump(asm.JGE, label) case "<=": f.Jump(asm.JLE, label) } }