q/src/core/CompileCall.go

83 lines
2.1 KiB
Go

package core
import (
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/eval"
"git.urbach.dev/cli/q/src/expression"
"git.urbach.dev/cli/q/src/token"
"git.urbach.dev/cli/q/src/types"
)
// CompileCall executes a function call.
// All call registers must hold the correct parameter values before the function invocation.
// Registers that are in use must be saved if they are modified by the function.
// After the function call, they must be restored in reverse order.
func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error) {
if root.Children[0].Token.Kind == token.Identifier {
name := root.Children[0].Token.Text(f.File.Bytes)
switch name {
case "len":
return _len.OutputTypes, f.CompileLen(root)
case "syscall":
return nil, f.CompileSyscall(root)
case "new":
typ, err := f.CompileNew(root)
return []types.Type{typ}, err
case "delete":
return nil, f.CompileDelete(root)
case "store":
return nil, f.CompileMemoryStore(root)
}
}
value, err := f.Evaluate(root.Children[0])
if err != nil {
return nil, err
}
parameters := root.Children[1:]
registers := f.CPU.Input[:len(parameters)]
switch value := value.(type) {
case *eval.Label:
fn, exists := f.All.Functions[value.Label]
if !exists {
if value.Label == "main.main" && f.UniqueName == "core.init" {
f.Label(asm.CALL, "main.main")
return nil, nil
}
return nil, errors.New(&errors.UnknownIdentifier{Name: value.Label}, f.File, root.Children[0].Token.Position)
}
if len(parameters) != len(fn.Input) {
return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, root.Children[0].Token.End())
}
if fn.IsExtern() {
return f.CallExtern(fn, parameters)
}
err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil {
return nil, err
}
f.CallSafe(fn, registers)
return fn.OutputTypes, nil
case *eval.Register:
f.Register(asm.CALL, value.Register)
case *eval.Memory:
f.Memory(asm.CALL, value.Memory)
}
return nil, nil
}