From 66651ed67cfc80a30e6eb166ba17e6efcab2f227 Mon Sep 17 00:00:00 2001 From: MrLetsplay Date: Wed, 13 Mar 2024 23:26:20 +0100 Subject: [PATCH] Some expression parsing --- lexer.go | 20 +++- main.go | 4 + parser.go | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++---- types.go | 9 ++ 4 files changed, 341 insertions(+), 26 deletions(-) diff --git a/lexer.go b/lexer.go index d857c88..1e9e0fc 100644 --- a/lexer.go +++ b/lexer.go @@ -19,6 +19,7 @@ const ( Type_Keyword Type_Separator Type_Literal + Type_Operator ) type Keyword uint32 @@ -26,6 +27,7 @@ type Keyword uint32 const ( Keyword_Import Keyword = iota Keyword_Void + Keyword_Return ) type Separator uint32 @@ -39,6 +41,20 @@ const ( Separator_Comma ) +type Operator uint32 + +const ( + Operator_Equals Operator = iota + Operator_Greater + Operator_Less + Operator_Not + Operator_Plus + Operator_Minus + Operator_Multiply + Operator_Divide + Operator_Modulo +) + type LiteralType uint32 const ( @@ -64,7 +80,7 @@ type Lexer struct { } func (l *Lexer) error(message string) error { - return errors.New(message + " (at " + strconv.FormatUint(l.Position, 10) + ")") + return CompilerError{Position: l.Position, Message: message} } func (l *Lexer) peekRune() *rune { @@ -230,6 +246,8 @@ func (l *Lexer) parseToken(token string) (*LexToken, error) { return &LexToken{Type: Type_Keyword, Position: l.Position, Value: Keyword_Void}, nil case "import": return &LexToken{Type: Type_Keyword, Position: l.Position, Value: Keyword_Import}, nil + case "return": + return &LexToken{Type: Type_Keyword, Position: l.Position, Value: Keyword_Return}, nil case "(": return &LexToken{Type: Type_Separator, Position: l.Position, Value: Separator_OpenParen}, nil case ")": diff --git a/main.go b/main.go index 958aa35..c80fa7d 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,10 @@ func main() { parser := Parser{Tokens: tokens} parsed, err := parser.parseFile() if err != nil { + if c, ok := err.(CompilerError); ok { + log.Fatalln(err, "\nv- here\n"+string([]rune(string(content))[c.Position:])) + } + log.Fatalln(err) } diff --git a/parser.go b/parser.go index dbe3b3e..1e5e217 100644 --- a/parser.go +++ b/parser.go @@ -1,9 +1,7 @@ package main import ( - "errors" "slices" - "strconv" "strings" ) @@ -58,7 +56,7 @@ type ReturnStatement struct { type DeclareLocalVariableStatement struct { Variable string - Initializer Expression + Initializer *Expression } type ExpressionType uint32 @@ -68,6 +66,7 @@ const ( Expression_Literal Expression_VariableReference Expression_Arithmetic + Expression_Tuple ) type Expression struct { @@ -105,6 +104,10 @@ type ArithmeticExpression struct { Right Expression } +type TupleExpression struct { + Members []Expression +} + type Block struct { Statements []Statement } @@ -135,8 +138,12 @@ type Parser struct { Position uint64 } -func (p *Parser) error(message string) error { - return errors.New(message + " (at " + strconv.FormatUint(p.Position, 10) + ")") +func (p Parser) copy() Parser { + return p +} + +func (p *Parser) error(message string) CompilerError { + return CompilerError{Position: p.Position, Message: message} } func (p *Parser) peekToken() *LexToken { @@ -158,23 +165,40 @@ func (p *Parser) nextToken() *LexToken { return &token } -func (p *Parser) expectSeparator(separators ...Separator) (Separator, error) { - var separatorNames []string - for _, sep := range separators { - separatorNames = append(separatorNames, string(Separators[sep])) +func (p *Parser) trySeparator(separators ...Separator) (*Separator, error) { + pCopy := p.copy() + + separator := pCopy.nextToken() + if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) { + return nil, nil } - separator := p.nextToken() - if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) { + *p = pCopy + sep := separator.Value.(Separator) + return &sep, nil +} + +func (p *Parser) expectSeparator(separators ...Separator) (Separator, error) { + sep, err := p.trySeparator(separators...) + if err != nil { + return InvalidValue, err + } + + if sep == nil { + var separatorNames []string + for _, sep := range separators { + separatorNames = append(separatorNames, string(Separators[sep])) + } + return InvalidValue, p.error("expected one of " + strings.Join(separatorNames, " ")) } - return separator.Value.(Separator), nil + return *sep, nil } func (p *Parser) expectIdentifier() (string, error) { identifier := p.nextToken() - if identifier == nil || identifier.Type != Type_Separator && identifier.Type != Type_Identifier { + if identifier == nil || identifier.Type != Type_Identifier { return "", p.error("expected identifier") } @@ -202,24 +226,55 @@ func (p *Parser) expectImport() (*Import, error) { return &Import{Import: identifier.Value.(string)}, nil } -func (p *Parser) expectType() (*Type, error) { - var err error +func (p *Parser) tryType() (*Type, error) { + pCopy := p.copy() - tok := p.nextToken() + tok := pCopy.nextToken() if tok == nil { - return nil, p.error("expected type") + return nil, nil } if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void { + *p = pCopy return &Type{Type: Type_Void, Value: nil}, nil } + if tok.Type == Type_Identifier { + // TODO: array type + *p = pCopy + return &Type{Type: Type_Named, Value: tok.Value}, nil + } + + return nil, nil +} + +func (p *Parser) expectType() (*Type, error) { + t, err := p.tryType() + if err != nil { + return nil, err + } + + if t != nil { + return t, nil + } + + return nil, p.error("expected type") +} + +func (p *Parser) expectTypeOrTupleType() (*Type, error) { + var err error + + tok := p.peekToken() + if tok == nil { + return nil, p.error("expected type or tuple type") + } + if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen { // Tuple type + p.nextToken() var types []Type for { - var parsedType *Type - parsedType, err = p.expectType() + parsedType, err := p.expectType() if err != nil { return nil, err } @@ -244,11 +299,236 @@ func (p *Parser) expectType() (*Type, error) { return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, nil } - if tok.Type == Type_Identifier { - return &Type{Type: Type_Named, Value: tok.Value}, nil + t, err := p.tryType() + if err != nil { + return nil, err } - return nil, p.error("expected type") + if t != nil { + return t, nil + } + + return nil, p.error("expected type or tuple type") +} + +func (p *Parser) tryParanthesizedExpression() (*Expression, error) { + pCopy := p.copy() + + token := pCopy.nextToken() + if token == nil || token.Type != Type_Separator || token.Value.(Separator) != Separator_OpenParen { + return nil, nil + } + + expr, err := pCopy.tryExpression() + if err != nil { + *p = pCopy + return nil, err + } + + if expr == nil { + return nil, nil + } + + // Assuming we're in a paranthesized statement + _, err = pCopy.expectSeparator(Separator_CloseParen) + if err != nil { + *p = pCopy + return nil, err + } + + *p = pCopy + return expr, nil +} + +func (p *Parser) tryUnaryExpression() (*Expression, error) { + pCopy := p.copy() + + token := pCopy.peekToken() + if token == nil { + return nil, nil + } + + if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenParen { + paren, err := pCopy.tryParanthesizedExpression() + if err != nil { + *p = pCopy + return nil, err + } + + if paren != nil { + *p = pCopy + return paren, nil + } + + // TODO: cast + } + + if token.Type == Type_Identifier { + pCopy.nextToken() + *p = pCopy + return &Expression{Type: Expression_VariableReference, Value: VariableReferenceExpression{Variable: token.Value.(string)}}, nil + } + + return nil, nil +} + +func (p *Parser) tryMultiplicativeExpression() (*Expression, error) { + return p.tryUnaryExpression() +} + +func (p *Parser) tryAdditiveExpression() (*Expression, error) { + return p.tryMultiplicativeExpression() +} + +func (p *Parser) tryArithmeticExpression() (*Expression, error) { + return p.tryAdditiveExpression() +} + +func (p *Parser) tryExpression() (*Expression, error) { + return p.tryArithmeticExpression() +} + +func (p *Parser) tryTupleExpression() (*Expression, error) { + pCopy := p.copy() + + var members []Expression + for { + expr, err := pCopy.tryExpression() + if err != nil { + return nil, err + } + + if expr == nil { + return nil, nil + } + + members = append(members, *expr) + + token := pCopy.peekToken() + if token == nil || token.Type != Type_Separator || token.Value.(Separator) != Separator_Comma { + if len(members) <= 1 { + return nil, nil // None/One experession -> not a tuple expression + } + + break + } + + pCopy.nextToken() + } + + *p = pCopy + return &Expression{Type: Expression_Tuple, Value: TupleExpression{Members: members}}, nil +} + +func (p *Parser) expectTupleExpression() (*Expression, error) { + return p.expect(p.tryTupleExpression, "expected tuple expression") +} + +func (p *Parser) expect(try func() (*Expression, error), message string) (*Expression, error) { + expr, err := try() + if err != nil { + return nil, err + } + + if expr == nil { + return nil, p.error(message) + } + + return expr, nil +} + +func (p *Parser) tryDeclareLocalVariableStatement() (*Statement, error) { + pCopy := p.copy() + + token := pCopy.nextToken() + if token == nil { + return nil, nil + } + + variableType, err := pCopy.tryType() + if err != nil { + *p = pCopy + return nil, err + } + + if variableType == nil { + return nil, nil + } + + name := pCopy.nextToken() + if name == nil || name.Type != Type_Identifier { + return nil, nil + } + + variableName := name.Value.(string) + + token = pCopy.nextToken() + if token.Type == Type_Separator && token.Value.(Separator) == Separator_Semicolon { + return &Statement{Type: Statement_DeclareLocalVariable, Value: DeclareLocalVariableStatement{Variable: variableName, Initializer: nil}}, nil + } + + if token.Type != Type_Operator || token.Value.(Operator) != Operator_Equals { + return nil, nil + } + + initializer, err := p.expect(p.tryExpression, "expected initializer expression") + if err != nil { + *p = pCopy + return nil, err + } + + _, err = p.expectSeparator(Separator_Semicolon) + if err != nil { + *p = pCopy + return nil, err + } + + *p = pCopy + return &Statement{Type: Statement_DeclareLocalVariable, Value: DeclareLocalVariableStatement{Variable: variableName, Initializer: initializer}}, nil +} + +func (p *Parser) expectStatement() (*Statement, error) { + token := p.peekToken() + if token == nil { + return nil, p.error("expected statement") + } + + if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_Return { + p.nextToken() + + token = p.peekToken() + if token == nil { + return nil, p.error("expected expression or ;") + } + + if token.Type == Type_Separator && token.Value.(Separator) == Separator_Semicolon { + p.nextToken() + return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: nil}}, nil + } + + expr, err := p.expectTupleExpression() + if err != nil { + return nil, err + } + + _, err = p.expectSeparator(Separator_Semicolon) + if err != nil { + return nil, err + } + + return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: expr}}, nil + } + + if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenCurly { + block, err := p.expectBlock() + if err != nil { + return nil, err + } + + return &Statement{Type: Statement_Block, Value: BlockStatement{Block: *block}}, nil + } + + return nil, p.error("expected statement") } func (p *Parser) expectBlock() (*Block, error) { @@ -269,8 +549,12 @@ func (p *Parser) expectBlock() (*Block, error) { break } - // TODO: parse statement - p.nextToken() + stmt, err := p.expectStatement() + if err != nil { + return nil, err + } + + statements = append(statements, *stmt) } return &Block{Statements: statements}, nil @@ -284,7 +568,7 @@ func (p *Parser) expectFunction() (*ParsedFunction, error) { var returnType *Type var body *Block - returnType, err = p.expectType() + returnType, err = p.expectTypeOrTupleType() if err != nil { return nil, err } diff --git a/types.go b/types.go index 1be8d7c..8ae8c84 100644 --- a/types.go +++ b/types.go @@ -33,6 +33,15 @@ const ( const InvalidValue = 0xEEEEEE // Magic value +type CompilerError struct { + Position uint64 + Message string +} + +func (e CompilerError) Error() string { + return e.Message + " (at " + strconv.FormatUint(e.Position, 10) + ")" +} + func isSignedInt(primitiveType PrimitiveType) bool { switch primitiveType { case Primitive_I8, Primitive_I16, Primitive_I32, Primitive_I64: