Simplified return code

This commit is contained in:
Eduard Urbach 2025-02-12 17:34:48 +01:00
parent 3fb05c382a
commit b7b4dad1a5
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
12 changed files with 66 additions and 77 deletions

View File

@ -26,7 +26,7 @@ func (f *Function) CallExtern(fn *Function, parameters []*expression.Expression)
}
registers := x86.WindowsInputRegisters[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, fn.Input)
err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil {
return nil, err

View File

@ -75,7 +75,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
}
registers := f.CPU.Input[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, fn.Input)
err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil {
return nil, err

View File

@ -3,7 +3,6 @@ package core
import (
"git.akyoto.dev/cli/q/src/ast"
"git.akyoto.dev/cli/q/src/errors"
"git.akyoto.dev/cli/q/src/types"
)
// CompileReturn compiles a return instruction.
@ -17,29 +16,12 @@ func (f *Function) CompileReturn(node *ast.Return) error {
return errors.New(&errors.ReturnCountMismatch{Count: len(node.Values), ExpectedCount: len(f.Output)}, f.File, node.Values[0].Token.Position)
}
for i := len(node.Values) - 1; i >= 0; i-- {
for j := range i {
if f.UsesRegister(node.Values[j], f.CPU.Output[i]) {
f.SaveRegister(f.CPU.Output[i])
break
}
}
typ, err := f.ExpressionToRegister(node.Values[i], f.CPU.Output[i])
err := f.ExpressionsToRegisters(node.Values, f.CPU.Output, f.Output, false)
if err != nil {
return err
}
if !types.Is(typ, f.Output[i].Type) {
if f.Package == "mem" && f.Name == "alloc" {
continue
}
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: f.Output[i].Type.Name(), ParameterName: "", IsReturn: true}, f.File, node.Values[i].Token.Position)
}
}
f.Return()
return nil
}

View File

