mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-16 05:53:30 +00:00
added block and no return value generation
This commit is contained in:
parent
9ac98c344f
commit
5b46794539
@ -7,6 +7,15 @@ import (
|
||||
|
||||
type Program struct {
|
||||
Functions []Function
|
||||
MainFunction *Function
|
||||
}
|
||||
|
||||
func (p *Program) executableAsmHeader() string {
|
||||
|
||||
if p.MainFunction.HasReturnValue {
|
||||
return executableAsmHeader
|
||||
}
|
||||
return executableAsmHeaderNoReturnValue
|
||||
}
|
||||
|
||||
// This calls the main function and uses it's return value to exit
|
||||
@ -19,9 +28,18 @@ const executableAsmHeader = "format ELF64 executable\n" +
|
||||
" mov rax, 60\n" +
|
||||
" syscall\n"
|
||||
|
||||
const executableAsmHeaderNoReturnValue = "format ELF64 executable\n" +
|
||||
"segment readable executable\n" +
|
||||
"entry _start\n" +
|
||||
"_start:\n" +
|
||||
" call main\n" +
|
||||
" mov rdi, 0\n" +
|
||||
" mov rax, 60\n" +
|
||||
" syscall\n"
|
||||
|
||||
func (p *Program) Emit() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(executableAsmHeader)
|
||||
builder.WriteString(p.executableAsmHeader())
|
||||
|
||||
for _, function := range p.Functions {
|
||||
builder.WriteString(function.Emit())
|
||||
@ -34,6 +52,7 @@ func (p *Program) Emit() string {
|
||||
type Function struct {
|
||||
StackOffset int64
|
||||
Name string
|
||||
HasReturnValue bool
|
||||
Instructions []Instruction
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,12 @@ func CgProgram(prog *ttir.Program) *Program {
|
||||
newProgram = replacePseudo(newProgram)
|
||||
newProgram = instructionFixup(newProgram)
|
||||
|
||||
for i, f := range newProgram.Functions {
|
||||
if f.Name == "main" {
|
||||
newProgram.MainFunction = &newProgram.Functions[i]
|
||||
}
|
||||
}
|
||||
|
||||
return &newProgram
|
||||
}
|
||||
|
||||
@ -45,12 +51,14 @@ func cgFunction(f ttir.Function) Function {
|
||||
return Function{
|
||||
Name: f.Name,
|
||||
Instructions: newInstructions,
|
||||
HasReturnValue: f.HasReturnValue,
|
||||
}
|
||||
}
|
||||
|
||||
func cgInstruction(i ttir.Instruction) []Instruction {
|
||||
switch i := i.(type) {
|
||||
case *ttir.Ret:
|
||||
if i.Op != nil {
|
||||
return []Instruction{
|
||||
&SimpleInstruction{
|
||||
Opcode: Mov,
|
||||
@ -61,6 +69,9 @@ func cgInstruction(i ttir.Instruction) []Instruction {
|
||||
Opcode: Ret,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return []Instruction{&SimpleInstruction{Opcode: Ret}}
|
||||
}
|
||||
case *ttir.Binary:
|
||||
return cgBinary(i)
|
||||
}
|
||||
@ -149,7 +160,7 @@ func rpFunction(f Function) Function {
|
||||
newInstructions = append(newInstructions, rpInstruction(i, r))
|
||||
}
|
||||
|
||||
return Function{Instructions: newInstructions, Name: f.Name, StackOffset: r.currentOffset}
|
||||
return Function{Instructions: newInstructions, Name: f.Name, StackOffset: r.currentOffset, HasReturnValue: f.HasReturnValue}
|
||||
}
|
||||
|
||||
func rpInstruction(i Instruction, r *replacePseudoPass) Instruction {
|
||||
@ -209,7 +220,7 @@ func fixupFunction(f Function) Function {
|
||||
newInstructions = append(newInstructions, fixupInstruction(i)...)
|
||||
}
|
||||
|
||||
return Function{Name: f.Name, Instructions: newInstructions, StackOffset: f.StackOffset}
|
||||
return Function{Name: f.Name, Instructions: newInstructions, StackOffset: f.StackOffset, HasReturnValue: f.HasReturnValue}
|
||||
}
|
||||
|
||||
func fixupInstruction(i Instruction) []Instruction {
|
||||
|
29
tast/tast.go
29
tast/tast.go
@ -111,3 +111,32 @@ func (be *BinaryExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BinaryExpression) String() string {
|
||||
return fmt.Sprintf("(%s %s %s :> %s)", be.Lhs, be.Operator.SymbolString(), be.Rhs, be.ResultType.Name())
|
||||
}
|
||||
|
||||
type BlockExpression struct {
|
||||
Token token.Token // The '{'
|
||||
Expressions []Expression
|
||||
ReturnExpression Expression // A expression that does not end with a semicolon, there can only be one of those and it hast to be at the end
|
||||
ReturnType types.Type
|
||||
}
|
||||
|
||||
func (be *BlockExpression) expressionNode() {}
|
||||
func (be *BlockExpression) Type() types.Type {
|
||||
return be.ReturnType
|
||||
}
|
||||
func (be *BlockExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BlockExpression) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString("({\n")
|
||||
for _, expr := range be.Expressions {
|
||||
builder.WriteString("\t")
|
||||
builder.WriteString(expr.String())
|
||||
builder.WriteString(";\n")
|
||||
}
|
||||
if be.ReturnExpression != nil {
|
||||
builder.WriteString(fmt.Sprintf("\t%s\n", be.ReturnExpression.String()))
|
||||
}
|
||||
builder.WriteString("})")
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
18
ttir/emit.go
18
ttir/emit.go
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"robaertschi.xyz/robaertschi/tt/tast"
|
||||
"robaertschi.xyz/robaertschi/tt/types"
|
||||
)
|
||||
|
||||
var uniqueId int64
|
||||
@ -33,6 +34,7 @@ func emitFunction(function *tast.FunctionDeclaration) *Function {
|
||||
return &Function{
|
||||
Name: function.Name,
|
||||
Instructions: instructions,
|
||||
HasReturnValue: !function.ReturnType.IsSameType(types.Unit),
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +58,22 @@ func emitExpression(expr tast.Expression) (Operand, []Instruction) {
|
||||
instructions = append(instructions, &Binary{Operator: expr.Operator, Lhs: lhsDst, Rhs: rhsDst, Dst: dst})
|
||||
return dst, instructions
|
||||
}
|
||||
case *tast.BlockExpression:
|
||||
instructions := []Instruction{}
|
||||
|
||||
for _, expr := range expr.Expressions {
|
||||
_, insts := emitExpression(expr)
|
||||
instructions = append(instructions, insts...)
|
||||
}
|
||||
|
||||
var value Operand
|
||||
if expr.ReturnExpression != nil {
|
||||
dst, insts := emitExpression(expr.ReturnExpression)
|
||||
value = dst
|
||||
instructions = append(instructions, insts...)
|
||||
}
|
||||
|
||||
return value, instructions
|
||||
}
|
||||
panic("unhandled tast.Expression case in ir emitter")
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ func (p *Program) String() string {
|
||||
type Function struct {
|
||||
Name string
|
||||
Instructions []Instruction
|
||||
HasReturnValue bool
|
||||
}
|
||||
|
||||
func (f *Function) String() string {
|
||||
@ -40,11 +41,16 @@ type Instruction interface {
|
||||
}
|
||||
|
||||
type Ret struct {
|
||||
// Nullable, if it does not return anything
|
||||
Op Operand
|
||||
}
|
||||
|
||||
func (r *Ret) String() string {
|
||||
if r.Op != nil {
|
||||
return fmt.Sprintf("ret %s\n", r.Op)
|
||||
} else {
|
||||
return "ret\n"
|
||||
}
|
||||
}
|
||||
func (r *Ret) instruction() {}
|
||||
|
||||
|
@ -85,6 +85,16 @@ func (c *Checker) checkExpression(expr tast.Expression) error {
|
||||
}
|
||||
|
||||
return errors.Join(lhsErr, rhsErr, operandErr)
|
||||
case *tast.BlockExpression:
|
||||
errs := []error{}
|
||||
|
||||
for _, expr := range expr.Expressions {
|
||||
errs = append(errs, c.checkExpression(expr))
|
||||
}
|
||||
return fmt.Errorf("unhandled expression in type checker")
|
||||
if expr.ReturnExpression != nil {
|
||||
errs = append(errs, c.checkExpression(expr.ReturnExpression))
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
return fmt.Errorf("unhandled expression %T in type checker", expr)
|
||||
}
|
||||
|
@ -60,6 +60,39 @@ func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error)
|
||||
}
|
||||
|
||||
return &tast.BinaryExpression{Lhs: lhs, Rhs: rhs, Operator: expr.Operator, Token: expr.Token, ResultType: resultType}, errors.Join(lhsErr, rhsErr)
|
||||
case *ast.BlockExpression:
|
||||
expressions := []tast.Expression{}
|
||||
errs := []error{}
|
||||
|
||||
for _, expr := range expr.Expressions {
|
||||
newExpr, err := c.inferExpression(expr)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
expressions = append(expressions, newExpr)
|
||||
}
|
||||
}
|
||||
|
||||
var returnExpr tast.Expression
|
||||
var returnType types.Type
|
||||
if expr.ReturnExpression != nil {
|
||||
expr, err := c.inferExpression(expr.ReturnExpression)
|
||||
returnExpr = expr
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
returnType = returnExpr.Type()
|
||||
}
|
||||
} else {
|
||||
returnType = types.Unit
|
||||
}
|
||||
|
||||
return &tast.BlockExpression{
|
||||
Token: expr.Token,
|
||||
Expressions: expressions,
|
||||
ReturnType: returnType,
|
||||
ReturnExpression: returnExpr,
|
||||
}, errors.Join(errs...)
|
||||
}
|
||||
return nil, fmt.Errorf("unhandled expression in type inferer")
|
||||
}
|
||||
|
@ -15,11 +15,13 @@ type TypeId struct {
|
||||
}
|
||||
|
||||
const (
|
||||
I64Id int64 = iota
|
||||
UnitId int64 = iota
|
||||
I64Id
|
||||
BoolId
|
||||
)
|
||||
|
||||
var (
|
||||
Unit = New(UnitId, "()")
|
||||
I64 = New(I64Id, "i64")
|
||||
Bool = New(BoolId, "bool")
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user