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)] registers := x86.WindowsInputRegisters[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, fn.Input) err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil { if err != nil {
return nil, err 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)] registers := f.CPU.Input[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, fn.Input) err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -3,7 +3,6 @@ package core
import ( import (
"git.akyoto.dev/cli/q/src/ast" "git.akyoto.dev/cli/q/src/ast"
"git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/errors"
"git.akyoto.dev/cli/q/src/types"
) )
// CompileReturn compiles a return instruction. // CompileReturn compiles a return instruction.
@ -17,27 +16,10 @@ 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) 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-- { err := f.ExpressionsToRegisters(node.Values, f.CPU.Output, f.Output, false)
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]) if err != nil {
return err
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() f.Return()

View File

@ -8,7 +8,7 @@ import (
func (f *Function) CompileSyscall(root *expression.Expression) error { func (f *Function) CompileSyscall(root *expression.Expression) error {
parameters := root.Children[1:] parameters := root.Children[1:]
registers := f.CPU.SyscallInput[:len(parameters)] registers := f.CPU.SyscallInput[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, nil) err := f.ExpressionsToRegisters(parameters, registers, nil, true)
if err != nil { if err != nil {
return err 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. // 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-- { for i := len(expressions) - 1; i >= 0; i-- {
f.SaveRegister(registers[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]) typ, err := f.ExpressionToRegister(expressions[i], registers[i])
if err != nil { if err != nil {
return err return err
} }
if input == nil { if params == nil {
continue continue
} }
if !types.Is(typ, input[i].Type) { if !types.Is(typ, params[i].Type()) {
_, expectsPointer := input[i].Type.(*types.Pointer) _, expectsPointer := params[i].Type().(*types.Pointer)
if expectsPointer && expressions[i].Token.Kind == token.Number && expressions[i].Token.Text(f.File.Bytes) == "0" { if expectsPointer && expressions[i].Token.Kind == token.Number && expressions[i].Token.Text(f.File.Bytes) == "0" {
continue 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 UniqueName string
File *fs.File File *fs.File
Body token.List Body token.List
Input []*Input Input []*Parameter
Output []*Output Output []*Parameter
OutputTypes []types.Type OutputTypes []types.Type
Functions map[string]*Function Functions map[string]*Function
Structs map[string]*types.Struct 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 { if len(f.Input) > 0 {
for i, input := range f.Input { 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") ansi.Dim.Print(" │\n")
} }

View File

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

View File

@ -97,7 +97,7 @@ func scanFunctionSignature(file *fs.File, tokens token.List, i int, delimiter to
outputTokens := tokens[typeStart:typeEnd] outputTokens := tokens[typeStart:typeEnd]
err := outputTokens.Split(func(tokens token.List) error { 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 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()) 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 return nil
}) })