Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125package core
import ( "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types")
// 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, thenBlock *ssa.Block, elseBlock *ssa.Block) error { f.Block().AddSuccessor(thenBlock) f.Block().AddSuccessor(elseBlock)
switch condition.Token.Kind { case token.LogicalOr: f.Count.SubBranch++ leftFailLabel := f.CreateLabel("or", f.Count.SubBranch) leftFail := ssa.NewBlock(leftFailLabel)
// Left left := condition.Children[0] err := f.compileCondition(left, thenBlock, leftFail)
if err != nil { return err }
f.AddBlock(leftFail)
// Right right := condition.Children[1] err = f.compileCondition(right, thenBlock, elseBlock) return err case token.LogicalAnd: f.Count.SubBranch++ leftSuccessLabel := f.CreateLabel("and", f.Count.SubBranch) leftSuccess := ssa.NewBlock(leftSuccessLabel)
// Left left := condition.Children[0] err := f.compileCondition(left, leftSuccess, elseBlock)
if err != nil { return err }
f.AddBlock(leftSuccess)
// Right right := condition.Children[1] err = f.compileCondition(right, thenBlock, elseBlock) return err case token.Equal, token.NotEqual, token.Greater, token.Less, token.GreaterEqual, token.LessEqual: conditionValue, err := f.evaluateRight(condition)
if err != nil { return err }
binaryOp, isBinaryOp := conditionValue.(*ssa.BinaryOp)
if isBinaryOp && binaryOp.Op.IsComparison() { left := binaryOp.Left
if left.Type() == types.Error { right := binaryOp.Right.(*ssa.Int)
switch { case condition.Token.Kind == token.NotEqual && right.Int == 0: for _, protected := range thenBlock.Protected[left] { thenBlock.Unidentify(protected) }
thenBlock.Unprotect(left) elseBlock.Unidentify(left) elseBlock.Unprotect(left) case condition.Token.Kind == token.Equal && right.Int == 0: for _, protected := range elseBlock.Protected[left] { elseBlock.Unidentify(protected) }
elseBlock.Unprotect(left) thenBlock.Unidentify(left) thenBlock.Unprotect(left) } } }
branch := &ssa.Branch{ Condition: conditionValue, Then: thenBlock, Else: elseBlock, }
f.Append(branch) return nil case token.Not: return f.compileCondition(condition.Children[0], elseBlock, thenBlock) default: if condition.Token.Kind.IsAssignment() { return errors.New(InvalidCondition, f.File, condition.Token) }
value, err := f.evaluateRight(condition)
if err != nil { return err }
if !types.Is(value.Type(), types.Bool) { return errors.New(&TypeMismatch{Encountered: value.Type().Name(), Expected: types.Bool.Name()}, f.File, condition.Source()) }
branch := &ssa.Branch{ Condition: value, Then: thenBlock, Else: elseBlock, }
f.Append(branch) return nil }}