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 uint64
|
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
|
|
|
|
)
|
|
|
|
|
|
|
|
type Statement struct {
|
2024-03-21 19:55:05 +01:00
|
|
|
Type StatementType
|
|
|
|
Value any
|
|
|
|
Position uint64
|
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 {
|
|
|
|
Block Block
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
type ExpressionType uint32
|
|
|
|
|
|
|
|
const (
|
|
|
|
Expression_Assignment ExpressionType = iota
|
|
|
|
Expression_Literal
|
|
|
|
Expression_VariableReference
|
|
|
|
Expression_Arithmetic
|
2024-03-13 23:26:20 +01:00
|
|
|
Expression_Tuple
|
2024-03-20 19:26:48 +01:00
|
|
|
Expression_FunctionCall
|
|
|
|
Expression_Negate
|
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 uint64
|
2024-03-11 22:05:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type AssignmentExpression struct {
|
|
|
|
Variable string
|
|
|
|
Value Expression
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
type ArithmeticOperation uint32
|
|
|
|
|
|
|
|
const (
|
|
|
|
Arithmetic_Add ArithmeticOperation = iota
|
|
|
|
Arithmetic_Sub
|
|
|
|
Arithmetic_Mul
|
|
|
|
Arithmetic_Div
|
|
|
|
Arithmetic_Mod
|
|
|
|
)
|
|
|
|
|
|
|
|
type ArithmeticExpression struct {
|
|
|
|
Operation ArithmeticOperation
|
|
|
|
Left Expression
|
|
|
|
Right Expression
|
|
|
|
}
|
|
|
|
|
2024-03-13 23:26:20 +01:00
|
|
|
type TupleExpression struct {
|
|
|
|
Members []Expression
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
type FunctionCallExpression struct {
|
|
|
|
Function string
|
|
|
|
Parameters *Expression
|
|
|
|
}
|
|
|
|
|
|
|
|
type NegateExpression struct {
|
|
|
|
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-18 21:14:28 +01:00
|
|
|
Parent *Block // TODO: implement
|
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
|
|
|
|
Parameters []ParsedParameter
|
2024-03-21 19:55:05 +01:00
|
|
|
ReturnType *Type
|
2024-03-11 22:05:36 +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 {
|
|
|
|
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 uint64
|
|
|
|
}
|
|
|
|
|
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-12 22:47:45 +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 {
|
|
|
|
return InvalidValue, 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-13 17:17:09 +01:00
|
|
|
return InvalidValue, p.error("expected one of " + strings.Join(separatorNames, " "))
|
2024-03-12 22:00:03 +01:00
|
|
|
}
|
|
|
|
|
2024-03-13 23:26:20 +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 {
|
|
|
|
// TODO: array type
|
2024-03-17 19:55:28 +01:00
|
|
|
|
|
|
|
index := slices.Index(PRIMITIVE_TYPE_NAMES, tok.Value.(string))
|
|
|
|
if index != -1 {
|
|
|
|
*p = pCopy
|
2024-03-21 19:55:05 +01:00
|
|
|
return &Type{Type: Type_Primitive, Value: PrimitiveType(index), Position: tok.Position}, nil
|
2024-03-17 19:55:28 +01:00
|
|
|
}
|
|
|
|
|
2024-03-13 23:26:20 +01:00
|
|
|
*p = pCopy
|
2024-03-21 19:55:05 +01:00
|
|
|
return &Type{Type: Type_Named, Value: tok.Value, Position: tok.Position}, 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)
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if sep == Separator_CloseParen {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
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
|
|
|
}
|
2024-03-13 23:26:20 +01:00
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if token.Type == Type_Operator {
|
|
|
|
op := token.Value.(Operator)
|
|
|
|
if op == Operator_Minus || op == Operator_Plus {
|
|
|
|
pCopy.nextToken()
|
|
|
|
expr, err := pCopy.tryUnaryExpression()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if expr == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if op == Operator_Minus {
|
2024-03-21 19:55:05 +01:00
|
|
|
expr = &Expression{Type: Expression_Negate, Value: NegateExpression{Value: *expr}, Position: token.Position}
|
2024-03-20 19:26:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return expr, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 23:26:20 +01:00
|
|
|
if token.Type == Type_Identifier {
|
|
|
|
pCopy.nextToken()
|
2024-03-20 19:26:48 +01:00
|
|
|
|
|
|
|
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-20 19:26:48 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) tryMultiplicativeExpression() (*Expression, error) {
|
2024-03-17 19:55:28 +01:00
|
|
|
left, err := p.tryUnaryExpression()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if left == nil {
|
|
|
|
return nil, nil
|
2024-03-17 19:55:28 +01:00
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
for {
|
|
|
|
op, err := p.tryOperator(Operator_Multiply, Operator_Divide, Operator_Modulo)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if op == nil {
|
|
|
|
return left, nil
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
right, err := p.tryUnaryExpression()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if right == nil {
|
|
|
|
return nil, p.error("expected expression")
|
|
|
|
}
|
|
|
|
|
|
|
|
var operation ArithmeticOperation
|
|
|
|
switch *op {
|
|
|
|
case Operator_Multiply:
|
|
|
|
operation = Arithmetic_Mul
|
|
|
|
case Operator_Divide:
|
|
|
|
operation = Arithmetic_Div
|
|
|
|
case Operator_Plus:
|
|
|
|
operation = Arithmetic_Add
|
|
|
|
case Operator_Minus:
|
|
|
|
operation = Arithmetic_Sub
|
|
|
|
case Operator_Modulo:
|
|
|
|
fallthrough
|
|
|
|
default:
|
|
|
|
operation = Arithmetic_Mod
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-21 19:55:05 +01:00
|
|
|
left = &Expression{Type: Expression_Arithmetic, Value: ArithmeticExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
|
2024-03-20 19:26:48 +01:00
|
|
|
}
|
2024-03-13 23:26:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) tryAdditiveExpression() (*Expression, error) {
|
2024-03-17 19:55:28 +01:00
|
|
|
left, err := p.tryMultiplicativeExpression()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if left == nil {
|
|
|
|
return nil, nil
|
2024-03-17 19:55:28 +01:00
|
|
|
}
|
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
for {
|
|
|
|
op, err := p.tryOperator(Operator_Plus, Operator_Minus)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if op == nil {
|
|
|
|
return left, nil
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
right, err := p.tryMultiplicativeExpression()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-20 19:26:48 +01:00
|
|
|
if right == nil {
|
|
|
|
return nil, p.error("expected expression")
|
|
|
|
}
|
|
|
|
|
|
|
|
var operation ArithmeticOperation
|
|
|
|
if *op == Operator_Plus {
|
|
|
|
operation = Arithmetic_Add
|
|
|
|
} else {
|
|
|
|
operation = Arithmetic_Sub
|
|
|
|
}
|
2024-03-17 19:55:28 +01:00
|
|
|
|
2024-03-21 19:55:05 +01:00
|
|
|
left = &Expression{Type: Expression_Arithmetic, Value: ArithmeticExpression{Operation: operation, Left: *left, Right: *right}, Position: left.Position}
|
2024-03-20 19:26:48 +01:00
|
|
|
}
|
2024-03-13 23:26:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if token.Type == Type_Separator && token.Value.(Separator) == Separator_OpenCurly {
|
|
|
|
block, err := p.expectBlock()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-03-21 19:55:05 +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
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Parser) expectBlock() (*Block, error) {
|
|
|
|
_, err := p.expectSeparator(Separator_OpenCurly)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var statements []Statement
|
|
|
|
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-13 23:26:20 +01:00
|
|
|
stmt, err := p.expectStatement()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
statements = append(statements, *stmt)
|
2024-03-13 17:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return &Block{Statements: statements}, 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
|
|
|
|
}
|
|
|
|
|
|
|
|
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-13 17:17:09 +01:00
|
|
|
body, err = p.expectBlock()
|
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-21 19:55:05 +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 functions []ParsedFunction
|
|
|
|
var imports []Import
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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{Imports: imports, Functions: functions}, nil
|
|
|
|
}
|