Some expression parsing

This commit is contained in:
MrLetsplay 2024-03-13 23:26:20 +01:00
parent 0318a83099
commit 66651ed67c
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
4 changed files with 341 additions and 26 deletions

View File

@ -19,6 +19,7 @@ const (
Type_Keyword Type_Keyword
Type_Separator Type_Separator
Type_Literal Type_Literal
Type_Operator
) )
type Keyword uint32 type Keyword uint32
@ -26,6 +27,7 @@ type Keyword uint32
const ( const (
Keyword_Import Keyword = iota Keyword_Import Keyword = iota
Keyword_Void Keyword_Void
Keyword_Return
) )
type Separator uint32 type Separator uint32
@ -39,6 +41,20 @@ const (
Separator_Comma 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 type LiteralType uint32
const ( const (
@ -64,7 +80,7 @@ type Lexer struct {
} }
func (l *Lexer) error(message string) error { 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 { 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 return &LexToken{Type: Type_Keyword, Position: l.Position, Value: Keyword_Void}, nil
case "import": case "import":
return &LexToken{Type: Type_Keyword, Position: l.Position, Value: Keyword_Import}, nil 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 "(": case "(":
return &LexToken{Type: Type_Separator, Position: l.Position, Value: Separator_OpenParen}, nil return &LexToken{Type: Type_Separator, Position: l.Position, Value: Separator_OpenParen}, nil
case ")": case ")":

View File

@ -26,6 +26,10 @@ func main() {
parser := Parser{Tokens: tokens} parser := Parser{Tokens: tokens}
parsed, err := parser.parseFile() parsed, err := parser.parseFile()
if err != nil { if err != nil {
if c, ok := err.(CompilerError); ok {
log.Fatalln(err, "\nv- here\n"+string([]rune(string(content))[c.Position:]))
}
log.Fatalln(err) log.Fatalln(err)
} }

334
parser.go
View File

@ -1,9 +1,7 @@
package main package main
import ( import (
"errors"
"slices" "slices"
"strconv"
"strings" "strings"
) )
@ -58,7 +56,7 @@ type ReturnStatement struct {
type DeclareLocalVariableStatement struct { type DeclareLocalVariableStatement struct {
Variable string Variable string
Initializer Expression Initializer *Expression
} }
type ExpressionType uint32 type ExpressionType uint32
@ -68,6 +66,7 @@ const (
Expression_Literal Expression_Literal
Expression_VariableReference Expression_VariableReference
Expression_Arithmetic Expression_Arithmetic
Expression_Tuple
) )
type Expression struct { type Expression struct {
@ -105,6 +104,10 @@ type ArithmeticExpression struct {
Right Expression Right Expression
} }
type TupleExpression struct {
Members []Expression
}
type Block struct { type Block struct {
Statements []Statement Statements []Statement
} }
@ -135,8 +138,12 @@ type Parser struct {
Position uint64 Position uint64
} }
func (p *Parser) error(message string) error { func (p Parser) copy() Parser {
return errors.New(message + " (at " + strconv.FormatUint(p.Position, 10) + ")") return p
}
func (p *Parser) error(message string) CompilerError {
return CompilerError{Position: p.Position, Message: message}
} }
func (p *Parser) peekToken() *LexToken { func (p *Parser) peekToken() *LexToken {
@ -158,23 +165,40 @@ func (p *Parser) nextToken() *LexToken {
return &token return &token
} }
func (p *Parser) expectSeparator(separators ...Separator) (Separator, error) { func (p *Parser) trySeparator(separators ...Separator) (*Separator, error) {
var separatorNames []string pCopy := p.copy()
for _, sep := range separators {
separatorNames = append(separatorNames, string(Separators[sep])) separator := pCopy.nextToken()
if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) {
return nil, nil
} }
separator := p.nextToken() *p = pCopy
if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) { 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 InvalidValue, p.error("expected one of " + strings.Join(separatorNames, " "))
} }
return separator.Value.(Separator), nil return *sep, nil
} }
func (p *Parser) expectIdentifier() (string, error) { func (p *Parser) expectIdentifier() (string, error) {
identifier := p.nextToken() 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") return "", p.error("expected identifier")
} }
@ -202,24 +226,55 @@ func (p *Parser) expectImport() (*Import, error) {
return &Import{Import: identifier.Value.(string)}, nil return &Import{Import: identifier.Value.(string)}, nil
} }
func (p *Parser) expectType() (*Type, error) { func (p *Parser) tryType() (*Type, error) {
var err error pCopy := p.copy()
tok := p.nextToken() tok := pCopy.nextToken()
if tok == nil { if tok == nil {
return nil, p.error("expected type") return nil, nil
} }
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void { if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void {
*p = pCopy
return &Type{Type: Type_Void, Value: nil}, nil 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 { if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen {
// Tuple type // Tuple type
p.nextToken()
var types []Type var types []Type
for { for {
var parsedType *Type parsedType, err := p.expectType()
parsedType, err = p.expectType()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -244,11 +299,236 @@ func (p *Parser) expectType() (*Type, error) {
return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, nil return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, nil
} }
if tok.Type == Type_Identifier { t, err := p.tryType()
return &Type{Type: Type_Named, Value: tok.Value}, nil 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) { func (p *Parser) expectBlock() (*Block, error) {
@ -269,8 +549,12 @@ func (p *Parser) expectBlock() (*Block, error) {
break break
} }
// TODO: parse statement stmt, err := p.expectStatement()
p.nextToken() if err != nil {
return nil, err
}
statements = append(statements, *stmt)
} }
return &Block{Statements: statements}, nil return &Block{Statements: statements}, nil
@ -284,7 +568,7 @@ func (p *Parser) expectFunction() (*ParsedFunction, error) {
var returnType *Type var returnType *Type
var body *Block var body *Block
returnType, err = p.expectType() returnType, err = p.expectTypeOrTupleType()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -33,6 +33,15 @@ const (
const InvalidValue = 0xEEEEEE // Magic value 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 { func isSignedInt(primitiveType PrimitiveType) bool {
switch primitiveType { switch primitiveType {
case Primitive_I8, Primitive_I16, Primitive_I32, Primitive_I64: case Primitive_I8, Primitive_I16, Primitive_I32, Primitive_I64: