Implemented for loops

This commit is contained in:
2025-02-19 23:46:17 +01:00
parent 7922cff7ba
commit 45a36a645a
16 changed files with 142 additions and 120 deletions

View File

@ -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
}