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_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 ")":
|
||||||
|
4
main.go
4
main.go
@ -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
334
parser.go
@ -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
|
||||||
}
|
}
|
||||||
|
9
types.go
9
types.go
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user