153 lines
4.1 KiB
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
|
|
}
|