221 lines
5.4 KiB
Go
221 lines
5.4 KiB
Go
package parser
|
|
|
|
import "strconv"
|
|
import "git.tebibyte.media/sashakoshka/fspl/lexer"
|
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|
|
|
var descriptionType = "type"
|
|
var startTokensType = []lexer.TokenKind {
|
|
lexer.Ident,
|
|
lexer.TypeIdent,
|
|
lexer.Star,
|
|
lexer.Int,
|
|
lexer.LParen,
|
|
}
|
|
|
|
func (this *Parser) parseType () (entity.Type, error) {
|
|
err := this.expectDesc(descriptionType, startTokensType...)
|
|
if err != nil { return nil, err }
|
|
|
|
switch this.kind() {
|
|
case lexer.Ident:
|
|
ident := this.token.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(ident)
|
|
|
|
case lexer.TypeIdent:
|
|
if this.value() == "Int" || this.value() == "UInt" {
|
|
return this.parseTypeWord()
|
|
}
|
|
|
|
if this.token.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("")
|
|
|
|
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()
|
|
}
|
|
panic(this.bug())
|
|
}
|
|
panic(this.bug())
|
|
}
|
|
|
|
func (this *Parser) parseTypeNamedCore (module string) (entity.Type, error) {
|
|
err := this.expect(lexer.TypeIdent)
|
|
if err != nil { return nil, err }
|
|
|
|
defer this.next()
|
|
return &entity.TypeNamed {
|
|
Position: this.pos(),
|
|
Name: this.value(),
|
|
Module: module,
|
|
}, nil
|
|
}
|
|
|
|
func (this *Parser) 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.token.Is(lexer.Colon) {
|
|
this.next()
|
|
element, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
return &entity.TypeSlice {
|
|
Position: start.Union(this.pos()),
|
|
Element: element,
|
|
}, nil
|
|
} else {
|
|
referenced, err := this.parseType()
|
|
if err != nil { return nil, err }
|
|
return &entity.TypePointer {
|
|
Position: start.Union(this.pos()),
|
|
Referenced: referenced,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func (this *Parser) 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 {
|
|
Position: start.Union(this.pos()),
|
|
Length: length,
|
|
Element: element,
|
|
}, nil
|
|
}
|
|
|
|
func (this *Parser) parseTypeStructCore () (entity.Type, error) {
|
|
err := this.expect(lexer.Dot)
|
|
if err != nil { return nil, err }
|
|
ty := &entity.TypeStruct {
|
|
Position: 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.Position = ty.Position.Union(this.pos())
|
|
this.next()
|
|
return ty, nil
|
|
}
|
|
|
|
func (this *Parser) parseTypeInterfaceCore () (entity.Type, error) {
|
|
err := this.expectValue(lexer.Symbol, "?")
|
|
if err != nil { return nil, err }
|
|
ty := &entity.TypeInterface {
|
|
Position: 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.Position = ty.Position.Union(this.pos())
|
|
this.next()
|
|
return ty, nil
|
|
}
|
|
|
|
func (this *Parser) 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 {
|
|
Position: this.pos(),
|
|
Width: width,
|
|
Signed: value[0] == 'I',
|
|
}, nil
|
|
}
|
|
|
|
func (this *Parser) parseTypeWord () (entity.Type, error) {
|
|
err := this.expectValue(lexer.TypeIdent, "Int", "UInt")
|
|
if err != nil { return nil, err }
|
|
defer this.next()
|
|
return &entity.TypeWord {
|
|
Position: this.pos(),
|
|
Signed: this.value()[0] == 'I',
|
|
}, nil
|
|
}
|
|
|
|
func (this *Parser) 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 {
|
|
Position: this.pos(),
|
|
Width: width,
|
|
}, nil
|
|
}
|