github.com/cloudwego/thriftgo@v0.3.10/parser/parser.go (about) 1 // Copyright 2021 CloudWeGo Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package parser parses a thrift IDL file with its dependencies into an abstract syntax tree. 16 // The acceptable IDL grammar is defined in the 'thrift.peg' file. 17 package parser 18 19 import ( 20 "errors" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "strconv" 26 "strings" 27 ) 28 29 // NOTSET is a value to express 'not set'. 30 const NOTSET = -999999 31 32 type parser struct { 33 ThriftIDL 34 Thrift 35 IncludeDirs []string 36 Annotations *Annotations 37 DefinitionReservedComment string 38 } 39 40 func exists(path string) bool { 41 fi, err := os.Stat(path) 42 if err != nil { 43 return os.IsExist(err) 44 } 45 return !fi.IsDir() 46 } 47 48 func search(file, dir string, includeDirs []string) (string, error) { 49 ps := []string{file, filepath.Join(dir, file)} 50 for _, inc := range includeDirs { 51 ps = append(ps, filepath.Join(inc, file)) 52 } 53 for _, p := range ps { 54 if exists(p) { 55 return normalizeFilename(p), nil 56 } 57 } 58 return file, &os.PathError{Op: "search", Path: file, Err: os.ErrNotExist} 59 } 60 61 // ParseFile parses a thrift file and returns an AST. 62 // If recursive is true, then the include IDLs are parsed recursively as well. 63 func ParseFile(path string, includeDirs []string, recursive bool) (*Thrift, error) { 64 if recursive { 65 thriftMap := make(map[string]*Thrift) 66 dir := filepath.Dir(normalizeFilename(path)) 67 return parseFileRecursively(path, dir, includeDirs, thriftMap) 68 } 69 bs, err := ioutil.ReadFile(path) 70 if err != nil { 71 return nil, err 72 } 73 return parseString(path, string(bs), includeDirs) 74 } 75 76 func parseFileRecursively(file, dir string, includeDirs []string, thriftMap map[string]*Thrift) (*Thrift, error) { 77 path, err := search(file, dir, includeDirs) 78 if err != nil { 79 return nil, err 80 } 81 if t, ok := thriftMap[path]; ok { 82 return t, nil 83 } 84 bs, err := ioutil.ReadFile(path) 85 if err != nil { 86 return nil, err 87 } 88 t, err := parseString(path, string(bs), includeDirs) 89 if err != nil { 90 return nil, fmt.Errorf("parse %s err: %w", path, err) 91 } 92 thriftMap[path] = t 93 dir = filepath.Dir(path) 94 for _, inc := range t.Includes { 95 t, err := parseFileRecursively(inc.Path, dir, includeDirs, thriftMap) 96 if err != nil { 97 return nil, err 98 } 99 inc.Reference = t 100 } 101 return t, nil 102 } 103 104 // ParseString parses the thrift file path and file content then return an AST. 105 func ParseString(path, content string) (*Thrift, error) { 106 return parseString(path, content, nil) 107 } 108 109 func parseString(path, content string, includeDirs []string) (*Thrift, error) { 110 p := &parser{ 111 IncludeDirs: includeDirs, 112 } 113 p.Filename = path 114 p.Buffer = content 115 p.Init() 116 if err := p.ThriftIDL.Parse(); err != nil { 117 return nil, err 118 } 119 if err := p.parse(); err != nil { 120 return nil, err 121 } 122 return &p.Thrift, nil 123 } 124 125 func (p *parser) parse() (err error) { 126 root := p.AST() 127 if root == nil || root.pegRule != ruleDocument { 128 return errors.New("not document") 129 } 130 // Header* Definition* !. 131 for n := root.up; n != nil; n = n.next { 132 switch n.pegRule { 133 case ruleSkip, ruleSkipLine: 134 continue 135 case ruleHeader: 136 if err := p.parseHeader(n); err != nil { 137 return err 138 } 139 case ruleDefinition: 140 if err := p.parseDefinition(n); err != nil { 141 return err 142 } 143 default: 144 return fmt.Errorf("unknown rule: " + rul3s[n.pegRule]) 145 } 146 } 147 return nil 148 } 149 150 func (p *parser) pegText(node *node32) string { 151 for n := node; n != nil; n = n.next { 152 if s := p.pegText(n.up); s != "" { 153 return s 154 } 155 if n.pegRule != rulePegText { 156 continue 157 } 158 159 quote := p.buffer[n.begin-1] 160 runes := make([]rune, 0, n.end-n.begin) 161 for i := n.begin; i < n.end-1; i++ { 162 r := p.buffer[i] 163 164 // unescape \' for single quoted, \" for double quoted 165 if r == '\\' { 166 switch p.buffer[i+1] { 167 case '\\': 168 i++ 169 runes = append(runes, r) 170 case quote: 171 continue 172 } 173 } 174 runes = append(runes, r) 175 } 176 runes = append(runes, p.buffer[n.end-1]) 177 return string(runes) 178 } 179 return "" 180 } 181 182 func (p *parser) parseHeader(node *node32) (err error) { 183 node, err = checkrule(node, ruleHeader) 184 if err != nil { 185 return err 186 } 187 // Skip (Include / CppInclude / Namespace) SkipLine 188 if node.pegRule == ruleSkip { 189 node = node.next 190 } 191 switch node.pegRule { 192 case ruleInclude: 193 if err := p.parseInclude(node); err != nil { 194 return err 195 } 196 case ruleNamespace: 197 if err := p.parseNamespace(node); err != nil { 198 return err 199 } 200 case ruleCppInclude: 201 if err := p.parseCppInclude(node); err != nil { 202 return err 203 } 204 default: 205 return fmt.Errorf("unknown rule: " + rul3s[node.pegRule]) 206 } 207 return nil 208 } 209 210 func (p *parser) parseInclude(node *node32) (err error) { 211 node, err = checkrule(node, ruleInclude) 212 if err != nil { 213 return err 214 } 215 filename := p.pegText(node) 216 if filename == "" { 217 return 218 } 219 for _, inc := range p.Includes { 220 if inc.Path == filename { 221 return 222 } 223 } 224 p.Includes = append(p.Includes, &Include{Path: filename}) 225 return nil 226 } 227 228 func (p *parser) parseCppInclude(node *node32) (err error) { 229 node, err = checkrule(node, ruleCppInclude) 230 if err != nil { 231 return err 232 } 233 p.CppIncludes = append(p.CppIncludes, p.pegText(node)) 234 return nil 235 } 236 237 func (p *parser) parseNamespace(node *node32) (err error) { 238 ns := Namespace{} 239 node, err = checkrule(node, ruleNamespace) 240 if err != nil { 241 return err 242 } 243 node = node.next // ignore "namespace" 244 ns.Language = p.pegText(node.up) 245 node = node.next 246 ns.Name = p.pegText(node.up) 247 node = node.next 248 if node != nil && node.pegRule == ruleAnnotations { // ANNOTATIONS 249 ns.Annotations, err = p.parseAnnotations(node) 250 if err != nil { 251 return err 252 } 253 } 254 p.Namespaces = append(p.Namespaces, &ns) 255 return nil 256 } 257 258 func (p *parser) parseDefinition(node *node32) (err error) { 259 node, err = checkrule(node, ruleDefinition) 260 if err != nil { 261 return err 262 } 263 p.DefinitionReservedComment = "" 264 // ReservedComments Skip (Const / Typedef / Enum / Struct / Union / Service / Exception) Annotations? SkipLine 265 if node.pegRule == ruleReservedComments { 266 reservedComments, err := p.parseReservedComments(node) 267 if err != nil { 268 return err 269 } 270 p.DefinitionReservedComment = reservedComments 271 node = node.next 272 } 273 // skip Skip 274 if node.pegRule == ruleSkip { 275 node = node.next 276 } 277 switch node.pegRule { 278 case ruleConst: 279 if err := p.parseConst(node); err != nil { 280 return err 281 } 282 case ruleTypedef: 283 if err := p.parseTypedef(node); err != nil { 284 return err 285 } 286 case ruleEnum: 287 if err := p.parseEnum(node); err != nil { 288 return err 289 } 290 case ruleUnion: 291 if err := p.parseUnion(node); err != nil { 292 return err 293 } 294 case ruleStruct: 295 if err := p.parseStruct(node); err != nil { 296 return err 297 } 298 case ruleException: 299 if err := p.parseException(node); err != nil { 300 return err 301 } 302 case ruleService: 303 if err := p.parseService(node); err != nil { 304 return err 305 } 306 default: 307 return fmt.Errorf("unknown rule: " + rul3s[node.pegRule]) 308 } 309 node = node.next 310 if node != nil && node.pegRule == ruleAnnotations { 311 ann, err := p.parseAnnotations(node) 312 if err != nil { 313 return err 314 } 315 *p.Annotations = ann 316 } 317 return nil 318 } 319 320 func (p *parser) parseConst(node *node32) (err error) { 321 node, err = checkrule(node, ruleConst) 322 if err != nil { 323 return err 324 } 325 // CONST FieldType Identifier EQUAL ConstValue ListSeparator? 326 node = node.next // ignore CONST 327 ft, err := p.parseFieldType(node) 328 if err != nil { 329 return err 330 } 331 node = node.next 332 name := p.pegText(node) 333 node = node.next.next // ignore EQUAL 334 value, err := p.parseConstValue(node) 335 if err != nil { 336 return err 337 } 338 c := &Constant{Name: name, Type: ft, Value: value} 339 c.ReservedComments = p.DefinitionReservedComment 340 p.Constants = append(p.Constants, c) 341 p.Annotations = &c.Annotations 342 return nil 343 } 344 345 func (p *parser) parseFieldType(node *node32) (typ *Type, err error) { 346 node, err = checkrule(node, ruleFieldType) 347 if err != nil { 348 return nil, err 349 } 350 // ContainerType / BaseType / Identifier 351 switch node.pegRule { 352 case ruleContainerType: 353 typ, err = p.parseContainerType(node) 354 if err != nil { 355 return typ, err 356 } 357 case ruleIdentifier, ruleBaseType: 358 typ = &Type{Name: p.pegText(node)} 359 default: 360 return typ, fmt.Errorf("unknown rule: " + rul3s[node.pegRule]) 361 } 362 node = node.next 363 if node != nil && node.pegRule == ruleAnnotations { 364 typ.Annotations, err = p.parseAnnotations(node) 365 if err != nil { 366 return typ, err 367 } 368 } 369 return typ, nil 370 } 371 372 func (p *parser) parseContainerType(node *node32) (typ *Type, err error) { 373 node, err = checkrule(node, ruleContainerType) 374 if err != nil { 375 return &Type{}, err 376 } 377 // MapType / SetType / ListType 378 switch node.pegRule { 379 case ruleMapType: // MAP CppType? LPOINT FieldType COMMA FieldType RPOINT 380 node = node.up.next // ignore MAP LPOINT 381 var cppType string 382 if node.pegRule == ruleCppType { 383 cppType = p.pegText(node.up.next) // ignore CPPTYPE 384 node = node.next 385 } 386 node = node.next // ignore LPOINT 387 kt, err := p.parseFieldType(node) 388 if err != nil { 389 return kt, err 390 } 391 node = node.next.next // ignore COMMA 392 vt, err := p.parseFieldType(node) 393 if err != nil { 394 return vt, err 395 } 396 return &Type{Name: "map", KeyType: kt, ValueType: vt, CppType: cppType}, nil 397 case ruleSetType: // SET CppType? LPOINT FieldType RPOINT 398 node = node.up.next // ignore SET 399 var cppType string 400 if node.pegRule == ruleCppType { 401 cppType = p.pegText(node.up.next) // ignore CPPTYPE 402 node = node.next 403 } 404 node = node.next // ignore LPOINT 405 vt, err := p.parseFieldType(node) 406 if err != nil { 407 return vt, err 408 } 409 return &Type{Name: "set", ValueType: vt, CppType: cppType}, nil 410 case ruleListType: // LIST LPOINT FieldType RPOINT CppType? 411 node = node.up.next.next // ignore LIST LPOINT 412 vt, err := p.parseFieldType(node) 413 if err != nil { 414 return vt, err 415 } 416 node = node.next.next // ignore RPOINT 417 var cppType string 418 if node != nil && node.pegRule == ruleCppType { 419 cppType = p.pegText(node.up.next) // ignore CPPTYPE 420 } 421 return &Type{Name: "list", ValueType: vt, CppType: cppType}, nil 422 default: 423 return &Type{}, fmt.Errorf("unknown rule: " + rul3s[node.pegRule]) 424 } 425 } 426 427 func (p *parser) parseConstValue(node *node32) (cv *ConstValue, err error) { 428 node, err = checkrule(node, ruleConstValue) 429 if err != nil { 430 return nil, err 431 } 432 // DoubleConstant / IntConstant / Literal / Identifier / ConstList / ConstMap 433 switch node.pegRule { 434 case ruleDoubleConstant: 435 double, _ := strconv.ParseFloat(p.pegText(node), 64) 436 return &ConstValue{Type: ConstType_ConstDouble, TypedValue: &ConstTypedValue{Double: &double}}, nil 437 case ruleIntConstant: 438 i, err := strconv.ParseInt(p.pegText(node), 0, 64) 439 if err != nil { 440 return nil, fmt.Errorf("parseConstValue failed at '%s': %w", p.pegText(node), err) 441 } 442 return &ConstValue{Type: ConstType_ConstInt, TypedValue: &ConstTypedValue{Int: &i}}, nil 443 case ruleLiteral: 444 literal := p.pegText(node) 445 return &ConstValue{Type: ConstType_ConstLiteral, TypedValue: &ConstTypedValue{Literal: &literal}}, nil 446 case ruleIdentifier: 447 identifier := p.pegText(node) 448 return &ConstValue{Type: ConstType_ConstIdentifier, TypedValue: &ConstTypedValue{Identifier: &identifier}}, nil 449 case ruleConstList: 450 // LBRK (ConstValue ListSeparator?)* RBRK 451 ret := []*ConstValue{} // important: can't not be nil 452 for n := node.up; n != nil; n = n.next { 453 if n.pegRule == ruleConstValue { 454 val, err := p.parseConstValue(n) 455 if err != nil { 456 return nil, err 457 } 458 ret = append(ret, val) 459 } 460 } 461 return &ConstValue{Type: ConstType_ConstList, TypedValue: &ConstTypedValue{List: ret}}, nil 462 case ruleConstMap: 463 node = node.up 464 // LWING (ConstValue COLON ConstValue ListSeparator?)* RWING 465 ret := []*MapConstValue{} // important: can't not be nil 466 for n := node.next; n != nil; n = n.next { 467 if n.pegRule != ruleConstValue { 468 continue 469 } 470 k, err := p.parseConstValue(n) 471 if err != nil { 472 return nil, err 473 } 474 n = n.next.next // ignore COLON 475 v, err := p.parseConstValue(n) 476 if err != nil { 477 return nil, err 478 } 479 ret = append(ret, &MapConstValue{Key: k, Value: v}) 480 } 481 return &ConstValue{Type: ConstType_ConstMap, TypedValue: &ConstTypedValue{Map: ret}}, nil 482 default: 483 return nil, fmt.Errorf("unknown rule: " + rul3s[node.pegRule]) 484 } 485 } 486 487 func (p *parser) parseTypedef(node *node32) (err error) { 488 node, err = checkrule(node, ruleTypedef) 489 if err != nil { 490 return err 491 } 492 // TYPEDEF FieldType Identifier 493 node = node.next // ignore TYPEDEF 494 ft, err := p.parseFieldType(node) 495 if err != nil { 496 return err 497 } 498 var typd Typedef 499 typd.Type = ft 500 node = node.next 501 typd.Alias = p.pegText(node) 502 typd.ReservedComments = p.DefinitionReservedComment 503 p.Typedefs = append(p.Typedefs, &typd) 504 p.Annotations = &typd.Annotations 505 return nil 506 } 507 508 func (p *parser) parseEnum(node *node32) (err error) { 509 node, err = checkrule(node, ruleEnum) 510 if err != nil { 511 return err 512 } 513 // ENUM Identifier LWING ( ReservedComments Identifier (EQUAL IntConstant)? Annotations? ListSeparator? ReservedEndLineComments SkipLine)* RWING 514 node = node.next // ignore ENUM 515 name := p.pegText(node) 516 var values []*EnumValue 517 for n := node.next.next; n != nil; n = n.next { 518 valueComments := "" 519 if n.pegRule == ruleReservedComments { 520 valueComments, err = p.parseReservedComments(n) 521 if err != nil { 522 return err 523 } 524 n = n.next 525 } 526 if n.pegRule == ruleIdentifier { 527 var v EnumValue 528 v.ReservedComments = valueComments 529 v.Name = p.pegText(n) 530 if n.next.pegRule == ruleEQUAL { 531 n = n.next.next 532 v.Value, _ = strconv.ParseInt(p.pegText(n), 0, 64) 533 } else { 534 if len(values) == 0 { 535 v.Value = 0 536 } else { 537 v.Value = values[len(values)-1].Value + 1 538 } 539 } 540 541 if n.next.pegRule == ruleAnnotations { 542 n = n.next 543 v.Annotations, err = p.parseAnnotations(n) 544 if err != nil { 545 return err 546 } 547 } 548 if n.next.pegRule == ruleListSeparator { 549 n = n.next 550 } 551 if n.next.pegRule == ruleReservedEndLineComments && v.ReservedComments == "" { 552 n = n.next 553 v.ReservedComments, err = p.parseReservedEndLineComments(n) 554 if err != nil { 555 return err 556 } 557 } 558 values = append(values, &v) 559 } 560 } 561 e := &Enum{Name: name, Values: values} 562 e.ReservedComments = p.DefinitionReservedComment 563 p.Enums = append(p.Enums, e) 564 p.Annotations = &e.Annotations 565 return nil 566 } 567 568 func (p *parser) parseUnion(node *node32) (err error) { 569 node, err = checkrule(node, ruleUnion) 570 if err != nil { 571 return err 572 } 573 // UNION Identifier LWING Field* RWING 574 node = node.next // ignore UNION 575 name := p.pegText(node) 576 node = node.next 577 var fields []*Field 578 for n := node.next; n != nil; n = n.next { 579 switch n.pegRule { 580 case ruleField: 581 field, err := p.parseField(n) 582 if err != nil { 583 return err 584 } 585 if field.ID == NOTSET { 586 if len(fields) > 0 { 587 field.ID = fields[len(fields)-1].ID + 1 588 } else { 589 field.ID = 1 590 } 591 } 592 fields = append(fields, field) 593 } 594 } 595 u := &StructLike{Category: "union", Name: name, Fields: fields} 596 u.ReservedComments = p.DefinitionReservedComment 597 p.Unions = append(p.Unions, u) 598 p.Annotations = &u.Annotations 599 return nil 600 } 601 602 func (p *parser) parseStruct(node *node32) (err error) { 603 node, err = checkrule(node, ruleStruct) 604 if err != nil { 605 return err 606 } 607 // STRUCT Identifier LWING Field* RWING 608 node = node.next // ignore STRUCT 609 name := p.pegText(node) 610 node = node.next 611 var fields []*Field 612 for n := node.next; n != nil; n = n.next { 613 switch n.pegRule { 614 case ruleField: 615 field, err := p.parseField(n) 616 if err != nil { 617 return err 618 } 619 if field.ID == NOTSET { 620 if len(fields) > 0 { 621 field.ID = fields[len(fields)-1].ID + 1 622 } else { 623 field.ID = 1 624 } 625 } 626 fields = append(fields, field) 627 } 628 } 629 s := &StructLike{Category: "struct", Name: name, Fields: fields} 630 s.ReservedComments = p.DefinitionReservedComment 631 p.Structs = append(p.Structs, s) 632 p.Annotations = &s.Annotations 633 return nil 634 } 635 636 func (p *parser) parseException(node *node32) (err error) { 637 node, err = checkrule(node, ruleException) 638 if err != nil { 639 return err 640 } 641 // EXCEPTION Identifier LWING Field* RWING 642 node = node.next // ignore EXCEPTION 643 name := p.pegText(node) 644 var fields []*Field 645 for n := node.next; n != nil; n = n.next { 646 if n.pegRule == ruleField { 647 field, err := p.parseField(n) 648 if err != nil { 649 return err 650 } 651 if field.ID == NOTSET { 652 if len(fields) > 0 { 653 field.ID = fields[len(fields)-1].ID + 1 654 } else { 655 field.ID = 1 656 } 657 } 658 fields = append(fields, field) 659 } 660 } 661 e := &StructLike{Category: "exception", Name: name, Fields: fields} 662 e.ReservedComments = p.DefinitionReservedComment 663 p.Exceptions = append(p.Exceptions, e) 664 p.Annotations = &e.Annotations 665 return nil 666 } 667 668 func (p *parser) parseField(node *node32) (field *Field, err error) { 669 node, err = checkrule(node, ruleField) 670 if err != nil { 671 return nil, err 672 } 673 // ReservedComments Skip FieldId? FieldReq? FieldType Identifier (EQUAL ConstValue)? Annotations? ListSeparator? ReservedEndLineComments 674 var f Field 675 f.ID = NOTSET 676 for ; node != nil; node = node.next { 677 switch node.pegRule { 678 case ruleSkip, ruleSkipLine: 679 continue 680 case ruleReservedComments: 681 reservedComments, err := p.parseReservedComments(node) 682 if err != nil { 683 return nil, err 684 } 685 f.ReservedComments = reservedComments 686 case ruleReservedEndLineComments: 687 // endline comment's priority is lower than the header comment 688 reservedComments, err := p.parseReservedEndLineComments(node) 689 if err != nil { 690 return nil, err 691 } 692 if f.ReservedComments == "" { 693 f.ReservedComments = reservedComments 694 } 695 case ruleFieldId: 696 i, _ := strconv.Atoi(p.pegText(node)) 697 f.ID = int32(i) 698 case ruleFieldReq: 699 require := p.pegText(node) 700 f.Requiredness = FieldType_Default 701 if require == "required" { 702 f.Requiredness = FieldType_Required 703 } else if require == "optional" { 704 f.Requiredness = FieldType_Optional 705 } 706 case ruleFieldType: 707 f.Type, err = p.parseFieldType(node) 708 if err != nil { 709 return nil, err 710 } 711 case ruleIdentifier: 712 f.Name = p.pegText(node) 713 case ruleEQUAL: 714 node = node.next // ignore EQUAL 715 f.Default, err = p.parseConstValue(node) 716 if err != nil { 717 return nil, err 718 } 719 case ruleAnnotations: 720 f.Annotations, err = p.parseAnnotations(node) 721 if err != nil { 722 return nil, err 723 } 724 } 725 } 726 return &f, nil 727 } 728 729 func (p *parser) parseAnnotations(node *node32) ([]*Annotation, error) { 730 // LPAR Annotation+ RPAR 731 var err error 732 var ret Annotations 733 node, err = checkrule(node, ruleAnnotations) 734 if err != nil { 735 return nil, err 736 } 737 for node = node.next; node != nil; node = node.next { 738 if node.pegRule == ruleAnnotation { 739 k, v, err := p.parseAnnotation(node) 740 if err != nil { 741 return nil, err 742 } 743 ret.Append(k, v) 744 } 745 } 746 return ret, nil 747 } 748 749 func (p *parser) parseAnnotation(node *node32) (k, v string, err error) { 750 // Identifier EQUAL Literal ListSeparator? 751 node, err = checkrule(node, ruleAnnotation) 752 if err != nil { 753 return "", "", err 754 } 755 756 k = p.pegText(node) // Identifier 757 node = node.next.next 758 v = p.pegText(node) // Literal 759 return k, v, nil 760 } 761 762 func (p *parser) parseService(node *node32) (err error) { 763 node, err = checkrule(node, ruleService) 764 if err != nil { 765 return err 766 } 767 // SERVICE Identifier ( EXTENDS Identifier )? LWING Function* RWING 768 var s Service 769 node = node.next // ignore SERVICE 770 s.Name = p.pegText(node) 771 node = node.next 772 if node.pegRule == ruleEXTENDS { 773 s.Extends = p.pegText(node) 774 node = node.next 775 } 776 for node = node.next; node != nil; node = node.next { 777 if node.pegRule == ruleFunction { 778 fu, err := p.parseFunction(node) 779 if err != nil { 780 return err 781 } 782 s.Functions = append(s.Functions, fu) 783 } 784 } 785 s.ReservedComments = p.DefinitionReservedComment 786 p.Services = append(p.Services, &s) 787 p.Annotations = &s.Annotations 788 return nil 789 } 790 791 func (p *parser) parseFunction(node *node32) (fu *Function, err error) { 792 node, err = checkrule(node, ruleFunction) 793 if err != nil { 794 return nil, err 795 } 796 // ReservedComments ONEWAY? FunctionType Identifier LPAR Field* RPAR Throws? Annotations? ListSeparator? 797 var f Function 798 for ; node != nil; node = node.next { 799 switch node.pegRule { 800 case ruleReservedComments: 801 reservedComments, err := p.parseReservedComments(node) 802 if err != nil { 803 return nil, err 804 } 805 f.ReservedComments = reservedComments 806 case ruleONEWAY: 807 f.Oneway = true 808 case ruleFunctionType: 809 n := node.up 810 if n.pegRule == ruleFieldType { 811 f.FunctionType, err = p.parseFieldType(n) 812 if err != nil { 813 return nil, err 814 } 815 } else if n.pegRule == ruleVOID { 816 f.Void = true 817 f.FunctionType = &Type{Name: "void"} 818 } 819 case ruleIdentifier: 820 f.Name = p.pegText(node) 821 case ruleField: 822 field, err := p.parseField(node) 823 if err != nil { 824 return nil, err 825 } 826 f.Arguments = addField(f.Arguments, field) 827 case ruleThrows: 828 f.Throws, err = p.parseThrows(node) 829 if err != nil { 830 return nil, err 831 } 832 case ruleAnnotations: 833 f.Annotations, err = p.parseAnnotations(node) 834 if err != nil { 835 return nil, err 836 } 837 } 838 } 839 return &f, nil 840 } 841 842 func (p *parser) parseThrows(node *node32) (fs []*Field, err error) { 843 node, err = checkrule(node, ruleThrows) 844 if err != nil { 845 return nil, err 846 } 847 // THROWS LPAR Field* RPAR 848 node = node.next // ignore THROWS 849 var fields []*Field 850 for ; node != nil; node = node.next { 851 if node.pegRule == ruleField { 852 field, err := p.parseField(node) 853 if err != nil { 854 return nil, err 855 } 856 field.Requiredness = FieldType_Optional 857 fields = addField(fields, field) 858 } 859 } 860 return fields, nil 861 } 862 863 func (p *parser) parseReservedComments(node *node32) (ReservedComments string, err error) { 864 node, err = checkrule(node, ruleReservedComments) 865 if err != nil { 866 return "", err 867 } 868 // Skip 869 node = node.up 870 // (Space / Comment)* 871 var comments []string 872 for ; node != nil; node = node.next { 873 if node.pegRule == ruleComment { 874 comment := strings.TrimRight(string(p.buffer[int(node.up.begin):int(node.up.end)]), "\r\n") 875 if strings.HasPrefix(comment, "#") { 876 comment = strings.TrimPrefix(comment, "#") 877 comment = "//" + comment 878 } 879 if comment != "" { 880 comments = append(comments, comment) 881 } 882 } 883 } 884 return strings.Join(comments, "\n"), nil 885 } 886 887 func (p *parser) parseReservedEndLineComments(node *node32) (ReservedComments string, err error) { 888 node, err = checkrule(node, ruleReservedEndLineComments) 889 if err != nil { 890 return "", err 891 } 892 // Skip 893 node = node.up 894 // (Space / Comment)* 895 var comments []string 896 for ; node != nil; node = node.next { 897 if node.pegRule == ruleComment { 898 comment := strings.TrimRight(string(p.buffer[int(node.up.begin):int(node.up.end)]), "\r\n") 899 if strings.HasPrefix(comment, "#") { 900 comment = strings.TrimPrefix(comment, "#") 901 comment = "//" + comment 902 } 903 if comment != "" { 904 comments = append(comments, comment) 905 } 906 } 907 } 908 return strings.Join(comments, "\n"), nil 909 }