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 := f.All.Functions[value.Label] 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.BeforeCall() f.Label(asm.CALL, value.Label) f.AfterCall(registers) return fn.OutputTypes, nil case *eval.Register: err := f.ExpressionsToRegisters(parameters, registers, nil, true) if err != nil { return nil, err } f.BeforeCall() f.Register(asm.CALL, value.Register) f.AfterCall(registers) case *eval.Memory: err := f.ExpressionsToRegisters(parameters, registers, nil, true) if err != nil { return nil, err } f.BeforeCall() f.Memory(asm.CALL, value.Memory) f.AfterCall(registers) } return nil, nil }