github.com/bakjos/protoreflect@v1.9.2/desc/protoparse/ast/options.go (about)

     1  package ast
     2  
     3  import "fmt"
     4  
     5  // OptionDeclNode is a placeholder interface for AST nodes that represent
     6  // options. This allows NoSourceNode to be used in place of *OptionNode
     7  // for some usages.
     8  type OptionDeclNode interface {
     9  	Node
    10  	GetName() Node
    11  	GetValue() ValueNode
    12  }
    13  
    14  var _ OptionDeclNode = (*OptionNode)(nil)
    15  var _ OptionDeclNode = NoSourceNode{}
    16  
    17  // OptionNode represents the declaration of a single option for an element.
    18  // It is used both for normal option declarations (start with "option" keyword
    19  // and end with semicolon) and for compact options found in fields, enum values,
    20  // and extension ranges. Example:
    21  //
    22  //  option (custom.option) = "foo";
    23  type OptionNode struct {
    24  	compositeNode
    25  	Keyword   *KeywordNode // absent for compact options
    26  	Name      *OptionNameNode
    27  	Equals    *RuneNode
    28  	Val       ValueNode
    29  	Semicolon *RuneNode // absent for compact options
    30  }
    31  
    32  func (e *OptionNode) fileElement()    {}
    33  func (e *OptionNode) msgElement()     {}
    34  func (e *OptionNode) oneOfElement()   {}
    35  func (e *OptionNode) enumElement()    {}
    36  func (e *OptionNode) serviceElement() {}
    37  func (e *OptionNode) methodElement()  {}
    38  
    39  // NewOptionNode creates a new *OptionNode for a full option declaration (as
    40  // used in files, messages, oneofs, enums, services, and methods). All arguments
    41  // must be non-nil. (Also see NewCompactOptionNode.)
    42  //  - keyword: The token corresponding to the "option" keyword.
    43  //  - name: The token corresponding to the name of the option.
    44  //  - equals: The token corresponding to the "=" rune after the name.
    45  //  - val: The token corresponding to the option value.
    46  //  - semicolon: The token corresponding to the ";" rune that ends the declaration.
    47  func NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, val ValueNode, semicolon *RuneNode) *OptionNode {
    48  	if keyword == nil {
    49  		panic("keyword is nil")
    50  	}
    51  	if name == nil {
    52  		panic("name is nil")
    53  	}
    54  	if equals == nil {
    55  		panic("equals is nil")
    56  	}
    57  	if val == nil {
    58  		panic("val is nil")
    59  	}
    60  	if semicolon == nil {
    61  		panic("semicolon is nil")
    62  	}
    63  	children := []Node{keyword, name, equals, val, semicolon}
    64  	return &OptionNode{
    65  		compositeNode: compositeNode{
    66  			children: children,
    67  		},
    68  		Keyword:   keyword,
    69  		Name:      name,
    70  		Equals:    equals,
    71  		Val:       val,
    72  		Semicolon: semicolon,
    73  	}
    74  }
    75  
    76  // NewCompactOptionNode creates a new *OptionNode for a full compact declaration
    77  // (as used in fields, enum values, and extension ranges). All arguments must be
    78  // non-nil.
    79  //  - name: The token corresponding to the name of the option.
    80  //  - equals: The token corresponding to the "=" rune after the name.
    81  //  - val: The token corresponding to the option value.
    82  func NewCompactOptionNode(name *OptionNameNode, equals *RuneNode, val ValueNode) *OptionNode {
    83  	if name == nil {
    84  		panic("name is nil")
    85  	}
    86  	if equals == nil {
    87  		panic("equals is nil")
    88  	}
    89  	if val == nil {
    90  		panic("val is nil")
    91  	}
    92  	children := []Node{name, equals, val}
    93  	return &OptionNode{
    94  		compositeNode: compositeNode{
    95  			children: children,
    96  		},
    97  		Name:   name,
    98  		Equals: equals,
    99  		Val:    val,
   100  	}
   101  }
   102  
   103  func (n *OptionNode) GetName() Node {
   104  	return n.Name
   105  }
   106  
   107  func (n *OptionNode) GetValue() ValueNode {
   108  	return n.Val
   109  }
   110  
   111  // OptionNameNode represents an option name or even a traversal through message
   112  // types to name a nested option field. Example:
   113  //
   114  //   (foo.bar).baz.(bob)
   115  type OptionNameNode struct {
   116  	compositeNode
   117  	Parts []*FieldReferenceNode
   118  	// Dots represent the separating '.' characters between name parts. The
   119  	// length of this slice must be exactly len(Parts)-1, each item in Parts
   120  	// having a corresponding item in this slice *except the last* (since a
   121  	// trailing dot is not allowed).
   122  	//
   123  	// These do *not* include dots that are inside of an extension name. For
   124  	// example: (foo.bar).baz.(bob) has three parts:
   125  	//    1. (foo.bar)  - an extension name
   126  	//    2. baz        - a regular field in foo.bar
   127  	//    3. (bob)      - an extension field in baz
   128  	// Note that the dot in foo.bar will thus not be present in Dots but is
   129  	// instead in Parts[0].
   130  	Dots []*RuneNode
   131  }
   132  
   133  // NewOptionNameNode creates a new *OptionNameNode. The dots arg must have a
   134  // length that is one less than the length of parts. The parts arg must not be
   135  // empty.
   136  func NewOptionNameNode(parts []*FieldReferenceNode, dots []*RuneNode) *OptionNameNode {
   137  	if len(parts) == 0 {
   138  		panic("must have at least one part")
   139  	}
   140  	if len(dots) != len(parts)-1 {
   141  		panic(fmt.Sprintf("%d parts requires %d dots, not %d", len(parts), len(parts)-1, len(dots)))
   142  	}
   143  	children := make([]Node, 0, len(parts)*2-1)
   144  	for i, part := range parts {
   145  		if part == nil {
   146  			panic(fmt.Sprintf("parts[%d] is nil", i))
   147  		}
   148  		if i > 0 {
   149  			if dots[i-1] == nil {
   150  				panic(fmt.Sprintf("dots[%d] is nil", i-1))
   151  			}
   152  			children = append(children, dots[i-1])
   153  		}
   154  		children = append(children, part)
   155  	}
   156  	return &OptionNameNode{
   157  		compositeNode: compositeNode{
   158  			children: children,
   159  		},
   160  		Parts: parts,
   161  		Dots:  dots,
   162  	}
   163  }
   164  
   165  // FieldReferenceNode is a reference to a field name. It can indicate a regular
   166  // field (simple unqualified name) or an extension field (possibly-qualified
   167  // name that is enclosed either in brackets or parentheses).
   168  //
   169  // This is used in options to indicate the names of custom options (which are
   170  // actually extensions), in which case the name is enclosed in parentheses "("
   171  // and ")". It is also used in message literals to set extension fields, in
   172  // which case the name is enclosed in square brackets "[" and "]".
   173  //
   174  // Example:
   175  //   (foo.bar)
   176  type FieldReferenceNode struct {
   177  	compositeNode
   178  	Open  *RuneNode // only present for extension names
   179  	Name  IdentValueNode
   180  	Close *RuneNode // only present for extension names
   181  }
   182  
   183  // NewFieldReferenceNode creates a new *FieldReferenceNode for a regular field.
   184  // The name arg must not be nil.
   185  func NewFieldReferenceNode(name *IdentNode) *FieldReferenceNode {
   186  	if name == nil {
   187  		panic("name is nil")
   188  	}
   189  	children := []Node{name}
   190  	return &FieldReferenceNode{
   191  		compositeNode: compositeNode{
   192  			children: children,
   193  		},
   194  		Name: name,
   195  	}
   196  }
   197  
   198  // NewExtensionFieldReferenceNode creates a new *FieldReferenceNode for an
   199  // extension field. All args must be non-nil. The openSym and closeSym runes
   200  // should be "(" and ")" or "[" and "]".
   201  func NewExtensionFieldReferenceNode(openSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode {
   202  	if name == nil {
   203  		panic("name is nil")
   204  	}
   205  	if openSym == nil {
   206  		panic("openSym is nil")
   207  	}
   208  	if closeSym == nil {
   209  		panic("closeSym is nil")
   210  	}
   211  	children := []Node{openSym, name, closeSym}
   212  	return &FieldReferenceNode{
   213  		compositeNode: compositeNode{
   214  			children: children,
   215  		},
   216  		Open:  openSym,
   217  		Name:  name,
   218  		Close: closeSym,
   219  	}
   220  }
   221  
   222  // IsExtension reports if this is an extension name or not (e.g. enclosed in
   223  // punctuation, such as parentheses or brackets).
   224  func (a *FieldReferenceNode) IsExtension() bool {
   225  	return a.Open != nil
   226  }
   227  
   228  func (a *FieldReferenceNode) Value() string {
   229  	if a.Open != nil {
   230  		return string(a.Open.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune)
   231  	} else {
   232  		return string(a.Name.AsIdentifier())
   233  	}
   234  }
   235  
   236  // CompactOptionsNode represents a compact options declaration, as used with
   237  // fields, enum values, and extension ranges. Example:
   238  //
   239  //  [deprecated = true, json_name = "foo_bar"]
   240  type CompactOptionsNode struct {
   241  	compositeNode
   242  	OpenBracket *RuneNode
   243  	Options     []*OptionNode
   244  	// Commas represent the separating ',' characters between options. The
   245  	// length of this slice must be exactly len(Options)-1, with each item
   246  	// in Options having a corresponding item in this slice *except the last*
   247  	// (since a trailing comma is not allowed).
   248  	Commas       []*RuneNode
   249  	CloseBracket *RuneNode
   250  }
   251  
   252  // NewCompactOptionsNode creates a *CompactOptionsNode. All args must be
   253  // non-nil. The commas arg must have a length that is one less than the
   254  // length of opts. The opts arg must not be empty.
   255  func NewCompactOptionsNode(openBracket *RuneNode, opts []*OptionNode, commas []*RuneNode, closeBracket *RuneNode) *CompactOptionsNode {
   256  	if openBracket == nil {
   257  		panic("openBracket is nil")
   258  	}
   259  	if closeBracket == nil {
   260  		panic("closeBracket is nil")
   261  	}
   262  	if len(opts) == 0 {
   263  		panic("must have at least one part")
   264  	}
   265  	if len(commas) != len(opts)-1 {
   266  		panic(fmt.Sprintf("%d opts requires %d commas, not %d", len(opts), len(opts)-1, len(commas)))
   267  	}
   268  	children := make([]Node, 0, len(opts)*2+1)
   269  	children = append(children, openBracket)
   270  	for i, opt := range opts {
   271  		if i > 0 {
   272  			if commas[i-1] == nil {
   273  				panic(fmt.Sprintf("commas[%d] is nil", i-1))
   274  			}
   275  			children = append(children, commas[i-1])
   276  		}
   277  		if opt == nil {
   278  			panic(fmt.Sprintf("opts[%d] is nil", i))
   279  		}
   280  		children = append(children, opt)
   281  	}
   282  	children = append(children, closeBracket)
   283  
   284  	return &CompactOptionsNode{
   285  		compositeNode: compositeNode{
   286  			children: children,
   287  		},
   288  		OpenBracket:  openBracket,
   289  		Options:      opts,
   290  		Commas:       commas,
   291  		CloseBracket: closeBracket,
   292  	}
   293  }
   294  
   295  func (e *CompactOptionsNode) GetElements() []*OptionNode {
   296  	if e == nil {
   297  		return nil
   298  	}
   299  	return e.Options
   300  }