Implement more features (WIP)

This commit is contained in:
MrLetsplay 2024-03-23 14:03:20 +01:00
parent 8433736096
commit 508ed37040
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
6 changed files with 250 additions and 81 deletions

View File

@ -180,8 +180,8 @@ func compileExpressionWAT(expr Expression, block Block) (string, error) {
} }
return "local.get $" + strconv.Itoa(block.Locals[ref.Variable].Index) + "\n" + cast, nil return "local.get $" + strconv.Itoa(block.Locals[ref.Variable].Index) + "\n" + cast, nil
case Expression_Arithmetic: case Expression_Binary:
arith := expr.Value.(ArithmeticExpression) arith := expr.Value.(BinaryExpression)
log.Printf("%+#v", arith) log.Printf("%+#v", arith)
@ -228,6 +228,8 @@ func compileExpressionWAT(expr Expression, block Block) (string, error) {
op = getPrimitiveWATType(exprType) + ".div_" + suffix + "\n" op = getPrimitiveWATType(exprType) + ".div_" + suffix + "\n"
case Arithmetic_Mod: case Arithmetic_Mod:
op = getPrimitiveWATType(exprType) + ".rem_" + suffix + "\n" op = getPrimitiveWATType(exprType) + ".rem_" + suffix + "\n"
default:
panic("operation not implemented")
} }
return watLeft + castLeft + watRight + castRight + op + getTypeCast(exprType), nil return watLeft + castLeft + watRight + castRight + op + getTypeCast(exprType), nil
@ -319,7 +321,7 @@ func compileStatementWAT(stmt Statement, block Block) (string, error) {
return wat + "local.set $" + strconv.Itoa(block.Locals[dlv.Variable].Index) + "\n", nil return wat + "local.set $" + strconv.Itoa(block.Locals[dlv.Variable].Index) + "\n", nil
} }
return "", nil panic("stmt not implemented")
} }
func compileBlockWAT(block Block) (string, error) { func compileBlockWAT(block Block) (string, error) {

View File

@ -2,7 +2,11 @@ u64 add(u8 a, u8 b) {
return add(a - 1u8, a); return add(a - 1u8, a);
} }
u64 addわ(u64 a, u64 b) { u64 add2(u64 a, u64 b) {
if(a == b) {
return 0;
}
return a + b; return a + b;
} }

118
lexer.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"log"
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
@ -21,7 +22,7 @@ const (
type Keyword uint32 type Keyword uint32
var Keywords []string = []string{"import", "void", "return", "true", "false"} var Keywords []string = []string{"import", "void", "return", "true", "false", "if", "else"}
const ( const (
Keyword_Import Keyword = iota Keyword_Import Keyword = iota
@ -29,6 +30,8 @@ const (
Keyword_Return Keyword_Return
Keyword_True Keyword_True
KeyWord_False KeyWord_False
Keyword_If
Keyword_Else
) )
type Separator uint32 type Separator uint32
@ -46,7 +49,7 @@ const (
type Operator uint32 type Operator uint32
var Operators []rune = []rune{'=', '>', '<', '!', '+', '-', '*', '/', '%'} var Operators []string = []string{"=", ">", "<", "!", "+", "-", "*", "/", "%", "==", ">=", "<=", "!=", "+=", "-=", "*=", "/=", "%="}
const ( const (
Operator_Equals Operator = iota Operator_Equals Operator = iota
@ -58,6 +61,15 @@ const (
Operator_Multiply Operator_Multiply
Operator_Divide Operator_Divide
Operator_Modulo Operator_Modulo
Operator_EqualsEquals
Operator_GreaterEquals
Operator_LessEquals
Operator_NotEquals
Operator_PlusEquals
Operator_MinusEquals
Operator_MultiplyEquals
Operator_DivideEquals
Operator_ModuloEquals
) )
type LiteralType uint32 type LiteralType uint32
@ -98,6 +110,30 @@ func (l *Lexer) peekRune() *rune {
return &l.Runes[0] return &l.Runes[0]
} }
func (l *Lexer) tryOperator() Operator {
var foundOp Operator = InvalidValue
var foundOpLen int = 0
str := string(l.Runes)
for i, operator := range Operators {
operatorLen := len([]rune(operator))
if operatorLen <= foundOpLen {
continue
}
if strings.HasPrefix(str, operator) {
foundOp = Operator(i)
foundOpLen = len([]rune(operator))
}
}
for i := 0; i < foundOpLen; i++ {
l.nextRune()
}
return foundOp
}
func (l *Lexer) nextRune() *rune { func (l *Lexer) nextRune() *rune {
if len(l.Runes) == 0 { if len(l.Runes) == 0 {
return nil return nil
@ -145,12 +181,12 @@ func (l *Lexer) stringLiteral() (string, error) {
} }
// TODO: maybe this method should directly return LexToken // TODO: maybe this method should directly return LexToken
func (l *Lexer) nextToken() (string, error) { func (l *Lexer) nextToken() (*LexToken, error) {
// Skip whitespace // Skip whitespace
for { for {
r := l.peekRune() r := l.peekRune()
if r == nil { if r == nil {
return "", nil return nil, nil
} }
if !slices.Contains(Whitespace, *r) { if !slices.Contains(Whitespace, *r) {
@ -164,55 +200,40 @@ func (l *Lexer) nextToken() (string, error) {
r := l.peekRune() r := l.peekRune()
if r == nil { if r == nil {
return "", nil return nil, nil
} }
if *r == '"' { if *r == '"' {
literal, err := l.stringLiteral() literal, err := l.stringLiteral()
if err != nil { if err != nil {
return "", err return nil, err
} }
return "\"" + literal + "\"", nil return &LexToken{Type: Type_Literal, Position: l.LastTokenPosition, Value: Literal{Type: Literal_String, Primitive: InvalidValue, Value: literal}}, nil
}
op := l.tryOperator()
if op != InvalidValue {
return &LexToken{Type: Type_Operator, Position: l.LastTokenPosition, Value: op}, nil
} }
token := "" token := ""
for { for {
r := l.peekRune() r := l.peekRune()
if r == nil || slices.Contains(Whitespace, *r) || slices.Contains(Separators, *r) || slices.Contains(Operators, *r) { if r == nil || slices.Contains(Whitespace, *r) || slices.Contains(Separators, *r) {
break break
} }
token += string(*l.nextRune()) token += string(*l.nextRune())
} }
if len(token) == 0 && len(l.Runes) != 0 { if len(token) == 0 {
return string(*l.nextRune()), nil if len(l.Runes) == 0 {
println("E3")
return nil, nil
} }
return token, nil token = string(*l.nextRune())
}
func parseNumber(raw string, numberType PrimitiveType) (any, error) {
// TODO: return compiler errors
if isSignedInt(numberType) {
return strconv.ParseInt(raw, 10, getBits(numberType))
}
if isUnsignedInt(numberType) {
return strconv.ParseUint(raw, 10, getBits(numberType))
}
if isFloatingPoint(numberType) {
return strconv.ParseFloat(raw, getBits(numberType))
}
panic("Unhandled type (" + strconv.FormatUint(uint64(numberType), 10) + ") in parseNumber()")
}
func (l *Lexer) parseToken(token string) (*LexToken, error) {
if strings.HasPrefix(token, "\"") {
return &LexToken{Type: Type_Literal, Position: l.LastTokenPosition, Value: Literal{Type: Literal_String, Primitive: InvalidValue, Value: token[1 : len(token)-1]}}, nil
} }
runes := []rune(token) runes := []rune(token)
@ -254,10 +275,6 @@ func (l *Lexer) parseToken(token string) (*LexToken, error) {
if idx := slices.Index(Separators, runes[0]); idx != -1 { if idx := slices.Index(Separators, runes[0]); idx != -1 {
return &LexToken{Type: Type_Separator, Position: l.LastTokenPosition, Value: Separator(idx)}, nil return &LexToken{Type: Type_Separator, Position: l.LastTokenPosition, Value: Separator(idx)}, nil
} }
if idx := slices.Index(Operators, runes[0]); idx != -1 {
return &LexToken{Type: Type_Operator, Position: l.LastTokenPosition, Value: Operator(idx)}, nil
}
} }
if idx := slices.Index(Keywords, token); idx != -1 { if idx := slices.Index(Keywords, token); idx != -1 {
@ -267,6 +284,23 @@ func (l *Lexer) parseToken(token string) (*LexToken, error) {
return &LexToken{Type: Type_Identifier, Position: l.LastTokenPosition, Value: token}, nil return &LexToken{Type: Type_Identifier, Position: l.LastTokenPosition, Value: token}, nil
} }
func parseNumber(raw string, numberType PrimitiveType) (any, error) {
// TODO: return compiler errors
if isSignedInt(numberType) {
return strconv.ParseInt(raw, 10, getBits(numberType))
}
if isUnsignedInt(numberType) {
return strconv.ParseUint(raw, 10, getBits(numberType))
}
if isFloatingPoint(numberType) {
return strconv.ParseFloat(raw, getBits(numberType))
}
panic("Unhandled type (" + strconv.FormatUint(uint64(numberType), 10) + ") in parseNumber()")
}
func lexer(program string) ([]LexToken, error) { func lexer(program string) ([]LexToken, error) {
var tokens []LexToken var tokens []LexToken
@ -274,20 +308,16 @@ func lexer(program string) ([]LexToken, error) {
for { for {
token, err := lexer.nextToken() token, err := lexer.nextToken()
log.Printf("%+#v %+#v", token, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(token) == 0 { if token == nil {
break break
} }
lexToken, err := lexer.parseToken(token) tokens = append(tokens, *token)
if err != nil {
return nil, err
}
tokens = append(tokens, *lexToken)
} }
return tokens, nil return tokens, nil

153
parser.go
View File

@ -39,6 +39,7 @@ const (
Statement_Block Statement_Block
Statement_Return Statement_Return
Statement_DeclareLocalVariable Statement_DeclareLocalVariable
Statement_If
) )
type Statement struct { type Statement struct {
@ -65,13 +66,19 @@ type DeclareLocalVariableStatement struct {
Initializer *Expression Initializer *Expression
} }
type IfStatement struct {
Condition Expression
ConditionalBlock Block
ElseBlock *Block
}
type ExpressionType uint32 type ExpressionType uint32
const ( const (
Expression_Assignment ExpressionType = iota Expression_Assignment ExpressionType = iota
Expression_Literal Expression_Literal
Expression_VariableReference Expression_VariableReference
Expression_Arithmetic Expression_Binary
Expression_Tuple Expression_Tuple
Expression_FunctionCall Expression_FunctionCall
Expression_Negate Expression_Negate
@ -105,9 +112,16 @@ const (
Arithmetic_Mul Arithmetic_Mul
Arithmetic_Div Arithmetic_Div
Arithmetic_Mod Arithmetic_Mod
Arithmetic_Greater
Arithmetic_Less
Arithmetic_GreaterEquals
Arithmetic_LessEquals
Arithmetic_LogicalNot
Arithmetic_NotEquals
Arithmetic_Equals
) )
type ArithmeticExpression struct { type BinaryExpression struct {
Operation ArithmeticOperation Operation ArithmeticOperation
Left Expression Left Expression
Right Expression Right Expression
@ -502,23 +516,7 @@ func (p *Parser) tryMultiplicativeExpression() (*Expression, error) {
return nil, p.error("expected expression") return nil, p.error("expected expression")
} }
var operation ArithmeticOperation left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: getArithmeticOperation(*op), Left: *left, Right: *right}, Position: left.Position}
switch *op {
case Operator_Multiply:
operation = Arithmetic_Mul
case Operator_Divide:
operation = Arithmetic_Div
case Operator_Plus:
operation = Arithmetic_Add
case Operator_Minus:
operation = Arithmetic_Sub
case Operator_Modulo:
fallthrough
default:
operation = Arithmetic_Mod
}
left = &Expression{Type: Expression_Arithmetic, Value: ArithmeticExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
} }
} }
@ -551,23 +549,86 @@ func (p *Parser) tryAdditiveExpression() (*Expression, error) {
return nil, p.error("expected expression") return nil, p.error("expected expression")
} }
var operation ArithmeticOperation left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: getArithmeticOperation(*op), Left: *left, Right: *right}, Position: left.Position}
if *op == Operator_Plus {
operation = Arithmetic_Add
} else {
operation = Arithmetic_Sub
}
left = &Expression{Type: Expression_Arithmetic, Value: ArithmeticExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
} }
} }
func (p *Parser) tryArithmeticExpression() (*Expression, error) { func (p *Parser) tryRelationalExpression() (*Expression, error) {
return p.tryAdditiveExpression() left, err := p.tryAdditiveExpression()
if err != nil {
return nil, err
}
if left == nil {
return nil, nil
}
for {
op, err := p.tryOperator(Operator_Less, Operator_Greater, Operator_LessEquals, Operator_GreaterEquals)
if err != nil {
return nil, err
}
if op == nil {
return left, nil
}
right, err := p.tryAdditiveExpression()
if err != nil {
return nil, err
}
if right == nil {
return nil, p.error("expected expression")
}
left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: getArithmeticOperation(*op), Left: *left, Right: *right}, Position: left.Position}
}
}
func (p *Parser) tryEqualityExpression() (*Expression, error) {
left, err := p.tryRelationalExpression()
if err != nil {
return nil, err
}
if left == nil {
return nil, nil
}
for {
op, err := p.tryOperator(Operator_EqualsEquals, Operator_NotEquals)
if err != nil {
return nil, err
}
if op == nil {
return left, nil
}
right, err := p.tryRelationalExpression()
if err != nil {
return nil, err
}
if right == nil {
return nil, p.error("expected expression")
}
left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: getArithmeticOperation(*op), Left: *left, Right: *right}, Position: left.Position}
}
}
func (p *Parser) tryBinaryExpression() (*Expression, error) {
return p.tryEqualityExpression()
} }
func (p *Parser) tryExpression() (*Expression, error) { func (p *Parser) tryExpression() (*Expression, error) {
return p.tryArithmeticExpression() return p.tryBinaryExpression()
}
func (p *Parser) expectExpression() (*Expression, error) {
return p.expect(p.tryExpression, "expected expression")
} }
func (p *Parser) tryTupleExpression() (*Expression, error) { func (p *Parser) tryTupleExpression() (*Expression, error) {
@ -698,6 +759,38 @@ func (p *Parser) expectStatement() (*Statement, error) {
return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: expr}, Position: token.Position}, nil return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: expr}, Position: token.Position}, nil
} }
if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_If {
p.nextToken()
_, err := p.expectSeparator(Separator_OpenParen)
if err != nil {
return nil, err
}
cond, err := p.expectExpression()
if err != nil {
return nil, err
}
_, err = p.expectSeparator(Separator_CloseParen)
if err != nil {
return nil, err
}
conditionalBlock, err := p.expectBlock()
if err != nil {
return nil, err
}
tok := p.peekToken()
if tok == nil || tok.Type != Type_Keyword || tok.Value.(Keyword) != Keyword_Else {
return &Statement{Type: Statement_If, Value: IfStatement{Condition: *cond, ConditionalBlock: *conditionalBlock, ElseBlock: nil}, Position: token.Position}, nil
}
p.nextToken()
// TODO: else block
}
if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenCurly { if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenCurly {
block, err := p.expectBlock() block, err := p.expectBlock()
if err != nil { if err != nil {

View File

@ -101,3 +101,43 @@ func getPrimitiveTypeByName(name string) (PrimitiveType, error) {
return PrimitiveType(idx), nil return PrimitiveType(idx), nil
} }
func isAssigmentOperator(operator Operator) bool {
switch operator {
case Operator_Equals, Operator_PlusEquals, Operator_MinusEquals, Operator_MultiplyEquals, Operator_DivideEquals, Operator_ModuloEquals:
return true
default:
return false
}
}
func getArithmeticOperation(operator Operator) ArithmeticOperation {
switch operator {
case Operator_Greater:
return Arithmetic_Greater
case Operator_Less:
return Arithmetic_Less
case Operator_Not:
return Arithmetic_LogicalNot
case Operator_Plus, Operator_PlusEquals:
return Arithmetic_Add
case Operator_Minus, Operator_MinusEquals:
return Arithmetic_Sub
case Operator_Multiply, Operator_MultiplyEquals:
return Arithmetic_Mul
case Operator_Divide, Operator_DivideEquals:
return Arithmetic_Div
case Operator_Modulo, Operator_ModuloEquals:
return Arithmetic_Mod
case Operator_EqualsEquals:
return Arithmetic_Equals
case Operator_GreaterEquals:
return Arithmetic_GreaterEquals
case Operator_LessEquals:
return Arithmetic_LessEquals
case Operator_NotEquals:
return Arithmetic_NotEquals
default:
return InvalidValue
}
}

View File

@ -117,8 +117,8 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression, block *B
} }
expr.ValueType = &local.Type expr.ValueType = &local.Type
case Expression_Arithmetic: case Expression_Binary:
arithmethic := expr.Value.(ArithmeticExpression) arithmethic := expr.Value.(BinaryExpression)
errors = append(errors, v.validateExpression(&arithmethic.Left, block)...) errors = append(errors, v.validateExpression(&arithmethic.Left, block)...)
errors = append(errors, v.validateExpression(&arithmethic.Right, block)...) errors = append(errors, v.validateExpression(&arithmethic.Right, block)...)