github.com/jhump/protoreflect@v1.16.0/desc/protoparse/ast/ranges.go (about)

     1  package ast
     2  
     3  import "fmt"
     4  
     5  // ExtensionRangeNode represents an extension range declaration in an extendable
     6  // message. Example:
     7  //
     8  //	extensions 100 to max;
     9  type ExtensionRangeNode struct {
    10  	compositeNode
    11  	Keyword *KeywordNode
    12  	Ranges  []*RangeNode
    13  	// Commas represent the separating ',' characters between ranges. The
    14  	// length of this slice must be exactly len(Ranges)-1, each item in Ranges
    15  	// having a corresponding item in this slice *except the last* (since a
    16  	// trailing comma is not allowed).
    17  	Commas    []*RuneNode
    18  	Options   *CompactOptionsNode
    19  	Semicolon *RuneNode
    20  }
    21  
    22  func (e *ExtensionRangeNode) msgElement() {}
    23  
    24  // NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be
    25  // non-nil except opts, which may be nil.
    26  //   - keyword: The token corresponding to the "extends" keyword.
    27  //   - ranges: One or more range expressions.
    28  //   - commas: Tokens that represent the "," runes that delimit the range expressions.
    29  //     The length of commas must be one less than the length of ranges.
    30  //   - opts: The node corresponding to options that apply to each of the ranges.
    31  //   - semicolon The token corresponding to the ";" rune that ends the declaration.
    32  func NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, opts *CompactOptionsNode, semicolon *RuneNode) *ExtensionRangeNode {
    33  	if keyword == nil {
    34  		panic("keyword is nil")
    35  	}
    36  	if semicolon == nil {
    37  		panic("semicolon is nil")
    38  	}
    39  	if len(ranges) == 0 {
    40  		panic("must have at least one range")
    41  	}
    42  	if len(commas) != len(ranges)-1 {
    43  		panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas)))
    44  	}
    45  	numChildren := len(ranges)*2 + 1
    46  	if opts != nil {
    47  		numChildren++
    48  	}
    49  	children := make([]Node, 0, numChildren)
    50  	children = append(children, keyword)
    51  	for i, rng := range ranges {
    52  		if i > 0 {
    53  			if commas[i-1] == nil {
    54  				panic(fmt.Sprintf("commas[%d] is nil", i-1))
    55  			}
    56  			children = append(children, commas[i-1])
    57  		}
    58  		if rng == nil {
    59  			panic(fmt.Sprintf("ranges[%d] is nil", i))
    60  		}
    61  		children = append(children, rng)
    62  	}
    63  	if opts != nil {
    64  		children = append(children, opts)
    65  	}
    66  	children = append(children, semicolon)
    67  	return &ExtensionRangeNode{
    68  		compositeNode: compositeNode{
    69  			children: children,
    70  		},
    71  		Keyword:   keyword,
    72  		Ranges:    ranges,
    73  		Commas:    commas,
    74  		Options:   opts,
    75  		Semicolon: semicolon,
    76  	}
    77  }
    78  
    79  // RangeDeclNode is a placeholder interface for AST nodes that represent
    80  // numeric values. This allows NoSourceNode to be used in place of *RangeNode
    81  // for some usages.
    82  type RangeDeclNode interface {
    83  	Node
    84  	RangeStart() Node
    85  	RangeEnd() Node
    86  }
    87  
    88  var _ RangeDeclNode = (*RangeNode)(nil)
    89  var _ RangeDeclNode = NoSourceNode{}
    90  
    91  // RangeNode represents a range expression, used in both extension ranges and
    92  // reserved ranges. Example:
    93  //
    94  //	1000 to max
    95  type RangeNode struct {
    96  	compositeNode
    97  	StartVal IntValueNode
    98  	// if To is non-nil, then exactly one of EndVal or Max must also be non-nil
    99  	To *KeywordNode
   100  	// EndVal and Max are mutually exclusive
   101  	EndVal IntValueNode
   102  	Max    *KeywordNode
   103  }
   104  
   105  // NewRangeNode creates a new *RangeNode. The start argument must be non-nil.
   106  // The to argument represents the "to" keyword. If present (i.e. if it is non-nil),
   107  // then so must be exactly one of end or max. If max is non-nil, it indicates a
   108  // "100 to max" style range. But if end is non-nil, the end of the range is a
   109  // literal, such as "100 to 200".
   110  func NewRangeNode(start IntValueNode, to *KeywordNode, end IntValueNode, max *KeywordNode) *RangeNode {
   111  	if start == nil {
   112  		panic("start is nil")
   113  	}
   114  	numChildren := 1
   115  	if to != nil {
   116  		if end == nil && max == nil {
   117  			panic("to is not nil, but end and max both are")
   118  		}
   119  		if end != nil && max != nil {
   120  			panic("end and max cannot be both non-nil")
   121  		}
   122  		numChildren = 3
   123  	} else {
   124  		if end != nil {
   125  			panic("to is nil, but end is not")
   126  		}
   127  		if max != nil {
   128  			panic("to is nil, but max is not")
   129  		}
   130  	}
   131  	children := make([]Node, 0, numChildren)
   132  	children = append(children, start)
   133  	if to != nil {
   134  		children = append(children, to)
   135  		if end != nil {
   136  			children = append(children, end)
   137  		} else {
   138  			children = append(children, max)
   139  		}
   140  	}
   141  	return &RangeNode{
   142  		compositeNode: compositeNode{
   143  			children: children,
   144  		},
   145  		StartVal: start,
   146  		To:       to,
   147  		EndVal:   end,
   148  		Max:      max,
   149  	}
   150  }
   151  
   152  func (n *RangeNode) RangeStart() Node {
   153  	return n.StartVal
   154  }
   155  
   156  func (n *RangeNode) RangeEnd() Node {
   157  	if n.Max != nil {
   158  		return n.Max
   159  	}
   160  	if n.EndVal != nil {
   161  		return n.EndVal
   162  	}
   163  	return n.StartVal
   164  }
   165  
   166  func (n *RangeNode) StartValue() interface{} {
   167  	return n.StartVal.Value()
   168  }
   169  
   170  func (n *RangeNode) StartValueAsInt32(min, max int32) (int32, bool) {
   171  	return AsInt32(n.StartVal, min, max)
   172  }
   173  
   174  func (n *RangeNode) EndValue() interface{} {
   175  	if n.EndVal == nil {
   176  		return nil
   177  	}
   178  	return n.EndVal.Value()
   179  }
   180  
   181  func (n *RangeNode) EndValueAsInt32(min, max int32) (int32, bool) {
   182  	if n.Max != nil {
   183  		return max, true
   184  	}
   185  	if n.EndVal == nil {
   186  		return n.StartValueAsInt32(min, max)
   187  	}
   188  	return AsInt32(n.EndVal, min, max)
   189  }
   190  
   191  // ReservedNode represents reserved declaration, which can be used to reserve
   192  // either names or numbers. Examples:
   193  //
   194  //	reserved 1, 10-12, 15;
   195  //	reserved "foo", "bar", "baz";
   196  type ReservedNode struct {
   197  	compositeNode
   198  	Keyword *KeywordNode
   199  	// If non-empty, this node represents reserved ranges and Names will be empty.
   200  	Ranges []*RangeNode
   201  	// If non-empty, this node represents reserved names and Ranges will be empty.
   202  	Names []StringValueNode
   203  	// Commas represent the separating ',' characters between options. The
   204  	// length of this slice must be exactly len(Ranges)-1 or len(Names)-1, depending
   205  	// on whether this node represents reserved ranges or reserved names. Each item
   206  	// in Ranges or Names has a corresponding item in this slice *except the last*
   207  	// (since a trailing comma is not allowed).
   208  	Commas    []*RuneNode
   209  	Semicolon *RuneNode
   210  }
   211  
   212  func (*ReservedNode) msgElement()  {}
   213  func (*ReservedNode) enumElement() {}
   214  
   215  // NewReservedRangesNode creates a new *ReservedNode that represents reserved
   216  // numeric ranges. All args must be non-nil.
   217  //   - keyword: The token corresponding to the "reserved" keyword.
   218  //   - ranges: One or more range expressions.
   219  //   - commas: Tokens that represent the "," runes that delimit the range expressions.
   220  //     The length of commas must be one less than the length of ranges.
   221  //   - semicolon The token corresponding to the ";" rune that ends the declaration.
   222  func NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {
   223  	if keyword == nil {
   224  		panic("keyword is nil")
   225  	}
   226  	if semicolon == nil {
   227  		panic("semicolon is nil")
   228  	}
   229  	if len(ranges) == 0 {
   230  		panic("must have at least one range")
   231  	}
   232  	if len(commas) != len(ranges)-1 {
   233  		panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas)))
   234  	}
   235  	children := make([]Node, 0, len(ranges)*2+1)
   236  	children = append(children, keyword)
   237  	for i, rng := range ranges {
   238  		if i > 0 {
   239  			if commas[i-1] == nil {
   240  				panic(fmt.Sprintf("commas[%d] is nil", i-1))
   241  			}
   242  			children = append(children, commas[i-1])
   243  		}
   244  		if rng == nil {
   245  			panic(fmt.Sprintf("ranges[%d] is nil", i))
   246  		}
   247  		children = append(children, rng)
   248  	}
   249  	children = append(children, semicolon)
   250  	return &ReservedNode{
   251  		compositeNode: compositeNode{
   252  			children: children,
   253  		},
   254  		Keyword:   keyword,
   255  		Ranges:    ranges,
   256  		Commas:    commas,
   257  		Semicolon: semicolon,
   258  	}
   259  }
   260  
   261  // NewReservedNamesNode creates a new *ReservedNode that represents reserved
   262  // names. All args must be non-nil.
   263  //   - keyword: The token corresponding to the "reserved" keyword.
   264  //   - names: One or more names.
   265  //   - commas: Tokens that represent the "," runes that delimit the names.
   266  //     The length of commas must be one less than the length of names.
   267  //   - semicolon The token corresponding to the ";" rune that ends the declaration.
   268  func NewReservedNamesNode(keyword *KeywordNode, names []StringValueNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {
   269  	if keyword == nil {
   270  		panic("keyword is nil")
   271  	}
   272  	if semicolon == nil {
   273  		panic("semicolon is nil")
   274  	}
   275  	if len(names) == 0 {
   276  		panic("must have at least one name")
   277  	}
   278  	if len(commas) != len(names)-1 {
   279  		panic(fmt.Sprintf("%d names requires %d commas, not %d", len(names), len(names)-1, len(commas)))
   280  	}
   281  	children := make([]Node, 0, len(names)*2+1)
   282  	children = append(children, keyword)
   283  	for i, name := range names {
   284  		if i > 0 {
   285  			if commas[i-1] == nil {
   286  				panic(fmt.Sprintf("commas[%d] is nil", i-1))
   287  			}
   288  			children = append(children, commas[i-1])
   289  		}
   290  		if name == nil {
   291  			panic(fmt.Sprintf("names[%d] is nil", i))
   292  		}
   293  		children = append(children, name)
   294  	}
   295  	children = append(children, semicolon)
   296  	return &ReservedNode{
   297  		compositeNode: compositeNode{
   298  			children: children,
   299  		},
   300  		Keyword:   keyword,
   301  		Names:     names,
   302  		Commas:    commas,
   303  		Semicolon: semicolon,
   304  	}
   305  }