mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-16 05:53:30 +00:00
added new equality operators
This commit is contained in:
parent
5b46794539
commit
bc554cdedf
@ -71,8 +71,12 @@ func (f *Function) Emit() string {
|
|||||||
type CondCode string
|
type CondCode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Equal CondCode = "e"
|
Equal CondCode = "e"
|
||||||
NotEqual CondCode = "ne"
|
NotEqual CondCode = "ne"
|
||||||
|
Greater CondCode = "g"
|
||||||
|
GreaterEqual CondCode = "ge"
|
||||||
|
Less CondCode = "l"
|
||||||
|
LessEqual CondCode = "le"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Opcode string
|
type Opcode string
|
||||||
|
@ -124,6 +124,10 @@ func expectOperand(t *testing.T, expected Operand, actual Operand) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func trim(s string) string {
|
||||||
|
return strings.Trim(s, " \n\t")
|
||||||
|
}
|
||||||
|
|
||||||
func TestOperands(t *testing.T) {
|
func TestOperands(t *testing.T) {
|
||||||
var op Operand
|
var op Operand
|
||||||
|
|
||||||
@ -145,7 +149,8 @@ func TestCodegen(t *testing.T) {
|
|||||||
program := &ttir.Program{
|
program := &ttir.Program{
|
||||||
Functions: []ttir.Function{
|
Functions: []ttir.Function{
|
||||||
{
|
{
|
||||||
Name: "main",
|
Name: "main",
|
||||||
|
HasReturnValue: true,
|
||||||
Instructions: []ttir.Instruction{
|
Instructions: []ttir.Instruction{
|
||||||
&ttir.Ret{Op: &ttir.Constant{Value: 0}},
|
&ttir.Ret{Op: &ttir.Constant{Value: 0}},
|
||||||
},
|
},
|
||||||
@ -154,6 +159,7 @@ func TestCodegen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedProgram := Program{
|
expectedProgram := Program{
|
||||||
|
|
||||||
Functions: []Function{
|
Functions: []Function{
|
||||||
{
|
{
|
||||||
Name: "main",
|
Name: "main",
|
||||||
@ -167,6 +173,7 @@ func TestCodegen(t *testing.T) {
|
|||||||
Opcode: Ret,
|
Opcode: Ret,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
HasReturnValue: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -176,8 +183,8 @@ func TestCodegen(t *testing.T) {
|
|||||||
|
|
||||||
actual := actualProgram.Emit()
|
actual := actualProgram.Emit()
|
||||||
expected := basicTest
|
expected := basicTest
|
||||||
if strings.Trim(actual, " \n\t") != strings.Trim(expected, " \n\t") {
|
if trim(actual) != trim(expected) {
|
||||||
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", expected, actual)
|
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", trim(expected), trim(actual))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,12 +205,63 @@ func TestBinary(t *testing.T) {
|
|||||||
},
|
},
|
||||||
&ttir.Ret{Op: &ttir.Var{Value: "temp.1"}},
|
&ttir.Ret{Op: &ttir.Var{Value: "temp.1"}},
|
||||||
},
|
},
|
||||||
|
HasReturnValue: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := CgProgram(program).Emit()
|
actual := CgProgram(program).Emit()
|
||||||
if strings.Trim(actual, " \n\t") != strings.Trim(binaryTest, " \n\t") {
|
if trim(actual) != trim(binaryTest) {
|
||||||
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", binaryTest, actual)
|
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", trim(binaryTest), trim(actual))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed equality_test.txt
|
||||||
|
var equalityTest string
|
||||||
|
|
||||||
|
// There was once a bug with how the cmp instructions were generated, this check should fail if it happens again
|
||||||
|
func TestEqualityOperators(t *testing.T) {
|
||||||
|
program := ttir.Program{
|
||||||
|
Functions: []ttir.Function{
|
||||||
|
{
|
||||||
|
Name: "main",
|
||||||
|
HasReturnValue: false,
|
||||||
|
Instructions: []ttir.Instruction{
|
||||||
|
&ttir.Binary{
|
||||||
|
Lhs: &ttir.Constant{Value: 5},
|
||||||
|
Rhs: &ttir.Constant{Value: 4},
|
||||||
|
Dst: &ttir.Var{Value: "temp.1"},
|
||||||
|
Operator: ast.LessThanEqual,
|
||||||
|
},
|
||||||
|
&ttir.Binary{
|
||||||
|
Lhs: &ttir.Constant{Value: 5},
|
||||||
|
Rhs: &ttir.Constant{Value: 4},
|
||||||
|
Dst: &ttir.Var{Value: "temp.2"},
|
||||||
|
Operator: ast.LessThan,
|
||||||
|
},
|
||||||
|
&ttir.Binary{
|
||||||
|
Lhs: &ttir.Constant{Value: 5},
|
||||||
|
Rhs: &ttir.Constant{Value: 4},
|
||||||
|
Dst: &ttir.Var{Value: "temp.3"},
|
||||||
|
Operator: ast.GreaterThanEqual,
|
||||||
|
},
|
||||||
|
&ttir.Binary{
|
||||||
|
Lhs: &ttir.Constant{Value: 5},
|
||||||
|
Rhs: &ttir.Constant{Value: 4},
|
||||||
|
Dst: &ttir.Var{Value: "temp.4"},
|
||||||
|
Operator: ast.GreaterThan,
|
||||||
|
},
|
||||||
|
&ttir.Ret{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := CgProgram(&program).Emit()
|
||||||
|
actualTrimmed := trim(actual)
|
||||||
|
expectedTrimmed := trim(actualTrimmed)
|
||||||
|
|
||||||
|
if expectedTrimmed != actualTrimmed {
|
||||||
|
t.Errorf("Expected program to be:\n>>%s<<\nbut got:\n>>%s<<\n", expectedTrimmed, actualTrimmed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func cgInstruction(i ttir.Instruction) []Instruction {
|
|||||||
|
|
||||||
func cgBinary(b *ttir.Binary) []Instruction {
|
func cgBinary(b *ttir.Binary) []Instruction {
|
||||||
switch b.Operator {
|
switch b.Operator {
|
||||||
case ast.Equal, ast.NotEqual:
|
case ast.Equal, ast.NotEqual, ast.GreaterThan, ast.GreaterThanEqual, ast.LessThan, ast.LessThanEqual:
|
||||||
var condCode CondCode
|
var condCode CondCode
|
||||||
|
|
||||||
switch b.Operator {
|
switch b.Operator {
|
||||||
@ -89,6 +89,14 @@ func cgBinary(b *ttir.Binary) []Instruction {
|
|||||||
condCode = Equal
|
condCode = Equal
|
||||||
case ast.NotEqual:
|
case ast.NotEqual:
|
||||||
condCode = NotEqual
|
condCode = NotEqual
|
||||||
|
case ast.GreaterThan:
|
||||||
|
condCode = Greater
|
||||||
|
case ast.GreaterThanEqual:
|
||||||
|
condCode = GreaterEqual
|
||||||
|
case ast.LessThan:
|
||||||
|
condCode = Less
|
||||||
|
case ast.LessThanEqual:
|
||||||
|
condCode = LessEqual
|
||||||
}
|
}
|
||||||
|
|
||||||
return []Instruction{
|
return []Instruction{
|
||||||
@ -278,7 +286,7 @@ func fixupInstruction(i Instruction) []Instruction {
|
|||||||
&SimpleInstruction{
|
&SimpleInstruction{
|
||||||
Opcode: Cmp,
|
Opcode: Cmp,
|
||||||
Lhs: Register(R11),
|
Lhs: Register(R11),
|
||||||
Rhs: i.Lhs,
|
Rhs: i.Rhs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
asm/amd64/equality_test.txt
Normal file
33
asm/amd64/equality_test.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
format ELF64 executable
|
||||||
|
segment readable executable
|
||||||
|
entry _start
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
mov rdi, 0
|
||||||
|
mov rax, 60
|
||||||
|
syscall
|
||||||
|
main:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
add rsp, -16
|
||||||
|
mov r11, 5
|
||||||
|
cmp r11, 4
|
||||||
|
mov qword [rsp -4], 0
|
||||||
|
setle byte [rsp -4]
|
||||||
|
mov r11, 5
|
||||||
|
cmp r11, 4
|
||||||
|
mov qword [rsp -8], 0
|
||||||
|
setl byte [rsp -8]
|
||||||
|
mov r11, 5
|
||||||
|
cmp r11, 4
|
||||||
|
mov qword [rsp -12], 0
|
||||||
|
setge byte [rsp -12]
|
||||||
|
mov r11, 5
|
||||||
|
cmp r11, 4
|
||||||
|
mov qword [rsp -16], 0
|
||||||
|
setg byte [rsp -16]
|
||||||
|
mov rsp, rbp
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
14
ast/ast.go
14
ast/ast.go
@ -93,10 +93,14 @@ const (
|
|||||||
Divide
|
Divide
|
||||||
Equal
|
Equal
|
||||||
NotEqual
|
NotEqual
|
||||||
|
LessThan
|
||||||
|
LessThanEqual
|
||||||
|
GreaterThan
|
||||||
|
GreaterThanEqual
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bo BinaryOperator) IsBooleanOperator() bool {
|
func (bo BinaryOperator) IsBooleanOperator() bool {
|
||||||
return bo == Equal || bo == NotEqual
|
return bo == Equal || bo == NotEqual || bo == LessThan || bo == LessThanEqual || bo == GreaterThan || bo == GreaterThanEqual
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bo BinaryOperator) SymbolString() string {
|
func (bo BinaryOperator) SymbolString() string {
|
||||||
@ -113,6 +117,14 @@ func (bo BinaryOperator) SymbolString() string {
|
|||||||
return "=="
|
return "=="
|
||||||
case NotEqual:
|
case NotEqual:
|
||||||
return "!="
|
return "!="
|
||||||
|
case LessThan:
|
||||||
|
return "<"
|
||||||
|
case LessThanEqual:
|
||||||
|
return "<="
|
||||||
|
case GreaterThan:
|
||||||
|
return ">"
|
||||||
|
case GreaterThanEqual:
|
||||||
|
return ">="
|
||||||
}
|
}
|
||||||
return "<INVALID BINARY OPERATOR>"
|
return "<INVALID BINARY OPERATOR>"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
```tt
|
```tt
|
||||||
|
|
||||||
// Return type is i64
|
// Return type is i64
|
||||||
fn main() = {
|
fn main() = {
|
||||||
let i = 34;
|
let i = 34;
|
||||||
|
@ -75,6 +75,26 @@ func (l *Lexer) NextToken() token.Token {
|
|||||||
return tok
|
return tok
|
||||||
}
|
}
|
||||||
tok = l.newToken(token.Equal)
|
tok = l.newToken(token.Equal)
|
||||||
|
case '<':
|
||||||
|
if l.peekByte() == '=' {
|
||||||
|
pos := l.position
|
||||||
|
l.readChar()
|
||||||
|
l.readChar()
|
||||||
|
tok.Type = token.LessThanEqual
|
||||||
|
tok.Literal = l.input[pos:l.position]
|
||||||
|
return tok
|
||||||
|
}
|
||||||
|
tok = l.newToken(token.LessThan)
|
||||||
|
case '>':
|
||||||
|
if l.peekByte() == '=' {
|
||||||
|
pos := l.position
|
||||||
|
l.readChar()
|
||||||
|
l.readChar()
|
||||||
|
tok.Type = token.GreaterThanEqual
|
||||||
|
tok.Literal = l.input[pos:l.position]
|
||||||
|
return tok
|
||||||
|
}
|
||||||
|
tok = l.newToken(token.GreaterThan)
|
||||||
case '(':
|
case '(':
|
||||||
tok = l.newToken(token.OpenParen)
|
tok = l.newToken(token.OpenParen)
|
||||||
case ')':
|
case ')':
|
||||||
|
@ -19,12 +19,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var precedences = map[token.TokenType]precedence{
|
var precedences = map[token.TokenType]precedence{
|
||||||
token.Plus: PrecSum,
|
token.Plus: PrecSum,
|
||||||
token.Minus: PrecSum,
|
token.Minus: PrecSum,
|
||||||
token.Asterisk: PrecProduct,
|
token.Asterisk: PrecProduct,
|
||||||
token.Slash: PrecProduct,
|
token.Slash: PrecProduct,
|
||||||
token.DoubleEqual: PrecComparison,
|
token.DoubleEqual: PrecComparison,
|
||||||
token.NotEqual: PrecComparison,
|
token.NotEqual: PrecComparison,
|
||||||
|
token.GreaterThan: PrecComparison,
|
||||||
|
token.GreaterThanEqual: PrecComparison,
|
||||||
|
token.LessThan: PrecComparison,
|
||||||
|
token.LessThanEqual: PrecComparison,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorCallback func(token.Token, string, ...any)
|
type ErrorCallback func(token.Token, string, ...any)
|
||||||
@ -60,6 +64,10 @@ func New(l *lexer.Lexer) *Parser {
|
|||||||
p.registerInfixFn(token.Slash, p.parseBinaryExpression)
|
p.registerInfixFn(token.Slash, p.parseBinaryExpression)
|
||||||
p.registerInfixFn(token.DoubleEqual, p.parseBinaryExpression)
|
p.registerInfixFn(token.DoubleEqual, p.parseBinaryExpression)
|
||||||
p.registerInfixFn(token.NotEqual, p.parseBinaryExpression)
|
p.registerInfixFn(token.NotEqual, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.GreaterThan, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.GreaterThanEqual, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.LessThan, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.LessThanEqual, p.parseBinaryExpression)
|
||||||
|
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
@ -270,6 +278,14 @@ func (p *Parser) parseBinaryExpression(lhs ast.Expression) ast.Expression {
|
|||||||
op = ast.Equal
|
op = ast.Equal
|
||||||
case token.NotEqual:
|
case token.NotEqual:
|
||||||
op = ast.NotEqual
|
op = ast.NotEqual
|
||||||
|
case token.LessThan:
|
||||||
|
op = ast.LessThan
|
||||||
|
case token.LessThanEqual:
|
||||||
|
op = ast.LessThanEqual
|
||||||
|
case token.GreaterThan:
|
||||||
|
op = ast.GreaterThan
|
||||||
|
case token.GreaterThanEqual:
|
||||||
|
op = ast.GreaterThanEqual
|
||||||
default:
|
default:
|
||||||
return p.exprError(p.curToken, "invalid token for binary expression %s", p.curToken.Type)
|
return p.exprError(p.curToken, "invalid token for binary expression %s", p.curToken.Type)
|
||||||
}
|
}
|
||||||
|
7
test.tt
7
test.tt
@ -1,5 +1,6 @@
|
|||||||
fn main() = {
|
fn main() = {
|
||||||
3 + 3;
|
5 <= 4;
|
||||||
3 * 43 * 34 / 34;
|
5 < 4;
|
||||||
3
|
5 >= 4;
|
||||||
|
5 > 4;
|
||||||
};
|
};
|
||||||
|
@ -36,12 +36,16 @@ const (
|
|||||||
CloseBrack TokenType = "}"
|
CloseBrack TokenType = "}"
|
||||||
|
|
||||||
// Binary Operators
|
// Binary Operators
|
||||||
Plus TokenType = "+"
|
Plus TokenType = "+"
|
||||||
Minus TokenType = "-"
|
Minus TokenType = "-"
|
||||||
Asterisk TokenType = "*"
|
Asterisk TokenType = "*"
|
||||||
Slash TokenType = "/"
|
Slash TokenType = "/"
|
||||||
DoubleEqual TokenType = "=="
|
DoubleEqual TokenType = "=="
|
||||||
NotEqual TokenType = "!="
|
NotEqual TokenType = "!="
|
||||||
|
LessThan TokenType = "<"
|
||||||
|
LessThanEqual TokenType = "<="
|
||||||
|
GreaterThan TokenType = ">"
|
||||||
|
GreaterThanEqual TokenType = ">="
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
Fn TokenType = "FN"
|
Fn TokenType = "FN"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user