mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-15 21:43:30 +00:00
added some tests
This commit is contained in:
parent
cefa2698c6
commit
1dae344e09
@ -5,66 +5,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"robaertschi.xyz/robaertschi/tt/ast"
|
||||
"robaertschi.xyz/robaertschi/tt/ttir"
|
||||
)
|
||||
|
||||
func TestOperands(t *testing.T) {
|
||||
var op Operand
|
||||
|
||||
op = AX
|
||||
if str := op.OperandString(One); str != "al" {
|
||||
t.Errorf("The register AX should be \"al\" but got %q", str)
|
||||
}
|
||||
|
||||
op = Imm(3)
|
||||
if str := op.OperandString(One); str != "3" {
|
||||
t.Errorf("The immediate value 3 should be \"3\" but got %q", str)
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed basic_test.txt
|
||||
var basicTest string
|
||||
|
||||
func TestCodegen(t *testing.T) {
|
||||
program := &ttir.Program{
|
||||
Functions: []ttir.Function{
|
||||
{
|
||||
Name: "main",
|
||||
Instructions: []ttir.Instruction{
|
||||
&ttir.Ret{Op: &ttir.Constant{Value: 0}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedProgram := Program{
|
||||
Functions: []Function{
|
||||
{
|
||||
Name: "main",
|
||||
Instructions: []Instruction{
|
||||
&SimpleInstruction{
|
||||
Opcode: Mov,
|
||||
Lhs: AX,
|
||||
Rhs: Imm(0),
|
||||
},
|
||||
&SimpleInstruction{
|
||||
Opcode: Ret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualProgram := CgProgram(program)
|
||||
expectProgram(t, expectedProgram, actualProgram)
|
||||
|
||||
actual := actualProgram.Emit()
|
||||
expected := basicTest
|
||||
if strings.Trim(actual, " \n\t") != strings.Trim(expected, " \n\t") {
|
||||
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func expectProgram(t *testing.T, expected Program, actual Program) {
|
||||
t.Helper()
|
||||
if len(expected.Functions) != len(actual.Functions) {
|
||||
@ -179,3 +123,87 @@ func expectOperand(t *testing.T, expected Operand, actual Operand) {
|
||||
t.Errorf("Unknown operand type %T", expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOperands(t *testing.T) {
|
||||
var op Operand
|
||||
|
||||
op = AX
|
||||
if str := op.OperandString(One); str != "al" {
|
||||
t.Errorf("The register AX should be \"al\" but got %q", str)
|
||||
}
|
||||
|
||||
op = Imm(3)
|
||||
if str := op.OperandString(One); str != "3" {
|
||||
t.Errorf("The immediate value 3 should be \"3\" but got %q", str)
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed basic_test.txt
|
||||
var basicTest string
|
||||
|
||||
func TestCodegen(t *testing.T) {
|
||||
program := &ttir.Program{
|
||||
Functions: []ttir.Function{
|
||||
{
|
||||
Name: "main",
|
||||
Instructions: []ttir.Instruction{
|
||||
&ttir.Ret{Op: &ttir.Constant{Value: 0}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedProgram := Program{
|
||||
Functions: []Function{
|
||||
{
|
||||
Name: "main",
|
||||
Instructions: []Instruction{
|
||||
&SimpleInstruction{
|
||||
Opcode: Mov,
|
||||
Lhs: AX,
|
||||
Rhs: Imm(0),
|
||||
},
|
||||
&SimpleInstruction{
|
||||
Opcode: Ret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualProgram := CgProgram(program)
|
||||
expectProgram(t, expectedProgram, *actualProgram)
|
||||
|
||||
actual := actualProgram.Emit()
|
||||
expected := basicTest
|
||||
if strings.Trim(actual, " \n\t") != strings.Trim(expected, " \n\t") {
|
||||
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed binary_test.txt
|
||||
var binaryTest string
|
||||
|
||||
func TestBinary(t *testing.T) {
|
||||
program := &ttir.Program{
|
||||
Functions: []ttir.Function{
|
||||
{
|
||||
Name: "main",
|
||||
Instructions: []ttir.Instruction{
|
||||
&ttir.Binary{
|
||||
Lhs: &ttir.Constant{Value: 3},
|
||||
Rhs: &ttir.Constant{Value: 3},
|
||||
Operator: ast.Add,
|
||||
Dst: &ttir.Var{Value: "temp.1"},
|
||||
},
|
||||
&ttir.Ret{Op: &ttir.Var{Value: "temp.1"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actual := CgProgram(program).Emit()
|
||||
if strings.Trim(actual, " \n\t") != strings.Trim(binaryTest, " \n\t") {
|
||||
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", binaryTest, actual)
|
||||
}
|
||||
}
|
||||
|
20
asm/amd64/binary_test.txt
Normal file
20
asm/amd64/binary_test.txt
Normal file
@ -0,0 +1,20 @@
|
||||
format ELF64 executable
|
||||
segment readable executable
|
||||
entry _start
|
||||
_start:
|
||||
call main
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
main:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
add rsp, -4
|
||||
mov qword [rsp -4], 3
|
||||
add qword [rsp -4], 3
|
||||
mov rax, qword [rsp -4]
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
@ -18,7 +18,7 @@ func toAsmOperand(op ttir.Operand) Operand {
|
||||
}
|
||||
}
|
||||
|
||||
func CgProgram(prog *ttir.Program) Program {
|
||||
func CgProgram(prog *ttir.Program) *Program {
|
||||
funcs := make([]Function, 0)
|
||||
|
||||
for _, f := range prog.Functions {
|
||||
@ -32,7 +32,7 @@ func CgProgram(prog *ttir.Program) Program {
|
||||
newProgram = replacePseudo(newProgram)
|
||||
newProgram = instructionFixup(newProgram)
|
||||
|
||||
return newProgram
|
||||
return &newProgram
|
||||
}
|
||||
|
||||
func cgFunction(f ttir.Function) Function {
|
||||
|
@ -123,7 +123,7 @@ func Compile(args Arguments) {
|
||||
os.Exit(1)
|
||||
}
|
||||
if (args.ToPrint & PrintAst) != 0 {
|
||||
fmt.Printf("AST:\n%s\n", program.String())
|
||||
fmt.Printf("AST:\n%s\n%+#v\n", program.String(), program)
|
||||
}
|
||||
|
||||
tprogram, err := typechecker.New().CheckProgram(program)
|
||||
@ -132,12 +132,12 @@ func Compile(args Arguments) {
|
||||
os.Exit(1)
|
||||
}
|
||||
if (args.ToPrint & PrintTAst) != 0 {
|
||||
fmt.Printf("TAST:\n%s\n", tprogram.String())
|
||||
fmt.Printf("TAST:\n%s\n%+#v\n", tprogram.String(), tprogram)
|
||||
}
|
||||
|
||||
ir := ttir.EmitProgram(tprogram)
|
||||
if (args.ToPrint & PrintIr) != 0 {
|
||||
fmt.Printf("TTIR:\n%s\n", ir.String())
|
||||
fmt.Printf("TTIR:\n%s\n%+#v\n", ir.String(), ir)
|
||||
}
|
||||
asm := amd64.CgProgram(ir)
|
||||
|
||||
|
@ -40,7 +40,7 @@ func runLexerTest(t *testing.T, test lexerTest) {
|
||||
|
||||
func TestBasicFunctionality(t *testing.T) {
|
||||
runLexerTest(t, lexerTest{
|
||||
input: "fn main() = 0 + 3;",
|
||||
input: "fn main() = 0 + 3 == 3;",
|
||||
expectedToken: []token.Token{
|
||||
{Type: token.Fn, Literal: "fn"},
|
||||
{Type: token.Ident, Literal: "main"},
|
||||
@ -50,6 +50,8 @@ func TestBasicFunctionality(t *testing.T) {
|
||||
{Type: token.Int, Literal: "0"},
|
||||
{Type: token.Plus, Literal: "+"},
|
||||
{Type: token.Int, Literal: "3"},
|
||||
{Type: token.DoubleEqual, Literal: "=="},
|
||||
{Type: token.Int, Literal: "3"},
|
||||
{Type: token.Semicolon, Literal: ";"},
|
||||
{Type: token.Eof, Literal: ""},
|
||||
},
|
||||
|
@ -87,6 +87,30 @@ func expectExpression(t *testing.T, expected ast.Expression, actual ast.Expressi
|
||||
if integerExpr.Value != expected.Value {
|
||||
t.Errorf("expected integer value %d, got %d", expected.Value, integerExpr.Value)
|
||||
}
|
||||
case *ast.BinaryExpression:
|
||||
binaryExpr, ok := actual.(*ast.BinaryExpression)
|
||||
if !ok {
|
||||
t.Errorf("expected %T, got %T", expected, actual)
|
||||
return
|
||||
}
|
||||
|
||||
if binaryExpr.Operator != expected.Operator {
|
||||
t.Errorf("expected %q operator for binary expression, got %q", expected.Operator.SymbolString(), binaryExpr.Operator.SymbolString())
|
||||
}
|
||||
expectExpression(t, expected.Lhs, binaryExpr.Lhs)
|
||||
expectExpression(t, expected.Rhs, binaryExpr.Rhs)
|
||||
case *ast.BooleanExpression:
|
||||
booleanExpr, ok := actual.(*ast.BooleanExpression)
|
||||
if !ok {
|
||||
t.Errorf("expected %T, got %T", expected, actual)
|
||||
return
|
||||
}
|
||||
|
||||
if booleanExpr.Value != expected.Value {
|
||||
t.Errorf("expected boolean %v, got %v", expected.Value, booleanExpr.Value)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("unknown expression type %T", expected)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,3 +128,27 @@ func TestFunctionDeclaration(t *testing.T) {
|
||||
}
|
||||
runParserTest(test, t)
|
||||
}
|
||||
|
||||
func TestBinaryExpressions(t *testing.T) {
|
||||
test := parserTest{
|
||||
input: "fn main() = true == true == true;",
|
||||
expectedProgram: ast.Program{
|
||||
Declarations: []ast.Declaration{
|
||||
&ast.FunctionDeclaration{
|
||||
Name: "main",
|
||||
Body: &ast.BinaryExpression{
|
||||
Lhs: &ast.BinaryExpression{
|
||||
Lhs: &ast.BooleanExpression{Value: true},
|
||||
Rhs: &ast.BooleanExpression{Value: true},
|
||||
Operator: ast.Equal,
|
||||
},
|
||||
Rhs: &ast.BooleanExpression{Value: true},
|
||||
Operator: ast.Equal,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runParserTest(test, t)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"robaertschi.xyz/robaertschi/tt/ast"
|
||||
"robaertschi.xyz/robaertschi/tt/lexer"
|
||||
"robaertschi.xyz/robaertschi/tt/parser"
|
||||
"robaertschi.xyz/robaertschi/tt/token"
|
||||
@ -86,6 +87,17 @@ func expectInstruction(t *testing.T, inst Instruction, actual Instruction) {
|
||||
}
|
||||
|
||||
expectOperand(t, inst.Op, ret.Op)
|
||||
case *Binary:
|
||||
binary, ok := actual.(*Binary)
|
||||
|
||||
if !ok {
|
||||
t.Errorf("expected inst to be %T, but got %T", inst, binary)
|
||||
return
|
||||
}
|
||||
|
||||
expectOperand(t, inst.Lhs, binary.Lhs)
|
||||
expectOperand(t, inst.Rhs, binary.Rhs)
|
||||
expectOperand(t, inst.Dst, binary.Dst)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +116,16 @@ func expectOperand(t *testing.T, expected Operand, actual Operand) {
|
||||
if expected.Value != constant.Value {
|
||||
t.Errorf("expected *Constant.Value to be %d, but got %d", expected.Value, constant.Value)
|
||||
}
|
||||
case *Var:
|
||||
v, ok := actual.(*Var)
|
||||
|
||||
if !ok {
|
||||
t.Errorf("expected operand to be %T, but got %T", expected, actual)
|
||||
return
|
||||
}
|
||||
if expected.Value != v.Value {
|
||||
t.Errorf("expected var to be %q, but got %q", expected.Value, v.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,3 +146,18 @@ func TestBasicFunction(t *testing.T) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestBinaryExpression(t *testing.T) {
|
||||
runTTIREmitterTest(t, ttirEmitterTest{
|
||||
input: "fn main() = 3 + 3 + 3;",
|
||||
expected: Program{
|
||||
Functions: []Function{
|
||||
{Name: "main", Instructions: []Instruction{
|
||||
&Binary{Operator: ast.Add, Lhs: &Constant{Value: 3}, Rhs: &Constant{Value: 3}, Dst: &Var{Value: "temp.1"}},
|
||||
&Binary{Operator: ast.Add, Lhs: &Var{Value: "temp.1"}, Rhs: &Constant{Value: 3}, Dst: &Var{Value: "temp.2"}},
|
||||
&Ret{Op: &Var{Value: "temp.2"}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user