Some expression parsing
This commit is contained in:
parent
0318a83099
commit
66651ed67c
20
lexer.go
20
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 ")":
|
||||
|
4
main.go
4
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)
|
||||
}
|
||||
|
||||
|
326
parser.go
326
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) 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
|
||||
}
|
||||
|
||||
*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]))
|
||||
}
|
||||
|
||||
separator := p.nextToken()
|
||||
if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) {
|
||||
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
|
||||
}
|
||||
|
9
types.go
9
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:
|
||||
|
Loading…
Reference in New Issue
Block a user