Implemented extern functions

This commit is contained in:
2025-02-12 00:04:30 +01:00
parent 1083db6ab2
commit 3b66dae1d4
24 changed files with 304 additions and 169 deletions

View File

@ -5,7 +5,6 @@ import (
"git.akyoto.dev/cli/q/src/errors"
"git.akyoto.dev/cli/q/src/expression"
"git.akyoto.dev/cli/q/src/token"
"git.akyoto.dev/cli/q/src/types"
"git.akyoto.dev/cli/q/src/x86"
)
@ -48,22 +47,13 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
name = nameNode.Token.Text(f.File.Bytes)
}
if pkg == "kernel32" || pkg == "user32" || pkg == "gdi32" || pkg == "comctl32" {
parameters := root.Children[1:]
registers := x86.WindowsInputRegisters[:len(parameters)]
fn, exists = f.Functions[pkg+"."+name]
for i := len(parameters) - 1; i >= 0; i-- {
_, err := f.ExpressionToRegister(parameters[i], registers[i])
if !exists {
return nil, errors.New(&errors.UnknownFunction{Name: name}, f.File, nameNode.Token.Position)
}
if err != nil {
return nil, err
}
}
f.DLLs = f.DLLs.Append(pkg, name)
f.DLLCall(fmt.Sprintf("%s.%s", pkg, name))
return nil, nil
} else if pkg != f.File.Package {
if pkg != f.File.Package && !fn.IsExtern() {
if f.File.Imports == nil {
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, pkgNode.Token.Position)
}
@ -77,36 +67,30 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
imp.Used = true
}
fn, exists = f.Functions[pkg+"."+name]
if !exists {
return nil, errors.New(&errors.UnknownFunction{Name: name}, f.File, nameNode.Token.Position)
}
parameters := root.Children[1:]
if len(parameters) != len(fn.Input) {
return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, nameNode.Token.End())
}
registers := f.CPU.Input[:len(parameters)]
for i := len(parameters) - 1; i >= 0; i-- {
typ, err := f.ExpressionToRegister(parameters[i], registers[i])
if fn.IsExtern() {
f.DLLs = f.DLLs.Append(pkg, name)
registers := x86.WindowsInputRegisters[:len(parameters)]
err := f.BeforeCall(fn, parameters, registers)
if err != nil {
return nil, err
}
if !types.Is(typ, fn.Input[i].Type) {
_, expectsPointer := fn.Input[i].Type.(*types.Pointer)
f.DLLCall(fmt.Sprintf("%s.%s", pkg, name))
return fn.OutputTypes, nil
}
if expectsPointer && parameters[i].Token.Kind == token.Number && parameters[i].Token.Text(f.File.Bytes) == "0" {
continue
}
registers := f.CPU.Input[:len(parameters)]
err := f.BeforeCall(fn, parameters, registers)
return nil, errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: fn.Input[i].Type.Name(), ParameterName: fn.Input[i].Name}, f.File, parameters[i].Token.Position)
}
if err != nil {
return nil, err
}
f.CallSafe(fn, registers)