fspl/parser/fspl/type.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
}