summaryrefslogtreecommitdiff
path: root/vendor/github.com/bufbuild/protocompile/ast/options.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bufbuild/protocompile/ast/options.go')
-rw-r--r--vendor/github.com/bufbuild/protocompile/ast/options.go413
1 files changed, 413 insertions, 0 deletions
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)