207 lines
5.4 KiB
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
|
|
}
|