hopp/generate/parse.go

207 lines
5.4 KiB
Go

package generate
import "io"
import "strconv"
import "git.tebibyte.media/sashakoshka/goparse"
func Parse(lx parse.Lexer) (*Protocol, error) {
protocol := defaultProtocol()
par := parser {
Parser: parse.Parser {
Lexer: lx,
TokenNames: tokenNames,
},
protocol: &protocol,
}
err := par.parse()
if err != nil { return nil, err }
return par.protocol, nil
}
func defaultProtocol() Protocol {
return Protocol {
Messages: make(map[uint16] Message),
Types: map[string] Type {
"U8": TypeInt { Bits: 8 },
"U16": TypeInt { Bits: 16 },
"U32": TypeInt { Bits: 32 },
"U64": TypeInt { Bits: 64 },
"U128": TypeInt { Bits: 128 },
"U256": TypeInt { Bits: 256 },
"I8": TypeInt { Bits: 8, Signed: true },
"I16": TypeInt { Bits: 16, Signed: true },
"I32": TypeInt { Bits: 32, Signed: true },
"I64": TypeInt { Bits: 64, Signed: true },
"I128": TypeInt { Bits: 128, Signed: true },
"I256": TypeInt { Bits: 256, Signed: true },
"F16": TypeFloat { Bits: 16 },
"F32": TypeFloat { Bits: 32 },
"F64": TypeFloat { Bits: 64 },
"F128": TypeFloat { Bits: 128 },
"F256": TypeFloat { Bits: 256 },
"String": TypeString { },
"Buffer": TypeBuffer { },
"Table": TypeTable { },
},
}
}
func ParseReader(reader io.Reader) (*Protocol, error) {
lx, err := Lex("test.pdl", reader)
if err != nil { return nil, err }
return Parse(lx)
}
type parser struct {
parse.Parser
protocol *Protocol
}
func (this *parser) parse() error {
err := this.Next()
if err != nil { return err }
for this.Token.Kind != parse.EOF {
err = this.parseTopLevel()
if err != nil { return err }
}
return nil
}
func (this *parser) parseTopLevel() error {
err := this.ExpectDesc("message or typedef", TokenMethod, TokenIdent)
if err != nil { return err }
if this.EOF() { return nil }
switch this.Kind() {
case TokenMethod: return this.parseMessage()
case TokenIdent: return this.parseTypedef()
}
panic("bug")
}
func (this *parser) parseMessage() error {
err := this.Expect(TokenMethod)
if err != nil { return err }
method, err := this.parseHexNumber(this.Value(), 0xFFFF)
if err != nil { return err }
err = this.ExpectNext(TokenIdent)
if err != nil { return err }
name := this.Value()
err = this.Next()
if err != nil { return err }
typ, err := this.parseType()
if err != nil { return err }
this.protocol.Messages[uint16(method)] = Message {
Name: name,
Type: typ,
}
return nil
}
func (this *parser) parseTypedef() error {
err := this.Expect(TokenIdent)
if err != nil { return err }
name := this.Value()
err = this.Next()
if err != nil { return err }
typ, err := this.parseType()
if err != nil { return err }
this.protocol.Types[name] = typ
return nil
}
func (this *parser) parseType() (Type, error) {
err := this.ExpectDesc("type", TokenIdent, TokenLBracket, TokenLBrace)
if err != nil { return nil, err }
switch this.Kind() {
case TokenIdent:
return this.parseTypeNamed()
case TokenLBracket:
return this.parseTypeArray()
case TokenLBrace:
return this.parseTypeTable()
}
panic("bug")
}
func (this *parser) parseTypeNamed() (TypeNamed, error) {
err := this.Expect(TokenIdent)
if err != nil { return TypeNamed { }, err }
name := this.Value()
err = this.Next()
if err != nil { return TypeNamed { }, err }
return TypeNamed { Name: name }, nil
}
func (this *parser) parseTypeArray() (TypeArray, error) {
err := this.Expect(TokenLBracket)
if err != nil { return TypeArray { }, err }
err = this.ExpectNext(TokenRBracket)
if err != nil { return TypeArray { }, err }
err = this.Next()
if err != nil { return TypeArray { }, err }
typ, err := this.parseType()
if err != nil { return TypeArray { }, err }
return TypeArray { Element: typ }, nil
}
func (this *parser) parseTypeTable() (TypeTableDefined, error) {
err := this.Expect(TokenLBrace)
if err != nil { return TypeTableDefined { }, err }
err = this.Next()
if err != nil { return TypeTableDefined { }, err }
typ := TypeTableDefined {
Fields: make(map[uint16] Field),
}
for {
err := this.ExpectDesc("table field", TokenKey, TokenRBrace)
if err != nil { return TypeTableDefined { }, err }
if this.Is(TokenRBrace) {
break
}
key, field, err := this.parseField()
if err != nil { return TypeTableDefined { }, err }
typ.Fields[key] = field
err = this.Expect(TokenComma, TokenRBrace)
if err != nil { return TypeTableDefined { }, err }
if this.Is(TokenRBrace) {
break
}
err = this.Next()
if err != nil { return TypeTableDefined { }, err }
}
err = this.Next()
if err != nil { return TypeTableDefined { }, err }
return typ, nil
}
func (this *parser) parseField() (uint16, Field, error) {
err := this.Expect(TokenKey)
if err != nil { return 0, Field { }, err }
key, err := this.parseHexNumber(this.Value(), 0xFFFF)
if err != nil { return 0, Field { }, err }
err = this.ExpectNext(TokenIdent)
if err != nil { return 0, Field { }, err }
name := this.Value()
err = this.Next()
if err != nil { return 0, Field { }, err }
typ, err := this.parseType()
if err != nil { return 0, Field { }, err }
return uint16(key), Field {
Name: name,
Type: typ,
}, nil
}
func (this *parser) parseHexNumber(input string, maxValue int64) (int64, error) {
number, err := strconv.ParseInt(input, 16, 64)
if err != nil {
return 0, parse.Errorf(this.Pos(), "%v", err)
}
if maxValue > 0 && number > maxValue {
return 0, parse.Errorf(this.Pos(), "value too large (max %X)", maxValue)
}
return number, nil
}