247 lines
6.1 KiB
Go
247 lines
6.1 KiB
Go
package fsplParser
|
|
|
|
import "strconv"
|
|
import "git.tebibyte.media/fspl/fspl/lexer"
|
|
import "git.tebibyte.media/fspl/fspl/errors"
|
|
import "git.tebibyte.media/fspl/fspl/entity"
|
|
|
|
var descriptionType = "type"
|
|
var startTokensType = []lexer.TokenKind {
|
|
lexer.Ident,
|
|
lexer.TypeIdent,
|
|
lexer.Star,
|
|
lexer.Int,
|
|
lexer.LParen,
|
|
}
|
|
|
|
func (this *treeParser) parseType () (entity.Type, error) {
|
|
err := this.ExpectDesc(descriptionType, startTokensType...)
|
|
if err != nil { return nil, err }
|
|
pos := this.Pos()
|
|
|
|
switch this.Kind() {
|
|
case lexer.Ident:
|
|
ident := this.Value()
|
|
err := this.ExpectNext(lexer.DoubleColon)
|
|
if err != nil { return nil, err }
|
|
err = this.ExpectNext(lexer.TypeIdent)
|
|
if err != nil { return nil, err }
|
|
return this.parseTypeNamedCore(pos, ident)
|
|
|
|
case lexer.TypeIdent:
|
|
if this.Value() == "Int" || this.Value() == "UInt" {
|
|
return this.parseTypeWord()
|
|
}
|
|
|
|
if this.ValueIs("F16", "F32", "F64", "F128") {
|
|
return this.parseTypeFloat()
|
|
}
|
|
|
|
if len(this.Value()) > 0 {
|
|
_, err := strconv.Atoi(this.Value()[1:])
|
|
if err == nil && (
|
|
this.Value()[0] == 'U' ||
|
|
this.Value()[0] == 'I') {
|
|
|
|
return this.parseTypeInt()
|
|
}
|
|
}
|
|
|
|
return this.parseTypeNamedCore(pos, "")
|
|
|
|
case lexer.Star:
|
|
return this.parseTypePointerOrSlice()
|
|
|
|
case lexer.Int:
|
|
return this.parseTypeArray()
|
|
|
|
case lexer.LParen:
|
|
err := this.ExpectNext(lexer.Dot, lexer.Symbol)
|
|
if err != nil { return nil, err }
|
|
err = this.ExpectValue(0, ".", "&", "|")
|
|
if err != nil { return nil, err }
|
|
|
|
switch this.Value() {
|
|
case ".": return this.parseTypeStructCore()
|
|
case "&": return this.parseTypeInterfaceCore()
|
|
case "|": return this.parseTypeUnionCore()
|
|
}
|
|
panic(this.bug())
|
|
}
|
|
panic(this.bug())
|
|
}
|
|
|
|
func (this *treeParser) parseTypeNamedCore (pos errors.Position, unitNickname string) (entity.Type, error) {
|
|
err := this.Expect(lexer.TypeIdent)
|
|
if err != nil { return nil, err }
|
|
|
|
defer this.Next()
|
|
return &entity.TypeNamed {
|
|
Pos: pos.Union(this.Pos()),
|
|
Name: this.Value(),
|
|
UnitNickname: unitNickname,
|
|
}, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypePointerOrSlice () (entity.Type, error) {
|
|
err := this.ExpectDesc("pointer type or slice type", lexer.Star)
|
|
if err != nil { return nil, err }
|
|
start := this.Pos()
|
|
|
|
err = this.ExpectNextDesc (
|
|
"Colon or Type",
|
|
appendCopy(startTokensType, lexer.Colon)...)
|
|
if err != nil { return nil, err }
|
|
|
|
if this.Is(lexer.Colon) {
|
|
this.Next()
|
|
element, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
return &entity.TypeSlice {
|
|
Pos: start.Union(this.Pos()),
|
|
Element: element,
|
|
}, nil
|
|
} else {
|
|
referenced, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
return &entity.TypePointer {
|
|
Pos: start.Union(this.Pos()),
|
|
Referenced: referenced,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (this *treeParser) parseTypeArray () (entity.Type, error) {
|
|
err := this.ExpectDesc("array type", lexer.Int)
|
|
if err != nil { return nil, err }
|
|
start := this.Pos()
|
|
|
|
length, err := strconv.Atoi(this.Value())
|
|
if err != nil { return nil, err }
|
|
err = this.ExpectNext(lexer.Colon)
|
|
if err != nil { return nil, err }
|
|
err = this.Next()
|
|
if err != nil { return nil, err }
|
|
element, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
|
|
return &entity.TypeArray {
|
|
Pos: start.Union(this.Pos()),
|
|
Length: length,
|
|
Element: element,
|
|
}, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeStructCore () (entity.Type, error) {
|
|
err := this.Expect(lexer.Dot)
|
|
if err != nil { return nil, err }
|
|
ty := &entity.TypeStruct {
|
|
Pos: this.Pos(),
|
|
}
|
|
this.Next()
|
|
|
|
for {
|
|
err := this.ExpectDesc (
|
|
"struct member or end",
|
|
appendCopy(startTokensDeclaration, lexer.RParen)...)
|
|
if err != nil { return nil, err }
|
|
if this.Kind() == lexer.RParen { break }
|
|
|
|
member, err := this.parseDeclaration()
|
|
if err != nil { return nil, err }
|
|
ty.Members = append(ty.Members, member)
|
|
}
|
|
ty.Pos = ty.Position().Union(this.Pos())
|
|
this.Next()
|
|
return ty, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeInterfaceCore () (entity.Type, error) {
|
|
err := this.ExpectValue(lexer.Symbol, "&")
|
|
if err != nil { return nil, err }
|
|
ty := &entity.TypeInterface {
|
|
Pos: this.Pos(),
|
|
}
|
|
this.Next()
|
|
|
|
for {
|
|
err := this.ExpectDesc (
|
|
"interface behavior or end",
|
|
appendCopy(startTokensSignature, lexer.RParen)...)
|
|
if err != nil { return nil, err }
|
|
if this.Kind() == lexer.RParen { break }
|
|
|
|
behavior, err := this.parseSignature()
|
|
if err != nil { return nil, err }
|
|
ty.Behaviors = append(ty.Behaviors, behavior)
|
|
}
|
|
ty.Pos = ty.Position().Union(this.Pos())
|
|
this.Next()
|
|
return ty, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeUnionCore () (entity.Type, error) {
|
|
err := this.ExpectValue(lexer.Symbol, "|")
|
|
if err != nil { return nil, err }
|
|
ty := &entity.TypeUnion {
|
|
Pos: this.Pos(),
|
|
}
|
|
this.Next()
|
|
|
|
for {
|
|
err := this.ExpectDesc (
|
|
"allowed type or end",
|
|
appendCopy(startTokensType, lexer.RParen)...)
|
|
if err != nil { return nil, err }
|
|
if this.Kind() == lexer.RParen { break }
|
|
|
|
allowed, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
ty.Allowed = append(ty.Allowed, allowed)
|
|
}
|
|
ty.Pos = ty.Position().Union(this.Pos())
|
|
this.Next()
|
|
return ty, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeInt () (entity.Type, error) {
|
|
err := this.Expect(lexer.TypeIdent)
|
|
if err != nil { return nil, err }
|
|
|
|
value := this.Value()
|
|
width, err := strconv.Atoi(value[1:])
|
|
if err != nil || !(value[0] == 'I' || value[0] == 'U') {
|
|
return nil, errors.Errorf(this.Pos(), "malformed Integer type")
|
|
}
|
|
|
|
defer this.Next()
|
|
return &entity.TypeInt {
|
|
Pos: this.Pos(),
|
|
Width: width,
|
|
Signed: value[0] == 'I',
|
|
}, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeWord () (entity.Type, error) {
|
|
err := this.ExpectValue(lexer.TypeIdent, "Int", "UInt")
|
|
if err != nil { return nil, err }
|
|
defer this.Next()
|
|
return &entity.TypeWord {
|
|
Pos: this.Pos(),
|
|
Signed: this.Value()[0] == 'I',
|
|
}, nil
|
|
}
|
|
|
|
func (this *treeParser) parseTypeFloat () (entity.Type, error) {
|
|
err := this.ExpectValue(lexer.TypeIdent, "F16", "F32", "F64", "F128")
|
|
if err != nil { return nil, err }
|
|
|
|
width, _ := strconv.Atoi(this.Value()[1:])
|
|
|
|
defer this.Next()
|
|
return &entity.TypeFloat {
|
|
Pos: this.Pos(),
|
|
Width: width,
|
|
}, nil
|
|
}
|