Implemented extern functions
This commit is contained in:
32
src/core/BeforeCall.go
Normal file
32
src/core/BeforeCall.go
Normal file
@ -0,0 +1,32 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
"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"
|
||||
)
|
||||
|
||||
// BeforeCall loads the registers with the parameter values and checks that the types match with the function signature.
|
||||
func (f *Function) BeforeCall(fn *Function, parameters []*expression.Expression, registers []cpu.Register) error {
|
||||
for i := len(parameters) - 1; i >= 0; i-- {
|
||||
typ, err := f.ExpressionToRegister(parameters[i], registers[i])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !types.Is(typ, fn.Input[i].Type) {
|
||||
_, expectsPointer := fn.Input[i].Type.(*types.Pointer)
|
||||
|
||||
if expectsPointer && parameters[i].Token.Kind == token.Number && parameters[i].Token.Text(f.File.Bytes) == "0" {
|
||||
continue
|
||||
}
|
||||
|
||||
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: fn.Input[i].Type.Name(), ParameterName: fn.Input[i].Name}, f.File, parameters[i].Token.Position)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -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)
|
||||
|
6
src/core/IsExtern.go
Normal file
6
src/core/IsExtern.go
Normal file
@ -0,0 +1,6 @@
|
||||
package core
|
||||
|
||||
// IsExtern returns true if the function has no body.
|
||||
func (f *Function) IsExtern() bool {
|
||||
return f.Body == nil
|
||||
}
|
@ -19,6 +19,10 @@ func (f *Function) ResolveTypes() error {
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||
}
|
||||
|
||||
if f.IsExtern() {
|
||||
continue
|
||||
}
|
||||
|
||||
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, param.Name)
|
||||
|
||||
if uses == 0 && param.Name != "_" {
|
||||
@ -38,7 +42,7 @@ func (f *Function) ResolveTypes() error {
|
||||
param.Type = types.ByName(typeName, f.Package, f.Structs)
|
||||
|
||||
if param.Type == nil {
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[0].Position)
|
||||
}
|
||||
|
||||
f.OutputTypes = append(f.OutputTypes, param.Type)
|
||||
|
Reference in New Issue
Block a user