83 lines
2.1 KiB
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
|
|
}
|