fspl/parser/fspl/toplevel.go

153 lines
4.1 KiB
Go

package fsplParser
import "git.tebibyte.media/fspl/fspl/lexer"
import "git.tebibyte.media/fspl/fspl/errors"
import "git.tebibyte.media/fspl/fspl/entity"
var descriptionTopLevel = "typedef, function, or method"
var startTokensTopLevel = []lexer.TokenKind {
lexer.Symbol,
lexer.LBracket,
lexer.TypeIdent,
lexer.EOF,
}
func (this *treeParser) parseTopLevel () error {
err := this.ExpectDesc (
descriptionTopLevel,
startTokensTopLevel...)
if err != nil { return err }
if this.EOF() { return nil }
pos := this.Pos()
access := entity.AccessPrivate
if this.Is(lexer.Symbol) {
access, err = this.parseAccess()
err = this.ExpectDesc (
descriptionTopLevel,
lexer.Symbol,
lexer.LBracket,
lexer.Ident,
lexer.TypeIdent)
if err != nil { return err }
}
// LBracket: Function
if this.Is(lexer.LBracket) {
function, err := this.parseFunctionCore(pos, access)
if err != nil { return err }
this.tree.AddDeclaration(function)
return nil
}
// TypeIdent: Method, or Typedef
typeName := this.Value()
err = this.ExpectNext(lexer.Dot, lexer.Colon)
if err != nil { return err }
switch this.Kind() {
case lexer.Dot:
// Dot: Method
err = this.ExpectNextDesc(descriptionSignature, startTokensSignature...)
if err != nil { return err }
method, err := this.parseMethodCore(pos, access, typeName)
if err != nil { return err }
this.tree.AddDeclaration(method)
case lexer.Colon:
// Colon: Typedef
err = this.ExpectNextDesc(descriptionType, startTokensType...)
if err != nil { return err }
typedef, err := this.parseTypedefCore(pos, access, typeName)
if err != nil { return err }
this.tree.AddDeclaration(typedef)
default: panic(this.bug())
}
return nil
}
func (this *treeParser) parseAccess () (entity.Access, error) {
err := this.ExpectValueDesc (
"Access control specifier",
lexer.Symbol, "-", "#", "+")
if err != nil { return 0, err }
defer this.Next()
switch this.Value() {
case "-": return entity.AccessPrivate, nil
case "#": return entity.AccessOpaque, nil
case "+": return entity.AccessPublic, nil
default: panic(this.bug())
}
}
func (this *treeParser) parseFunctionCore (pos errors.Position, access entity.Access) (*entity.Function, error) {
signature, err := this.parseSignature()
if err != nil { return nil, err }
function := &entity.Function {
Pos: pos.Union(signature.Position()),
Acc: access,
Signature: signature,
}
err = this.ExpectDesc (
"function body, link name, or top-level declaration",
appendCopy(startTokensTopLevel, lexer.Symbol, lexer.String)...)
if err != nil { return nil, err }
if this.Is(lexer.String) {
// String: Link name
function.LinkName = this.Value()
err = this.ExpectNextDesc (
"Function body, " + descriptionTopLevel,
appendCopy(startTokensTopLevel, lexer.Symbol)...)
if err != nil { return nil, err }
}
if !(this.Is(lexer.Symbol) && this.ValueIs("=")) {
// function has no body and is finished,
// move on to next top level declaration or graceful EOF.
return function, nil
}
// Symbol '=': Function body
err = this.ExpectValueDesc("function body", lexer.Symbol, "=")
if err != nil { return nil, err }
// Expression
err = this.ExpectNextDesc(descriptionExpression, startTokensExpression...)
if err != nil { return nil, err }
bodyExpression, err := this.parseExpression()
if err != nil { return nil, err }
if !this.skim {
function.Body = bodyExpression
}
return function, nil
}
func (this *treeParser) parseMethodCore (pos errors.Position, access entity.Access, typeName string) (*entity.Method, error) {
function, err := this.parseFunctionCore(pos, access)
if err != nil { return nil, err }
return &entity.Method {
Pos: function.Position(),
Acc: function.Acc,
TypeName: typeName,
Signature: function.Signature,
LinkName: function.LinkName,
Body: function.Body,
}, nil
}
func (this *treeParser) parseTypedefCore (pos errors.Position, access entity.Access, typeName string) (*entity.Typedef, error) {
pos = pos.Union(this.Pos())
ty, err := this.parseType()
if err != nil { return nil, err }
return &entity.Typedef {
Pos: pos,
Acc: access,
Name: typeName,
Type: ty,
}, nil
}