package core import ( "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types" ) // CompileFor compiles a for loop. func (f *Function) CompileFor(loop *ast.For) error { for _, register := range f.CPU.Input { f.SaveRegister(register) } f.count.loop++ var ( label = f.CreateLabel("for", f.count.loop) labelEnd = f.CreateLabel("for end", f.count.loop) counter cpu.Register from *expression.Expression to *expression.Expression ) scope := f.PushScope(loop.Body, f.File.Bytes) scope.InLoop = true switch loop.Head.Token.Kind { case token.Define: variable, err := f.Define(loop.Head.Children[0]) if err != nil { return err } counter = variable.Register from = loop.Head.Children[1].Children[0] to = loop.Head.Children[1].Children[1] f.AddVariable(variable) case token.Range: counter = f.NewRegister() defer f.FreeRegister(counter) from = loop.Head.Children[0] to = loop.Head.Children[1] default: panic("could not recognize loop header") } _, err := f.ExpressionToRegister(from, counter) if err != nil { return err } if to.Token.IsNumeric() { number, err := f.ToNumber(to.Token) if err != nil { return err } f.AddLabel(label) f.RegisterNumber(asm.COMPARE, counter, number) } else { value, isTemporary, err := f.Evaluate(to) if err != nil { return err } if !types.Is(value.Type, types.AnyInt) { return errors.New(&errors.TypeMismatch{Encountered: value.Type.Name(), Expected: types.AnyInt.Name()}, f.File, to.Token.Position) } if isTemporary { defer f.FreeRegister(value.Register) } f.AddLabel(label) f.RegisterRegister(asm.COMPARE, counter, value.Register) } f.Jump(asm.JGE, labelEnd) err = f.CompileAST(loop.Body) f.RegisterNumber(asm.ADD, counter, 1) f.Jump(asm.JUMP, label) f.AddLabel(labelEnd) f.PopScope() return err }