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 }