Implemented multiple return values
This commit is contained in:
@ -3,5 +3,5 @@ package x64
|
||||
// Return transfers program control to a return address located on the top of the stack.
|
||||
// The address is usually placed on the stack by a Call instruction.
|
||||
func Return(code []byte) []byte {
|
||||
return append(code, 0xc3)
|
||||
return append(code, 0xC3)
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ func Count(body AST, buffer []byte, kind token.Kind, name string) uint8 {
|
||||
count += Count(node.Body, buffer, kind, name)
|
||||
|
||||
case *Return:
|
||||
if node.Value != nil {
|
||||
count += node.Value.Count(buffer, kind, name)
|
||||
for _, value := range node.Values {
|
||||
count += value.Count(buffer, kind, name)
|
||||
}
|
||||
|
||||
case *Switch:
|
||||
|
@ -6,5 +6,5 @@ import (
|
||||
|
||||
// Return represents a return statement.
|
||||
type Return struct {
|
||||
Value *expression.Expression
|
||||
Values []*expression.Expression
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ func parseKeyword(tokens token.List, source []byte, nodes AST) (Node, error) {
|
||||
return &Return{}, nil
|
||||
}
|
||||
|
||||
value := expression.Parse(tokens[1:])
|
||||
return &Return{Value: value}, nil
|
||||
values := expression.NewList(tokens[1:])
|
||||
return &Return{Values: values}, nil
|
||||
|
||||
case token.Switch:
|
||||
blockStart := tokens.IndexKind(token.BlockStart)
|
||||
|
@ -31,7 +31,10 @@ func (f *Function) CompileASTNode(node ast.Node) error {
|
||||
return f.CompileLoop(node)
|
||||
|
||||
case *ast.Return:
|
||||
f.Fold(node.Value)
|
||||
for _, value := range node.Values {
|
||||
f.Fold(value)
|
||||
}
|
||||
|
||||
return f.CompileReturn(node)
|
||||
|
||||
case *ast.Switch:
|
||||
|
@ -69,6 +69,7 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Save all return value registers of the function
|
||||
f.SaveRegister(f.CPU.Output[0])
|
||||
|
||||
// Push
|
||||
|
@ -1,36 +1,50 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/ast"
|
||||
"git.akyoto.dev/cli/q/src/build/errors"
|
||||
"git.akyoto.dev/cli/q/src/build/scope"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
)
|
||||
|
||||
// CompileDefinition compiles a variable definition.
|
||||
func (f *Function) CompileDefinition(node *ast.Define) error {
|
||||
left := node.Expression.Children[0]
|
||||
right := node.Expression.Children[1]
|
||||
name := left.Token.Text(f.File.Bytes)
|
||||
|
||||
if f.IdentifierExists(name) {
|
||||
return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, left.Token.Position)
|
||||
if left.IsLeaf() {
|
||||
variable, err := f.Define(left)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.ExpressionToRegister(right, variable.Register)
|
||||
f.AddVariable(variable)
|
||||
return err
|
||||
}
|
||||
|
||||
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, name) - 1
|
||||
|
||||
if uses == 0 {
|
||||
return errors.New(&errors.UnusedVariable{Name: name}, f.File, left.Token.Position)
|
||||
if !ast.IsFunctionCall(right) {
|
||||
return errors.New(errors.NotImplemented, f.File, node.Expression.Token.Position)
|
||||
}
|
||||
|
||||
register := f.NewRegister()
|
||||
err := f.ExpressionToRegister(right, register)
|
||||
count := 0
|
||||
err := f.CompileCall(right)
|
||||
|
||||
f.AddVariable(&scope.Variable{
|
||||
Name: name,
|
||||
Register: register,
|
||||
Alive: uses,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return left.EachLeaf(func(leaf *expression.Expression) error {
|
||||
variable, err := f.Define(leaf)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.RegisterRegister(asm.MOVE, variable.Register, f.CPU.Output[count])
|
||||
f.AddVariable(variable)
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
func (f *Function) CompileReturn(node *ast.Return) error {
|
||||
defer f.Return()
|
||||
|
||||
if node.Value == nil {
|
||||
if len(node.Values) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.ExpressionToRegister(node.Value, f.CPU.Output[0])
|
||||
return f.ExpressionsToRegisters(node.Values, f.CPU.Output)
|
||||
}
|
||||
|
31
src/build/core/Define.go
Normal file
31
src/build/core/Define.go
Normal file
@ -0,0 +1,31 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/build/errors"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
"git.akyoto.dev/cli/q/src/build/scope"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
)
|
||||
|
||||
// Define defines a new variable.
|
||||
func (f *Function) Define(leaf *expression.Expression) (*scope.Variable, error) {
|
||||
name := leaf.Token.Text(f.File.Bytes)
|
||||
|
||||
if f.IdentifierExists(name) {
|
||||
return nil, errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, leaf.Token.Position)
|
||||
}
|
||||
|
||||
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, name) - 1
|
||||
|
||||
if uses == 0 {
|
||||
return nil, errors.New(&errors.UnusedVariable{Name: name}, f.File, leaf.Token.Position)
|
||||
}
|
||||
|
||||
variable := &scope.Variable{
|
||||
Name: name,
|
||||
Register: f.NewRegister(),
|
||||
Alive: uses,
|
||||
}
|
||||
|
||||
return variable, nil
|
||||
}
|
@ -11,8 +11,9 @@ import (
|
||||
|
||||
// ExpressionToRegister puts the result of an expression into the specified register.
|
||||
func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) error {
|
||||
f.SaveRegister(register)
|
||||
|
||||
if node.IsFolded {
|
||||
f.SaveRegister(register)
|
||||
f.RegisterNumber(asm.MOVE, register, node.Value)
|
||||
return nil
|
||||
}
|
||||
@ -25,7 +26,6 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
err := f.CompileCall(node)
|
||||
|
||||
if register != f.CPU.Output[0] {
|
||||
f.SaveRegister(register)
|
||||
f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0])
|
||||
}
|
||||
|
||||
@ -70,7 +70,6 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
err = f.Execute(node.Token, register, right)
|
||||
|
||||
if register != final {
|
||||
f.SaveRegister(final)
|
||||
f.RegisterRegister(asm.MOVE, final, register)
|
||||
f.FreeRegister(register)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
||||
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
||||
for i := len(registers) - 1; i >= 0; i-- {
|
||||
for i := len(expressions) - 1; i >= 0; i-- {
|
||||
err := f.ExpressionToRegister(expressions[i], registers[i])
|
||||
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user