@ -8,7 +8,7 @@ import (
func (f *Function) CompileSyscall(root *expression.Expression) error {
parameters := root.Children[1:]
registers := f.CPU.SyscallInput[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, nil)
err := f.ExpressionsToRegisters(parameters, registers, nil, true)
if err != nil {
return err

View File

@ -9,27 +9,41 @@ import (
)
// ExpressionsToRegisters moves multiple expressions into the specified registers and checks that the types match with the function signature.
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register, input []*Input) error {
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register, params []*Parameter, alwaysSave bool) error {
for i := len(expressions) - 1; i >= 0; i-- {
if alwaysSave {
f.SaveRegister(registers[i])
} else {
for j := i - 1; j >= 0; j-- {
if f.UsesRegister(expressions[j], registers[i]) {
f.SaveRegister(registers[i])
break
}
}
}
typ, err := f.ExpressionToRegister(expressions[i], registers[i])
if err != nil {
return err
}
if input == nil {
if params == nil {
continue
}
if !types.Is(typ, input[i].Type) {
_, expectsPointer := input[i].Type.(*types.Pointer)
if !types.Is(typ, params[i].Type()) {
_, expectsPointer := params[i].Type().(*types.Pointer)
if expectsPointer && expressions[i].Token.Kind == token.Number && expressions[i].Token.Text(f.File.Bytes) == "0" {
continue
}
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: input[i].Type.Name(), ParameterName: input[i].Name}, f.File, expressions[i].Token.Position)
if f.Package == "mem" && f.Name == "alloc" {
continue
}
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: params[i].Type().Name(), ParameterName: params[i].Name()}, f.File, expressions[i].Token.Position)
}
}

View File

@ -16,8 +16,8 @@ type Function struct {
UniqueName string
File *fs.File
Body token.List
Input []*Input
Output []*Output
Input []*Parameter
Output []*Parameter
OutputTypes []types.Type
Functions map[string]*Function
Structs map[string]*types.Struct

View File

@ -1,16 +0,0 @@
package core
import (
"git.akyoto.dev/cli/q/src/token"
"git.akyoto.dev/cli/q/src/types"
)
type Input struct {
Name string
Type types.Type
tokens token.List
}
func NewInput(tokens token.List) *Input {
return &Input{tokens: tokens}
}

View File

@ -1,15 +0,0 @@
package core
import (
"git.akyoto.dev/cli/q/src/token"
"git.akyoto.dev/cli/q/src/types"
)
type Output struct {
Type types.Type
tokens token.List
}
func NewOutput(tokens token.List) *Output {
return &Output{tokens: tokens}
}

24
src/core/Parameter.go Normal file
View File

@ -0,0 +1,24 @@
package core
import (
"git.akyoto.dev/cli/q/src/token"
"git.akyoto.dev/cli/q/src/types"
)
type Parameter struct {
name string
typ types.Type
tokens token.List
}
func NewParameter(tokens token.List) *Parameter {
return &Parameter{tokens: tokens}
}
func (p *Parameter) Name() string {
return p.name
}
func (p *Parameter) Type() types.Type {
return p.typ
}

View File

@ -14,7 +14,7 @@ func (f *Function) PrintInstructions() {
if len(f.Input) > 0 {
for i, input := range f.Input {
ansi.Dim.Printf("│ %-44s%-32s", input.Name, f.CPU.Input[i])
ansi.Dim.Printf("│ %-44s%-32s", input.name, f.CPU.Input[i])
ansi.Dim.Print(" │\n")
}

View File

@ -11,11 +11,11 @@ import (
// ResolveTypes parses the input and output types.
func (f *Function) ResolveTypes() error {
for i, param := range f.Input {
param.Name = param.tokens[0].Text(f.File.Bytes)
param.name = param.tokens[0].Text(f.File.Bytes)
typeName := param.tokens[1:].Text(f.File.Bytes)
param.Type = types.ByName(typeName, f.Package, f.Structs)
param.typ = types.ByName(typeName, f.Package, f.Structs)
if param.Type == nil {
if param.typ == nil {
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
}
@ -23,15 +23,15 @@ func (f *Function) ResolveTypes() error {
continue
}
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, param.Name)
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, param.name)
if uses == 0 && param.Name != "_" {
return errors.New(&errors.UnusedVariable{Name: param.Name}, f.File, param.tokens[0].Position)
if uses == 0 && param.name != "_" {
return errors.New(&errors.UnusedVariable{Name: param.name}, f.File, param.tokens[0].Position)
}
f.AddVariable(&scope.Variable{
Name: param.Name,
Type: param.Type,
Name: param.name,
Type: param.typ,
Register: x86.InputRegisters[i],
Alive: uses,
})
@ -39,13 +39,13 @@ func (f *Function) ResolveTypes() error {
for _, param := range f.Output {
typeName := param.tokens.Text(f.File.Bytes)
param.Type = types.ByName(typeName, f.Package, f.Structs)
param.typ = types.ByName(typeName, f.Package, f.Structs)
if param.Type == nil {
if param.typ == nil {
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[0].Position)
}
f.OutputTypes = append(f.OutputTypes, param.Type)
f.OutputTypes = append(f.OutputTypes, param.typ)
}
return nil

View File

@ -97,7 +97,7 @@ func scanFunctionSignature(file *fs.File, tokens token.List, i int, delimiter to
outputTokens := tokens[typeStart:typeEnd]
err := outputTokens.Split(func(tokens token.List) error {
function.Output = append(function.Output, core.NewOutput(tokens))
function.Output = append(function.Output, core.NewParameter(tokens))
return nil
})
@ -117,7 +117,7 @@ func scanFunctionSignature(file *fs.File, tokens token.List, i int, delimiter to
return errors.New(errors.MissingType, file, tokens[0].End())
}
function.Input = append(function.Input, core.NewInput(tokens))
function.Input = append(function.Input, core.NewParameter(tokens))
return nil
})