elysium/parser.go

355 lines
6.3 KiB
Go
Raw Normal View History

2024-03-11 22:05:36 +01:00
package main
import (
"errors"
2024-03-12 22:47:45 +01:00
"log"
2024-03-11 22:05:36 +01:00
"slices"
"strings"
)
type TypeType uint32
const (
Type_Primitive TypeType = iota
Type_Void
Type_Named
Type_Array
Type_Tuple
)
type Type struct {
Type TypeType
Value any
}
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 {
Type StatementType
Value any
}
type BlockStatement struct {
Block Block
}
type ReturnStatement struct {
Value *Expression
}
type DeclareLocalVariableStatement struct {
Variable string
Initializer Expression
}
type ExpressionType uint32
const (
Expression_Assignment ExpressionType = iota
Expression_Literal
Expression_VariableReference
Expression_Arithmetic
)
type Expression struct {
Type ExpressionType
Value any
}
type AssignmentExpression struct {
Variable string
Value Expression
}
type LiteralExpression struct {
Type PrimitiveType
Value any
}
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
}
type Block struct {
Statements []Statement
}
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-11 22:05:36 +01:00
ReturnType Type
Body Block
}
type Import struct {
Import string
}
type ParsedFile struct {
Imports []Import
Functions []ParsedFunction
}
2024-03-12 22:47:45 +01:00
type Parser struct {
tokens []LexToken
}
2024-03-11 22:05:36 +01:00
2024-03-12 22:47:45 +01:00
func (p *Parser) peekToken() *LexToken {
if len(p.tokens) == 0 {
return nil
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
return &p.tokens[0]
}
func (p *Parser) nextToken() *LexToken {
if len(p.tokens) == 0 {
return nil
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
token := p.tokens[0]
p.tokens = p.tokens[1:]
return &token
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
func (p *Parser) expectSeparator(separators ...Separator) (Separator, error) {
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, errors.New("expected one of " + strings.Join(separatorNames, " "))
2024-03-12 22:00:03 +01:00
}
2024-03-12 22:47:45 +01:00
return separator.Value.(Separator), nil
}
func (p *Parser) expectIdentifier() (string, error) {
identifier := p.nextToken()
if identifier == nil || identifier.Type != Type_Separator && identifier.Type != Type_Identifier {
return "", errors.New("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 {
return nil, errors.New("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 {
return nil, errors.New("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-12 22:47:45 +01:00
func (p *Parser) expectType() (*Type, error) {
2024-03-11 22:05:36 +01:00
var err error
2024-03-12 22:47:45 +01:00
tok := p.nextToken()
if tok == nil {
return nil, errors.New("expected type")
2024-03-11 22:05:36 +01:00
}
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void {
2024-03-12 22:47:45 +01:00
return &Type{Type: Type_Void, Value: nil}, nil
2024-03-11 22:05:36 +01:00
}
if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen {
// Tuple type
var types []Type
for {
var parsedType *Type
2024-03-12 22:47:45 +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-12 22:47:45 +01:00
return nil, errors.New("empty tuple")
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, nil
2024-03-11 22:05:36 +01:00
}
if tok.Type == Type_Identifier {
2024-03-12 22:47:45 +01:00
return &Type{Type: Type_Named, Value: tok.Value}, nil
2024-03-11 22:05:36 +01:00
}
2024-03-12 22:47:45 +01:00
return nil, errors.New("expected type")
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
var body Block
2024-03-12 22:47:45 +01:00
returnType, 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-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 {
return nil, errors.New("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-12 22:47:45 +01:00
_, err = p.expectSeparator(Separator_OpenCurly)
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
}
// TODO: body, closing curly
2024-03-11 22:05:36 +01:00
2024-03-12 22:47:45 +01:00
_, err = p.expectSeparator(Separator_CloseCurly)
if err != nil {
return nil, err
}
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
}
log.Printf("%+#v\n", token)
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
}