elysium/parser.go

1159 lines
24 KiB
Go
Raw Normal View History

2024-03-11 22:05:36 +01:00
package main
import (
"slices"
"strings"
)
type TypeType uint32
const (
Type_Primitive TypeType = iota
Type_Named
Type_Array
Type_Tuple
)
type Type struct {
2024-03-21 19:55:05 +01:00
Type TypeType
Value any
Position TokenPosition
2024-03-11 22:05:36 +01:00
}
type NamedType struct {
TypeName string
}
type ArrayType struct {
ElementType Type
}
type TupleType struct {
Types []Type
}
type StatementType uint32
const (
Statement_Expression StatementType = iota
Statement_Block
Statement_Return
Statement_DeclareLocalVariable
2024-03-23 14:03:20 +01:00
Statement_If
Statement_WhileLoop
2024-03-11 22:05:36 +01:00
)
type Statement struct {
2024-03-21 19:55:05 +01:00
Type StatementType
Value any
Position TokenPosition
2024-03-11 22:05:36 +01:00
}
2024-03-16 20:12:00 +01:00
type ExpressionStatement struct {
Expression Expression
}
2024-03-11 22:05:36 +01:00
type BlockStatement struct {
2024-03-24 20:53:34 +01:00
Block *Block
2024-03-11 22:05:36 +01:00
}
type ReturnStatement struct {
Value *Expression
}
type DeclareLocalVariableStatement struct {
2024-03-16 20:12:00 +01:00
Variable string
VariableType Type
Initializer *Expression
2024-03-11 22:05:36 +01:00
}
2024-03-23 14:03:20 +01:00
type IfStatement struct {
Condition Expression
2024-03-24 20:53:34 +01:00
ConditionalBlock *Block
2024-03-23 14:03:20 +01:00
ElseBlock *Block
}
type WhileLoopStatement struct {
Condition Expression
Body *Block
}
2024-03-11 22:05:36 +01:00
type ExpressionType uint32
const (
Expression_Assignment ExpressionType = iota
Expression_Literal
Expression_VariableReference
2024-03-23 14:03:20 +01:00
Expression_Binary
2024-03-13 23:26:20 +01:00
Expression_Tuple
Expression_FunctionCall
2024-04-09 13:57:17 +02:00
Expression_Unary
Expression_ArrayAccess
Expression_RawMemoryReference
Expression_Cast
2024-03-11 22:05:36 +01:00
)
type Expression struct {
2024-03-16 20:12:00 +01:00
Type ExpressionType
Value any
2024-03-21 19:55:05 +01:00
ValueType *Type
Position TokenPosition
2024-03-11 22:05:36 +01:00
}
type AssignmentExpression struct {
2024-04-02 19:43:05 +02:00
Lhs Expression
Value Expression
2024-03-11 22:05:36 +01:00
}
type LiteralExpression struct {
2024-03-14 16:42:22 +01:00
Literal Literal
2024-03-11 22:05:36 +01:00
}
type VariableReferenceExpression struct {
Variable string
}
2024-03-24 14:01:23 +01:00
type Operation uint32
2024-03-11 22:05:36 +01:00
const (
2024-03-24 14:01:23 +01:00
Operation_Add Operation = iota
Operation_Sub
Operation_Mul
Operation_Div
Operation_Mod
Operation_Greater
Operation_Less
Operation_GreaterEquals
Operation_LessEquals
Operation_NotEquals
Operation_Equals
2024-03-11 22:05:36 +01:00
)
2024-04-09 13:57:17 +02:00
type UnaryOperation uint32
const (
UnaryOperation_Negate UnaryOperation = iota
UnaryOperation_Nop
UnaryOperation_BitwiseNot
UnaryOperation_LogicalNot
2024-04-11 13:40:04 +02:00
UnaryOperation_PreIncrement
UnaryOperation_PreDecrement
UnaryOperation_PostIncrement
UnaryOperation_PostDecrement
2024-04-09 13:57:17 +02:00
)
2024-03-23 14:03:20 +01:00
type BinaryExpression struct {
Operation Operation
Left Expression
Right Expression
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
type TupleExpression struct {
Members []Expression
}
type FunctionCallExpression struct {
Function string
Parameters *Expression
}
2024-04-09 13:57:17 +02:00
type UnaryExpression struct {
Operation UnaryOperation
Value Expression
}
type ArrayAccessExpression struct {
Array Expression
Index Expression
}
type RawMemoryReferenceExpression struct {
Type Type
Address Expression
}
type CastExpression struct {
Type Type
Value Expression
}
2024-03-16 20:12:00 +01:00
type Local struct {
2024-03-18 21:14:28 +01:00
Name string
Type Type
IsParameter bool
Index int // unique, 0-based index of the local in the current function
2024-03-16 20:12:00 +01:00
}
2024-03-11 22:05:36 +01:00
type Block struct {
2024-03-31 20:33:50 +02:00
Parent *Block
2024-03-11 22:05:36 +01:00
Statements []Statement
2024-03-16 20:12:00 +01:00
Locals map[string]Local
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:00:03 +01:00
type ParsedParameter struct {
Name string
Type Type
}
2024-03-11 22:05:36 +01:00
type ParsedFunction struct {
2024-03-12 22:00:03 +01:00
Name string
FullName string // The fully-qualified name of the function, including the module name
2024-03-12 22:00:03 +01:00
Parameters []ParsedParameter
2024-03-21 19:55:05 +01:00
ReturnType *Type
2024-03-24 20:53:34 +01:00
Body *Block
2024-03-18 21:14:28 +01:00
Locals []Local // All of the locals of the function, ordered by their index
2024-03-11 22:05:36 +01:00
}
type Import struct {
Import string
}
type ParsedFile struct {
Module string
2024-03-11 22:05:36 +01:00
Imports []Import
Functions []ParsedFunction
}
2024-03-12 22:47:45 +01:00
type Parser struct {
2024-03-13 17:17:09 +01:00
Tokens []LexToken
Position TokenPosition
2024-03-13 17:17:09 +01:00
}
2024-03-13 23:26:20 +01:00
func (p Parser) copy() Parser {
return p
}
func (p *Parser) error(message string) CompilerError {
return CompilerError{Position: p.Position, Message: message}
2024-03-12 22:47:45 +01:00
}
2024-03-11 22:05:36 +01:00
2024-03-12 22:47:45 +01:00
func (p *Parser) peekToken() *LexToken {
2024-03-13 17:17:09 +01:00
if len(p.Tokens) == 0 {
2024-03-12 22:47:45 +01:00
return nil
2024-03-11 22:05:36 +01:00
}
2024-03-13 17:17:09 +01:00
return &p.Tokens[0]
2024-03-12 22:47:45 +01:00
}
func (p *Parser) nextToken() *LexToken {
2024-03-13 17:17:09 +01:00
if len(p.Tokens) == 0 {
2024-03-12 22:47:45 +01:00
return nil
2024-03-11 22:05:36 +01:00
}
2024-03-13 17:17:09 +01:00
token := p.Tokens[0]
p.Tokens = p.Tokens[1:]
p.Position = token.Position
2024-03-12 22:47:45 +01:00
return &token
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
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
}
2024-03-28 18:20:52 +01:00
func (p *Parser) expectSeparator(separators ...Separator) (*Separator, error) {
2024-03-13 23:26:20 +01:00
sep, err := p.trySeparator(separators...)
if err != nil {
2024-03-28 18:20:52 +01:00
return nil, err
2024-03-12 22:47:45 +01:00
}
2024-03-13 23:26:20 +01:00
if sep == nil {
var separatorNames []string
for _, sep := range separators {
separatorNames = append(separatorNames, string(Separators[sep]))
}
2024-03-28 18:20:52 +01:00
return nil, p.error("expected one of " + strings.Join(separatorNames, " "))
2024-03-12 22:00:03 +01:00
}
2024-03-28 18:20:52 +01:00
return sep, nil
2024-03-12 22:47:45 +01:00
}
2024-03-17 19:55:28 +01:00
func (p *Parser) tryOperator(operators ...Operator) (*Operator, error) {
pCopy := p.copy()
operator := pCopy.nextToken()
if operator == nil || operator.Type != Type_Operator || !slices.Contains(operators, operator.Value.(Operator)) {
return nil, nil
}
*p = pCopy
sep := operator.Value.(Operator)
return &sep, nil
}
2024-03-12 22:47:45 +01:00
func (p *Parser) expectIdentifier() (string, error) {
identifier := p.nextToken()
2024-03-13 23:26:20 +01:00
if identifier == nil || identifier.Type != Type_Identifier {
2024-03-13 17:17:09 +01:00
return "", p.error("expected identifier")
2024-03-12 22:00:03 +01:00
}
2024-03-12 22:47:45 +01:00
return identifier.Value.(string), nil
2024-03-12 22:00:03 +01:00
}
2024-03-12 22:47:45 +01:00
func (p *Parser) expectImport() (*Import, error) {
2024-03-11 22:05:36 +01:00
var err error
2024-03-12 22:47:45 +01:00
importToken := p.nextToken()
if importToken == nil || importToken.Type != Type_Keyword || importToken.Value.(Keyword) != Keyword_Import {
2024-03-13 17:17:09 +01:00
return nil, p.error("expected import")
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
identifier := p.nextToken()
if identifier == nil || identifier.Type != Type_Identifier {
2024-03-13 17:17:09 +01:00
return nil, p.error("expected identifier")
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
_, err = p.expectSeparator(Separator_Semicolon)
2024-03-11 22:05:36 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
return &Import{Import: identifier.Value.(string)}, nil
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
func (p *Parser) tryType() (*Type, error) {
pCopy := p.copy()
2024-03-11 22:05:36 +01:00
2024-03-13 23:26:20 +01:00
tok := pCopy.nextToken()
2024-03-12 22:47:45 +01:00
if tok == nil {
2024-03-13 23:26:20 +01:00
return nil, nil
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
if tok.Type == Type_Identifier {
2024-03-28 18:20:52 +01:00
var theType Type
2024-03-17 19:55:28 +01:00
index := slices.Index(PRIMITIVE_TYPE_NAMES, tok.Value.(string))
if index != -1 {
2024-03-28 18:20:52 +01:00
theType = Type{Type: Type_Primitive, Value: PrimitiveType(index), Position: tok.Position}
} else {
theType = Type{Type: Type_Named, Value: tok.Value, Position: tok.Position}
}
for {
sep, err := pCopy.trySeparator(Separator_OpenSquare)
if err != nil {
return nil, err
}
if sep == nil {
break
}
sep, err = pCopy.trySeparator(Separator_CloseSquare)
2024-03-28 18:20:52 +01:00
if err != nil {
return nil, err
}
if sep == nil {
return nil, nil
}
2024-03-28 18:20:52 +01:00
theType = Type{Type: Type_Array, Value: ArrayType{ElementType: theType}, Position: theType.Position}
2024-03-17 19:55:28 +01:00
}
2024-03-13 23:26:20 +01:00
*p = pCopy
2024-03-28 18:20:52 +01:00
return &theType, nil
2024-03-13 23:26:20 +01:00
}
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")
}
2024-03-11 22:05:36 +01:00
if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen {
// Tuple type
2024-03-13 23:26:20 +01:00
p.nextToken()
2024-03-11 22:05:36 +01:00
var types []Type
for {
2024-03-13 23:26:20 +01:00
parsedType, err := p.expectType()
2024-03-11 22:05:36 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-11 22:05:36 +01:00
}
types = append(types, *parsedType)
2024-03-28 18:20:52 +01:00
var sep *Separator
2024-03-12 22:47:45 +01:00
sep, err = p.expectSeparator(Separator_Comma, Separator_CloseParen)
2024-03-11 22:05:36 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-11 22:05:36 +01:00
}
2024-03-28 18:20:52 +01:00
if *sep == Separator_CloseParen {
2024-03-11 22:05:36 +01:00
break
}
}
if len(types) == 0 {
2024-03-13 17:17:09 +01:00
return nil, p.error("empty tuple")
2024-03-11 22:05:36 +01:00
}
2024-03-21 19:55:05 +01:00
return &Type{Type: Type_Tuple, Value: TupleType{Types: types}, Position: tok.Position}, nil
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
t, err := p.tryType()
if err != nil {
return nil, err
2024-03-11 22:05:36 +01:00
}
2024-03-13 23:26:20 +01:00
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
}
2024-04-02 19:43:05 +02:00
func (p *Parser) tryPrimaryExpressionNoArrayAccess() (*Expression, error) {
2024-03-13 23:26:20 +01:00
pCopy := p.copy()
token := pCopy.peekToken()
if token == nil {
return nil, nil
}
if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenParen {
2024-03-14 16:42:22 +01:00
// TODO: cast
2024-03-13 23:26:20 +01:00
paren, err := pCopy.tryParanthesizedExpression()
if err != nil {
*p = pCopy
return nil, err
}
if paren != nil {
*p = pCopy
return paren, nil
}
2024-03-14 16:42:22 +01:00
}
2024-03-13 23:26:20 +01:00
2024-03-14 16:42:22 +01:00
if token.Type == Type_Literal {
pCopy.nextToken()
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Expression{Type: Expression_Literal, Value: LiteralExpression{Literal: token.Value.(Literal)}, Position: token.Position}, nil
2024-03-14 16:42:22 +01:00
}
if token.Type == Type_Keyword {
keyword := token.Value.(Keyword)
if keyword == Keyword_True || keyword == KeyWord_False {
pCopy.nextToken()
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Expression{Type: Expression_Literal, Value: LiteralExpression{Literal: Literal{Type: Literal_Boolean, Primitive: Primitive_Bool, Value: keyword == Keyword_True}}, Position: token.Position}, nil
2024-03-14 16:42:22 +01:00
}
if keyword == Keyword_Raw {
pCopy.nextToken()
2024-04-02 19:43:05 +02:00
_, err := pCopy.expectSeparator(Separator_OpenParen)
if err != nil {
return nil, err
}
rawType, err := pCopy.expectType()
if err != nil {
return nil, err
}
_, err = pCopy.expectSeparator(Separator_Comma)
if err != nil {
return nil, err
}
address, err := pCopy.expectExpression()
if err != nil {
return nil, err
}
2024-04-02 19:43:05 +02:00
_, err = pCopy.expectSeparator(Separator_CloseParen)
if err != nil {
return nil, err
}
2024-04-02 19:43:05 +02:00
*p = pCopy
return &Expression{Type: Expression_RawMemoryReference, Value: RawMemoryReferenceExpression{Type: *rawType, Address: *address}, Position: token.Position}, nil
}
}
2024-03-13 23:26:20 +01:00
if token.Type == Type_Identifier {
pCopy.nextToken()
// TODO: possible module name
next, err := pCopy.trySeparator(Separator_OpenParen)
if err != nil {
return nil, err
}
if next != nil {
// Function call
params, err := pCopy.tryTupleExpression()
if err != nil {
return nil, err
}
_, err = pCopy.expectSeparator(Separator_CloseParen)
if err != nil {
return nil, err
}
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Expression{Type: Expression_FunctionCall, Value: FunctionCallExpression{Function: token.Value.(string), Parameters: params}, Position: token.Position}, nil
}
2024-03-13 23:26:20 +01:00
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Expression{Type: Expression_VariableReference, Value: VariableReferenceExpression{Variable: token.Value.(string)}, Position: token.Position}, nil
2024-03-13 23:26:20 +01:00
}
return nil, nil
}
2024-04-02 19:43:05 +02:00
func (p *Parser) tryPrimaryExpression() (*Expression, error) {
pCopy := p.copy()
2024-04-02 19:43:05 +02:00
expr, err := pCopy.tryPrimaryExpressionNoArrayAccess()
if err != nil {
return nil, err
}
if expr == nil {
return nil, nil
}
for {
open, err := pCopy.trySeparator(Separator_OpenSquare)
if err != nil {
return nil, err
}
if open == nil {
*p = pCopy
return expr, nil
}
index, err := pCopy.expectExpression()
if err != nil {
return nil, err
}
_, err = pCopy.expectSeparator(Separator_CloseSquare)
if err != nil {
return nil, err
}
expr = &Expression{Type: Expression_ArrayAccess, Value: ArrayAccessExpression{Array: *expr, Index: *index}, Position: expr.Position}
}
}
2024-04-02 19:43:05 +02:00
func (p *Parser) tryUnaryExpression() (*Expression, error) {
pCopy := p.copy()
token := pCopy.peekToken()
if token == nil {
return nil, nil
}
2024-04-11 13:40:04 +02:00
op, err := pCopy.tryOperator(Operator_Minus, Operator_Plus, Operator_BitwiseNot, Operator_Not, Operator_PlusPlus, Operator_MinusMinus)
2024-04-09 13:57:17 +02:00
if err != nil {
return nil, err
}
2024-04-02 19:43:05 +02:00
2024-04-09 13:57:17 +02:00
if op != nil {
expr, err := pCopy.tryPrimaryExpression()
if err != nil {
return nil, err
}
2024-04-02 19:43:05 +02:00
2024-04-09 13:57:17 +02:00
if expr == nil {
return nil, nil
2024-04-02 19:43:05 +02:00
}
2024-04-09 13:57:17 +02:00
*p = pCopy
2024-04-11 13:40:04 +02:00
switch *op {
case Operator_PlusPlus:
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: UnaryOperation_PreIncrement, Value: *expr}, Position: token.Position}, nil
case Operator_MinusMinus:
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: UnaryOperation_PreDecrement, Value: *expr}, Position: token.Position}, nil
}
2024-04-09 13:57:17 +02:00
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: getUnaryOperation(*op), Value: *expr}, Position: token.Position}, nil
2024-04-02 19:43:05 +02:00
}
2024-04-11 13:40:04 +02:00
expr, err := pCopy.tryPrimaryExpression()
if err != nil {
return nil, err
}
if expr == nil {
return nil, nil
}
op, err = pCopy.tryOperator(Operator_PlusPlus, Operator_MinusMinus)
if err != nil {
return nil, err
}
if op == nil {
*p = pCopy
return expr, nil
}
*p = pCopy
switch *op {
case Operator_PlusPlus:
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: UnaryOperation_PostIncrement, Value: *expr}, Position: token.Position}, nil
case Operator_MinusMinus:
return &Expression{Type: Expression_Unary, Value: UnaryExpression{Operation: UnaryOperation_PostDecrement, Value: *expr}, Position: token.Position}, nil
}
2024-04-09 13:57:17 +02:00
2024-04-11 13:40:04 +02:00
panic("Operator not implemented")
2024-04-02 19:43:05 +02:00
}
2024-03-23 14:10:53 +01:00
func (p *Parser) tryBinaryExpression0(opFunc func() (*Expression, error), operators ...Operator) (*Expression, error) {
left, err := opFunc()
2024-03-17 19:55:28 +01:00
if err != nil {
return nil, err
}
if left == nil {
return nil, nil
2024-03-17 19:55:28 +01:00
}
for {
2024-03-23 14:10:53 +01:00
op, err := p.tryOperator(operators...)
if err != nil {
return nil, err
}
2024-03-17 19:55:28 +01:00
if op == nil {
return left, nil
}
2024-03-17 19:55:28 +01:00
2024-03-23 14:10:53 +01:00
right, err := opFunc()
if err != nil {
return nil, err
}
2024-03-17 19:55:28 +01:00
if right == nil {
return nil, p.error("expected expression")
}
2024-04-09 13:57:17 +02:00
operation := getOperation(*op)
if operation == InvalidValue {
return nil, p.error("operator not allowed in binary expression")
}
left = &Expression{Type: Expression_Binary, Value: BinaryExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
}
2024-03-13 23:26:20 +01:00
}
2024-03-23 14:10:53 +01:00
func (p *Parser) tryMultiplicativeExpression() (*Expression, error) {
2024-04-04 20:11:01 +02:00
return p.tryBinaryExpression0(p.tryUnaryExpression, Operator_Multiply, Operator_Divide, Operator_Modulo)
2024-03-23 14:10:53 +01:00
}
2024-03-23 14:10:53 +01:00
func (p *Parser) tryAdditiveExpression() (*Expression, error) {
return p.tryBinaryExpression0(p.tryMultiplicativeExpression, Operator_Plus, Operator_Minus)
2024-03-23 14:03:20 +01:00
}
func (p *Parser) tryRelationalExpression() (*Expression, error) {
2024-03-23 14:10:53 +01:00
return p.tryBinaryExpression0(p.tryAdditiveExpression, Operator_Less, Operator_Greater, Operator_LessEquals, Operator_GreaterEquals)
2024-03-13 23:26:20 +01:00
}
2024-03-23 14:03:20 +01:00
func (p *Parser) tryEqualityExpression() (*Expression, error) {
2024-03-23 14:10:53 +01:00
return p.tryBinaryExpression0(p.tryRelationalExpression, Operator_EqualsEquals, Operator_NotEquals)
2024-03-23 14:03:20 +01:00
}
func (p *Parser) tryBinaryExpression() (*Expression, error) {
return p.tryEqualityExpression()
2024-03-13 23:26:20 +01:00
}
2024-03-24 21:36:34 +01:00
func (p *Parser) tryAssignmentExpression() (*Expression, error) {
pCopy := p.copy()
2024-04-02 19:43:05 +02:00
lhs, err := pCopy.tryPrimaryExpression()
2024-03-24 21:36:34 +01:00
if err != nil {
return nil, err
}
2024-04-09 13:57:17 +02:00
if lhs == nil || (lhs.Type != Expression_VariableReference && lhs.Type != Expression_ArrayAccess && lhs.Type != Expression_RawMemoryReference) {
2024-03-24 21:36:34 +01:00
return p.tryBinaryExpression()
}
op, err := pCopy.tryOperator(Operator_Equals, Operator_PlusEquals, Operator_MinusEquals, Operator_MultiplyEquals, Operator_DivideEquals, Operator_ModuloEquals)
2024-03-24 21:36:34 +01:00
if err != nil {
return nil, err
}
if op == nil {
return p.tryBinaryExpression()
}
expr, err := pCopy.expectExpression()
if err != nil {
return nil, err
}
if *op != Operator_Equals {
operation := getOperation(*op)
expr = &Expression{Type: Expression_Binary, Value: BinaryExpression{Left: *lhs, Right: *expr, Operation: operation}, Position: lhs.Position}
}
2024-03-24 21:36:34 +01:00
*p = pCopy
2024-04-02 19:43:05 +02:00
return &Expression{Type: Expression_Assignment, Value: AssignmentExpression{Lhs: *lhs, Value: *expr}, Position: lhs.Position}, nil
2024-03-24 21:36:34 +01:00
}
2024-03-13 23:26:20 +01:00
func (p *Parser) tryExpression() (*Expression, error) {
2024-03-24 21:36:34 +01:00
return p.tryAssignmentExpression()
2024-03-23 14:03:20 +01:00
}
func (p *Parser) expectExpression() (*Expression, error) {
return p.expect(p.tryExpression, "expected expression")
2024-03-13 23:26:20 +01:00
}
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 {
2024-03-14 16:42:22 +01:00
if len(members) == 1 {
*p = pCopy
return expr, nil
2024-03-13 23:26:20 +01:00
}
break
}
pCopy.nextToken()
}
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Expression{Type: Expression_Tuple, Value: TupleExpression{Members: members}, Position: members[0].Position}, nil
2024-03-13 23:26:20 +01:00
}
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()
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)
2024-03-14 16:42:22 +01:00
token := pCopy.nextToken()
2024-03-13 23:26:20 +01:00
if token.Type == Type_Separator && token.Value.(Separator) == Separator_Semicolon {
2024-03-18 21:14:28 +01:00
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Statement{Type: Statement_DeclareLocalVariable, Value: DeclareLocalVariableStatement{Variable: variableName, VariableType: *variableType, Initializer: nil}, Position: variableType.Position}, nil
2024-03-13 23:26:20 +01:00
}
if token.Type != Type_Operator || token.Value.(Operator) != Operator_Equals {
return nil, nil
}
2024-03-14 16:42:22 +01:00
initializer, err := pCopy.expect(pCopy.tryExpression, "expected initializer expression")
2024-03-13 23:26:20 +01:00
if err != nil {
*p = pCopy
return nil, err
}
2024-03-14 16:42:22 +01:00
_, err = pCopy.expectSeparator(Separator_Semicolon)
2024-03-13 23:26:20 +01:00
if err != nil {
*p = pCopy
return nil, err
}
*p = pCopy
2024-03-21 19:55:05 +01:00
return &Statement{Type: Statement_DeclareLocalVariable, Value: DeclareLocalVariableStatement{Variable: variableName, VariableType: *variableType, Initializer: initializer}, Position: variableType.Position}, nil
2024-03-13 23:26:20 +01:00
}
2024-03-24 20:53:34 +01:00
func (p *Parser) expectStatement(block *Block) (*Statement, error) {
2024-03-13 23:26:20 +01:00
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()
2024-03-21 19:55:05 +01:00
return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: nil}, Position: token.Position}, nil
2024-03-13 23:26:20 +01:00
}
expr, err := p.expectTupleExpression()
if err != nil {
return nil, err
}
_, err = p.expectSeparator(Separator_Semicolon)
if err != nil {
return nil, err
}
2024-03-21 19:55:05 +01:00
return &Statement{Type: Statement_Return, Value: ReturnStatement{Value: expr}, Position: token.Position}, nil
2024-03-13 23:26:20 +01:00
}
2024-03-23 14:03:20 +01:00
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
}
2024-03-24 20:53:34 +01:00
conditionalBlock, err := p.expectBlock(block)
2024-03-23 14:03:20 +01:00
if err != nil {
return nil, err
}
tok := p.peekToken()
if tok == nil || tok.Type != Type_Keyword || tok.Value.(Keyword) != Keyword_Else {
2024-03-24 20:53:34 +01:00
return &Statement{Type: Statement_If, Value: IfStatement{Condition: *cond, ConditionalBlock: conditionalBlock, ElseBlock: nil}, Position: token.Position}, nil
2024-03-23 14:03:20 +01:00
}
p.nextToken()
2024-03-24 20:53:34 +01:00
var elseBlock *Block
tok = p.peekToken()
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_If {
stmt, err := p.expectStatement(block)
if err != nil {
return nil, err
}
elseBlock = &Block{Parent: block, Statements: []Statement{*stmt}}
} else {
elseBlock, err = p.expectBlock(block)
if err != nil {
return nil, err
}
}
return &Statement{Type: Statement_If, Value: IfStatement{Condition: *cond, ConditionalBlock: conditionalBlock, ElseBlock: elseBlock}, Position: token.Position}, nil
2024-03-23 14:03:20 +01:00
}
if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_While {
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
}
body, err := p.expectBlock(block)
if err != nil {
return nil, err
}
return &Statement{Type: Statement_WhileLoop, Value: WhileLoopStatement{Condition: *cond, Body: body}, Position: token.Position}, nil
}
2024-03-13 23:26:20 +01:00
if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenCurly {
2024-03-24 20:53:34 +01:00
block, err := p.expectBlock(block)
2024-03-13 23:26:20 +01:00
if err != nil {
return nil, err
}
2024-03-24 20:53:34 +01:00
return &Statement{Type: Statement_Block, Value: BlockStatement{Block: block}, Position: token.Position}, nil
2024-03-13 23:26:20 +01:00
}
2024-03-14 16:42:22 +01:00
stmt, err := p.tryDeclareLocalVariableStatement()
if err != nil {
return nil, err
}
if stmt != nil {
return stmt, nil
}
2024-03-20 20:28:23 +01:00
expr, err := p.tryExpression()
if err != nil {
return nil, err
}
if expr != nil {
_, err := p.expectSeparator(Separator_Semicolon)
if err != nil {
return nil, err
}
2024-03-21 19:55:05 +01:00
return &Statement{Type: Statement_Expression, Value: ExpressionStatement{Expression: *expr}, Position: expr.Position}, nil
2024-03-20 20:28:23 +01:00
}
2024-03-13 23:26:20 +01:00
return nil, p.error("expected statement")
2024-03-13 17:17:09 +01:00
}
2024-03-24 20:53:34 +01:00
func (p *Parser) expectBlock(parent *Block) (*Block, error) {
2024-03-13 17:17:09 +01:00
_, err := p.expectSeparator(Separator_OpenCurly)
if err != nil {
return nil, err
}
2024-03-24 20:53:34 +01:00
block := &Block{Parent: parent}
2024-03-13 17:17:09 +01:00
for {
token := p.peekToken()
if token == nil {
return nil, p.error("expected statement or }")
}
if token.Type == Type_Separator && token.Value.(Separator) == Separator_CloseCurly {
p.nextToken()
break
}
2024-03-24 20:53:34 +01:00
stmt, err := p.expectStatement(block)
2024-03-13 23:26:20 +01:00
if err != nil {
return nil, err
}
2024-03-24 20:53:34 +01:00
block.Statements = append(block.Statements, *stmt)
2024-03-13 17:17:09 +01:00
}
2024-03-24 20:53:34 +01:00
return block, nil
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
func (p *Parser) expectFunction() (*ParsedFunction, error) {
2024-03-11 22:05:36 +01:00
var err error
2024-03-12 22:00:03 +01:00
var name string
var parameters []ParsedParameter
2024-03-11 22:05:36 +01:00
var returnType *Type
2024-03-13 17:17:09 +01:00
var body *Block
2024-03-11 22:05:36 +01:00
2024-03-21 19:55:05 +01:00
tok := p.peekToken()
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void {
p.nextToken()
returnType = nil
} else {
returnType, err = p.expectTypeOrTupleType()
if err != nil {
return nil, err
}
2024-03-12 22:00:03 +01:00
}
2024-03-12 22:47:45 +01:00
name, err = p.expectIdentifier()
2024-03-12 22:00:03 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-12 22:00:03 +01:00
}
2024-03-12 22:47:45 +01:00
_, err = p.expectSeparator(Separator_OpenParen)
2024-03-12 22:00:03 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-12 22:00:03 +01:00
}
for {
2024-03-12 22:47:45 +01:00
token := p.peekToken()
if token == nil {
2024-03-13 17:17:09 +01:00
return nil, p.error("incomplete function declaration")
2024-03-12 22:00:03 +01:00
}
if token.Type == Type_Separator && token.Value.(Separator) == Separator_CloseParen {
2024-03-12 22:47:45 +01:00
p.nextToken()
2024-03-12 22:00:03 +01:00
break
}
2024-03-21 20:37:21 +01:00
if len(parameters) != 0 {
2024-03-12 22:47:45 +01:00
_, err := p.expectSeparator(Separator_Comma)
if err != nil {
return nil, err
2024-03-12 22:00:03 +01:00
}
}
var paramType *Type
2024-03-12 22:47:45 +01:00
paramType, err = p.expectType()
2024-03-12 22:00:03 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-12 22:00:03 +01:00
}
var paramName string
2024-03-12 22:47:45 +01:00
paramName, err = p.expectIdentifier()
2024-03-12 22:00:03 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-12 22:00:03 +01:00
}
parameters = append(parameters, ParsedParameter{Name: paramName, Type: *paramType})
}
2024-03-24 20:53:34 +01:00
body, err = p.expectBlock(nil)
2024-03-12 22:00:03 +01:00
if err != nil {
2024-03-12 22:47:45 +01:00
return nil, err
2024-03-12 22:00:03 +01:00
}
2024-03-24 20:53:34 +01:00
return &ParsedFunction{Name: name, Parameters: parameters, ReturnType: returnType, Body: body}, nil
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
func (p *Parser) parseFile() (*ParsedFile, error) {
2024-03-11 22:05:36 +01:00
var err error
var module string
2024-03-11 22:05:36 +01:00
var imports []Import
var functions []ParsedFunction
2024-03-11 22:05:36 +01:00
2024-03-12 22:47:45 +01:00
for {
token := p.peekToken()
if token == nil {
break
}
if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_Import {
2024-03-11 22:05:36 +01:00
var parsedImport *Import
2024-03-12 22:47:45 +01:00
parsedImport, err = p.expectImport()
2024-03-11 22:05:36 +01:00
if err != nil {
return nil, err
}
imports = append(imports, *parsedImport)
continue
}
if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_Module {
p.nextToken()
if module != "" {
return nil, p.error("duplicate module declaration")
}
module, err = p.expectIdentifier()
if err != nil {
return nil, err
}
_, err := p.expectSeparator(Separator_Semicolon)
if err != nil {
return nil, err
}
}
2024-03-11 22:05:36 +01:00
var parsedFunction *ParsedFunction
2024-03-12 22:47:45 +01:00
parsedFunction, err = p.expectFunction()
2024-03-11 22:05:36 +01:00
if err != nil {
return nil, err
}
functions = append(functions, *parsedFunction)
}
return &ParsedFile{Module: module, Imports: imports, Functions: functions}, nil
2024-03-11 22:05:36 +01:00
}