summaryrefslogtreecommitdiff
path: root/vendor/github.com/bufbuild/protocompile/ast
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-05-20 14:28:06 -0600
committermo khan <mo@mokhan.ca>2025-05-23 14:49:19 -0600
commit4beee46dc6c7642316e118a4d3aa51e4b407256e (patch)
tree039bdf57b99061844aeb0fe55ad0bc1c864166af /vendor/github.com/bufbuild/protocompile/ast
parent0ba49bfbde242920d8675a193d7af89420456fc0 (diff)
feat: add external authorization service (authzd) with JWT authentication
- Add new authzd gRPC service implementing Envoy's external authorization API - Integrate JWT authentication filter in Envoy configuration with claim extraction - Update middleware to support both cookie-based and header-based user authentication - Add comprehensive test coverage for authorization service and server - Configure proper service orchestration with authzd, sparkled, and Envoy - Update build system and Docker configuration for multi-service deployment - Add grpcurl tool for gRPC service debugging and testing This enables fine-grained authorization control through Envoy's ext_authz filter while maintaining backward compatibility with existing cookie-based authentication.
Diffstat (limited to 'vendor/github.com/bufbuild/protocompile/ast')
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/doc.go75
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/enum.go185
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/field.go795
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/file.go358
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/file_info.go701
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/identifiers.go153
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/message.go223
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/no_source.go142
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/node.go139
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/options.go413
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/ranges.go386
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/service.go308
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/values.go519
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/walk.go931
14 files changed, 5328 insertions, 0 deletions
diff --git a/vendor/github.com/bufbuild/protocompile/ast/doc.go b/vendor/github.com/bufbuild/protocompile/ast/doc.go
new file mode 100644
index 0000000..cda4068
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/doc.go
@@ -0,0 +1,75 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package ast defines types for modeling the AST (Abstract Syntax
+// Tree) for the Protocol Buffers interface definition language.
+//
+// # Nodes
+//
+// All nodes of the tree implement the [Node] interface. Leaf nodes in the
+// tree implement [TerminalNode], and all others implement [CompositeNode].
+// The root of the tree for a proto source file is a *[FileNode].
+//
+// A [TerminalNode] represents a single lexical element, or [Token]. A
+// [CompositeNode] represents a sub-tree of the AST and range of tokens.
+//
+// Position information is tracked using a *[FileInfo]. The lexer invokes its
+// various Add* methods to add details as the file is tokenized. Storing
+// the position information in the *[FileInfo], instead of in each AST node,
+// allows the AST to have a much more compact representation. To extract
+// detailed position information, you must use the NodeInfo method, available
+// on either the *[FileInfo] which produced the node's items or the *[FileNode]
+// root of the tree that contains the node.
+//
+// # Items, Tokens, and Comments
+//
+// An [Item] represents a lexical item, excluding whitespace. This can be
+// either a [Token] or a [Comment].
+//
+// Comments are not represented as nodes in the tree. Instead, they are
+// attributed to terminal nodes in the tree. So, when lexing, comments
+// are accumulated until the next non-comment token is found. The AST
+// model in this package thus provides access to all comments in the
+// file, regardless of location (unlike the SourceCodeInfo present in
+// descriptor protos, which is lossy). The comments associated with a
+// non-leaf/non-token node (i.e. a CompositeNode) come from the first
+// and last nodes in its sub-tree, for leading and trailing comments
+// respectively.
+//
+// A [Comment] value corresponds to a line ("//") or block ("/*") style
+// comment in the source. These have no bearing on the grammar and are
+// effectively ignored as the parser is determining the shape of the
+// syntax tree.
+//
+// A [Token] value corresponds to a component of the grammar, that is
+// used to produce an AST. They correspond to leaves in the AST (i.e.
+// [TerminalNode]).
+//
+// The *[FileInfo] and *[FileNode] types provide methods for querying
+// and iterating through all the items or tokens in the file. They also
+// include a method for resolving an [Item] into a [Token] or [Comment].
+//
+// # Factory Functions
+//
+// Creation of AST nodes should use the factory functions in this
+// package instead of struct literals. Some factory functions accept
+// optional arguments, which means the arguments can be nil. If nil
+// values are provided for other (non-optional) arguments, the resulting
+// node may be invalid and cause panics later in the program.
+//
+// This package defines numerous interfaces. However, user code should
+// not attempt to implement any of them. Most consumers of an AST will
+// not work correctly if they encounter concrete implementations other
+// than the ones defined in this package.
+package ast
diff --git a/vendor/github.com/bufbuild/protocompile/ast/enum.go b/vendor/github.com/bufbuild/protocompile/ast/enum.go
new file mode 100644
index 0000000..55a6229
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/enum.go
@@ -0,0 +1,185 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// EnumNode represents an enum declaration. Example:
+//
+// enum Foo { BAR = 0; BAZ = 1 }
+type EnumNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name *IdentNode
+ OpenBrace *RuneNode
+ Decls []EnumElement
+ CloseBrace *RuneNode
+}
+
+func (*EnumNode) fileElement() {}
+func (*EnumNode) msgElement() {}
+
+// NewEnumNode creates a new *EnumNode. All arguments must be non-nil. While
+// it is technically allowed for decls to be nil or empty, the resulting node
+// will not be a valid enum, which must have at least one value.
+// - keyword: The token corresponding to the "enum" keyword.
+// - name: The token corresponding to the enum's name.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the enum body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewEnumNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []EnumElement, closeBrace *RuneNode) *EnumNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 4+len(decls))
+ children = append(children, keyword, name, openBrace)
+ for _, decl := range decls {
+ switch decl.(type) {
+ case *OptionNode, *EnumValueNode, *ReservedNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid EnumElement type: %T", decl))
+ }
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ return &EnumNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ OpenBrace: openBrace,
+ CloseBrace: closeBrace,
+ Decls: decls,
+ }
+}
+
+func (n *EnumNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// EnumElement is an interface implemented by all AST nodes that can
+// appear in the body of an enum declaration.
+type EnumElement interface {
+ Node
+ enumElement()
+}
+
+var _ EnumElement = (*OptionNode)(nil)
+var _ EnumElement = (*EnumValueNode)(nil)
+var _ EnumElement = (*ReservedNode)(nil)
+var _ EnumElement = (*EmptyDeclNode)(nil)
+
+// EnumValueDeclNode is a placeholder interface for AST nodes that represent
+// enum values. This allows NoSourceNode to be used in place of *EnumValueNode
+// for some usages.
+type EnumValueDeclNode interface {
+ NodeWithOptions
+ GetName() Node
+ GetNumber() Node
+}
+
+var _ EnumValueDeclNode = (*EnumValueNode)(nil)
+var _ EnumValueDeclNode = (*NoSourceNode)(nil)
+
+// EnumValueNode represents an enum declaration. Example:
+//
+// UNSET = 0 [deprecated = true];
+type EnumValueNode struct {
+ compositeNode
+ Name *IdentNode
+ Equals *RuneNode
+ Number IntValueNode
+ Options *CompactOptionsNode
+ Semicolon *RuneNode
+}
+
+func (*EnumValueNode) enumElement() {}
+
+// NewEnumValueNode creates a new *EnumValueNode. All arguments must be non-nil
+// except opts which is only non-nil if the declaration included options.
+// - name: The token corresponding to the enum value's name.
+// - equals: The token corresponding to the '=' rune after the name.
+// - number: The token corresponding to the enum value's number.
+// - opts: Optional set of enum value options.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewEnumValueNode(name *IdentNode, equals *RuneNode, number IntValueNode, opts *CompactOptionsNode, semicolon *RuneNode) *EnumValueNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ if equals == nil {
+ panic("equals is nil")
+ }
+ if number == nil {
+ panic("number is nil")
+ }
+ numChildren := 3
+ if semicolon != nil {
+ numChildren++
+ }
+ if opts != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, name, equals, number)
+ if opts != nil {
+ children = append(children, opts)
+ }
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+ return &EnumValueNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Name: name,
+ Equals: equals,
+ Number: number,
+ Options: opts,
+ Semicolon: semicolon,
+ }
+}
+
+func (e *EnumValueNode) GetName() Node {
+ return e.Name
+}
+
+func (e *EnumValueNode) GetNumber() Node {
+ return e.Number
+}
+
+func (e *EnumValueNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, opt := range e.Options.Options {
+ if !fn(opt) {
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/field.go b/vendor/github.com/bufbuild/protocompile/ast/field.go
new file mode 100644
index 0000000..63d65b3
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/field.go
@@ -0,0 +1,795 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// FieldDeclNode is a node in the AST that defines a field. This includes
+// normal message fields as well as extensions. There are multiple types
+// of AST nodes that declare fields:
+// - *FieldNode
+// - *GroupNode
+// - *MapFieldNode
+// - *SyntheticMapField
+//
+// This also allows NoSourceNode and SyntheticMapField to be used in place of
+// one of the above for some usages.
+type FieldDeclNode interface {
+ NodeWithOptions
+ FieldLabel() Node
+ FieldName() Node
+ FieldType() Node
+ FieldTag() Node
+ FieldExtendee() Node
+ GetGroupKeyword() Node
+ GetOptions() *CompactOptionsNode
+}
+
+var _ FieldDeclNode = (*FieldNode)(nil)
+var _ FieldDeclNode = (*GroupNode)(nil)
+var _ FieldDeclNode = (*MapFieldNode)(nil)
+var _ FieldDeclNode = (*SyntheticMapField)(nil)
+var _ FieldDeclNode = (*NoSourceNode)(nil)
+
+// FieldNode represents a normal field declaration (not groups or maps). It
+// can represent extension fields as well as non-extension fields (both inside
+// of messages and inside of one-ofs). Example:
+//
+// optional string foo = 1;
+type FieldNode struct {
+ compositeNode
+ Label FieldLabel
+ FldType IdentValueNode
+ Name *IdentNode
+ Equals *RuneNode
+ Tag *UintLiteralNode
+ Options *CompactOptionsNode
+ Semicolon *RuneNode
+
+ // This is an up-link to the containing *ExtendNode for fields
+ // that are defined inside of "extend" blocks.
+ Extendee *ExtendNode
+}
+
+func (*FieldNode) msgElement() {}
+func (*FieldNode) oneofElement() {}
+func (*FieldNode) extendElement() {}
+
+// NewFieldNode creates a new *FieldNode. The label and options arguments may be
+// nil but the others must be non-nil.
+// - label: The token corresponding to the label keyword if present ("optional",
+// "required", or "repeated").
+// - fieldType: The token corresponding to the field's type.
+// - name: The token corresponding to the field's name.
+// - equals: The token corresponding to the '=' rune after the name.
+// - tag: The token corresponding to the field's tag number.
+// - opts: Optional set of field options.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewFieldNode(label *KeywordNode, fieldType IdentValueNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *FieldNode {
+ if fieldType == nil {
+ panic("fieldType is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ numChildren := 2
+ if equals != nil {
+ numChildren++
+ }
+ if tag != nil {
+ numChildren++
+ }
+ if semicolon != nil {
+ numChildren++
+ }
+ if label != nil {
+ numChildren++
+ }
+ if opts != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ if label != nil {
+ children = append(children, label)
+ }
+ children = append(children, fieldType, name)
+ if equals != nil {
+ children = append(children, equals)
+ }
+ if tag != nil {
+ children = append(children, tag)
+ }
+ if opts != nil {
+ children = append(children, opts)
+ }
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+
+ return &FieldNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Label: newFieldLabel(label),
+ FldType: fieldType,
+ Name: name,
+ Equals: equals,
+ Tag: tag,
+ Options: opts,
+ Semicolon: semicolon,
+ }
+}
+
+func (n *FieldNode) FieldLabel() Node {
+ // proto3 fields and fields inside one-ofs will not have a label and we need
+ // this check in order to return a nil node -- otherwise we'd return a
+ // non-nil node that has a nil pointer value in it :/
+ if n.Label.KeywordNode == nil {
+ return nil
+ }
+ return n.Label.KeywordNode
+}
+
+func (n *FieldNode) FieldName() Node {
+ return n.Name
+}
+
+func (n *FieldNode) FieldType() Node {
+ return n.FldType
+}
+
+func (n *FieldNode) FieldTag() Node {
+ if n.Tag == nil {
+ return n
+ }
+ return n.Tag
+}
+
+func (n *FieldNode) FieldExtendee() Node {
+ if n.Extendee != nil {
+ return n.Extendee.Extendee
+ }
+ return nil
+}
+
+func (n *FieldNode) GetGroupKeyword() Node {
+ return nil
+}
+
+func (n *FieldNode) GetOptions() *CompactOptionsNode {
+ return n.Options
+}
+
+func (n *FieldNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, opt := range n.Options.Options {
+ if !fn(opt) {
+ return
+ }
+ }
+}
+
+// FieldLabel represents the label of a field, which indicates its cardinality
+// (i.e. whether it is optional, required, or repeated).
+type FieldLabel struct {
+ *KeywordNode
+ Repeated bool
+ Required bool
+}
+
+func newFieldLabel(lbl *KeywordNode) FieldLabel {
+ repeated, required := false, false
+ if lbl != nil {
+ repeated = lbl.Val == "repeated"
+ required = lbl.Val == "required"
+ }
+ return FieldLabel{
+ KeywordNode: lbl,
+ Repeated: repeated,
+ Required: required,
+ }
+}
+
+// IsPresent returns true if a label keyword was present in the declaration
+// and false if it was absent.
+func (f *FieldLabel) IsPresent() bool {
+ return f.KeywordNode != nil
+}
+
+// GroupNode represents a group declaration, which doubles as a field and inline
+// message declaration. It can represent extension fields as well as
+// non-extension fields (both inside of messages and inside of one-ofs).
+// Example:
+//
+// optional group Key = 4 {
+// optional uint64 id = 1;
+// optional string name = 2;
+// }
+type GroupNode struct {
+ compositeNode
+ Label FieldLabel
+ Keyword *KeywordNode
+ Name *IdentNode
+ Equals *RuneNode
+ Tag *UintLiteralNode
+ Options *CompactOptionsNode
+ MessageBody
+
+ // This is an up-link to the containing *ExtendNode for groups
+ // that are defined inside of "extend" blocks.
+ Extendee *ExtendNode
+}
+
+func (*GroupNode) msgElement() {}
+func (*GroupNode) oneofElement() {}
+func (*GroupNode) extendElement() {}
+
+// NewGroupNode creates a new *GroupNode. The label and options arguments may be
+// nil but the others must be non-nil.
+// - label: The token corresponding to the label keyword if present ("optional",
+// "required", or "repeated").
+// - keyword: The token corresponding to the "group" keyword.
+// - name: The token corresponding to the field's name.
+// - equals: The token corresponding to the '=' rune after the name.
+// - tag: The token corresponding to the field's tag number.
+// - opts: Optional set of field options.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the group body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewGroupNode(label *KeywordNode, keyword *KeywordNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *GroupNode {
+ if keyword == nil {
+ panic("fieldType is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ numChildren := 4 + len(decls)
+ if label != nil {
+ numChildren++
+ }
+ if equals != nil {
+ numChildren++
+ }
+ if tag != nil {
+ numChildren++
+ }
+ if opts != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ if label != nil {
+ children = append(children, label)
+ }
+ children = append(children, keyword, name)
+ if equals != nil {
+ children = append(children, equals)
+ }
+ if tag != nil {
+ children = append(children, tag)
+ }
+ if opts != nil {
+ children = append(children, opts)
+ }
+ children = append(children, openBrace)
+ for _, decl := range decls {
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ ret := &GroupNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Label: newFieldLabel(label),
+ Keyword: keyword,
+ Name: name,
+ Equals: equals,
+ Tag: tag,
+ Options: opts,
+ }
+ populateMessageBody(&ret.MessageBody, openBrace, decls, closeBrace)
+ return ret
+}
+
+func (n *GroupNode) FieldLabel() Node {
+ if n.Label.KeywordNode == nil {
+ // return nil interface to indicate absence, not a typed nil
+ return nil
+ }
+ return n.Label.KeywordNode
+}
+
+func (n *GroupNode) FieldName() Node {
+ return n.Name
+}
+
+func (n *GroupNode) FieldType() Node {
+ return n.Keyword
+}
+
+func (n *GroupNode) FieldTag() Node {
+ if n.Tag == nil {
+ return n
+ }
+ return n.Tag
+}
+
+func (n *GroupNode) FieldExtendee() Node {
+ if n.Extendee != nil {
+ return n.Extendee.Extendee
+ }
+ return nil
+}
+
+func (n *GroupNode) GetGroupKeyword() Node {
+ return n.Keyword
+}
+
+func (n *GroupNode) GetOptions() *CompactOptionsNode {
+ return n.Options
+}
+
+func (n *GroupNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, opt := range n.Options.Options {
+ if !fn(opt) {
+ return
+ }
+ }
+}
+
+func (n *GroupNode) AsMessage() *SyntheticGroupMessageNode {
+ return (*SyntheticGroupMessageNode)(n)
+}
+
+// SyntheticGroupMessageNode is a view of a GroupNode that implements MessageDeclNode.
+// Since a group field implicitly defines a message type, this node represents
+// that message type while the corresponding GroupNode represents the field.
+//
+// This type is considered synthetic since it never appears in a file's AST, but
+// is only returned from other accessors (e.g. GroupNode.AsMessage).
+type SyntheticGroupMessageNode GroupNode
+
+func (n *SyntheticGroupMessageNode) MessageName() Node {
+ return n.Name
+}
+
+func (n *SyntheticGroupMessageNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// OneofDeclNode is a node in the AST that defines a oneof. There are
+// multiple types of AST nodes that declare oneofs:
+// - *OneofNode
+// - *SyntheticOneof
+//
+// This also allows NoSourceNode to be used in place of one of the above
+// for some usages.
+type OneofDeclNode interface {
+ NodeWithOptions
+ OneofName() Node
+}
+
+var _ OneofDeclNode = (*OneofNode)(nil)
+var _ OneofDeclNode = (*SyntheticOneof)(nil)
+var _ OneofDeclNode = (*NoSourceNode)(nil)
+
+// OneofNode represents a one-of declaration. Example:
+//
+// oneof query {
+// string by_name = 2;
+// Type by_type = 3;
+// Address by_address = 4;
+// Labels by_label = 5;
+// }
+type OneofNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name *IdentNode
+ OpenBrace *RuneNode
+ Decls []OneofElement
+ CloseBrace *RuneNode
+}
+
+func (*OneofNode) msgElement() {}
+
+// NewOneofNode creates a new *OneofNode. All arguments must be non-nil. While
+// it is technically allowed for decls to be nil or empty, the resulting node
+// will not be a valid oneof, which must have at least one field.
+// - keyword: The token corresponding to the "oneof" keyword.
+// - name: The token corresponding to the oneof's name.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the oneof body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewOneofNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []OneofElement, closeBrace *RuneNode) *OneofNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 4+len(decls))
+ children = append(children, keyword, name, openBrace)
+ for _, decl := range decls {
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ for _, decl := range decls {
+ switch decl := decl.(type) {
+ case *OptionNode, *FieldNode, *GroupNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid OneofElement type: %T", decl))
+ }
+ }
+
+ return &OneofNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ OpenBrace: openBrace,
+ Decls: decls,
+ CloseBrace: closeBrace,
+ }
+}
+
+func (n *OneofNode) OneofName() Node {
+ return n.Name
+}
+
+func (n *OneofNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// OneofElement is an interface implemented by all AST nodes that can
+// appear in the body of a oneof declaration.
+type OneofElement interface {
+ Node
+ oneofElement()
+}
+
+var _ OneofElement = (*OptionNode)(nil)
+var _ OneofElement = (*FieldNode)(nil)
+var _ OneofElement = (*GroupNode)(nil)
+var _ OneofElement = (*EmptyDeclNode)(nil)
+
+// SyntheticOneof is not an actual node in the AST but a synthetic node
+// that represents the oneof implied by a proto3 optional field.
+//
+// This type is considered synthetic since it never appears in a file's AST,
+// but is only returned from other functions (e.g. NewSyntheticOneof).
+type SyntheticOneof struct {
+ // The proto3 optional field that implies the presence of this oneof.
+ Field *FieldNode
+}
+
+var _ Node = (*SyntheticOneof)(nil)
+
+// NewSyntheticOneof creates a new *SyntheticOneof that corresponds to the
+// given proto3 optional field.
+func NewSyntheticOneof(field *FieldNode) *SyntheticOneof {
+ return &SyntheticOneof{Field: field}
+}
+
+func (n *SyntheticOneof) Start() Token {
+ return n.Field.Start()
+}
+
+func (n *SyntheticOneof) End() Token {
+ return n.Field.End()
+}
+
+func (n *SyntheticOneof) LeadingComments() []Comment {
+ return nil
+}
+
+func (n *SyntheticOneof) TrailingComments() []Comment {
+ return nil
+}
+
+func (n *SyntheticOneof) OneofName() Node {
+ return n.Field.FieldName()
+}
+
+func (n *SyntheticOneof) RangeOptions(_ func(*OptionNode) bool) {
+}
+
+// MapTypeNode represents the type declaration for a map field. It defines
+// both the key and value types for the map. Example:
+//
+// map<string, Values>
+type MapTypeNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ OpenAngle *RuneNode
+ KeyType *IdentNode
+ Comma *RuneNode
+ ValueType IdentValueNode
+ CloseAngle *RuneNode
+}
+
+// NewMapTypeNode creates a new *MapTypeNode. All arguments must be non-nil.
+// - keyword: The token corresponding to the "map" keyword.
+// - openAngle: The token corresponding to the "<" rune after the keyword.
+// - keyType: The token corresponding to the key type for the map.
+// - comma: The token corresponding to the "," rune between key and value types.
+// - valType: The token corresponding to the value type for the map.
+// - closeAngle: The token corresponding to the ">" rune that ends the declaration.
+func NewMapTypeNode(keyword *KeywordNode, openAngle *RuneNode, keyType *IdentNode, comma *RuneNode, valType IdentValueNode, closeAngle *RuneNode) *MapTypeNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if openAngle == nil {
+ panic("openAngle is nil")
+ }
+ if keyType == nil {
+ panic("keyType is nil")
+ }
+ if comma == nil {
+ panic("comma is nil")
+ }
+ if valType == nil {
+ panic("valType is nil")
+ }
+ if closeAngle == nil {
+ panic("closeAngle is nil")
+ }
+ children := []Node{keyword, openAngle, keyType, comma, valType, closeAngle}
+ return &MapTypeNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ OpenAngle: openAngle,
+ KeyType: keyType,
+ Comma: comma,
+ ValueType: valType,
+ CloseAngle: closeAngle,
+ }
+}
+
+// MapFieldNode represents a map field declaration. Example:
+//
+// map<string,string> replacements = 3 [deprecated = true];
+type MapFieldNode struct {
+ compositeNode
+ MapType *MapTypeNode
+ Name *IdentNode
+ Equals *RuneNode
+ Tag *UintLiteralNode
+ Options *CompactOptionsNode
+ Semicolon *RuneNode
+}
+
+func (*MapFieldNode) msgElement() {}
+
+// NewMapFieldNode creates a new *MapFieldNode. All arguments must be non-nil
+// except opts, which may be nil.
+// - mapType: The token corresponding to the map type.
+// - name: The token corresponding to the field's name.
+// - equals: The token corresponding to the '=' rune after the name.
+// - tag: The token corresponding to the field's tag number.
+// - opts: Optional set of field options.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewMapFieldNode(mapType *MapTypeNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *MapFieldNode {
+ if mapType == nil {
+ panic("mapType is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ numChildren := 2
+ if equals != nil {
+ numChildren++
+ }
+ if tag != nil {
+ numChildren++
+ }
+ if opts != nil {
+ numChildren++
+ }
+ if semicolon != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, mapType, name)
+ if equals != nil {
+ children = append(children, equals)
+ }
+ if tag != nil {
+ children = append(children, tag)
+ }
+ if opts != nil {
+ children = append(children, opts)
+ }
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+
+ return &MapFieldNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ MapType: mapType,
+ Name: name,
+ Equals: equals,
+ Tag: tag,
+ Options: opts,
+ Semicolon: semicolon,
+ }
+}
+
+func (n *MapFieldNode) FieldLabel() Node {
+ return nil
+}
+
+func (n *MapFieldNode) FieldName() Node {
+ return n.Name
+}
+
+func (n *MapFieldNode) FieldType() Node {
+ return n.MapType
+}
+
+func (n *MapFieldNode) FieldTag() Node {
+ if n.Tag == nil {
+ return n
+ }
+ return n.Tag
+}
+
+func (n *MapFieldNode) FieldExtendee() Node {
+ return nil
+}
+
+func (n *MapFieldNode) GetGroupKeyword() Node {
+ return nil
+}
+
+func (n *MapFieldNode) GetOptions() *CompactOptionsNode {
+ return n.Options
+}
+
+func (n *MapFieldNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, opt := range n.Options.Options {
+ if !fn(opt) {
+ return
+ }
+ }
+}
+
+func (n *MapFieldNode) AsMessage() *SyntheticMapEntryNode {
+ return (*SyntheticMapEntryNode)(n)
+}
+
+func (n *MapFieldNode) KeyField() *SyntheticMapField {
+ return NewSyntheticMapField(n.MapType.KeyType, 1)
+}
+
+func (n *MapFieldNode) ValueField() *SyntheticMapField {
+ return NewSyntheticMapField(n.MapType.ValueType, 2)
+}
+
+// SyntheticMapEntryNode is a view of a MapFieldNode that implements MessageDeclNode.
+// Since a map field implicitly defines a message type for the map entry,
+// this node represents that message type.
+//
+// This type is considered synthetic since it never appears in a file's AST, but
+// is only returned from other accessors (e.g. MapFieldNode.AsMessage).
+type SyntheticMapEntryNode MapFieldNode
+
+func (n *SyntheticMapEntryNode) MessageName() Node {
+ return n.Name
+}
+
+func (n *SyntheticMapEntryNode) RangeOptions(_ func(*OptionNode) bool) {
+}
+
+// SyntheticMapField is not an actual node in the AST but a synthetic node
+// that implements FieldDeclNode. These are used to represent the implicit
+// field declarations of the "key" and "value" fields in a map entry.
+//
+// This type is considered synthetic since it never appears in a file's AST,
+// but is only returned from other accessors and functions (e.g.
+// MapFieldNode.KeyField, MapFieldNode.ValueField, and NewSyntheticMapField).
+type SyntheticMapField struct {
+ Ident IdentValueNode
+ Tag *UintLiteralNode
+}
+
+// NewSyntheticMapField creates a new *SyntheticMapField for the given
+// identifier (either a key or value type in a map declaration) and tag
+// number (1 for key, 2 for value).
+func NewSyntheticMapField(ident IdentValueNode, tagNum uint64) *SyntheticMapField {
+ tag := &UintLiteralNode{
+ terminalNode: ident.Start().asTerminalNode(),
+ Val: tagNum,
+ }
+ return &SyntheticMapField{Ident: ident, Tag: tag}
+}
+
+func (n *SyntheticMapField) Start() Token {
+ return n.Ident.Start()
+}
+
+func (n *SyntheticMapField) End() Token {
+ return n.Ident.End()
+}
+
+func (n *SyntheticMapField) LeadingComments() []Comment {
+ return nil
+}
+
+func (n *SyntheticMapField) TrailingComments() []Comment {
+ return nil
+}
+
+func (n *SyntheticMapField) FieldLabel() Node {
+ return n.Ident
+}
+
+func (n *SyntheticMapField) FieldName() Node {
+ return n.Ident
+}
+
+func (n *SyntheticMapField) FieldType() Node {
+ return n.Ident
+}
+
+func (n *SyntheticMapField) FieldTag() Node {
+ if n.Tag == nil {
+ return n
+ }
+ return n.Tag
+}
+
+func (n *SyntheticMapField) FieldExtendee() Node {
+ return nil
+}
+
+func (n *SyntheticMapField) GetGroupKeyword() Node {
+ return nil
+}
+
+func (n *SyntheticMapField) GetOptions() *CompactOptionsNode {
+ return nil
+}
+
+func (n *SyntheticMapField) RangeOptions(_ func(*OptionNode) bool) {
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/file.go b/vendor/github.com/bufbuild/protocompile/ast/file.go
new file mode 100644
index 0000000..50d4ca9
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/file.go
@@ -0,0 +1,358 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// FileDeclNode is a placeholder interface for AST nodes that represent files.
+// This allows NoSourceNode to be used in place of *FileNode for some usages.
+type FileDeclNode interface {
+ NodeWithOptions
+ Name() string
+ NodeInfo(n Node) NodeInfo
+}
+
+var _ FileDeclNode = (*FileNode)(nil)
+var _ FileDeclNode = (*NoSourceNode)(nil)
+
+// FileNode is the root of the AST hierarchy. It represents an entire
+// protobuf source file.
+type FileNode struct {
+ compositeNode
+ fileInfo *FileInfo
+
+ // A file has either a Syntax or Edition node, never both.
+ // If both are nil, neither declaration is present and the
+ // file is assumed to use "proto2" syntax.
+ Syntax *SyntaxNode
+ Edition *EditionNode
+
+ Decls []FileElement
+
+ // This synthetic node allows access to final comments and whitespace
+ EOF *RuneNode
+}
+
+// NewFileNode creates a new *FileNode. The syntax parameter is optional. If it
+// is absent, it means the file had no syntax declaration.
+//
+// This function panics if the concrete type of any element of decls is not
+// from this package.
+func NewFileNode(info *FileInfo, syntax *SyntaxNode, decls []FileElement, eof Token) *FileNode {
+ return newFileNode(info, syntax, nil, decls, eof)
+}
+
+// NewFileNodeWithEdition creates a new *FileNode. The edition parameter is required. If a file
+// has no edition declaration, use NewFileNode instead.
+//
+// This function panics if the concrete type of any element of decls is not
+// from this package.
+func NewFileNodeWithEdition(info *FileInfo, edition *EditionNode, decls []FileElement, eof Token) *FileNode {
+ if edition == nil {
+ panic("edition is nil")
+ }
+ return newFileNode(info, nil, edition, decls, eof)
+}
+
+func newFileNode(info *FileInfo, syntax *SyntaxNode, edition *EditionNode, decls []FileElement, eof Token) *FileNode {
+ numChildren := len(decls) + 1
+ if syntax != nil || edition != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ if syntax != nil {
+ children = append(children, syntax)
+ } else if edition != nil {
+ children = append(children, edition)
+ }
+ for _, decl := range decls {
+ switch decl := decl.(type) {
+ case *PackageNode, *ImportNode, *OptionNode, *MessageNode,
+ *EnumNode, *ExtendNode, *ServiceNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid FileElement type: %T", decl))
+ }
+ children = append(children, decl)
+ }
+
+ eofNode := NewRuneNode(0, eof)
+ children = append(children, eofNode)
+
+ return &FileNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ fileInfo: info,
+ Syntax: syntax,
+ Edition: edition,
+ Decls: decls,
+ EOF: eofNode,
+ }
+}
+
+// NewEmptyFileNode returns an empty AST for a file with the given name.
+func NewEmptyFileNode(filename string) *FileNode {
+ fileInfo := NewFileInfo(filename, []byte{})
+ return NewFileNode(fileInfo, nil, nil, fileInfo.AddToken(0, 0))
+}
+
+func (f *FileNode) Name() string {
+ return f.fileInfo.Name()
+}
+
+func (f *FileNode) NodeInfo(n Node) NodeInfo {
+ return f.fileInfo.NodeInfo(n)
+}
+
+func (f *FileNode) TokenInfo(t Token) NodeInfo {
+ return f.fileInfo.TokenInfo(t)
+}
+
+func (f *FileNode) ItemInfo(i Item) ItemInfo {
+ return f.fileInfo.ItemInfo(i)
+}
+
+func (f *FileNode) GetItem(i Item) (Token, Comment) {
+ return f.fileInfo.GetItem(i)
+}
+
+func (f *FileNode) Items() Sequence[Item] {
+ return f.fileInfo.Items()
+}
+
+func (f *FileNode) Tokens() Sequence[Token] {
+ return f.fileInfo.Tokens()
+}
+
+func (f *FileNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range f.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// FileElement is an interface implemented by all AST nodes that are
+// allowed as top-level declarations in the file.
+type FileElement interface {
+ Node
+ fileElement()
+}
+
+var _ FileElement = (*ImportNode)(nil)
+var _ FileElement = (*PackageNode)(nil)
+var _ FileElement = (*OptionNode)(nil)
+var _ FileElement = (*MessageNode)(nil)
+var _ FileElement = (*EnumNode)(nil)
+var _ FileElement = (*ExtendNode)(nil)
+var _ FileElement = (*ServiceNode)(nil)
+var _ FileElement = (*EmptyDeclNode)(nil)
+
+// SyntaxNode represents a syntax declaration, which if present must be
+// the first non-comment content. Example:
+//
+// syntax = "proto2";
+//
+// Files that don't have a syntax node are assumed to use proto2 syntax.
+type SyntaxNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Equals *RuneNode
+ Syntax StringValueNode
+ Semicolon *RuneNode
+}
+
+// NewSyntaxNode creates a new *SyntaxNode. All four arguments must be non-nil:
+// - keyword: The token corresponding to the "syntax" keyword.
+// - equals: The token corresponding to the "=" rune.
+// - syntax: The actual syntax value, e.g. "proto2" or "proto3".
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewSyntaxNode(keyword *KeywordNode, equals *RuneNode, syntax StringValueNode, semicolon *RuneNode) *SyntaxNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if equals == nil {
+ panic("equals is nil")
+ }
+ if syntax == nil {
+ panic("syntax is nil")
+ }
+ var children []Node
+ if semicolon == nil {
+ children = []Node{keyword, equals, syntax}
+ } else {
+ children = []Node{keyword, equals, syntax, semicolon}
+ }
+ return &SyntaxNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Equals: equals,
+ Syntax: syntax,
+ Semicolon: semicolon,
+ }
+}
+
+// EditionNode represents an edition declaration, which if present must be
+// the first non-comment content. Example:
+//
+// edition = "2023";
+//
+// Files may include either an edition node or a syntax node, but not both.
+// If neither are present, the file is assumed to use proto2 syntax.
+type EditionNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Equals *RuneNode
+ Edition StringValueNode
+ Semicolon *RuneNode
+}
+
+// NewEditionNode creates a new *EditionNode. All four arguments must be non-nil:
+// - keyword: The token corresponding to the "edition" keyword.
+// - equals: The token corresponding to the "=" rune.
+// - edition: The actual edition value, e.g. "2023".
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewEditionNode(keyword *KeywordNode, equals *RuneNode, edition StringValueNode, semicolon *RuneNode) *EditionNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if equals == nil {
+ panic("equals is nil")
+ }
+ if edition == nil {
+ panic("edition is nil")
+ }
+ if semicolon == nil {
+ panic("semicolon is nil")
+ }
+ children := []Node{keyword, equals, edition, semicolon}
+ return &EditionNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Equals: equals,
+ Edition: edition,
+ Semicolon: semicolon,
+ }
+}
+
+// ImportNode represents an import statement. Example:
+//
+// import "google/protobuf/empty.proto";
+type ImportNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ // Optional; if present indicates this is a public import
+ Public *KeywordNode
+ // Optional; if present indicates this is a weak import
+ Weak *KeywordNode
+ Name StringValueNode
+ Semicolon *RuneNode
+}
+
+// NewImportNode creates a new *ImportNode. The public and weak arguments are optional
+// and only one or the other (or neither) may be specified, not both. When public is
+// non-nil, it indicates the "public" keyword in the import statement and means this is
+// a public import. When weak is non-nil, it indicates the "weak" keyword in the import
+// statement and means this is a weak import. When both are nil, this is a normal import.
+// The other arguments must be non-nil:
+// - keyword: The token corresponding to the "import" keyword.
+// - public: The token corresponding to the optional "public" keyword.
+// - weak: The token corresponding to the optional "weak" keyword.
+// - name: The actual imported file name.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewImportNode(keyword *KeywordNode, public *KeywordNode, weak *KeywordNode, name StringValueNode, semicolon *RuneNode) *ImportNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ numChildren := 2
+ if semicolon == nil {
+ numChildren++
+ }
+ if public != nil || weak != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, keyword)
+ if public != nil {
+ children = append(children, public)
+ } else if weak != nil {
+ children = append(children, weak)
+ }
+ children = append(children, name)
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+
+ return &ImportNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Public: public,
+ Weak: weak,
+ Name: name,
+ Semicolon: semicolon,
+ }
+}
+
+func (*ImportNode) fileElement() {}
+
+// PackageNode represents a package declaration. Example:
+//
+// package foobar.com;
+type PackageNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name IdentValueNode
+ Semicolon *RuneNode
+}
+
+func (*PackageNode) fileElement() {}
+
+// NewPackageNode creates a new *PackageNode. All three arguments must be non-nil:
+// - keyword: The token corresponding to the "package" keyword.
+// - name: The package name declared for the file.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewPackageNode(keyword *KeywordNode, name IdentValueNode, semicolon *RuneNode) *PackageNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ var children []Node
+ if semicolon == nil {
+ children = []Node{keyword, name}
+ } else {
+ children = []Node{keyword, name, semicolon}
+ }
+ return &PackageNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ Semicolon: semicolon,
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/file_info.go b/vendor/github.com/bufbuild/protocompile/ast/file_info.go
new file mode 100644
index 0000000..7c2d904
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/file_info.go
@@ -0,0 +1,701 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import (
+ "fmt"
+ "sort"
+ "unicode/utf8"
+)
+
+// FileInfo contains information about the contents of a source file, including
+// details about comments and items. A lexer accumulates these details as it
+// scans the file contents. This allows efficient representation of things like
+// source positions.
+type FileInfo struct {
+ // The name of the source file.
+ name string
+ // The raw contents of the source file.
+ data []byte
+ // The offsets for each line in the file. The value is the zero-based byte
+ // offset for a given line. The line is given by its index. So the value at
+ // index 0 is the offset for the first line (which is always zero). The
+ // value at index 1 is the offset at which the second line begins. Etc.
+ lines []int
+ // The info for every comment in the file. This is empty if the file has no
+ // comments. The first entry corresponds to the first comment in the file,
+ // and so on.
+ comments []commentInfo
+ // The info for every lexed item in the file. The last item in the slice
+ // corresponds to the EOF, so every file (even an empty one) should have at
+ // least one entry. This includes all terminal symbols (tokens) in the AST
+ // as well as all comments.
+ items []itemSpan
+}
+
+type commentInfo struct {
+ // the index of the item, in the file's items slice, that represents this
+ // comment
+ index int
+ // the index of the token to which this comment is attributed.
+ attributedToIndex int
+}
+
+type itemSpan struct {
+ // the offset into the file of the first character of an item.
+ offset int
+ // the length of the item
+ length int
+}
+
+// NewFileInfo creates a new instance for the given file.
+func NewFileInfo(filename string, contents []byte) *FileInfo {
+ return &FileInfo{
+ name: filename,
+ data: contents,
+ lines: []int{0},
+ }
+}
+
+func (f *FileInfo) Name() string {
+ return f.name
+}
+
+// AddLine adds the offset representing the beginning of the "next" line in the file.
+// The first line always starts at offset 0, the second line starts at offset-of-newline-char+1.
+func (f *FileInfo) AddLine(offset int) {
+ if offset < 0 {
+ panic(fmt.Sprintf("invalid offset: %d must not be negative", offset))
+ }
+ if offset > len(f.data) {
+ panic(fmt.Sprintf("invalid offset: %d is greater than file size %d", offset, len(f.data)))
+ }
+
+ if len(f.lines) > 0 {
+ lastOffset := f.lines[len(f.lines)-1]
+ if offset <= lastOffset {
+ panic(fmt.Sprintf("invalid offset: %d is not greater than previously observed line offset %d", offset, lastOffset))
+ }
+ }
+
+ f.lines = append(f.lines, offset)
+}
+
+// AddToken adds info about a token at the given location to this file. It
+// returns a value that allows access to all of the token's details.
+func (f *FileInfo) AddToken(offset, length int) Token {
+ if offset < 0 {
+ panic(fmt.Sprintf("invalid offset: %d must not be negative", offset))
+ }
+ if length < 0 {
+ panic(fmt.Sprintf("invalid length: %d must not be negative", length))
+ }
+ if offset+length > len(f.data) {
+ panic(fmt.Sprintf("invalid offset+length: %d is greater than file size %d", offset+length, len(f.data)))
+ }
+
+ tokenID := len(f.items)
+ if len(f.items) > 0 {
+ lastToken := f.items[tokenID-1]
+ lastEnd := lastToken.offset + lastToken.length - 1
+ if offset <= lastEnd {
+ panic(fmt.Sprintf("invalid offset: %d is not greater than previously observed token end %d", offset, lastEnd))
+ }
+ }
+
+ f.items = append(f.items, itemSpan{offset: offset, length: length})
+ return Token(tokenID)
+}
+
+// AddComment adds info about a comment to this file. Comments must first be
+// added as items via f.AddToken(). The given comment argument is the Token
+// from that step. The given attributedTo argument indicates another token in the
+// file with which the comment is associated. If comment's offset is before that
+// of attributedTo, then this is a leading comment. Otherwise, it is a trailing
+// comment.
+func (f *FileInfo) AddComment(comment, attributedTo Token) Comment {
+ if len(f.comments) > 0 {
+ lastComment := f.comments[len(f.comments)-1]
+ if int(comment) <= lastComment.index {
+ panic(fmt.Sprintf("invalid index: %d is not greater than previously observed comment index %d", comment, lastComment.index))
+ }
+ if int(attributedTo) < lastComment.attributedToIndex {
+ panic(fmt.Sprintf("invalid attribution: %d is not greater than previously observed comment attribution index %d", attributedTo, lastComment.attributedToIndex))
+ }
+ }
+
+ f.comments = append(f.comments, commentInfo{index: int(comment), attributedToIndex: int(attributedTo)})
+ return Comment{
+ fileInfo: f,
+ index: len(f.comments) - 1,
+ }
+}
+
+// NodeInfo returns details from the original source for the given AST node.
+//
+// If the given n is out of range, this returns an invalid NodeInfo (i.e.
+// nodeInfo.IsValid() returns false). If the given n is not out of range but
+// also from a different file than f, then the result is undefined.
+func (f *FileInfo) NodeInfo(n Node) NodeInfo {
+ return f.nodeInfo(int(n.Start()), int(n.End()))
+}
+
+// TokenInfo returns details from the original source for the given token.
+//
+// If the given t is out of range, this returns an invalid NodeInfo (i.e.
+// nodeInfo.IsValid() returns false). If the given t is not out of range but
+// also from a different file than f, then the result is undefined.
+func (f *FileInfo) TokenInfo(t Token) NodeInfo {
+ return f.nodeInfo(int(t), int(t))
+}
+
+func (f *FileInfo) nodeInfo(start, end int) NodeInfo {
+ if start < 0 || start >= len(f.items) {
+ return NodeInfo{fileInfo: f}
+ }
+ if end < 0 || end >= len(f.items) {
+ return NodeInfo{fileInfo: f}
+ }
+ return NodeInfo{fileInfo: f, startIndex: start, endIndex: end}
+}
+
+// ItemInfo returns details from the original source for the given item.
+//
+// If the given i is out of range, this returns nil. If the given i is not
+// out of range but also from a different file than f, then the result is
+// undefined.
+func (f *FileInfo) ItemInfo(i Item) ItemInfo {
+ tok, cmt := f.GetItem(i)
+ if tok != TokenError {
+ return f.TokenInfo(tok)
+ }
+ if cmt.IsValid() {
+ return cmt
+ }
+ return nil
+}
+
+// GetItem returns the token or comment represented by the given item. Only one
+// of the return values will be valid. If the item is a token then the returned
+// comment will be a zero value and thus invalid (i.e. comment.IsValid() returns
+// false). If the item is a comment then the returned token will be TokenError.
+//
+// If the given i is out of range, this returns (TokenError, Comment{}). If the
+// given i is not out of range but also from a different file than f, then
+// the result is undefined.
+func (f *FileInfo) GetItem(i Item) (Token, Comment) {
+ if i < 0 || int(i) >= len(f.items) {
+ return TokenError, Comment{}
+ }
+ if !f.isComment(i) {
+ return Token(i), Comment{}
+ }
+ // It's a comment, so find its location in f.comments
+ c := sort.Search(len(f.comments), func(c int) bool {
+ return f.comments[c].index >= int(i)
+ })
+ if c < len(f.comments) && f.comments[c].index == int(i) {
+ return TokenError, Comment{fileInfo: f, index: c}
+ }
+ // f.isComment(i) returned true, but we couldn't find it
+ // in f.comments? Uh oh... that shouldn't be possible.
+ return TokenError, Comment{}
+}
+
+func (f *FileInfo) isDummyFile() bool {
+ return f == nil || f.lines == nil
+}
+
+// Sequence represents a navigable sequence of elements.
+type Sequence[T any] interface {
+ // First returns the first element in the sequence. The bool return
+ // is false if this sequence contains no elements. For example, an
+ // empty file has no items or tokens.
+ First() (T, bool)
+ // Next returns the next element in the sequence that comes after
+ // the given element. The bool returns is false if there is no next
+ // item (i.e. the given element is the last one). It also returns
+ // false if the given element is invalid.
+ Next(T) (T, bool)
+ // Last returns the last element in the sequence. The bool return
+ // is false if this sequence contains no elements. For example, an
+ // empty file has no items or tokens.
+ Last() (T, bool)
+ // Previous returns the previous element in the sequence that comes
+ // before the given element. The bool returns is false if there is no
+ // previous item (i.e. the given element is the first one). It also
+ // returns false if the given element is invalid.
+ Previous(T) (T, bool)
+}
+
+func (f *FileInfo) Items() Sequence[Item] {
+ return items{fileInfo: f}
+}
+
+func (f *FileInfo) Tokens() Sequence[Token] {
+ return tokens{fileInfo: f}
+}
+
+type items struct {
+ fileInfo *FileInfo
+}
+
+func (i items) First() (Item, bool) {
+ if len(i.fileInfo.items) == 0 {
+ return 0, false
+ }
+ return 0, true
+}
+
+func (i items) Next(item Item) (Item, bool) {
+ if item < 0 || int(item) >= len(i.fileInfo.items)-1 {
+ return 0, false
+ }
+ return i.fileInfo.itemForward(item+1, true)
+}
+
+func (i items) Last() (Item, bool) {
+ if len(i.fileInfo.items) == 0 {
+ return 0, false
+ }
+ return Item(len(i.fileInfo.items) - 1), true
+}
+
+func (i items) Previous(item Item) (Item, bool) {
+ if item <= 0 || int(item) >= len(i.fileInfo.items) {
+ return 0, false
+ }
+ return i.fileInfo.itemBackward(item-1, true)
+}
+
+type tokens struct {
+ fileInfo *FileInfo
+}
+
+func (t tokens) First() (Token, bool) {
+ i, ok := t.fileInfo.itemForward(0, false)
+ return Token(i), ok
+}
+
+func (t tokens) Next(tok Token) (Token, bool) {
+ if tok < 0 || int(tok) >= len(t.fileInfo.items)-1 {
+ return 0, false
+ }
+ i, ok := t.fileInfo.itemForward(Item(tok+1), false)
+ return Token(i), ok
+}
+
+func (t tokens) Last() (Token, bool) {
+ i, ok := t.fileInfo.itemBackward(Item(len(t.fileInfo.items))-1, false)
+ return Token(i), ok
+}
+
+func (t tokens) Previous(tok Token) (Token, bool) {
+ if tok <= 0 || int(tok) >= len(t.fileInfo.items) {
+ return 0, false
+ }
+ i, ok := t.fileInfo.itemBackward(Item(tok-1), false)
+ return Token(i), ok
+}
+
+func (f *FileInfo) itemForward(i Item, allowComment bool) (Item, bool) {
+ end := Item(len(f.items))
+ for i < end {
+ if allowComment || !f.isComment(i) {
+ return i, true
+ }
+ i++
+ }
+ return 0, false
+}
+
+func (f *FileInfo) itemBackward(i Item, allowComment bool) (Item, bool) {
+ for i >= 0 {
+ if allowComment || !f.isComment(i) {
+ return i, true
+ }
+ i--
+ }
+ return 0, false
+}
+
+// isComment is comment returns true if i refers to a comment.
+// (If it returns false, i refers to a token.)
+func (f *FileInfo) isComment(i Item) bool {
+ item := f.items[i]
+ if item.length < 2 {
+ return false
+ }
+ // see if item text starts with "//" or "/*"
+ if f.data[item.offset] != '/' {
+ return false
+ }
+ c := f.data[item.offset+1]
+ return c == '/' || c == '*'
+}
+
+func (f *FileInfo) SourcePos(offset int) SourcePos {
+ lineNumber := sort.Search(len(f.lines), func(n int) bool {
+ return f.lines[n] > offset
+ })
+
+ // If it weren't for tabs and multibyte unicode characters, we
+ // could trivially compute the column just based on offset and the
+ // starting offset of lineNumber :(
+ // Wish this were more efficient... that would require also storing
+ // computed line+column information, which would triple the size of
+ // f's items slice...
+ col := 0
+ for i := f.lines[lineNumber-1]; i < offset; i++ {
+ if f.data[i] == '\t' {
+ nextTabStop := 8 - (col % 8)
+ col += nextTabStop
+ } else if utf8.RuneStart(f.data[i]) {
+ col++
+ }
+ }
+
+ return SourcePos{
+ Filename: f.name,
+ Offset: offset,
+ Line: lineNumber,
+ // Columns are 1-indexed in this AST
+ Col: col + 1,
+ }
+}
+
+// Token represents a single lexed token.
+type Token int
+
+// TokenError indicates an invalid token. It is returned from query
+// functions when no valid token satisfies the request.
+const TokenError = Token(-1)
+
+// AsItem returns the Item that corresponds to t.
+func (t Token) AsItem() Item {
+ return Item(t)
+}
+
+func (t Token) asTerminalNode() terminalNode {
+ return terminalNode(t)
+}
+
+// Item represents an item lexed from source. It represents either
+// a Token or a Comment.
+type Item int
+
+// ItemInfo provides details about an item's location in the source file and
+// its contents.
+type ItemInfo interface {
+ SourceSpan
+ LeadingWhitespace() string
+ RawText() string
+}
+
+// NodeInfo represents the details for a node or token in the source file's AST.
+// It provides access to information about the node's location in the source
+// file. It also provides access to the original text in the source file (with
+// all the original formatting intact) and also provides access to surrounding
+// comments.
+type NodeInfo struct {
+ fileInfo *FileInfo
+ startIndex, endIndex int
+}
+
+var _ ItemInfo = NodeInfo{}
+
+// IsValid returns true if this node info is valid. If n is a zero-value struct,
+// it is not valid.
+func (n NodeInfo) IsValid() bool {
+ return n.fileInfo != nil
+}
+
+// Start returns the starting position of the element. This is the first
+// character of the node or token.
+func (n NodeInfo) Start() SourcePos {
+ if n.fileInfo.isDummyFile() {
+ return UnknownPos(n.fileInfo.name)
+ }
+
+ tok := n.fileInfo.items[n.startIndex]
+ return n.fileInfo.SourcePos(tok.offset)
+}
+
+// End returns the ending position of the element, exclusive. This is the
+// location after the last character of the node or token. If n returns
+// the same position for Start() and End(), the element in source had a
+// length of zero (which should only happen for the special EOF token
+// that designates the end of the file).
+func (n NodeInfo) End() SourcePos {
+ if n.fileInfo.isDummyFile() {
+ return UnknownPos(n.fileInfo.name)
+ }
+
+ tok := n.fileInfo.items[n.endIndex]
+ // find offset of last character in the span
+ offset := tok.offset
+ if tok.length > 0 {
+ offset += tok.length - 1
+ }
+ pos := n.fileInfo.SourcePos(offset)
+ if tok.length > 0 {
+ // We return "open range", so end is the position *after* the
+ // last character in the span. So we adjust
+ pos.Col++
+ }
+ return pos
+}
+
+// LeadingWhitespace returns any whitespace prior to the element. If there
+// were comments in between this element and the previous one, this will
+// return the whitespace between the last such comment in the element. If
+// there were no such comments, this returns the whitespace between the
+// previous element and the current one.
+func (n NodeInfo) LeadingWhitespace() string {
+ if n.fileInfo.isDummyFile() {
+ return ""
+ }
+
+ tok := n.fileInfo.items[n.startIndex]
+ var prevEnd int
+ if n.startIndex > 0 {
+ prevTok := n.fileInfo.items[n.startIndex-1]
+ prevEnd = prevTok.offset + prevTok.length
+ }
+ return string(n.fileInfo.data[prevEnd:tok.offset])
+}
+
+// LeadingComments returns all comments in the source that exist between the
+// element and the previous element, except for any trailing comment on the
+// previous element.
+func (n NodeInfo) LeadingComments() Comments {
+ if n.fileInfo.isDummyFile() {
+ return EmptyComments
+ }
+
+ start := sort.Search(len(n.fileInfo.comments), func(i int) bool {
+ return n.fileInfo.comments[i].attributedToIndex >= n.startIndex
+ })
+
+ if start == len(n.fileInfo.comments) || n.fileInfo.comments[start].attributedToIndex != n.startIndex {
+ // no comments associated with this token
+ return EmptyComments
+ }
+
+ numComments := 0
+ for i := start; i < len(n.fileInfo.comments); i++ {
+ comment := n.fileInfo.comments[i]
+ if comment.attributedToIndex == n.startIndex &&
+ comment.index < n.startIndex {
+ numComments++
+ } else {
+ break
+ }
+ }
+
+ return Comments{
+ fileInfo: n.fileInfo,
+ first: start,
+ num: numComments,
+ }
+}
+
+// TrailingComments returns the trailing comment for the element, if any.
+// An element will have a trailing comment only if it is the last token
+// on a line and is followed by a comment on the same line. Typically, the
+// following comment is a line-style comment (starting with "//").
+//
+// If the following comment is a block-style comment that spans multiple
+// lines, and the next token is on the same line as the end of the comment,
+// the comment is NOT considered a trailing comment.
+//
+// Examples:
+//
+// foo // this is a trailing comment for foo
+//
+// bar /* this is a trailing comment for bar */
+//
+// baz /* this is a trailing
+// comment for baz */
+//
+// fizz /* this is NOT a trailing
+// comment for fizz because
+// its on the same line as the
+// following token buzz */ buzz
+func (n NodeInfo) TrailingComments() Comments {
+ if n.fileInfo.isDummyFile() {
+ return EmptyComments
+ }
+
+ start := sort.Search(len(n.fileInfo.comments), func(i int) bool {
+ comment := n.fileInfo.comments[i]
+ return comment.attributedToIndex >= n.endIndex &&
+ comment.index > n.endIndex
+ })
+
+ if start == len(n.fileInfo.comments) || n.fileInfo.comments[start].attributedToIndex != n.endIndex {
+ // no comments associated with this token
+ return EmptyComments
+ }
+
+ numComments := 0
+ for i := start; i < len(n.fileInfo.comments); i++ {
+ comment := n.fileInfo.comments[i]
+ if comment.attributedToIndex == n.endIndex {
+ numComments++
+ } else {
+ break
+ }
+ }
+
+ return Comments{
+ fileInfo: n.fileInfo,
+ first: start,
+ num: numComments,
+ }
+}
+
+// RawText returns the actual text in the source file that corresponds to the
+// element. If the element is a node in the AST that encompasses multiple
+// items (like an entire declaration), the full text of all items is returned
+// including any interior whitespace and comments.
+func (n NodeInfo) RawText() string {
+ startTok := n.fileInfo.items[n.startIndex]
+ endTok := n.fileInfo.items[n.endIndex]
+ return string(n.fileInfo.data[startTok.offset : endTok.offset+endTok.length])
+}
+
+// SourcePos identifies a location in a proto source file.
+type SourcePos struct {
+ Filename string
+ // The line and column numbers for this position. These are
+ // one-based, so the first line and column is 1 (not zero). If
+ // either is zero, then the line and column are unknown and
+ // only the file name is known.
+ Line, Col int
+ // The offset, in bytes, from the beginning of the file. This
+ // is zero-based: the first character in the file is offset zero.
+ Offset int
+}
+
+func (pos SourcePos) String() string {
+ if pos.Line <= 0 || pos.Col <= 0 {
+ return pos.Filename
+ }
+ return fmt.Sprintf("%s:%d:%d", pos.Filename, pos.Line, pos.Col)
+}
+
+// SourceSpan represents a range of source positions.
+type SourceSpan interface {
+ Start() SourcePos
+ End() SourcePos
+}
+
+// NewSourceSpan creates a new span that covers the given range.
+func NewSourceSpan(start SourcePos, end SourcePos) SourceSpan {
+ return sourceSpan{StartPos: start, EndPos: end}
+}
+
+type sourceSpan struct {
+ StartPos SourcePos
+ EndPos SourcePos
+}
+
+func (p sourceSpan) Start() SourcePos {
+ return p.StartPos
+}
+
+func (p sourceSpan) End() SourcePos {
+ return p.EndPos
+}
+
+var _ SourceSpan = sourceSpan{}
+
+// Comments represents a range of sequential comments in a source file
+// (e.g. no interleaving items or AST nodes).
+type Comments struct {
+ fileInfo *FileInfo
+ first, num int
+}
+
+// EmptyComments is an empty set of comments.
+var EmptyComments = Comments{}
+
+// Len returns the number of comments in c.
+func (c Comments) Len() int {
+ return c.num
+}
+
+func (c Comments) Index(i int) Comment {
+ if i < 0 || i >= c.num {
+ panic(fmt.Sprintf("index %d out of range (len = %d)", i, c.num))
+ }
+ return Comment{
+ fileInfo: c.fileInfo,
+ index: c.first + i,
+ }
+}
+
+// Comment represents a single comment in a source file. It indicates
+// the position of the comment and its contents. A single comment means
+// one line-style comment ("//" to end of line) or one block comment
+// ("/*" through "*/"). If a longer comment uses multiple line comments,
+// each line is considered to be a separate comment. For example:
+//
+// // This is a single comment, and
+// // this is a separate comment.
+type Comment struct {
+ fileInfo *FileInfo
+ index int
+}
+
+var _ ItemInfo = Comment{}
+
+// IsValid returns true if this comment is valid. If this comment is
+// a zero-value struct, it is not valid.
+func (c Comment) IsValid() bool {
+ return c.fileInfo != nil && c.index >= 0
+}
+
+// AsItem returns the Item that corresponds to c.
+func (c Comment) AsItem() Item {
+ return Item(c.fileInfo.comments[c.index].index)
+}
+
+func (c Comment) Start() SourcePos {
+ span := c.fileInfo.items[c.AsItem()]
+ return c.fileInfo.SourcePos(span.offset)
+}
+
+func (c Comment) End() SourcePos {
+ span := c.fileInfo.items[c.AsItem()]
+ return c.fileInfo.SourcePos(span.offset + span.length - 1)
+}
+
+func (c Comment) LeadingWhitespace() string {
+ item := c.AsItem()
+ span := c.fileInfo.items[item]
+ var prevEnd int
+ if item > 0 {
+ prevItem := c.fileInfo.items[item-1]
+ prevEnd = prevItem.offset + prevItem.length
+ }
+ return string(c.fileInfo.data[prevEnd:span.offset])
+}
+
+func (c Comment) RawText() string {
+ span := c.fileInfo.items[c.AsItem()]
+ return string(c.fileInfo.data[span.offset : span.offset+span.length])
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/identifiers.go b/vendor/github.com/bufbuild/protocompile/ast/identifiers.go
new file mode 100644
index 0000000..511389d
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/identifiers.go
@@ -0,0 +1,153 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Identifier is a possibly-qualified name. This is used to distinguish
+// ValueNode values that are references/identifiers vs. those that are
+// string literals.
+type Identifier string
+
+// IdentValueNode is an AST node that represents an identifier.
+type IdentValueNode interface {
+ ValueNode
+ AsIdentifier() Identifier
+}
+
+var _ IdentValueNode = (*IdentNode)(nil)
+var _ IdentValueNode = (*CompoundIdentNode)(nil)
+
+// IdentNode represents a simple, unqualified identifier. These are used to name
+// elements declared in a protobuf file or to refer to elements. Example:
+//
+// foobar
+type IdentNode struct {
+ terminalNode
+ Val string
+}
+
+// NewIdentNode creates a new *IdentNode. The given val is the identifier text.
+func NewIdentNode(val string, tok Token) *IdentNode {
+ return &IdentNode{
+ terminalNode: tok.asTerminalNode(),
+ Val: val,
+ }
+}
+
+func (n *IdentNode) Value() interface{} {
+ return n.AsIdentifier()
+}
+
+func (n *IdentNode) AsIdentifier() Identifier {
+ return Identifier(n.Val)
+}
+
+// ToKeyword is used to convert identifiers to keywords. Since keywords are not
+// reserved in the protobuf language, they are initially lexed as identifiers
+// and then converted to keywords based on context.
+func (n *IdentNode) ToKeyword() *KeywordNode {
+ return (*KeywordNode)(n)
+}
+
+// CompoundIdentNode represents a qualified identifier. A qualified identifier
+// has at least one dot and possibly multiple identifier names (all separated by
+// dots). If the identifier has a leading dot, then it is a *fully* qualified
+// identifier. Example:
+//
+// .com.foobar.Baz
+type CompoundIdentNode struct {
+ compositeNode
+ // Optional leading dot, indicating that the identifier is fully qualified.
+ LeadingDot *RuneNode
+ Components []*IdentNode
+ // Dots[0] is the dot after Components[0]. The length of Dots is always
+ // one less than the length of Components.
+ Dots []*RuneNode
+ // The text value of the identifier, with all components and dots
+ // concatenated.
+ Val string
+}
+
+// NewCompoundIdentNode creates a *CompoundIdentNode. The leadingDot may be nil.
+// The dots arg must have a length that is one less than the length of
+// components. The components arg must not be empty.
+func NewCompoundIdentNode(leadingDot *RuneNode, components []*IdentNode, dots []*RuneNode) *CompoundIdentNode {
+ if len(components) == 0 {
+ panic("must have at least one component")
+ }
+ if len(dots) != len(components)-1 && len(dots) != len(components) {
+ panic(fmt.Sprintf("%d components requires %d dots, not %d", len(components), len(components)-1, len(dots)))
+ }
+ numChildren := len(components) + len(dots)
+ if leadingDot != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ var b strings.Builder
+ if leadingDot != nil {
+ children = append(children, leadingDot)
+ b.WriteRune(leadingDot.Rune)
+ }
+ for i, comp := range components {
+ if i > 0 {
+ dot := dots[i-1]
+ children = append(children, dot)
+ b.WriteRune(dot.Rune)
+ }
+ children = append(children, comp)
+ b.WriteString(comp.Val)
+ }
+ if len(dots) == len(components) {
+ dot := dots[len(dots)-1]
+ children = append(children, dot)
+ b.WriteRune(dot.Rune)
+ }
+ return &CompoundIdentNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ LeadingDot: leadingDot,
+ Components: components,
+ Dots: dots,
+ Val: b.String(),
+ }
+}
+
+func (n *CompoundIdentNode) Value() interface{} {
+ return n.AsIdentifier()
+}
+
+func (n *CompoundIdentNode) AsIdentifier() Identifier {
+ return Identifier(n.Val)
+}
+
+// KeywordNode is an AST node that represents a keyword. Keywords are
+// like identifiers, but they have special meaning in particular contexts.
+// Example:
+//
+// message
+type KeywordNode IdentNode
+
+// NewKeywordNode creates a new *KeywordNode. The given val is the keyword.
+func NewKeywordNode(val string, tok Token) *KeywordNode {
+ return &KeywordNode{
+ terminalNode: tok.asTerminalNode(),
+ Val: val,
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/message.go b/vendor/github.com/bufbuild/protocompile/ast/message.go
new file mode 100644
index 0000000..eede28e
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/message.go
@@ -0,0 +1,223 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// MessageDeclNode is a node in the AST that defines a message type. This
+// includes normal message fields as well as implicit messages:
+// - *MessageNode
+// - *SyntheticGroupMessageNode (the group is a field and inline message type)
+// - *SyntheticMapEntryNode (map fields implicitly define a MapEntry message type)
+//
+// This also allows NoSourceNode to be used in place of one of the above
+// for some usages.
+type MessageDeclNode interface {
+ NodeWithOptions
+ MessageName() Node
+}
+
+var _ MessageDeclNode = (*MessageNode)(nil)
+var _ MessageDeclNode = (*SyntheticGroupMessageNode)(nil)
+var _ MessageDeclNode = (*SyntheticMapEntryNode)(nil)
+var _ MessageDeclNode = (*NoSourceNode)(nil)
+
+// MessageNode represents a message declaration. Example:
+//
+// message Foo {
+// string name = 1;
+// repeated string labels = 2;
+// bytes extra = 3;
+// }
+type MessageNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name *IdentNode
+ MessageBody
+}
+
+func (*MessageNode) fileElement() {}
+func (*MessageNode) msgElement() {}
+
+// NewMessageNode creates a new *MessageNode. All arguments must be non-nil.
+// - keyword: The token corresponding to the "message" keyword.
+// - name: The token corresponding to the field's name.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the message body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewMessageNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *MessageNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 4+len(decls))
+ children = append(children, keyword, name, openBrace)
+ for _, decl := range decls {
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ ret := &MessageNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ }
+ populateMessageBody(&ret.MessageBody, openBrace, decls, closeBrace)
+ return ret
+}
+
+func (n *MessageNode) MessageName() Node {
+ return n.Name
+}
+
+func (n *MessageNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// MessageBody represents the body of a message. It is used by both
+// MessageNodes and GroupNodes.
+type MessageBody struct {
+ OpenBrace *RuneNode
+ Decls []MessageElement
+ CloseBrace *RuneNode
+}
+
+func populateMessageBody(m *MessageBody, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) {
+ m.OpenBrace = openBrace
+ m.Decls = decls
+ for _, decl := range decls {
+ switch decl.(type) {
+ case *OptionNode, *FieldNode, *MapFieldNode, *GroupNode, *OneofNode,
+ *MessageNode, *EnumNode, *ExtendNode, *ExtensionRangeNode,
+ *ReservedNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid MessageElement type: %T", decl))
+ }
+ }
+ m.CloseBrace = closeBrace
+}
+
+// MessageElement is an interface implemented by all AST nodes that can
+// appear in a message body.
+type MessageElement interface {
+ Node
+ msgElement()
+}
+
+var _ MessageElement = (*OptionNode)(nil)
+var _ MessageElement = (*FieldNode)(nil)
+var _ MessageElement = (*MapFieldNode)(nil)
+var _ MessageElement = (*OneofNode)(nil)
+var _ MessageElement = (*GroupNode)(nil)
+var _ MessageElement = (*MessageNode)(nil)
+var _ MessageElement = (*EnumNode)(nil)
+var _ MessageElement = (*ExtendNode)(nil)
+var _ MessageElement = (*ExtensionRangeNode)(nil)
+var _ MessageElement = (*ReservedNode)(nil)
+var _ MessageElement = (*EmptyDeclNode)(nil)
+
+// ExtendNode represents a declaration of extension fields. Example:
+//
+// extend google.protobuf.FieldOptions {
+// bool redacted = 33333;
+// }
+type ExtendNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Extendee IdentValueNode
+ OpenBrace *RuneNode
+ Decls []ExtendElement
+ CloseBrace *RuneNode
+}
+
+func (*ExtendNode) fileElement() {}
+func (*ExtendNode) msgElement() {}
+
+// NewExtendNode creates a new *ExtendNode. All arguments must be non-nil.
+// - keyword: The token corresponding to the "extend" keyword.
+// - extendee: The token corresponding to the name of the extended message.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the message body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewExtendNode(keyword *KeywordNode, extendee IdentValueNode, openBrace *RuneNode, decls []ExtendElement, closeBrace *RuneNode) *ExtendNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if extendee == nil {
+ panic("extendee is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 4+len(decls))
+ children = append(children, keyword, extendee, openBrace)
+ for _, decl := range decls {
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ ret := &ExtendNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Extendee: extendee,
+ OpenBrace: openBrace,
+ Decls: decls,
+ CloseBrace: closeBrace,
+ }
+ for _, decl := range decls {
+ switch decl := decl.(type) {
+ case *FieldNode:
+ decl.Extendee = ret
+ case *GroupNode:
+ decl.Extendee = ret
+ case *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid ExtendElement type: %T", decl))
+ }
+ }
+ return ret
+}
+
+// ExtendElement is an interface implemented by all AST nodes that can
+// appear in the body of an extends declaration.
+type ExtendElement interface {
+ Node
+ extendElement()
+}
+
+var _ ExtendElement = (*FieldNode)(nil)
+var _ ExtendElement = (*GroupNode)(nil)
+var _ ExtendElement = (*EmptyDeclNode)(nil)
diff --git a/vendor/github.com/bufbuild/protocompile/ast/no_source.go b/vendor/github.com/bufbuild/protocompile/ast/no_source.go
new file mode 100644
index 0000000..44dbb71
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/no_source.go
@@ -0,0 +1,142 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+// UnknownPos is a placeholder position when only the source file
+// name is known.
+func UnknownPos(filename string) SourcePos {
+ return SourcePos{Filename: filename}
+}
+
+// UnknownSpan is a placeholder span when only the source file
+// name is known.
+func UnknownSpan(filename string) SourceSpan {
+ return unknownSpan{filename: filename}
+}
+
+type unknownSpan struct {
+ filename string
+}
+
+func (s unknownSpan) Start() SourcePos {
+ return UnknownPos(s.filename)
+}
+
+func (s unknownSpan) End() SourcePos {
+ return UnknownPos(s.filename)
+}
+
+// NoSourceNode is a placeholder AST node that implements numerous
+// interfaces in this package. It can be used to represent an AST
+// element for a file whose source is not available.
+type NoSourceNode FileInfo
+
+// NewNoSourceNode creates a new NoSourceNode for the given filename.
+func NewNoSourceNode(filename string) *NoSourceNode {
+ return &NoSourceNode{name: filename}
+}
+
+func (n *NoSourceNode) Name() string {
+ return n.name
+}
+
+func (n *NoSourceNode) Start() Token {
+ return 0
+}
+
+func (n *NoSourceNode) End() Token {
+ return 0
+}
+
+func (n *NoSourceNode) NodeInfo(Node) NodeInfo {
+ return NodeInfo{
+ fileInfo: (*FileInfo)(n),
+ }
+}
+
+func (n *NoSourceNode) GetSyntax() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetName() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetValue() ValueNode {
+ return n
+}
+
+func (n *NoSourceNode) FieldLabel() Node {
+ return n
+}
+
+func (n *NoSourceNode) FieldName() Node {
+ return n
+}
+
+func (n *NoSourceNode) FieldType() Node {
+ return n
+}
+
+func (n *NoSourceNode) FieldTag() Node {
+ return n
+}
+
+func (n *NoSourceNode) FieldExtendee() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetGroupKeyword() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetOptions() *CompactOptionsNode {
+ return nil
+}
+
+func (n *NoSourceNode) RangeStart() Node {
+ return n
+}
+
+func (n *NoSourceNode) RangeEnd() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetNumber() Node {
+ return n
+}
+
+func (n *NoSourceNode) MessageName() Node {
+ return n
+}
+
+func (n *NoSourceNode) OneofName() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetInputType() Node {
+ return n
+}
+
+func (n *NoSourceNode) GetOutputType() Node {
+ return n
+}
+
+func (n *NoSourceNode) Value() interface{} {
+ return nil
+}
+
+func (n *NoSourceNode) RangeOptions(func(*OptionNode) bool) {
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/node.go b/vendor/github.com/bufbuild/protocompile/ast/node.go
new file mode 100644
index 0000000..abb7643
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/node.go
@@ -0,0 +1,139 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+// Node is the interface implemented by all nodes in the AST. It
+// provides information about the span of this AST node in terms
+// of location in the source file. It also provides information
+// about all prior comments (attached as leading comments) and
+// optional subsequent comments (attached as trailing comments).
+type Node interface {
+ Start() Token
+ End() Token
+}
+
+// TerminalNode represents a leaf in the AST. These represent
+// the items/lexemes in the protobuf language. Comments and
+// whitespace are accumulated by the lexer and associated with
+// the following lexed token.
+type TerminalNode interface {
+ Node
+ Token() Token
+}
+
+var _ TerminalNode = (*StringLiteralNode)(nil)
+var _ TerminalNode = (*UintLiteralNode)(nil)
+var _ TerminalNode = (*FloatLiteralNode)(nil)
+var _ TerminalNode = (*IdentNode)(nil)
+var _ TerminalNode = (*SpecialFloatLiteralNode)(nil)
+var _ TerminalNode = (*KeywordNode)(nil)
+var _ TerminalNode = (*RuneNode)(nil)
+
+// CompositeNode represents any non-terminal node in the tree. These
+// are interior or root nodes and have child nodes.
+type CompositeNode interface {
+ Node
+ // Children contains all AST nodes that are immediate children of this one.
+ Children() []Node
+}
+
+// terminalNode contains bookkeeping shared by all TerminalNode
+// implementations. It is embedded in all such node types in this
+// package. It provides the implementation of the TerminalNode
+// interface.
+type terminalNode Token
+
+func (n terminalNode) Start() Token {
+ return Token(n)
+}
+
+func (n terminalNode) End() Token {
+ return Token(n)
+}
+
+func (n terminalNode) Token() Token {
+ return Token(n)
+}
+
+// compositeNode contains bookkeeping shared by all CompositeNode
+// implementations. It is embedded in all such node types in this
+// package. It provides the implementation of the CompositeNode
+// interface.
+type compositeNode struct {
+ children []Node
+}
+
+func (n *compositeNode) Children() []Node {
+ return n.children
+}
+
+func (n *compositeNode) Start() Token {
+ return n.children[0].Start()
+}
+
+func (n *compositeNode) End() Token {
+ return n.children[len(n.children)-1].End()
+}
+
+// RuneNode represents a single rune in protobuf source. Runes
+// are typically collected into items, but some runes stand on
+// their own, such as punctuation/symbols like commas, semicolons,
+// equals signs, open and close symbols (braces, brackets, angles,
+// and parentheses), and periods/dots.
+// TODO: make this more compact; if runes don't have attributed comments
+// then we don't need a Token to represent them and only need an offset
+// into the file's contents.
+type RuneNode struct {
+ terminalNode
+ Rune rune
+}
+
+// NewRuneNode creates a new *RuneNode with the given properties.
+func NewRuneNode(r rune, tok Token) *RuneNode {
+ return &RuneNode{
+ terminalNode: tok.asTerminalNode(),
+ Rune: r,
+ }
+}
+
+// EmptyDeclNode represents an empty declaration in protobuf source.
+// These amount to extra semicolons, with no actual content preceding
+// the semicolon.
+type EmptyDeclNode struct {
+ compositeNode
+ Semicolon *RuneNode
+}
+
+// NewEmptyDeclNode creates a new *EmptyDeclNode. The one argument must
+// be non-nil.
+func NewEmptyDeclNode(semicolon *RuneNode) *EmptyDeclNode {
+ if semicolon == nil {
+ panic("semicolon is nil")
+ }
+ return &EmptyDeclNode{
+ compositeNode: compositeNode{
+ children: []Node{semicolon},
+ },
+ Semicolon: semicolon,
+ }
+}
+
+func (e *EmptyDeclNode) fileElement() {}
+func (e *EmptyDeclNode) msgElement() {}
+func (e *EmptyDeclNode) extendElement() {}
+func (e *EmptyDeclNode) oneofElement() {}
+func (e *EmptyDeclNode) enumElement() {}
+func (e *EmptyDeclNode) serviceElement() {}
+func (e *EmptyDeclNode) methodElement() {}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/options.go b/vendor/github.com/bufbuild/protocompile/ast/options.go
new file mode 100644
index 0000000..be31f0b
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/options.go
@@ -0,0 +1,413 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// OptionDeclNode is a placeholder interface for AST nodes that represent
+// options. This allows NoSourceNode to be used in place of *OptionNode
+// for some usages.
+type OptionDeclNode interface {
+ Node
+ GetName() Node
+ GetValue() ValueNode
+}
+
+var _ OptionDeclNode = (*OptionNode)(nil)
+var _ OptionDeclNode = (*NoSourceNode)(nil)
+
+// OptionNode represents the declaration of a single option for an element.
+// It is used both for normal option declarations (start with "option" keyword
+// and end with semicolon) and for compact options found in fields, enum values,
+// and extension ranges. Example:
+//
+// option (custom.option) = "foo";
+type OptionNode struct {
+ compositeNode
+ Keyword *KeywordNode // absent for compact options
+ Name *OptionNameNode
+ Equals *RuneNode
+ Val ValueNode
+ Semicolon *RuneNode // absent for compact options
+}
+
+func (*OptionNode) fileElement() {}
+func (*OptionNode) msgElement() {}
+func (*OptionNode) oneofElement() {}
+func (*OptionNode) enumElement() {}
+func (*OptionNode) serviceElement() {}
+func (*OptionNode) methodElement() {}
+
+// NewOptionNode creates a new *OptionNode for a full option declaration (as
+// used in files, messages, oneofs, enums, services, and methods). All arguments
+// must be non-nil. (Also see NewCompactOptionNode.)
+// - keyword: The token corresponding to the "option" keyword.
+// - name: The token corresponding to the name of the option.
+// - equals: The token corresponding to the "=" rune after the name.
+// - val: The token corresponding to the option value.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, val ValueNode, semicolon *RuneNode) *OptionNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if equals == nil {
+ panic("equals is nil")
+ }
+ if val == nil {
+ panic("val is nil")
+ }
+ var children []Node
+ if semicolon == nil {
+ children = []Node{keyword, name, equals, val}
+ } else {
+ children = []Node{keyword, name, equals, val, semicolon}
+ }
+
+ return &OptionNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ Equals: equals,
+ Val: val,
+ Semicolon: semicolon,
+ }
+}
+
+// NewCompactOptionNode creates a new *OptionNode for a full compact declaration
+// (as used in fields, enum values, and extension ranges). All arguments must be
+// non-nil.
+// - name: The token corresponding to the name of the option.
+// - equals: The token corresponding to the "=" rune after the name.
+// - val: The token corresponding to the option value.
+func NewCompactOptionNode(name *OptionNameNode, equals *RuneNode, val ValueNode) *OptionNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ if equals == nil && val != nil {
+ panic("equals is nil but val is not")
+ }
+ if val == nil && equals != nil {
+ panic("val is nil but equals is not")
+ }
+ var children []Node
+ if equals == nil && val == nil {
+ children = []Node{name}
+ } else {
+ children = []Node{name, equals, val}
+ }
+ return &OptionNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Name: name,
+ Equals: equals,
+ Val: val,
+ }
+}
+
+func (n *OptionNode) GetName() Node {
+ return n.Name
+}
+
+func (n *OptionNode) GetValue() ValueNode {
+ return n.Val
+}
+
+// OptionNameNode represents an option name or even a traversal through message
+// types to name a nested option field. Example:
+//
+// (foo.bar).baz.(bob)
+type OptionNameNode struct {
+ compositeNode
+ Parts []*FieldReferenceNode
+ // Dots represent the separating '.' characters between name parts. The
+ // length of this slice must be exactly len(Parts)-1, each item in Parts
+ // having a corresponding item in this slice *except the last* (since a
+ // trailing dot is not allowed).
+ //
+ // These do *not* include dots that are inside of an extension name. For
+ // example: (foo.bar).baz.(bob) has three parts:
+ // 1. (foo.bar) - an extension name
+ // 2. baz - a regular field in foo.bar
+ // 3. (bob) - an extension field in baz
+ // Note that the dot in foo.bar will thus not be present in Dots but is
+ // instead in Parts[0].
+ Dots []*RuneNode
+}
+
+// NewOptionNameNode creates a new *OptionNameNode. The dots arg must have a
+// length that is one less than the length of parts. The parts arg must not be
+// empty.
+func NewOptionNameNode(parts []*FieldReferenceNode, dots []*RuneNode) *OptionNameNode {
+ if len(parts) == 0 {
+ panic("must have at least one part")
+ }
+ if len(dots) != len(parts)-1 && len(dots) != len(parts) {
+ panic(fmt.Sprintf("%d parts requires %d dots, not %d", len(parts), len(parts)-1, len(dots)))
+ }
+ children := make([]Node, 0, len(parts)+len(dots))
+ for i, part := range parts {
+ if part == nil {
+ panic(fmt.Sprintf("parts[%d] is nil", i))
+ }
+ if i > 0 {
+ if dots[i-1] == nil {
+ panic(fmt.Sprintf("dots[%d] is nil", i-1))
+ }
+ children = append(children, dots[i-1])
+ }
+ children = append(children, part)
+ }
+ if len(dots) == len(parts) { // Add the erroneous, but tolerated trailing dot.
+ if dots[len(dots)-1] == nil {
+ panic(fmt.Sprintf("dots[%d] is nil", len(dots)-1))
+ }
+ children = append(children, dots[len(dots)-1])
+ }
+ return &OptionNameNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Parts: parts,
+ Dots: dots,
+ }
+}
+
+// FieldReferenceNode is a reference to a field name. It can indicate a regular
+// field (simple unqualified name), an extension field (possibly-qualified name
+// that is enclosed either in brackets or parentheses), or an "any" type
+// reference (a type URL in the form "server.host/fully.qualified.Name" that is
+// enclosed in brackets).
+//
+// Extension names are used in options to refer to custom options (which are
+// actually extensions), in which case the name is enclosed in parentheses "("
+// and ")". They can also be used to refer to extension fields of options.
+//
+// Extension names are also used in message literals to set extension fields,
+// in which case the name is enclosed in square brackets "[" and "]".
+//
+// "Any" type references can only be used in message literals, and are not
+// allowed in option names. They are always enclosed in square brackets. An
+// "any" type reference is distinguished from an extension name by the presence
+// of a slash, which must be present in an "any" type reference and must be
+// absent in an extension name.
+//
+// Examples:
+//
+// foobar
+// (foo.bar)
+// [foo.bar]
+// [type.googleapis.com/foo.bar]
+type FieldReferenceNode struct {
+ compositeNode
+ Open *RuneNode // only present for extension names and "any" type references
+
+ // only present for "any" type references
+ URLPrefix IdentValueNode
+ Slash *RuneNode
+
+ Name IdentValueNode
+
+ Close *RuneNode // only present for extension names and "any" type references
+}
+
+// NewFieldReferenceNode creates a new *FieldReferenceNode for a regular field.
+// The name arg must not be nil.
+func NewFieldReferenceNode(name *IdentNode) *FieldReferenceNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ children := []Node{name}
+ return &FieldReferenceNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Name: name,
+ }
+}
+
+// NewExtensionFieldReferenceNode creates a new *FieldReferenceNode for an
+// extension field. All args must be non-nil. The openSym and closeSym runes
+// should be "(" and ")" or "[" and "]".
+func NewExtensionFieldReferenceNode(openSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ if openSym == nil {
+ panic("openSym is nil")
+ }
+ if closeSym == nil {
+ panic("closeSym is nil")
+ }
+ children := []Node{openSym, name, closeSym}
+ return &FieldReferenceNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Open: openSym,
+ Name: name,
+ Close: closeSym,
+ }
+}
+
+// NewAnyTypeReferenceNode creates a new *FieldReferenceNode for an "any"
+// type reference. All args must be non-nil. The openSym and closeSym runes
+// should be "[" and "]". The slashSym run should be "/".
+func NewAnyTypeReferenceNode(openSym *RuneNode, urlPrefix IdentValueNode, slashSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ if openSym == nil {
+ panic("openSym is nil")
+ }
+ if closeSym == nil {
+ panic("closeSym is nil")
+ }
+ if urlPrefix == nil {
+ panic("urlPrefix is nil")
+ }
+ if slashSym == nil {
+ panic("slashSym is nil")
+ }
+ children := []Node{openSym, urlPrefix, slashSym, name, closeSym}
+ return &FieldReferenceNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Open: openSym,
+ URLPrefix: urlPrefix,
+ Slash: slashSym,
+ Name: name,
+ Close: closeSym,
+ }
+}
+
+// IsExtension reports if this is an extension name or not (e.g. enclosed in
+// punctuation, such as parentheses or brackets).
+func (a *FieldReferenceNode) IsExtension() bool {
+ return a.Open != nil && a.Slash == nil
+}
+
+// IsAnyTypeReference reports if this is an Any type reference.
+func (a *FieldReferenceNode) IsAnyTypeReference() bool {
+ return a.Slash != nil
+}
+
+func (a *FieldReferenceNode) Value() string {
+ if a.Open != nil {
+ if a.Slash != nil {
+ return string(a.Open.Rune) + string(a.URLPrefix.AsIdentifier()) + string(a.Slash.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune)
+ }
+ return string(a.Open.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune)
+ }
+ return string(a.Name.AsIdentifier())
+}
+
+// CompactOptionsNode represents a compact options declaration, as used with
+// fields, enum values, and extension ranges. Example:
+//
+// [deprecated = true, json_name = "foo_bar"]
+type CompactOptionsNode struct {
+ compositeNode
+ OpenBracket *RuneNode
+ Options []*OptionNode
+ // Commas represent the separating ',' characters between options. The
+ // length of this slice must be exactly len(Options)-1, with each item
+ // in Options having a corresponding item in this slice *except the last*
+ // (since a trailing comma is not allowed).
+ Commas []*RuneNode
+ CloseBracket *RuneNode
+}
+
+// NewCompactOptionsNode creates a *CompactOptionsNode. All args must be
+// non-nil. The commas arg must have a length that is one less than the
+// length of opts. The opts arg must not be empty.
+func NewCompactOptionsNode(openBracket *RuneNode, opts []*OptionNode, commas []*RuneNode, closeBracket *RuneNode) *CompactOptionsNode {
+ if openBracket == nil {
+ panic("openBracket is nil")
+ }
+ if closeBracket == nil {
+ panic("closeBracket is nil")
+ }
+ if len(opts) == 0 && len(commas) != 0 {
+ panic("opts is empty but commas is not")
+ }
+ if len(opts) != len(commas) && len(opts) != len(commas)+1 {
+ panic(fmt.Sprintf("%d opts requires %d commas, not %d", len(opts), len(opts)-1, len(commas)))
+ }
+ children := make([]Node, 0, len(opts)+len(commas)+2)
+ children = append(children, openBracket)
+ if len(opts) > 0 {
+ for i, opt := range opts {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if opt == nil {
+ panic(fmt.Sprintf("opts[%d] is nil", i))
+ }
+ children = append(children, opt)
+ }
+ if len(opts) == len(commas) { // Add the erroneous, but tolerated trailing comma.
+ if commas[len(commas)-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", len(commas)-1))
+ }
+ children = append(children, commas[len(commas)-1])
+ }
+ }
+ children = append(children, closeBracket)
+
+ return &CompactOptionsNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ OpenBracket: openBracket,
+ Options: opts,
+ Commas: commas,
+ CloseBracket: closeBracket,
+ }
+}
+
+func (e *CompactOptionsNode) GetElements() []*OptionNode {
+ if e == nil {
+ return nil
+ }
+ return e.Options
+}
+
+// NodeWithOptions represents a node in the AST that contains
+// option statements.
+type NodeWithOptions interface {
+ Node
+ RangeOptions(func(*OptionNode) bool)
+}
+
+var _ NodeWithOptions = FileDeclNode(nil)
+var _ NodeWithOptions = MessageDeclNode(nil)
+var _ NodeWithOptions = OneofDeclNode(nil)
+var _ NodeWithOptions = (*EnumNode)(nil)
+var _ NodeWithOptions = (*ServiceNode)(nil)
+var _ NodeWithOptions = RPCDeclNode(nil)
+var _ NodeWithOptions = FieldDeclNode(nil)
+var _ NodeWithOptions = EnumValueDeclNode(nil)
+var _ NodeWithOptions = (*ExtensionRangeNode)(nil)
+var _ NodeWithOptions = (*NoSourceNode)(nil)
diff --git a/vendor/github.com/bufbuild/protocompile/ast/ranges.go b/vendor/github.com/bufbuild/protocompile/ast/ranges.go
new file mode 100644
index 0000000..c42908e
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/ranges.go
@@ -0,0 +1,386 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// ExtensionRangeNode represents an extension range declaration in an extendable
+// message. Example:
+//
+// extensions 100 to max;
+type ExtensionRangeNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Ranges []*RangeNode
+ // Commas represent the separating ',' characters between ranges. The
+ // length of this slice must be exactly len(Ranges)-1, each item in Ranges
+ // having a corresponding item in this slice *except the last* (since a
+ // trailing comma is not allowed).
+ Commas []*RuneNode
+ Options *CompactOptionsNode
+ Semicolon *RuneNode
+}
+
+func (*ExtensionRangeNode) msgElement() {}
+
+// NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be
+// non-nil except opts, which may be nil.
+// - keyword: The token corresponding to the "extends" keyword.
+// - ranges: One or more range expressions.
+// - commas: Tokens that represent the "," runes that delimit the range expressions.
+// The length of commas must be one less than the length of ranges.
+// - opts: The node corresponding to options that apply to each of the ranges.
+// - semicolon The token corresponding to the ";" rune that ends the declaration.
+func NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, opts *CompactOptionsNode, semicolon *RuneNode) *ExtensionRangeNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if semicolon == nil {
+ panic("semicolon is nil")
+ }
+ if len(ranges) == 0 {
+ panic("must have at least one range")
+ }
+ if len(commas) != len(ranges)-1 {
+ panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas)))
+ }
+ numChildren := len(ranges)*2 + 1
+ if opts != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, keyword)
+ for i, rng := range ranges {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if rng == nil {
+ panic(fmt.Sprintf("ranges[%d] is nil", i))
+ }
+ children = append(children, rng)
+ }
+ if opts != nil {
+ children = append(children, opts)
+ }
+ children = append(children, semicolon)
+ return &ExtensionRangeNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Ranges: ranges,
+ Commas: commas,
+ Options: opts,
+ Semicolon: semicolon,
+ }
+}
+
+func (e *ExtensionRangeNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, opt := range e.Options.Options {
+ if !fn(opt) {
+ return
+ }
+ }
+}
+
+// RangeDeclNode is a placeholder interface for AST nodes that represent
+// numeric values. This allows NoSourceNode to be used in place of *RangeNode
+// for some usages.
+type RangeDeclNode interface {
+ Node
+ RangeStart() Node
+ RangeEnd() Node
+}
+
+var _ RangeDeclNode = (*RangeNode)(nil)
+var _ RangeDeclNode = (*NoSourceNode)(nil)
+
+// RangeNode represents a range expression, used in both extension ranges and
+// reserved ranges. Example:
+//
+// 1000 to max
+type RangeNode struct {
+ compositeNode
+ StartVal IntValueNode
+ // if To is non-nil, then exactly one of EndVal or Max must also be non-nil
+ To *KeywordNode
+ // EndVal and Max are mutually exclusive
+ EndVal IntValueNode
+ Max *KeywordNode
+}
+
+// NewRangeNode creates a new *RangeNode. The start argument must be non-nil.
+// The to argument represents the "to" keyword. If present (i.e. if it is non-nil),
+// then so must be exactly one of end or max. If max is non-nil, it indicates a
+// "100 to max" style range. But if end is non-nil, the end of the range is a
+// literal, such as "100 to 200".
+func NewRangeNode(start IntValueNode, to *KeywordNode, end IntValueNode, maxEnd *KeywordNode) *RangeNode {
+ if start == nil {
+ panic("start is nil")
+ }
+ numChildren := 1
+ if to != nil {
+ if end == nil && maxEnd == nil {
+ panic("to is not nil, but end and max both are")
+ }
+ if end != nil && maxEnd != nil {
+ panic("end and max cannot be both non-nil")
+ }
+ numChildren = 3
+ } else {
+ if end != nil {
+ panic("to is nil, but end is not")
+ }
+ if maxEnd != nil {
+ panic("to is nil, but max is not")
+ }
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, start)
+ if to != nil {
+ children = append(children, to)
+ if end != nil {
+ children = append(children, end)
+ } else {
+ children = append(children, maxEnd)
+ }
+ }
+ return &RangeNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ StartVal: start,
+ To: to,
+ EndVal: end,
+ Max: maxEnd,
+ }
+}
+
+func (n *RangeNode) RangeStart() Node {
+ return n.StartVal
+}
+
+func (n *RangeNode) RangeEnd() Node {
+ if n.Max != nil {
+ return n.Max
+ }
+ if n.EndVal != nil {
+ return n.EndVal
+ }
+ return n.StartVal
+}
+
+func (n *RangeNode) StartValue() interface{} {
+ return n.StartVal.Value()
+}
+
+func (n *RangeNode) StartValueAsInt32(minVal, maxVal int32) (int32, bool) {
+ return AsInt32(n.StartVal, minVal, maxVal)
+}
+
+func (n *RangeNode) EndValue() interface{} {
+ if n.EndVal == nil {
+ return nil
+ }
+ return n.EndVal.Value()
+}
+
+func (n *RangeNode) EndValueAsInt32(minVal, maxVal int32) (int32, bool) {
+ if n.Max != nil {
+ return maxVal, true
+ }
+ if n.EndVal == nil {
+ return n.StartValueAsInt32(minVal, maxVal)
+ }
+ return AsInt32(n.EndVal, minVal, maxVal)
+}
+
+// ReservedNode represents reserved declaration, which can be used to reserve
+// either names or numbers. Examples:
+//
+// reserved 1, 10-12, 15;
+// reserved "foo", "bar", "baz";
+// reserved foo, bar, baz;
+type ReservedNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ // If non-empty, this node represents reserved ranges, and Names and Identifiers
+ // will be empty.
+ Ranges []*RangeNode
+ // If non-empty, this node represents reserved names as string literals, and
+ // Ranges and Identifiers will be empty. String literals are used for reserved
+ // names in proto2 and proto3 syntax.
+ Names []StringValueNode
+ // If non-empty, this node represents reserved names as identifiers, and Ranges
+ // and Names will be empty. Identifiers are used for reserved names in editions.
+ Identifiers []*IdentNode
+ // Commas represent the separating ',' characters between options. The
+ // length of this slice must be exactly len(Ranges)-1 or len(Names)-1, depending
+ // on whether this node represents reserved ranges or reserved names. Each item
+ // in Ranges or Names has a corresponding item in this slice *except the last*
+ // (since a trailing comma is not allowed).
+ Commas []*RuneNode
+ Semicolon *RuneNode
+}
+
+func (*ReservedNode) msgElement() {}
+func (*ReservedNode) enumElement() {}
+
+// NewReservedRangesNode creates a new *ReservedNode that represents reserved
+// numeric ranges. All args must be non-nil.
+// - keyword: The token corresponding to the "reserved" keyword.
+// - ranges: One or more range expressions.
+// - commas: Tokens that represent the "," runes that delimit the range expressions.
+// The length of commas must be one less than the length of ranges.
+// - semicolon The token corresponding to the ";" rune that ends the declaration.
+func NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if semicolon == nil {
+ panic("semicolon is nil")
+ }
+ if len(ranges) == 0 {
+ panic("must have at least one range")
+ }
+ if len(commas) != len(ranges)-1 {
+ panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas)))
+ }
+ children := make([]Node, 0, len(ranges)*2+1)
+ children = append(children, keyword)
+ for i, rng := range ranges {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if rng == nil {
+ panic(fmt.Sprintf("ranges[%d] is nil", i))
+ }
+ children = append(children, rng)
+ }
+ children = append(children, semicolon)
+ return &ReservedNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Ranges: ranges,
+ Commas: commas,
+ Semicolon: semicolon,
+ }
+}
+
+// NewReservedNamesNode creates a new *ReservedNode that represents reserved
+// names. All args must be non-nil.
+// - keyword: The token corresponding to the "reserved" keyword.
+// - names: One or more names.
+// - commas: Tokens that represent the "," runes that delimit the names.
+// The length of commas must be one less than the length of names.
+// - semicolon The token corresponding to the ";" rune that ends the declaration.
+func NewReservedNamesNode(keyword *KeywordNode, names []StringValueNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if len(names) == 0 {
+ panic("must have at least one name")
+ }
+ if len(commas) != len(names)-1 {
+ panic(fmt.Sprintf("%d names requires %d commas, not %d", len(names), len(names)-1, len(commas)))
+ }
+ numChildren := len(names) * 2
+ if semicolon != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, keyword)
+ for i, name := range names {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if name == nil {
+ panic(fmt.Sprintf("names[%d] is nil", i))
+ }
+ children = append(children, name)
+ }
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+ return &ReservedNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Names: names,
+ Commas: commas,
+ Semicolon: semicolon,
+ }
+}
+
+// NewReservedIdentifiersNode creates a new *ReservedNode that represents reserved
+// names. All args must be non-nil.
+// - keyword: The token corresponding to the "reserved" keyword.
+// - names: One or more names.
+// - commas: Tokens that represent the "," runes that delimit the names.
+// The length of commas must be one less than the length of names.
+// - semicolon The token corresponding to the ";" rune that ends the declaration.
+func NewReservedIdentifiersNode(keyword *KeywordNode, names []*IdentNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if len(names) == 0 {
+ panic("must have at least one name")
+ }
+ if len(commas) != len(names)-1 {
+ panic(fmt.Sprintf("%d names requires %d commas, not %d", len(names), len(names)-1, len(commas)))
+ }
+ numChildren := len(names) * 2
+ if semicolon != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, keyword)
+ for i, name := range names {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if name == nil {
+ panic(fmt.Sprintf("names[%d] is nil", i))
+ }
+ children = append(children, name)
+ }
+ if semicolon != nil {
+ children = append(children, semicolon)
+ }
+ return &ReservedNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Identifiers: names,
+ Commas: commas,
+ Semicolon: semicolon,
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/service.go b/vendor/github.com/bufbuild/protocompile/ast/service.go
new file mode 100644
index 0000000..eba22fd
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/service.go
@@ -0,0 +1,308 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// ServiceNode represents a service declaration. Example:
+//
+// service Foo {
+// rpc Bar (Baz) returns (Bob);
+// rpc Frobnitz (stream Parts) returns (Gyzmeaux);
+// }
+type ServiceNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name *IdentNode
+ OpenBrace *RuneNode
+ Decls []ServiceElement
+ CloseBrace *RuneNode
+}
+
+func (*ServiceNode) fileElement() {}
+
+// NewServiceNode creates a new *ServiceNode. All arguments must be non-nil.
+// - keyword: The token corresponding to the "service" keyword.
+// - name: The token corresponding to the service's name.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the service body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewServiceNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []ServiceElement, closeBrace *RuneNode) *ServiceNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 4+len(decls))
+ children = append(children, keyword, name, openBrace)
+ for _, decl := range decls {
+ switch decl := decl.(type) {
+ case *OptionNode, *RPCNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid ServiceElement type: %T", decl))
+ }
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ return &ServiceNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ OpenBrace: openBrace,
+ Decls: decls,
+ CloseBrace: closeBrace,
+ }
+}
+
+func (n *ServiceNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// ServiceElement is an interface implemented by all AST nodes that can
+// appear in the body of a service declaration.
+type ServiceElement interface {
+ Node
+ serviceElement()
+}
+
+var _ ServiceElement = (*OptionNode)(nil)
+var _ ServiceElement = (*RPCNode)(nil)
+var _ ServiceElement = (*EmptyDeclNode)(nil)
+
+// RPCDeclNode is a placeholder interface for AST nodes that represent RPC
+// declarations. This allows NoSourceNode to be used in place of *RPCNode
+// for some usages.
+type RPCDeclNode interface {
+ NodeWithOptions
+ GetName() Node
+ GetInputType() Node
+ GetOutputType() Node
+}
+
+var _ RPCDeclNode = (*RPCNode)(nil)
+var _ RPCDeclNode = (*NoSourceNode)(nil)
+
+// RPCNode represents an RPC declaration. Example:
+//
+// rpc Foo (Bar) returns (Baz);
+type RPCNode struct {
+ compositeNode
+ Keyword *KeywordNode
+ Name *IdentNode
+ Input *RPCTypeNode
+ Returns *KeywordNode
+ Output *RPCTypeNode
+ Semicolon *RuneNode
+ OpenBrace *RuneNode
+ Decls []RPCElement
+ CloseBrace *RuneNode
+}
+
+func (n *RPCNode) serviceElement() {}
+
+// NewRPCNode creates a new *RPCNode with no body. All arguments must be non-nil.
+// - keyword: The token corresponding to the "rpc" keyword.
+// - name: The token corresponding to the RPC's name.
+// - input: The token corresponding to the RPC input message type.
+// - returns: The token corresponding to the "returns" keyword that precedes the output type.
+// - output: The token corresponding to the RPC output message type.
+// - semicolon: The token corresponding to the ";" rune that ends the declaration.
+func NewRPCNode(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, semicolon *RuneNode) *RPCNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if input == nil {
+ panic("input is nil")
+ }
+ if returns == nil {
+ panic("returns is nil")
+ }
+ if output == nil {
+ panic("output is nil")
+ }
+ var children []Node
+ if semicolon == nil {
+ children = []Node{keyword, name, input, returns, output}
+ } else {
+ children = []Node{keyword, name, input, returns, output, semicolon}
+ }
+ return &RPCNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ Input: input,
+ Returns: returns,
+ Output: output,
+ Semicolon: semicolon,
+ }
+}
+
+// NewRPCNodeWithBody creates a new *RPCNode that includes a body (and possibly
+// options). All arguments must be non-nil.
+// - keyword: The token corresponding to the "rpc" keyword.
+// - name: The token corresponding to the RPC's name.
+// - input: The token corresponding to the RPC input message type.
+// - returns: The token corresponding to the "returns" keyword that precedes the output type.
+// - output: The token corresponding to the RPC output message type.
+// - openBrace: The token corresponding to the "{" rune that starts the body.
+// - decls: All declarations inside the RPC body.
+// - closeBrace: The token corresponding to the "}" rune that ends the body.
+func NewRPCNodeWithBody(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, openBrace *RuneNode, decls []RPCElement, closeBrace *RuneNode) *RPCNode {
+ if keyword == nil {
+ panic("keyword is nil")
+ }
+ if name == nil {
+ panic("name is nil")
+ }
+ if input == nil {
+ panic("input is nil")
+ }
+ if returns == nil {
+ panic("returns is nil")
+ }
+ if output == nil {
+ panic("output is nil")
+ }
+ if openBrace == nil {
+ panic("openBrace is nil")
+ }
+ if closeBrace == nil {
+ panic("closeBrace is nil")
+ }
+ children := make([]Node, 0, 7+len(decls))
+ children = append(children, keyword, name, input, returns, output, openBrace)
+ for _, decl := range decls {
+ switch decl := decl.(type) {
+ case *OptionNode, *EmptyDeclNode:
+ default:
+ panic(fmt.Sprintf("invalid RPCElement type: %T", decl))
+ }
+ children = append(children, decl)
+ }
+ children = append(children, closeBrace)
+
+ return &RPCNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Keyword: keyword,
+ Name: name,
+ Input: input,
+ Returns: returns,
+ Output: output,
+ OpenBrace: openBrace,
+ Decls: decls,
+ CloseBrace: closeBrace,
+ }
+}
+
+func (n *RPCNode) GetName() Node {
+ return n.Name
+}
+
+func (n *RPCNode) GetInputType() Node {
+ return n.Input.MessageType
+}
+
+func (n *RPCNode) GetOutputType() Node {
+ return n.Output.MessageType
+}
+
+func (n *RPCNode) RangeOptions(fn func(*OptionNode) bool) {
+ for _, decl := range n.Decls {
+ if opt, ok := decl.(*OptionNode); ok {
+ if !fn(opt) {
+ return
+ }
+ }
+ }
+}
+
+// RPCElement is an interface implemented by all AST nodes that can
+// appear in the body of an rpc declaration (aka method).
+type RPCElement interface {
+ Node
+ methodElement()
+}
+
+var _ RPCElement = (*OptionNode)(nil)
+var _ RPCElement = (*EmptyDeclNode)(nil)
+
+// RPCTypeNode represents the declaration of a request or response type for an
+// RPC. Example:
+//
+// (stream foo.Bar)
+type RPCTypeNode struct {
+ compositeNode
+ OpenParen *RuneNode
+ Stream *KeywordNode
+ MessageType IdentValueNode
+ CloseParen *RuneNode
+}
+
+// NewRPCTypeNode creates a new *RPCTypeNode. All arguments must be non-nil
+// except stream, which may be nil.
+// - openParen: The token corresponding to the "(" rune that starts the declaration.
+// - stream: The token corresponding to the "stream" keyword or nil if not present.
+// - msgType: The token corresponding to the message type's name.
+// - closeParen: The token corresponding to the ")" rune that ends the declaration.
+func NewRPCTypeNode(openParen *RuneNode, stream *KeywordNode, msgType IdentValueNode, closeParen *RuneNode) *RPCTypeNode {
+ if openParen == nil {
+ panic("openParen is nil")
+ }
+ if msgType == nil {
+ panic("msgType is nil")
+ }
+ if closeParen == nil {
+ panic("closeParen is nil")
+ }
+ var children []Node
+ if stream != nil {
+ children = []Node{openParen, stream, msgType, closeParen}
+ } else {
+ children = []Node{openParen, msgType, closeParen}
+ }
+
+ return &RPCTypeNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ OpenParen: openParen,
+ Stream: stream,
+ MessageType: msgType,
+ CloseParen: closeParen,
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/values.go b/vendor/github.com/bufbuild/protocompile/ast/values.go
new file mode 100644
index 0000000..22bd208
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/values.go
@@ -0,0 +1,519 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import (
+ "fmt"
+ "math"
+ "strings"
+)
+
+// ValueNode is an AST node that represents a literal value.
+//
+// It also includes references (e.g. IdentifierValueNode), which can be
+// used as values in some contexts, such as describing the default value
+// for a field, which can refer to an enum value.
+//
+// This also allows NoSourceNode to be used in place of a real value node
+// for some usages.
+type ValueNode interface {
+ Node
+ // Value returns a Go representation of the value. For scalars, this
+ // will be a string, int64, uint64, float64, or bool. This could also
+ // be an Identifier (e.g. IdentValueNodes). It can also be a composite
+ // literal:
+ // * For array literals, the type returned will be []ValueNode
+ // * For message literals, the type returned will be []*MessageFieldNode
+ //
+ // If the ValueNode is a NoSourceNode, indicating that there is no actual
+ // source code (and thus not AST information), then this method always
+ // returns nil.
+ Value() interface{}
+}
+
+var _ ValueNode = (*IdentNode)(nil)
+var _ ValueNode = (*CompoundIdentNode)(nil)
+var _ ValueNode = (*StringLiteralNode)(nil)
+var _ ValueNode = (*CompoundStringLiteralNode)(nil)
+var _ ValueNode = (*UintLiteralNode)(nil)
+var _ ValueNode = (*NegativeIntLiteralNode)(nil)
+var _ ValueNode = (*FloatLiteralNode)(nil)
+var _ ValueNode = (*SpecialFloatLiteralNode)(nil)
+var _ ValueNode = (*SignedFloatLiteralNode)(nil)
+var _ ValueNode = (*ArrayLiteralNode)(nil)
+var _ ValueNode = (*MessageLiteralNode)(nil)
+var _ ValueNode = (*NoSourceNode)(nil)
+
+// StringValueNode is an AST node that represents a string literal.
+// Such a node can be a single literal (*StringLiteralNode) or a
+// concatenation of multiple literals (*CompoundStringLiteralNode).
+type StringValueNode interface {
+ ValueNode
+ AsString() string
+}
+
+var _ StringValueNode = (*StringLiteralNode)(nil)
+var _ StringValueNode = (*CompoundStringLiteralNode)(nil)
+
+// StringLiteralNode represents a simple string literal. Example:
+//
+// "proto2"
+type StringLiteralNode struct {
+ terminalNode
+ // Val is the actual string value that the literal indicates.
+ Val string
+}
+
+// NewStringLiteralNode creates a new *StringLiteralNode with the given val.
+func NewStringLiteralNode(val string, tok Token) *StringLiteralNode {
+ return &StringLiteralNode{
+ terminalNode: tok.asTerminalNode(),
+ Val: val,
+ }
+}
+
+func (n *StringLiteralNode) Value() interface{} {
+ return n.AsString()
+}
+
+func (n *StringLiteralNode) AsString() string {
+ return n.Val
+}
+
+// CompoundStringLiteralNode represents a compound string literal, which is
+// the concatenaton of adjacent string literals. Example:
+//
+// "this " "is" " all one " "string"
+type CompoundStringLiteralNode struct {
+ compositeNode
+ Val string
+}
+
+// NewCompoundLiteralStringNode creates a new *CompoundStringLiteralNode that
+// consists of the given string components. The components argument may not be
+// empty.
+func NewCompoundLiteralStringNode(components ...*StringLiteralNode) *CompoundStringLiteralNode {
+ if len(components) == 0 {
+ panic("must have at least one component")
+ }
+ children := make([]Node, len(components))
+ var b strings.Builder
+ for i, comp := range components {
+ children[i] = comp
+ b.WriteString(comp.Val)
+ }
+ return &CompoundStringLiteralNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Val: b.String(),
+ }
+}
+
+func (n *CompoundStringLiteralNode) Value() interface{} {
+ return n.AsString()
+}
+
+func (n *CompoundStringLiteralNode) AsString() string {
+ return n.Val
+}
+
+// IntValueNode is an AST node that represents an integer literal. If
+// an integer literal is too large for an int64 (or uint64 for
+// positive literals), it is represented instead by a FloatValueNode.
+type IntValueNode interface {
+ ValueNode
+ AsInt64() (int64, bool)
+ AsUint64() (uint64, bool)
+}
+
+// AsInt32 range checks the given int value and returns its value is
+// in the range or 0, false if it is outside the range.
+func AsInt32(n IntValueNode, minVal, maxVal int32) (int32, bool) {
+ i, ok := n.AsInt64()
+ if !ok {
+ return 0, false
+ }
+ if i < int64(minVal) || i > int64(maxVal) {
+ return 0, false
+ }
+ return int32(i), true
+}
+
+var _ IntValueNode = (*UintLiteralNode)(nil)
+var _ IntValueNode = (*NegativeIntLiteralNode)(nil)
+
+// UintLiteralNode represents a simple integer literal with no sign character.
+type UintLiteralNode struct {
+ terminalNode
+ // Val is the numeric value indicated by the literal
+ Val uint64
+}
+
+// NewUintLiteralNode creates a new *UintLiteralNode with the given val.
+func NewUintLiteralNode(val uint64, tok Token) *UintLiteralNode {
+ return &UintLiteralNode{
+ terminalNode: tok.asTerminalNode(),
+ Val: val,
+ }
+}
+
+func (n *UintLiteralNode) Value() interface{} {
+ return n.Val
+}
+
+func (n *UintLiteralNode) AsInt64() (int64, bool) {
+ if n.Val > math.MaxInt64 {
+ return 0, false
+ }
+ return int64(n.Val), true
+}
+
+func (n *UintLiteralNode) AsUint64() (uint64, bool) {
+ return n.Val, true
+}
+
+func (n *UintLiteralNode) AsFloat() float64 {
+ return float64(n.Val)
+}
+
+// NegativeIntLiteralNode represents an integer literal with a negative (-) sign.
+type NegativeIntLiteralNode struct {
+ compositeNode
+ Minus *RuneNode
+ Uint *UintLiteralNode
+ Val int64
+}
+
+// NewNegativeIntLiteralNode creates a new *NegativeIntLiteralNode. Both
+// arguments must be non-nil.
+func NewNegativeIntLiteralNode(sign *RuneNode, i *UintLiteralNode) *NegativeIntLiteralNode {
+ if sign == nil {
+ panic("sign is nil")
+ }
+ if i == nil {
+ panic("i is nil")
+ }
+ children := []Node{sign, i}
+ return &NegativeIntLiteralNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Minus: sign,
+ Uint: i,
+ Val: -int64(i.Val),
+ }
+}
+
+func (n *NegativeIntLiteralNode) Value() interface{} {
+ return n.Val
+}
+
+func (n *NegativeIntLiteralNode) AsInt64() (int64, bool) {
+ return n.Val, true
+}
+
+func (n *NegativeIntLiteralNode) AsUint64() (uint64, bool) {
+ if n.Val < 0 {
+ return 0, false
+ }
+ return uint64(n.Val), true
+}
+
+// FloatValueNode is an AST node that represents a numeric literal with
+// a floating point, in scientific notation, or too large to fit in an
+// int64 or uint64.
+type FloatValueNode interface {
+ ValueNode
+ AsFloat() float64
+}
+
+var _ FloatValueNode = (*FloatLiteralNode)(nil)
+var _ FloatValueNode = (*SpecialFloatLiteralNode)(nil)
+var _ FloatValueNode = (*UintLiteralNode)(nil)
+
+// FloatLiteralNode represents a floating point numeric literal.
+type FloatLiteralNode struct {
+ terminalNode
+ // Val is the numeric value indicated by the literal
+ Val float64
+}
+
+// NewFloatLiteralNode creates a new *FloatLiteralNode with the given val.
+func NewFloatLiteralNode(val float64, tok Token) *FloatLiteralNode {
+ return &FloatLiteralNode{
+ terminalNode: tok.asTerminalNode(),
+ Val: val,
+ }
+}
+
+func (n *FloatLiteralNode) Value() interface{} {
+ return n.AsFloat()
+}
+
+func (n *FloatLiteralNode) AsFloat() float64 {
+ return n.Val
+}
+
+// SpecialFloatLiteralNode represents a special floating point numeric literal
+// for "inf" and "nan" values.
+type SpecialFloatLiteralNode struct {
+ *KeywordNode
+ Val float64
+}
+
+// NewSpecialFloatLiteralNode returns a new *SpecialFloatLiteralNode for the
+// given keyword. The given keyword should be "inf", "infinity", or "nan"
+// in any case.
+func NewSpecialFloatLiteralNode(name *KeywordNode) *SpecialFloatLiteralNode {
+ var f float64
+ switch strings.ToLower(name.Val) {
+ case "inf", "infinity":
+ f = math.Inf(1)
+ default:
+ f = math.NaN()
+ }
+ return &SpecialFloatLiteralNode{
+ KeywordNode: name,
+ Val: f,
+ }
+}
+
+func (n *SpecialFloatLiteralNode) Value() interface{} {
+ return n.AsFloat()
+}
+
+func (n *SpecialFloatLiteralNode) AsFloat() float64 {
+ return n.Val
+}
+
+// SignedFloatLiteralNode represents a signed floating point number.
+type SignedFloatLiteralNode struct {
+ compositeNode
+ Sign *RuneNode
+ Float FloatValueNode
+ Val float64
+}
+
+// NewSignedFloatLiteralNode creates a new *SignedFloatLiteralNode. Both
+// arguments must be non-nil.
+func NewSignedFloatLiteralNode(sign *RuneNode, f FloatValueNode) *SignedFloatLiteralNode {
+ if sign == nil {
+ panic("sign is nil")
+ }
+ if f == nil {
+ panic("f is nil")
+ }
+ children := []Node{sign, f}
+ val := f.AsFloat()
+ if sign.Rune == '-' {
+ val = -val
+ }
+ return &SignedFloatLiteralNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Sign: sign,
+ Float: f,
+ Val: val,
+ }
+}
+
+func (n *SignedFloatLiteralNode) Value() interface{} {
+ return n.Val
+}
+
+func (n *SignedFloatLiteralNode) AsFloat() float64 {
+ return n.Val
+}
+
+// ArrayLiteralNode represents an array literal, which is only allowed inside of
+// a MessageLiteralNode, to indicate values for a repeated field. Example:
+//
+// ["foo", "bar", "baz"]
+type ArrayLiteralNode struct {
+ compositeNode
+ OpenBracket *RuneNode
+ Elements []ValueNode
+ // Commas represent the separating ',' characters between elements. The
+ // length of this slice must be exactly len(Elements)-1, with each item
+ // in Elements having a corresponding item in this slice *except the last*
+ // (since a trailing comma is not allowed).
+ Commas []*RuneNode
+ CloseBracket *RuneNode
+}
+
+// NewArrayLiteralNode creates a new *ArrayLiteralNode. The openBracket and
+// closeBracket args must be non-nil and represent the "[" and "]" runes that
+// surround the array values. The given commas arg must have a length that is
+// one less than the length of the vals arg. However, vals may be empty, in
+// which case commas must also be empty.
+func NewArrayLiteralNode(openBracket *RuneNode, vals []ValueNode, commas []*RuneNode, closeBracket *RuneNode) *ArrayLiteralNode {
+ if openBracket == nil {
+ panic("openBracket is nil")
+ }
+ if closeBracket == nil {
+ panic("closeBracket is nil")
+ }
+ if len(vals) == 0 && len(commas) != 0 {
+ panic("vals is empty but commas is not")
+ }
+ if len(vals) > 0 && len(commas) != len(vals)-1 {
+ panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals)-1, len(commas)))
+ }
+ children := make([]Node, 0, len(vals)*2+1)
+ children = append(children, openBracket)
+ for i, val := range vals {
+ if i > 0 {
+ if commas[i-1] == nil {
+ panic(fmt.Sprintf("commas[%d] is nil", i-1))
+ }
+ children = append(children, commas[i-1])
+ }
+ if val == nil {
+ panic(fmt.Sprintf("vals[%d] is nil", i))
+ }
+ children = append(children, val)
+ }
+ children = append(children, closeBracket)
+
+ return &ArrayLiteralNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ OpenBracket: openBracket,
+ Elements: vals,
+ Commas: commas,
+ CloseBracket: closeBracket,
+ }
+}
+
+func (n *ArrayLiteralNode) Value() interface{} {
+ return n.Elements
+}
+
+// MessageLiteralNode represents a message literal, which is compatible with the
+// protobuf text format and can be used for custom options with message types.
+// Example:
+//
+// { foo:1 foo:2 foo:3 bar:<name:"abc" id:123> }
+type MessageLiteralNode struct {
+ compositeNode
+ Open *RuneNode // should be '{' or '<'
+ Elements []*MessageFieldNode
+ // Separator characters between elements, which can be either ','
+ // or ';' if present. This slice must be exactly len(Elements) in
+ // length, with each item in Elements having one corresponding item
+ // in Seps. Separators in message literals are optional, so a given
+ // item in this slice may be nil to indicate absence of a separator.
+ Seps []*RuneNode
+ Close *RuneNode // should be '}' or '>', depending on Open
+}
+
+// NewMessageLiteralNode creates a new *MessageLiteralNode. The openSym and
+// closeSym runes must not be nil and should be "{" and "}" or "<" and ">".
+//
+// Unlike separators (dots and commas) used for other AST nodes that represent
+// a list of elements, the seps arg must be the SAME length as vals, and it may
+// contain nil values to indicate absence of a separator (in fact, it could be
+// all nils).
+func NewMessageLiteralNode(openSym *RuneNode, vals []*MessageFieldNode, seps []*RuneNode, closeSym *RuneNode) *MessageLiteralNode {
+ if openSym == nil {
+ panic("openSym is nil")
+ }
+ if closeSym == nil {
+ panic("closeSym is nil")
+ }
+ if len(seps) != len(vals) {
+ panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals), len(seps)))
+ }
+ numChildren := len(vals) + 2
+ for _, sep := range seps {
+ if sep != nil {
+ numChildren++
+ }
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, openSym)
+ for i, val := range vals {
+ if val == nil {
+ panic(fmt.Sprintf("vals[%d] is nil", i))
+ }
+ children = append(children, val)
+ if seps[i] != nil {
+ children = append(children, seps[i])
+ }
+ }
+ children = append(children, closeSym)
+
+ return &MessageLiteralNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Open: openSym,
+ Elements: vals,
+ Seps: seps,
+ Close: closeSym,
+ }
+}
+
+func (n *MessageLiteralNode) Value() interface{} {
+ return n.Elements
+}
+
+// MessageFieldNode represents a single field (name and value) inside of a
+// message literal. Example:
+//
+// foo:"bar"
+type MessageFieldNode struct {
+ compositeNode
+ Name *FieldReferenceNode
+ // Sep represents the ':' separator between the name and value. If
+ // the value is a message or list literal (and thus starts with '<',
+ // '{', or '['), then the separator may be omitted and this field may
+ // be nil.
+ Sep *RuneNode
+ Val ValueNode
+}
+
+// NewMessageFieldNode creates a new *MessageFieldNode. All args except sep
+// must be non-nil.
+func NewMessageFieldNode(name *FieldReferenceNode, sep *RuneNode, val ValueNode) *MessageFieldNode {
+ if name == nil {
+ panic("name is nil")
+ }
+ if val == nil {
+ panic("val is nil")
+ }
+ numChildren := 2
+ if sep != nil {
+ numChildren++
+ }
+ children := make([]Node, 0, numChildren)
+ children = append(children, name)
+ if sep != nil {
+ children = append(children, sep)
+ }
+ children = append(children, val)
+
+ return &MessageFieldNode{
+ compositeNode: compositeNode{
+ children: children,
+ },
+ Name: name,
+ Sep: sep,
+ Val: val,
+ }
+}
diff --git a/vendor/github.com/bufbuild/protocompile/ast/walk.go b/vendor/github.com/bufbuild/protocompile/ast/walk.go
new file mode 100644
index 0000000..00e71ab
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/ast/walk.go
@@ -0,0 +1,931 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "fmt"
+
+// Walk conducts a walk of the AST rooted at the given root using the
+// given visitor. It performs a "pre-order traversal", visiting a
+// given AST node before it visits that node's descendants.
+//
+// If a visitor returns an error while walking the tree, the entire
+// operation is aborted and that error is returned.
+func Walk(root Node, v Visitor, opts ...WalkOption) error {
+ var wOpts walkOptions
+ for _, opt := range opts {
+ opt(&wOpts)
+ }
+ return walk(root, v, wOpts)
+}
+
+// WalkOption represents an option used with the Walk function. These
+// allow optional before and after hooks to be invoked as each node in
+// the tree is visited.
+type WalkOption func(*walkOptions)
+
+type walkOptions struct {
+ before, after func(Node) error
+}
+
+// WithBefore returns a WalkOption that will cause the given function to be
+// invoked before a node is visited during a walk operation. If this hook
+// returns an error, the node is not visited and the walk operation is aborted.
+func WithBefore(fn func(Node) error) WalkOption {
+ return func(options *walkOptions) {
+ options.before = fn
+ }
+}
+
+// WithAfter returns a WalkOption that will cause the given function to be
+// invoked after a node (as well as any descendants) is visited during a walk
+// operation. If this hook returns an error, the node is not visited and the
+// walk operation is aborted.
+//
+// If the walk is aborted due to some other visitor or before hook returning an
+// error, the after hook is still called for all nodes that have been visited.
+// However, the walk operation fails with the first error it encountered, so any
+// error returned from an after hook is effectively ignored.
+func WithAfter(fn func(Node) error) WalkOption {
+ return func(options *walkOptions) {
+ options.after = fn
+ }
+}
+
+func walk(root Node, v Visitor, opts walkOptions) (err error) {
+ if opts.before != nil {
+ if err := opts.before(root); err != nil {
+ return err
+ }
+ }
+ if opts.after != nil {
+ defer func() {
+ if afterErr := opts.after(root); afterErr != nil {
+ // if another call already returned an error then we
+ // have to ignore the error from the after hook
+ if err == nil {
+ err = afterErr
+ }
+ }
+ }()
+ }
+
+ if err := Visit(root, v); err != nil {
+ return err
+ }
+
+ if comp, ok := root.(CompositeNode); ok {
+ for _, child := range comp.Children() {
+ if err := walk(child, v, opts); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// Visit implements the double-dispatch idiom and visits the given node by
+// calling the appropriate method of the given visitor.
+func Visit(n Node, v Visitor) error {
+ switch n := n.(type) {
+ case *FileNode:
+ return v.VisitFileNode(n)
+ case *SyntaxNode:
+ return v.VisitSyntaxNode(n)
+ case *EditionNode:
+ return v.VisitEditionNode(n)
+ case *PackageNode:
+ return v.VisitPackageNode(n)
+ case *ImportNode:
+ return v.VisitImportNode(n)
+ case *OptionNode:
+ return v.VisitOptionNode(n)
+ case *OptionNameNode:
+ return v.VisitOptionNameNode(n)
+ case *FieldReferenceNode:
+ return v.VisitFieldReferenceNode(n)
+ case *CompactOptionsNode:
+ return v.VisitCompactOptionsNode(n)
+ case *MessageNode:
+ return v.VisitMessageNode(n)
+ case *ExtendNode:
+ return v.VisitExtendNode(n)
+ case *ExtensionRangeNode:
+ return v.VisitExtensionRangeNode(n)
+ case *ReservedNode:
+ return v.VisitReservedNode(n)
+ case *RangeNode:
+ return v.VisitRangeNode(n)
+ case *FieldNode:
+ return v.VisitFieldNode(n)
+ case *GroupNode:
+ return v.VisitGroupNode(n)
+ case *MapFieldNode:
+ return v.VisitMapFieldNode(n)
+ case *MapTypeNode:
+ return v.VisitMapTypeNode(n)
+ case *OneofNode:
+ return v.VisitOneofNode(n)
+ case *EnumNode:
+ return v.VisitEnumNode(n)
+ case *EnumValueNode:
+ return v.VisitEnumValueNode(n)
+ case *ServiceNode:
+ return v.VisitServiceNode(n)
+ case *RPCNode:
+ return v.VisitRPCNode(n)
+ case *RPCTypeNode:
+ return v.VisitRPCTypeNode(n)
+ case *IdentNode:
+ return v.VisitIdentNode(n)
+ case *CompoundIdentNode:
+ return v.VisitCompoundIdentNode(n)
+ case *StringLiteralNode:
+ return v.VisitStringLiteralNode(n)
+ case *CompoundStringLiteralNode:
+ return v.VisitCompoundStringLiteralNode(n)
+ case *UintLiteralNode:
+ return v.VisitUintLiteralNode(n)
+ case *NegativeIntLiteralNode:
+ return v.VisitNegativeIntLiteralNode(n)
+ case *FloatLiteralNode:
+ return v.VisitFloatLiteralNode(n)
+ case *SpecialFloatLiteralNode:
+ return v.VisitSpecialFloatLiteralNode(n)
+ case *SignedFloatLiteralNode:
+ return v.VisitSignedFloatLiteralNode(n)
+ case *ArrayLiteralNode:
+ return v.VisitArrayLiteralNode(n)
+ case *MessageLiteralNode:
+ return v.VisitMessageLiteralNode(n)
+ case *MessageFieldNode:
+ return v.VisitMessageFieldNode(n)
+ case *KeywordNode:
+ return v.VisitKeywordNode(n)
+ case *RuneNode:
+ return v.VisitRuneNode(n)
+ case *EmptyDeclNode:
+ return v.VisitEmptyDeclNode(n)
+ default:
+ panic(fmt.Sprintf("unexpected type of node: %T", n))
+ }
+}
+
+// AncestorTracker is used to track the path of nodes during a walk operation.
+// By passing AsWalkOptions to a call to Walk, a visitor can inspect the path to
+// the node being visited using this tracker.
+type AncestorTracker struct {
+ ancestors []Node
+}
+
+// AsWalkOptions returns WalkOption values that will cause this ancestor tracker
+// to track the path through the AST during the walk operation.
+func (t *AncestorTracker) AsWalkOptions() []WalkOption {
+ return []WalkOption{
+ WithBefore(func(n Node) error {
+ t.ancestors = append(t.ancestors, n)
+ return nil
+ }),
+ WithAfter(func(_ Node) error {
+ t.ancestors = t.ancestors[:len(t.ancestors)-1]
+ return nil
+ }),
+ }
+}
+
+// Path returns a slice of nodes that represents the path from the root of the
+// walk operaiton to the currently visited node. The first element in the path
+// is the root supplied to Walk. The last element in the path is the currently
+// visited node.
+//
+// The returned slice is not a defensive copy; so callers should NOT mutate it.
+func (t *AncestorTracker) Path() []Node {
+ return t.ancestors
+}
+
+// Parent returns the parent node of the currently visited node. If the node
+// currently being visited is the root supplied to Walk then nil is returned.
+func (t *AncestorTracker) Parent() Node {
+ if len(t.ancestors) <= 1 {
+ return nil
+ }
+ return t.ancestors[len(t.ancestors)-2]
+}
+
+// VisitChildren visits all direct children of the given node using the given
+// visitor. If visiting a child returns an error, that error is immediately
+// returned, and other children will not be visited.
+func VisitChildren(n CompositeNode, v Visitor) error {
+ for _, ch := range n.Children() {
+ if err := Visit(ch, v); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Visitor provides a technique for walking the AST that allows for
+// dynamic dispatch, where a particular function is invoked based on
+// the runtime type of the argument.
+//
+// It consists of a number of functions, each of which matches a
+// concrete Node type.
+//
+// NOTE: As the language evolves, new methods may be added to this
+// interface to correspond to new grammar elements. That is why it
+// cannot be directly implemented outside this package. Visitor
+// implementations must embed NoOpVisitor and then implement the
+// subset of methods of interest. If such an implementation is used
+// with an AST that has newer elements, the visitor will not do
+// anything in response to the new node types.
+//
+// An alternative to embedding NoOpVisitor is to use an instance of
+// SimpleVisitor.
+//
+// Visitors can be supplied to a Walk operation or passed to a call
+// to Visit or VisitChildren.
+//
+// Note that there are some AST node types defined in this package
+// that do not have corresponding visit methods. These are synthetic
+// node types, that have specialized use from the parser, but never
+// appear in an actual AST (which is always rooted at FileNode).
+// These include SyntheticMapField, SyntheticOneof,
+// SyntheticGroupMessageNode, and SyntheticMapEntryNode.
+type Visitor interface {
+ // VisitFileNode is invoked when visiting a *FileNode in the AST.
+ VisitFileNode(*FileNode) error
+ // VisitSyntaxNode is invoked when visiting a *SyntaxNode in the AST.
+ VisitSyntaxNode(*SyntaxNode) error
+ // VisitEditionNode is invoked when visiting an *EditionNode in the AST.
+ VisitEditionNode(*EditionNode) error
+ // VisitPackageNode is invoked when visiting a *PackageNode in the AST.
+ VisitPackageNode(*PackageNode) error
+ // VisitImportNode is invoked when visiting an *ImportNode in the AST.
+ VisitImportNode(*ImportNode) error
+ // VisitOptionNode is invoked when visiting an *OptionNode in the AST.
+ VisitOptionNode(*OptionNode) error
+ // VisitOptionNameNode is invoked when visiting an *OptionNameNode in the AST.
+ VisitOptionNameNode(*OptionNameNode) error
+ // VisitFieldReferenceNode is invoked when visiting a *FieldReferenceNode in the AST.
+ VisitFieldReferenceNode(*FieldReferenceNode) error
+ // VisitCompactOptionsNode is invoked when visiting a *CompactOptionsNode in the AST.
+ VisitCompactOptionsNode(*CompactOptionsNode) error
+ // VisitMessageNode is invoked when visiting a *MessageNode in the AST.
+ VisitMessageNode(*MessageNode) error
+ // VisitExtendNode is invoked when visiting an *ExtendNode in the AST.
+ VisitExtendNode(*ExtendNode) error
+ // VisitExtensionRangeNode is invoked when visiting an *ExtensionRangeNode in the AST.
+ VisitExtensionRangeNode(*ExtensionRangeNode) error
+ // VisitReservedNode is invoked when visiting a *ReservedNode in the AST.
+ VisitReservedNode(*ReservedNode) error
+ // VisitRangeNode is invoked when visiting a *RangeNode in the AST.
+ VisitRangeNode(*RangeNode) error
+ // VisitFieldNode is invoked when visiting a *FieldNode in the AST.
+ VisitFieldNode(*FieldNode) error
+ // VisitGroupNode is invoked when visiting a *GroupNode in the AST.
+ VisitGroupNode(*GroupNode) error
+ // VisitMapFieldNode is invoked when visiting a *MapFieldNode in the AST.
+ VisitMapFieldNode(*MapFieldNode) error
+ // VisitMapTypeNode is invoked when visiting a *MapTypeNode in the AST.
+ VisitMapTypeNode(*MapTypeNode) error
+ // VisitOneofNode is invoked when visiting a *OneofNode in the AST.
+ VisitOneofNode(*OneofNode) error
+ // VisitEnumNode is invoked when visiting an *EnumNode in the AST.
+ VisitEnumNode(*EnumNode) error
+ // VisitEnumValueNode is invoked when visiting an *EnumValueNode in the AST.
+ VisitEnumValueNode(*EnumValueNode) error
+ // VisitServiceNode is invoked when visiting a *ServiceNode in the AST.
+ VisitServiceNode(*ServiceNode) error
+ // VisitRPCNode is invoked when visiting an *RPCNode in the AST.
+ VisitRPCNode(*RPCNode) error
+ // VisitRPCTypeNode is invoked when visiting an *RPCTypeNode in the AST.
+ VisitRPCTypeNode(*RPCTypeNode) error
+ // VisitIdentNode is invoked when visiting an *IdentNode in the AST.
+ VisitIdentNode(*IdentNode) error
+ // VisitCompoundIdentNode is invoked when visiting a *CompoundIdentNode in the AST.
+ VisitCompoundIdentNode(*CompoundIdentNode) error
+ // VisitStringLiteralNode is invoked when visiting a *StringLiteralNode in the AST.
+ VisitStringLiteralNode(*StringLiteralNode) error
+ // VisitCompoundStringLiteralNode is invoked when visiting a *CompoundStringLiteralNode in the AST.
+ VisitCompoundStringLiteralNode(*CompoundStringLiteralNode) error
+ // VisitUintLiteralNode is invoked when visiting a *UintLiteralNode in the AST.
+ VisitUintLiteralNode(*UintLiteralNode) error
+ // VisitNegativeIntLiteralNode is invoked when visiting a *NegativeIntLiteralNode in the AST.
+ VisitNegativeIntLiteralNode(*NegativeIntLiteralNode) error
+ // VisitFloatLiteralNode is invoked when visiting a *FloatLiteralNode in the AST.
+ VisitFloatLiteralNode(*FloatLiteralNode) error
+ // VisitSpecialFloatLiteralNode is invoked when visiting a *SpecialFloatLiteralNode in the AST.
+ VisitSpecialFloatLiteralNode(*SpecialFloatLiteralNode) error
+ // VisitSignedFloatLiteralNode is invoked when visiting a *SignedFloatLiteralNode in the AST.
+ VisitSignedFloatLiteralNode(*SignedFloatLiteralNode) error
+ // VisitArrayLiteralNode is invoked when visiting an *ArrayLiteralNode in the AST.
+ VisitArrayLiteralNode(*ArrayLiteralNode) error
+ // VisitMessageLiteralNode is invoked when visiting a *MessageLiteralNode in the AST.
+ VisitMessageLiteralNode(*MessageLiteralNode) error
+ // VisitMessageFieldNode is invoked when visiting a *MessageFieldNode in the AST.
+ VisitMessageFieldNode(*MessageFieldNode) error
+ // VisitKeywordNode is invoked when visiting a *KeywordNode in the AST.
+ VisitKeywordNode(*KeywordNode) error
+ // VisitRuneNode is invoked when visiting a *RuneNode in the AST.
+ VisitRuneNode(*RuneNode) error
+ // VisitEmptyDeclNode is invoked when visiting a *EmptyDeclNode in the AST.
+ VisitEmptyDeclNode(*EmptyDeclNode) error
+
+ // Unexported method prevents callers from directly implementing.
+ isVisitor()
+}
+
+// NoOpVisitor is a visitor implementation that does nothing. All methods
+// unconditionally return nil. This can be embedded into a struct to make that
+// struct implement the Visitor interface, and only the relevant visit methods
+// then need to be implemented on the struct.
+type NoOpVisitor struct{}
+
+var _ Visitor = NoOpVisitor{}
+
+func (n NoOpVisitor) isVisitor() {}
+
+func (n NoOpVisitor) VisitFileNode(_ *FileNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitSyntaxNode(_ *SyntaxNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitEditionNode(_ *EditionNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitPackageNode(_ *PackageNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitImportNode(_ *ImportNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitOptionNode(_ *OptionNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitOptionNameNode(_ *OptionNameNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitFieldReferenceNode(_ *FieldReferenceNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitCompactOptionsNode(_ *CompactOptionsNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitMessageNode(_ *MessageNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitExtendNode(_ *ExtendNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitExtensionRangeNode(_ *ExtensionRangeNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitReservedNode(_ *ReservedNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitRangeNode(_ *RangeNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitFieldNode(_ *FieldNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitGroupNode(_ *GroupNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitMapFieldNode(_ *MapFieldNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitMapTypeNode(_ *MapTypeNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitOneofNode(_ *OneofNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitEnumNode(_ *EnumNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitEnumValueNode(_ *EnumValueNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitServiceNode(_ *ServiceNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitRPCNode(_ *RPCNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitRPCTypeNode(_ *RPCTypeNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitIdentNode(_ *IdentNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitCompoundIdentNode(_ *CompoundIdentNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitStringLiteralNode(_ *StringLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitCompoundStringLiteralNode(_ *CompoundStringLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitUintLiteralNode(_ *UintLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitNegativeIntLiteralNode(_ *NegativeIntLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitFloatLiteralNode(_ *FloatLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitSpecialFloatLiteralNode(_ *SpecialFloatLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitSignedFloatLiteralNode(_ *SignedFloatLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitArrayLiteralNode(_ *ArrayLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitMessageLiteralNode(_ *MessageLiteralNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitMessageFieldNode(_ *MessageFieldNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitKeywordNode(_ *KeywordNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitRuneNode(_ *RuneNode) error {
+ return nil
+}
+
+func (n NoOpVisitor) VisitEmptyDeclNode(_ *EmptyDeclNode) error {
+ return nil
+}
+
+// SimpleVisitor is a visitor implementation that uses numerous function fields.
+// If a relevant function field is not nil, then it will be invoked when a node
+// is visited.
+//
+// In addition to a function for each concrete node type (and thus for each
+// Visit* method of the Visitor interface), it also has function fields that
+// accept interface types. So a visitor can, for example, easily treat all
+// ValueNodes uniformly by providing a non-nil value for DoVisitValueNode
+// instead of having to supply values for the various DoVisit*Node methods
+// corresponding to all types that implement ValueNode.
+//
+// The most specific function provided that matches a given node is the one that
+// will be invoked. For example, DoVisitStringValueNode will be called if
+// present and applicable before DoVisitValueNode. Similarly, DoVisitValueNode
+// would be called before DoVisitTerminalNode or DoVisitCompositeNode. The
+// DoVisitNode is the most generic function and is called only if no more
+// specific function is present for a given node type.
+//
+// The *UintLiteralNode type implements both IntValueNode and FloatValueNode.
+// In this case, the DoVisitIntValueNode function is considered more specific
+// than DoVisitFloatValueNode, so will be preferred if present.
+//
+// Similarly, *MapFieldNode and *GroupNode implement both FieldDeclNode and
+// MessageDeclNode. In this case, the DoVisitFieldDeclNode function is
+// treated as more specific than DoVisitMessageDeclNode, so will be preferred
+// if both are present.
+type SimpleVisitor struct {
+ DoVisitFileNode func(*FileNode) error
+ DoVisitSyntaxNode func(*SyntaxNode) error
+ DoVisitEditionNode func(*EditionNode) error
+ DoVisitPackageNode func(*PackageNode) error
+ DoVisitImportNode func(*ImportNode) error
+ DoVisitOptionNode func(*OptionNode) error
+ DoVisitOptionNameNode func(*OptionNameNode) error
+ DoVisitFieldReferenceNode func(*FieldReferenceNode) error
+ DoVisitCompactOptionsNode func(*CompactOptionsNode) error
+ DoVisitMessageNode func(*MessageNode) error
+ DoVisitExtendNode func(*ExtendNode) error
+ DoVisitExtensionRangeNode func(*ExtensionRangeNode) error
+ DoVisitReservedNode func(*ReservedNode) error
+ DoVisitRangeNode func(*RangeNode) error
+ DoVisitFieldNode func(*FieldNode) error
+ DoVisitGroupNode func(*GroupNode) error
+ DoVisitMapFieldNode func(*MapFieldNode) error
+ DoVisitMapTypeNode func(*MapTypeNode) error
+ DoVisitOneofNode func(*OneofNode) error
+ DoVisitEnumNode func(*EnumNode) error
+ DoVisitEnumValueNode func(*EnumValueNode) error
+ DoVisitServiceNode func(*ServiceNode) error
+ DoVisitRPCNode func(*RPCNode) error
+ DoVisitRPCTypeNode func(*RPCTypeNode) error
+ DoVisitIdentNode func(*IdentNode) error
+ DoVisitCompoundIdentNode func(*CompoundIdentNode) error
+ DoVisitStringLiteralNode func(*StringLiteralNode) error
+ DoVisitCompoundStringLiteralNode func(*CompoundStringLiteralNode) error
+ DoVisitUintLiteralNode func(*UintLiteralNode) error
+ DoVisitNegativeIntLiteralNode func(*NegativeIntLiteralNode) error
+ DoVisitFloatLiteralNode func(*FloatLiteralNode) error
+ DoVisitSpecialFloatLiteralNode func(*SpecialFloatLiteralNode) error
+ DoVisitSignedFloatLiteralNode func(*SignedFloatLiteralNode) error
+ DoVisitArrayLiteralNode func(*ArrayLiteralNode) error
+ DoVisitMessageLiteralNode func(*MessageLiteralNode) error
+ DoVisitMessageFieldNode func(*MessageFieldNode) error
+ DoVisitKeywordNode func(*KeywordNode) error
+ DoVisitRuneNode func(*RuneNode) error
+ DoVisitEmptyDeclNode func(*EmptyDeclNode) error
+
+ DoVisitFieldDeclNode func(FieldDeclNode) error
+ DoVisitMessageDeclNode func(MessageDeclNode) error
+
+ DoVisitIdentValueNode func(IdentValueNode) error
+ DoVisitStringValueNode func(StringValueNode) error
+ DoVisitIntValueNode func(IntValueNode) error
+ DoVisitFloatValueNode func(FloatValueNode) error
+ DoVisitValueNode func(ValueNode) error
+
+ DoVisitTerminalNode func(TerminalNode) error
+ DoVisitCompositeNode func(CompositeNode) error
+ DoVisitNode func(Node) error
+}
+
+var _ Visitor = (*SimpleVisitor)(nil)
+
+func (v *SimpleVisitor) isVisitor() {}
+
+func (v *SimpleVisitor) visitInterface(node Node) error {
+ switch n := node.(type) {
+ case FieldDeclNode:
+ if v.DoVisitFieldDeclNode != nil {
+ return v.DoVisitFieldDeclNode(n)
+ }
+ // *MapFieldNode and *GroupNode both implement both FieldDeclNode and
+ // MessageDeclNode, so handle other case here
+ if fn, ok := n.(MessageDeclNode); ok && v.DoVisitMessageDeclNode != nil {
+ return v.DoVisitMessageDeclNode(fn)
+ }
+ case MessageDeclNode:
+ if v.DoVisitMessageDeclNode != nil {
+ return v.DoVisitMessageDeclNode(n)
+ }
+ case IdentValueNode:
+ if v.DoVisitIdentValueNode != nil {
+ return v.DoVisitIdentValueNode(n)
+ }
+ case StringValueNode:
+ if v.DoVisitStringValueNode != nil {
+ return v.DoVisitStringValueNode(n)
+ }
+ case IntValueNode:
+ if v.DoVisitIntValueNode != nil {
+ return v.DoVisitIntValueNode(n)
+ }
+ // *UintLiteralNode implements both IntValueNode and FloatValueNode,
+ // so handle other case here
+ if fn, ok := n.(FloatValueNode); ok && v.DoVisitFloatValueNode != nil {
+ return v.DoVisitFloatValueNode(fn)
+ }
+ case FloatValueNode:
+ if v.DoVisitFloatValueNode != nil {
+ return v.DoVisitFloatValueNode(n)
+ }
+ }
+
+ if n, ok := node.(ValueNode); ok && v.DoVisitValueNode != nil {
+ return v.DoVisitValueNode(n)
+ }
+
+ switch n := node.(type) {
+ case TerminalNode:
+ if v.DoVisitTerminalNode != nil {
+ return v.DoVisitTerminalNode(n)
+ }
+ case CompositeNode:
+ if v.DoVisitCompositeNode != nil {
+ return v.DoVisitCompositeNode(n)
+ }
+ }
+
+ if v.DoVisitNode != nil {
+ return v.DoVisitNode(node)
+ }
+
+ return nil
+}
+
+func (v *SimpleVisitor) VisitFileNode(node *FileNode) error {
+ if v.DoVisitFileNode != nil {
+ return v.DoVisitFileNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitSyntaxNode(node *SyntaxNode) error {
+ if v.DoVisitSyntaxNode != nil {
+ return v.DoVisitSyntaxNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitEditionNode(node *EditionNode) error {
+ if v.DoVisitEditionNode != nil {
+ return v.DoVisitEditionNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitPackageNode(node *PackageNode) error {
+ if v.DoVisitPackageNode != nil {
+ return v.DoVisitPackageNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitImportNode(node *ImportNode) error {
+ if v.DoVisitImportNode != nil {
+ return v.DoVisitImportNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitOptionNode(node *OptionNode) error {
+ if v.DoVisitOptionNode != nil {
+ return v.DoVisitOptionNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitOptionNameNode(node *OptionNameNode) error {
+ if v.DoVisitOptionNameNode != nil {
+ return v.DoVisitOptionNameNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitFieldReferenceNode(node *FieldReferenceNode) error {
+ if v.DoVisitFieldReferenceNode != nil {
+ return v.DoVisitFieldReferenceNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitCompactOptionsNode(node *CompactOptionsNode) error {
+ if v.DoVisitCompactOptionsNode != nil {
+ return v.DoVisitCompactOptionsNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitMessageNode(node *MessageNode) error {
+ if v.DoVisitMessageNode != nil {
+ return v.DoVisitMessageNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitExtendNode(node *ExtendNode) error {
+ if v.DoVisitExtendNode != nil {
+ return v.DoVisitExtendNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitExtensionRangeNode(node *ExtensionRangeNode) error {
+ if v.DoVisitExtensionRangeNode != nil {
+ return v.DoVisitExtensionRangeNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitReservedNode(node *ReservedNode) error {
+ if v.DoVisitReservedNode != nil {
+ return v.DoVisitReservedNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitRangeNode(node *RangeNode) error {
+ if v.DoVisitRangeNode != nil {
+ return v.DoVisitRangeNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitFieldNode(node *FieldNode) error {
+ if v.DoVisitFieldNode != nil {
+ return v.DoVisitFieldNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitGroupNode(node *GroupNode) error {
+ if v.DoVisitGroupNode != nil {
+ return v.DoVisitGroupNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitMapFieldNode(node *MapFieldNode) error {
+ if v.DoVisitMapFieldNode != nil {
+ return v.DoVisitMapFieldNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitMapTypeNode(node *MapTypeNode) error {
+ if v.DoVisitMapTypeNode != nil {
+ return v.DoVisitMapTypeNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitOneofNode(node *OneofNode) error {
+ if v.DoVisitOneofNode != nil {
+ return v.DoVisitOneofNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitEnumNode(node *EnumNode) error {
+ if v.DoVisitEnumNode != nil {
+ return v.DoVisitEnumNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitEnumValueNode(node *EnumValueNode) error {
+ if v.DoVisitEnumValueNode != nil {
+ return v.DoVisitEnumValueNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitServiceNode(node *ServiceNode) error {
+ if v.DoVisitServiceNode != nil {
+ return v.DoVisitServiceNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitRPCNode(node *RPCNode) error {
+ if v.DoVisitRPCNode != nil {
+ return v.DoVisitRPCNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitRPCTypeNode(node *RPCTypeNode) error {
+ if v.DoVisitRPCTypeNode != nil {
+ return v.DoVisitRPCTypeNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitIdentNode(node *IdentNode) error {
+ if v.DoVisitIdentNode != nil {
+ return v.DoVisitIdentNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitCompoundIdentNode(node *CompoundIdentNode) error {
+ if v.DoVisitCompoundIdentNode != nil {
+ return v.DoVisitCompoundIdentNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitStringLiteralNode(node *StringLiteralNode) error {
+ if v.DoVisitStringLiteralNode != nil {
+ return v.DoVisitStringLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitCompoundStringLiteralNode(node *CompoundStringLiteralNode) error {
+ if v.DoVisitCompoundStringLiteralNode != nil {
+ return v.DoVisitCompoundStringLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitUintLiteralNode(node *UintLiteralNode) error {
+ if v.DoVisitUintLiteralNode != nil {
+ return v.DoVisitUintLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitNegativeIntLiteralNode(node *NegativeIntLiteralNode) error {
+ if v.DoVisitNegativeIntLiteralNode != nil {
+ return v.DoVisitNegativeIntLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitFloatLiteralNode(node *FloatLiteralNode) error {
+ if v.DoVisitFloatLiteralNode != nil {
+ return v.DoVisitFloatLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitSpecialFloatLiteralNode(node *SpecialFloatLiteralNode) error {
+ if v.DoVisitSpecialFloatLiteralNode != nil {
+ return v.DoVisitSpecialFloatLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitSignedFloatLiteralNode(node *SignedFloatLiteralNode) error {
+ if v.DoVisitSignedFloatLiteralNode != nil {
+ return v.DoVisitSignedFloatLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitArrayLiteralNode(node *ArrayLiteralNode) error {
+ if v.DoVisitArrayLiteralNode != nil {
+ return v.DoVisitArrayLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitMessageLiteralNode(node *MessageLiteralNode) error {
+ if v.DoVisitMessageLiteralNode != nil {
+ return v.DoVisitMessageLiteralNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitMessageFieldNode(node *MessageFieldNode) error {
+ if v.DoVisitMessageFieldNode != nil {
+ return v.DoVisitMessageFieldNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitKeywordNode(node *KeywordNode) error {
+ if v.DoVisitKeywordNode != nil {
+ return v.DoVisitKeywordNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitRuneNode(node *RuneNode) error {
+ if v.DoVisitRuneNode != nil {
+ return v.DoVisitRuneNode(node)
+ }
+ return v.visitInterface(node)
+}
+
+func (v *SimpleVisitor) VisitEmptyDeclNode(node *EmptyDeclNode) error {
+ if v.DoVisitEmptyDeclNode != nil {
+ return v.DoVisitEmptyDeclNode(node)
+ }
+ return v.visitInterface(node)
+}