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
@ -6,7 +6,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
Functions []Function
|
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
|
// 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" +
|
" mov rax, 60\n" +
|
||||||
" syscall\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 {
|
func (p *Program) Emit() string {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
builder.WriteString(executableAsmHeader)
|
builder.WriteString(p.executableAsmHeader())
|
||||||
|
|
||||||
for _, function := range p.Functions {
|
for _, function := range p.Functions {
|
||||||
builder.WriteString(function.Emit())
|
builder.WriteString(function.Emit())
|
||||||
@ -32,9 +50,10 @@ func (p *Program) Emit() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Function struct {
|
type Function struct {
|
||||||
StackOffset int64
|
StackOffset int64
|
||||||
Name string
|
Name string
|
||||||
Instructions []Instruction
|
HasReturnValue bool
|
||||||
|
Instructions []Instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) Emit() string {
|
func (f *Function) Emit() string {
|
||||||
|
@ -32,6 +32,12 @@ func CgProgram(prog *ttir.Program) *Program {
|
|||||||
newProgram = replacePseudo(newProgram)
|
newProgram = replacePseudo(newProgram)
|
||||||
newProgram = instructionFixup(newProgram)
|
newProgram = instructionFixup(newProgram)
|
||||||
|
|
||||||
|
for i, f := range newProgram.Functions {
|
||||||
|
if f.Name == "main" {
|
||||||
|
newProgram.MainFunction = &newProgram.Functions[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &newProgram
|
return &newProgram
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,23 +49,28 @@ func cgFunction(f ttir.Function) Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Function{
|
return Function{
|
||||||
Name: f.Name,
|
Name: f.Name,
|
||||||
Instructions: newInstructions,
|
Instructions: newInstructions,
|
||||||
|
HasReturnValue: f.HasReturnValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cgInstruction(i ttir.Instruction) []Instruction {
|
func cgInstruction(i ttir.Instruction) []Instruction {
|
||||||
switch i := i.(type) {
|
switch i := i.(type) {
|
||||||
case *ttir.Ret:
|
case *ttir.Ret:
|
||||||
return []Instruction{
|
if i.Op != nil {
|
||||||
&SimpleInstruction{
|
return []Instruction{
|
||||||
Opcode: Mov,
|
&SimpleInstruction{
|
||||||
Lhs: AX,
|
Opcode: Mov,
|
||||||
Rhs: toAsmOperand(i.Op),
|
Lhs: AX,
|
||||||
},
|
Rhs: toAsmOperand(i.Op),
|
||||||
&SimpleInstruction{
|
},
|
||||||
Opcode: Ret,
|
&SimpleInstruction{
|
||||||
},
|
Opcode: Ret,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return []Instruction{&SimpleInstruction{Opcode: Ret}}
|
||||||
}
|
}
|
||||||
case *ttir.Binary:
|
case *ttir.Binary:
|
||||||
return cgBinary(i)
|
return cgBinary(i)
|
||||||
@ -149,7 +160,7 @@ func rpFunction(f Function) Function {
|
|||||||
newInstructions = append(newInstructions, rpInstruction(i, r))
|
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 {
|
func rpInstruction(i Instruction, r *replacePseudoPass) Instruction {
|
||||||
@ -209,7 +220,7 @@ func fixupFunction(f Function) Function {
|
|||||||
newInstructions = append(newInstructions, fixupInstruction(i)...)
|
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 {
|
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 {
|
func (be *BinaryExpression) String() string {
|
||||||
return fmt.Sprintf("(%s %s %s :> %s)", be.Lhs, be.Operator.SymbolString(), be.Rhs, be.ResultType.Name())
|
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()
|
||||||
|
}
|
||||||
|
22
ttir/emit.go
22
ttir/emit.go
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"robaertschi.xyz/robaertschi/tt/tast"
|
"robaertschi.xyz/robaertschi/tt/tast"
|
||||||
|
"robaertschi.xyz/robaertschi/tt/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var uniqueId int64
|
var uniqueId int64
|
||||||
@ -31,8 +32,9 @@ func emitFunction(function *tast.FunctionDeclaration) *Function {
|
|||||||
value, instructions := emitExpression(function.Body)
|
value, instructions := emitExpression(function.Body)
|
||||||
instructions = append(instructions, &Ret{Op: value})
|
instructions = append(instructions, &Ret{Op: value})
|
||||||
return &Function{
|
return &Function{
|
||||||
Name: function.Name,
|
Name: function.Name,
|
||||||
Instructions: instructions,
|
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})
|
instructions = append(instructions, &Binary{Operator: expr.Operator, Lhs: lhsDst, Rhs: rhsDst, Dst: dst})
|
||||||
return dst, instructions
|
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")
|
panic("unhandled tast.Expression case in ir emitter")
|
||||||
}
|
}
|
||||||
|
12
ttir/ttir.go
12
ttir/ttir.go
@ -20,8 +20,9 @@ func (p *Program) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Function struct {
|
type Function struct {
|
||||||
Name string
|
Name string
|
||||||
Instructions []Instruction
|
Instructions []Instruction
|
||||||
|
HasReturnValue bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) String() string {
|
func (f *Function) String() string {
|
||||||
@ -40,11 +41,16 @@ type Instruction interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Ret struct {
|
type Ret struct {
|
||||||
|
// Nullable, if it does not return anything
|
||||||
Op Operand
|
Op Operand
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ret) String() string {
|
func (r *Ret) String() string {
|
||||||
return fmt.Sprintf("ret %s\n", r.Op)
|
if r.Op != nil {
|
||||||
|
return fmt.Sprintf("ret %s\n", r.Op)
|
||||||
|
} else {
|
||||||
|
return "ret\n"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (r *Ret) instruction() {}
|
func (r *Ret) instruction() {}
|
||||||
|
|
||||||
|
@ -85,6 +85,16 @@ func (c *Checker) checkExpression(expr tast.Expression) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return errors.Join(lhsErr, rhsErr, operandErr)
|
return errors.Join(lhsErr, rhsErr, operandErr)
|
||||||
|
case *tast.BlockExpression:
|
||||||
|
errs := []error{}
|
||||||
|
|
||||||
|
for _, expr := range expr.Expressions {
|
||||||
|
errs = append(errs, c.checkExpression(expr))
|
||||||
|
}
|
||||||
|
if expr.ReturnExpression != nil {
|
||||||
|
errs = append(errs, c.checkExpression(expr.ReturnExpression))
|
||||||
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unhandled expression in type checker")
|
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)
|
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")
|
return nil, fmt.Errorf("unhandled expression in type inferer")
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,13 @@ type TypeId struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
I64Id int64 = iota
|
UnitId int64 = iota
|
||||||
|
I64Id
|
||||||
BoolId
|
BoolId
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
Unit = New(UnitId, "()")
|
||||||
I64 = New(I64Id, "i64")
|
I64 = New(I64Id, "i64")
|
||||||
Bool = New(BoolId, "bool")
|
Bool = New(BoolId, "bool")
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user