Implemented for loops
This commit is contained in:
@ -5,92 +5,21 @@ import (
|
||||
|
||||
"git.akyoto.dev/cli/q/src/asm"
|
||||
"git.akyoto.dev/cli/q/src/ast"
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// CompileLoop compiles a loop instruction.
|
||||
// CompileLoop compiles an infinite loop.
|
||||
func (f *Function) CompileLoop(loop *ast.Loop) error {
|
||||
if loop.Head == nil {
|
||||
return f.CompileLoopInfinite(loop)
|
||||
}
|
||||
|
||||
for _, register := range f.CPU.Input {
|
||||
f.SaveRegister(register)
|
||||
}
|
||||
|
||||
f.count.loop++
|
||||
|
||||
var (
|
||||
label = fmt.Sprintf("%s_loop_%d", f.UniqueName, f.count.loop)
|
||||
labelEnd = fmt.Sprintf("%s_loop_%d_end", f.UniqueName, f.count.loop)
|
||||
counter cpu.Register
|
||||
from *expression.Expression
|
||||
to *expression.Expression
|
||||
)
|
||||
|
||||
label := fmt.Sprintf("%s_loop_%d", f.UniqueName, f.count.loop)
|
||||
f.AddLabel(label)
|
||||
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 {
|
||||
_, register, isTemporary, err := f.Evaluate(to)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isTemporary {
|
||||
defer f.FreeRegister(register)
|
||||
}
|
||||
|
||||
f.AddLabel(label)
|
||||
f.RegisterRegister(asm.COMPARE, counter, register)
|
||||
}
|
||||
|
||||
f.Jump(asm.JGE, labelEnd)
|
||||
err = f.CompileAST(loop.Body)
|
||||
f.RegisterNumber(asm.ADD, counter, 1)
|
||||
err := f.CompileAST(loop.Body)
|
||||
f.Jump(asm.JUMP, label)
|
||||
f.AddLabel(labelEnd)
|
||||
f.PopScope()
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user