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 { }, } } 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: switch this.Value() { case "U8": return TypeInt { Bits: 8 }, this.Next() case "U16": return TypeInt { Bits: 16 }, this.Next() case "U32": return TypeInt { Bits: 32 }, this.Next() case "U64": return TypeInt { Bits: 64 }, this.Next() case "U128": return TypeInt { Bits: 128 }, this.Next() case "U256": return TypeInt { Bits: 256 }, this.Next() case "I8": return TypeInt { Bits: 8, Signed: true }, this.Next() case "I16": return TypeInt { Bits: 16, Signed: true }, this.Next() case "I32": return TypeInt { Bits: 32, Signed: true }, this.Next() case "I64": return TypeInt { Bits: 64, Signed: true }, this.Next() case "I128": return TypeInt { Bits: 128, Signed: true }, this.Next() case "I256": return TypeInt { Bits: 256, Signed: true }, this.Next() case "F16": return TypeFloat { Bits: 16 }, this.Next() case "F32": return TypeFloat { Bits: 32 }, this.Next() case "F64": return TypeFloat { Bits: 64 }, this.Next() case "F128": return TypeFloat { Bits: 128 }, this.Next() case "F256": return TypeFloat { Bits: 256 }, this.Next() case "String": return TypeString { }, this.Next() case "Buffer": return TypeBuffer { }, this.Next() case "Table": return TypeTable { }, this.Next() } 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 }