github.com/jhump/protocompile@v0.0.0-20221021153901-4f6f732835e8/ast/values.go (about)

     1  package ast
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  )
     8  
     9  // ValueNode is an AST node that represents a literal value.
    10  //
    11  // It also includes references (e.g. IdentifierValueNode), which can be
    12  // used as values in some contexts, such as describing the default value
    13  // for a field, which can refer to an enum value.
    14  //
    15  // This also allows NoSourceNode to be used in place of a real value node
    16  // for some usages.
    17  type ValueNode interface {
    18  	Node
    19  	// Value returns a Go representation of the value. For scalars, this
    20  	// will be a string, int64, uint64, float64, or bool. This could also
    21  	// be an Identifier (e.g. IdentValueNodes). It can also be a composite
    22  	// literal:
    23  	//   * For array literals, the type returned will be []ValueNode
    24  	//   * For message literals, the type returned will be []*MessageFieldNode
    25  	Value() interface{}
    26  }
    27  
    28  var _ ValueNode = (*IdentNode)(nil)
    29  var _ ValueNode = (*CompoundIdentNode)(nil)
    30  var _ ValueNode = (*StringLiteralNode)(nil)
    31  var _ ValueNode = (*CompoundStringLiteralNode)(nil)
    32  var _ ValueNode = (*UintLiteralNode)(nil)
    33  var _ ValueNode = (*PositiveUintLiteralNode)(nil)
    34  var _ ValueNode = (*NegativeIntLiteralNode)(nil)
    35  var _ ValueNode = (*FloatLiteralNode)(nil)
    36  var _ ValueNode = (*SpecialFloatLiteralNode)(nil)
    37  var _ ValueNode = (*SignedFloatLiteralNode)(nil)
    38  var _ ValueNode = (*BoolLiteralNode)(nil)
    39  var _ ValueNode = (*ArrayLiteralNode)(nil)
    40  var _ ValueNode = (*MessageLiteralNode)(nil)
    41  var _ ValueNode = NoSourceNode{}
    42  
    43  // StringValueNode is an AST node that represents a string literal.
    44  // Such a node can be a single literal (*StringLiteralNode) or a
    45  // concatenation of multiple literals (*CompoundStringLiteralNode).
    46  type StringValueNode interface {
    47  	ValueNode
    48  	AsString() string
    49  }
    50  
    51  var _ StringValueNode = (*StringLiteralNode)(nil)
    52  var _ StringValueNode = (*CompoundStringLiteralNode)(nil)
    53  
    54  // StringLiteralNode represents a simple string literal. Example:
    55  //
    56  //  "proto2"
    57  type StringLiteralNode struct {
    58  	terminalNode
    59  	// Val is the actual string value that the literal indicates.
    60  	Val string
    61  }
    62  
    63  // NewStringLiteralNode creates a new *StringLiteralNode with the given val.
    64  func NewStringLiteralNode(val string, tok Token) *StringLiteralNode {
    65  	return &StringLiteralNode{
    66  		terminalNode: tok.asTerminalNode(),
    67  		Val:          val,
    68  	}
    69  }
    70  
    71  func (n *StringLiteralNode) Value() interface{} {
    72  	return n.AsString()
    73  }
    74  
    75  func (n *StringLiteralNode) AsString() string {
    76  	return n.Val
    77  }
    78  
    79  // CompoundStringLiteralNode represents a compound string literal, which is
    80  // the concatenaton of adjacent string literals. Example:
    81  //
    82  //  "this "  "is"   " all one "   "string"
    83  type CompoundStringLiteralNode struct {
    84  	compositeNode
    85  	Val string
    86  }
    87  
    88  // NewCompoundLiteralStringNode creates a new *CompoundStringLiteralNode that
    89  // consists of the given string components. The components argument may not be
    90  // empty.
    91  func NewCompoundLiteralStringNode(components ...*StringLiteralNode) *CompoundStringLiteralNode {
    92  	if len(components) == 0 {
    93  		panic("must have at least one component")
    94  	}
    95  	children := make([]Node, len(components))
    96  	var b strings.Builder
    97  	for i, comp := range components {
    98  		children[i] = comp
    99  		b.WriteString(comp.Val)
   100  	}
   101  	return &CompoundStringLiteralNode{
   102  		compositeNode: compositeNode{
   103  			children: children,
   104  		},
   105  		Val: b.String(),
   106  	}
   107  }
   108  
   109  func (n *CompoundStringLiteralNode) Value() interface{} {
   110  	return n.AsString()
   111  }
   112  
   113  func (n *CompoundStringLiteralNode) AsString() string {
   114  	return n.Val
   115  }
   116  
   117  // IntValueNode is an AST node that represents an integer literal. If
   118  // an integer literal is too large for an int64 (or uint64 for
   119  // positive literals), it is represented instead by a FloatValueNode.
   120  type IntValueNode interface {
   121  	ValueNode
   122  	AsInt64() (int64, bool)
   123  	AsUint64() (uint64, bool)
   124  }
   125  
   126  // AsInt32 range checks the given int value and returns its value is
   127  // in the range or 0, false if it is outside the range.
   128  func AsInt32(n IntValueNode, min, max int32) (int32, bool) {
   129  	i, ok := n.AsInt64()
   130  	if !ok {
   131  		return 0, false
   132  	}
   133  	if i < int64(min) || i > int64(max) {
   134  		return 0, false
   135  	}
   136  	return int32(i), true
   137  }
   138  
   139  var _ IntValueNode = (*UintLiteralNode)(nil)
   140  var _ IntValueNode = (*PositiveUintLiteralNode)(nil)
   141  var _ IntValueNode = (*NegativeIntLiteralNode)(nil)
   142  
   143  // UintLiteralNode represents a simple integer literal with no sign character.
   144  type UintLiteralNode struct {
   145  	terminalNode
   146  	// Val is the numeric value indicated by the literal
   147  	Val uint64
   148  }
   149  
   150  // NewUintLiteralNode creates a new *UintLiteralNode with the given val.
   151  func NewUintLiteralNode(val uint64, tok Token) *UintLiteralNode {
   152  	return &UintLiteralNode{
   153  		terminalNode: tok.asTerminalNode(),
   154  		Val:          val,
   155  	}
   156  }
   157  
   158  func (n *UintLiteralNode) Value() interface{} {
   159  	return n.Val
   160  }
   161  
   162  func (n *UintLiteralNode) AsInt64() (int64, bool) {
   163  	if n.Val > math.MaxInt64 {
   164  		return 0, false
   165  	}
   166  	return int64(n.Val), true
   167  }
   168  
   169  func (n *UintLiteralNode) AsUint64() (uint64, bool) {
   170  	return n.Val, true
   171  }
   172  
   173  func (n *UintLiteralNode) AsFloat() float64 {
   174  	return float64(n.Val)
   175  }
   176  
   177  // PositiveUintLiteralNode represents an integer literal with a positive (+) sign.
   178  type PositiveUintLiteralNode struct {
   179  	compositeNode
   180  	Plus *RuneNode
   181  	Uint *UintLiteralNode
   182  	Val  uint64
   183  }
   184  
   185  // NewPositiveUintLiteralNode creates a new *PositiveUintLiteralNode. Both
   186  // arguments must be non-nil.
   187  func NewPositiveUintLiteralNode(sign *RuneNode, i *UintLiteralNode) *PositiveUintLiteralNode {
   188  	if sign == nil {
   189  		panic("sign is nil")
   190  	}
   191  	if i == nil {
   192  		panic("i is nil")
   193  	}
   194  	children := []Node{sign, i}
   195  	return &PositiveUintLiteralNode{
   196  		compositeNode: compositeNode{
   197  			children: children,
   198  		},
   199  		Plus: sign,
   200  		Uint: i,
   201  		Val:  i.Val,
   202  	}
   203  }
   204  
   205  func (n *PositiveUintLiteralNode) Value() interface{} {
   206  	return n.Val
   207  }
   208  
   209  func (n *PositiveUintLiteralNode) AsInt64() (int64, bool) {
   210  	if n.Val > math.MaxInt64 {
   211  		return 0, false
   212  	}
   213  	return int64(n.Val), true
   214  }
   215  
   216  func (n *PositiveUintLiteralNode) AsUint64() (uint64, bool) {
   217  	return n.Val, true
   218  }
   219  
   220  // NegativeIntLiteralNode represents an integer literal with a negative (-) sign.
   221  type NegativeIntLiteralNode struct {
   222  	compositeNode
   223  	Minus *RuneNode
   224  	Uint  *UintLiteralNode
   225  	Val   int64
   226  }
   227  
   228  // NewNegativeIntLiteralNode creates a new *NegativeIntLiteralNode. Both
   229  // arguments must be non-nil.
   230  func NewNegativeIntLiteralNode(sign *RuneNode, i *UintLiteralNode) *NegativeIntLiteralNode {
   231  	if sign == nil {
   232  		panic("sign is nil")
   233  	}
   234  	if i == nil {
   235  		panic("i is nil")
   236  	}
   237  	children := []Node{sign, i}
   238  	return &NegativeIntLiteralNode{
   239  		compositeNode: compositeNode{
   240  			children: children,
   241  		},
   242  		Minus: sign,
   243  		Uint:  i,
   244  		Val:   -int64(i.Val),
   245  	}
   246  }
   247  
   248  func (n *NegativeIntLiteralNode) Value() interface{} {
   249  	return n.Val
   250  }
   251  
   252  func (n *NegativeIntLiteralNode) AsInt64() (int64, bool) {
   253  	return n.Val, true
   254  }
   255  
   256  func (n *NegativeIntLiteralNode) AsUint64() (uint64, bool) {
   257  	if n.Val < 0 {
   258  		return 0, false
   259  	}
   260  	return uint64(n.Val), true
   261  }
   262  
   263  // FloatValueNode is an AST node that represents a numeric literal with
   264  // a floating point, in scientific notation, or too large to fit in an
   265  // int64 or uint64.
   266  type FloatValueNode interface {
   267  	ValueNode
   268  	AsFloat() float64
   269  }
   270  
   271  var _ FloatValueNode = (*FloatLiteralNode)(nil)
   272  var _ FloatValueNode = (*SpecialFloatLiteralNode)(nil)
   273  var _ FloatValueNode = (*UintLiteralNode)(nil)
   274  
   275  // FloatLiteralNode represents a floating point numeric literal.
   276  type FloatLiteralNode struct {
   277  	terminalNode
   278  	// Val is the numeric value indicated by the literal
   279  	Val float64
   280  }
   281  
   282  // NewFloatLiteralNode creates a new *FloatLiteralNode with the given val.
   283  func NewFloatLiteralNode(val float64, tok Token) *FloatLiteralNode {
   284  	return &FloatLiteralNode{
   285  		terminalNode: tok.asTerminalNode(),
   286  		Val:          val,
   287  	}
   288  }
   289  
   290  func (n *FloatLiteralNode) Value() interface{} {
   291  	return n.AsFloat()
   292  }
   293  
   294  func (n *FloatLiteralNode) AsFloat() float64 {
   295  	return n.Val
   296  }
   297  
   298  // SpecialFloatLiteralNode represents a special floating point numeric literal
   299  // for "inf" and "nan" values.
   300  type SpecialFloatLiteralNode struct {
   301  	*KeywordNode
   302  	Val float64
   303  }
   304  
   305  // NewSpecialFloatLiteralNode returns a new *SpecialFloatLiteralNode for the
   306  // given keyword, which must be "inf" or "nan".
   307  func NewSpecialFloatLiteralNode(name *KeywordNode) *SpecialFloatLiteralNode {
   308  	var f float64
   309  	if name.Val == "inf" {
   310  		f = math.Inf(1)
   311  	} else {
   312  		f = math.NaN()
   313  	}
   314  	return &SpecialFloatLiteralNode{
   315  		KeywordNode: name,
   316  		Val:         f,
   317  	}
   318  }
   319  
   320  func (n *SpecialFloatLiteralNode) Value() interface{} {
   321  	return n.AsFloat()
   322  }
   323  
   324  func (n *SpecialFloatLiteralNode) AsFloat() float64 {
   325  	return n.Val
   326  }
   327  
   328  // SignedFloatLiteralNode represents a signed floating point number.
   329  type SignedFloatLiteralNode struct {
   330  	compositeNode
   331  	Sign  *RuneNode
   332  	Float FloatValueNode
   333  	Val   float64
   334  }
   335  
   336  // NewSignedFloatLiteralNode creates a new *SignedFloatLiteralNode. Both
   337  // arguments must be non-nil.
   338  func NewSignedFloatLiteralNode(sign *RuneNode, f FloatValueNode) *SignedFloatLiteralNode {
   339  	if sign == nil {
   340  		panic("sign is nil")
   341  	}
   342  	if f == nil {
   343  		panic("f is nil")
   344  	}
   345  	children := []Node{sign, f}
   346  	val := f.AsFloat()
   347  	if sign.Rune == '-' {
   348  		val = -val
   349  	}
   350  	return &SignedFloatLiteralNode{
   351  		compositeNode: compositeNode{
   352  			children: children,
   353  		},
   354  		Sign:  sign,
   355  		Float: f,
   356  		Val:   val,
   357  	}
   358  }
   359  
   360  func (n *SignedFloatLiteralNode) Value() interface{} {
   361  	return n.Val
   362  }
   363  
   364  func (n *SignedFloatLiteralNode) AsFloat() float64 {
   365  	return n.Val
   366  }
   367  
   368  // BoolLiteralNode represents a boolean literal.
   369  type BoolLiteralNode struct {
   370  	*KeywordNode
   371  	Val bool
   372  }
   373  
   374  // NewBoolLiteralNode returns a new *BoolLiteralNode for the given keyword,
   375  // which must be "true" or "false".
   376  func NewBoolLiteralNode(name *KeywordNode) *BoolLiteralNode {
   377  	return &BoolLiteralNode{
   378  		KeywordNode: name,
   379  		Val:         name.Val == "true",
   380  	}
   381  }
   382  
   383  func (n *BoolLiteralNode) Value() interface{} {
   384  	return n.Val
   385  }
   386  
   387  // ArrayLiteralNode represents an array literal, which is only allowed inside of
   388  // a MessageLiteralNode, to indicate values for a repeated field. Example:
   389  //
   390  //  ["foo", "bar", "baz"]
   391  type ArrayLiteralNode struct {
   392  	compositeNode
   393  	OpenBracket *RuneNode
   394  	Elements    []ValueNode
   395  	// Commas represent the separating ',' characters between elements. The
   396  	// length of this slice must be exactly len(Elements)-1, with each item
   397  	// in Elements having a corresponding item in this slice *except the last*
   398  	// (since a trailing comma is not allowed).
   399  	Commas       []*RuneNode
   400  	CloseBracket *RuneNode
   401  }
   402  
   403  // NewArrayLiteralNode creates a new *ArrayLiteralNode. The openBracket and
   404  // closeBracket args must be non-nil and represent the "[" and "]" runes that
   405  // surround the array values. The given commas arg must have a length that is
   406  // one less than the length of the vals arg. However, vals may be empty, in
   407  // which case commas must also be empty.
   408  func NewArrayLiteralNode(openBracket *RuneNode, vals []ValueNode, commas []*RuneNode, closeBracket *RuneNode) *ArrayLiteralNode {
   409  	if openBracket == nil {
   410  		panic("openBracket is nil")
   411  	}
   412  	if closeBracket == nil {
   413  		panic("closeBracket is nil")
   414  	}
   415  	if len(vals) == 0 && len(commas) != 0 {
   416  		panic("vals is empty but commas is not")
   417  	}
   418  	if len(vals) > 0 && len(commas) != len(vals)-1 {
   419  		panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals)-1, len(commas)))
   420  	}
   421  	children := make([]Node, 0, len(vals)*2+1)
   422  	children = append(children, openBracket)
   423  	for i, val := range vals {
   424  		if i > 0 {
   425  			if commas[i-1] == nil {
   426  				panic(fmt.Sprintf("commas[%d] is nil", i-1))
   427  			}
   428  			children = append(children, commas[i-1])
   429  		}
   430  		if val == nil {
   431  			panic(fmt.Sprintf("vals[%d] is nil", i))
   432  		}
   433  		children = append(children, val)
   434  	}
   435  	children = append(children, closeBracket)
   436  
   437  	return &ArrayLiteralNode{
   438  		compositeNode: compositeNode{
   439  			children: children,
   440  		},
   441  		OpenBracket:  openBracket,
   442  		Elements:     vals,
   443  		Commas:       commas,
   444  		CloseBracket: closeBracket,
   445  	}
   446  }
   447  
   448  func (n *ArrayLiteralNode) Value() interface{} {
   449  	return n.Elements
   450  }
   451  
   452  // MessageLiteralNode represents a message literal, which is compatible with the
   453  // protobuf text format and can be used for custom options with message types.
   454  // Example:
   455  //
   456  //   { foo:1 foo:2 foo:3 bar:<name:"abc" id:123> }
   457  type MessageLiteralNode struct {
   458  	compositeNode
   459  	Open     *RuneNode // should be '{' or '<'
   460  	Elements []*MessageFieldNode
   461  	// Separator characters between elements, which can be either ','
   462  	// or ';' if present. This slice must be exactly len(Elements) in
   463  	// length, with each item in Elements having one corresponding item
   464  	// in Seps. Separators in message literals are optional, so a given
   465  	// item in this slice may be nil to indicate absence of a separator.
   466  	Seps  []*RuneNode
   467  	Close *RuneNode // should be '}' or '>', depending on Open
   468  }
   469  
   470  // NewMessageLiteralNode creates a new *MessageLiteralNode. The openSym and
   471  // closeSym runes must not be nil and should be "{" and "}" or "<" and ">".
   472  //
   473  // Unlike separators (dots and commas) used for other AST nodes that represent
   474  // a list of elements, the seps arg must be the SAME length as vals, and it may
   475  // contain nil values to indicate absence of a separator (in fact, it could be
   476  // all nils).
   477  func NewMessageLiteralNode(openSym *RuneNode, vals []*MessageFieldNode, seps []*RuneNode, closeSym *RuneNode) *MessageLiteralNode {
   478  	if openSym == nil {
   479  		panic("openSym is nil")
   480  	}
   481  	if closeSym == nil {
   482  		panic("closeSym is nil")
   483  	}
   484  	if len(seps) != len(vals) {
   485  		panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals), len(seps)))
   486  	}
   487  	numChildren := len(vals) + 2
   488  	for _, sep := range seps {
   489  		if sep != nil {
   490  			numChildren++
   491  		}
   492  	}
   493  	children := make([]Node, 0, numChildren)
   494  	children = append(children, openSym)
   495  	for i, val := range vals {
   496  		if val == nil {
   497  			panic(fmt.Sprintf("vals[%d] is nil", i))
   498  		}
   499  		children = append(children, val)
   500  		if seps[i] != nil {
   501  			children = append(children, seps[i])
   502  		}
   503  	}
   504  	children = append(children, closeSym)
   505  
   506  	return &MessageLiteralNode{
   507  		compositeNode: compositeNode{
   508  			children: children,
   509  		},
   510  		Open:     openSym,
   511  		Elements: vals,
   512  		Seps:     seps,
   513  		Close:    closeSym,
   514  	}
   515  }
   516  
   517  func (n *MessageLiteralNode) Value() interface{} {
   518  	return n.Elements
   519  }
   520  
   521  // MessageFieldNode represents a single field (name and value) inside of a
   522  // message literal. Example:
   523  //
   524  //   foo:"bar"
   525  type MessageFieldNode struct {
   526  	compositeNode
   527  	Name *FieldReferenceNode
   528  	// Sep represents the ':' separator between the name and value. If
   529  	// the value is a message literal (and thus starts with '<' or '{'),
   530  	// then the separator is optional, and thus may be nil.
   531  	Sep *RuneNode
   532  	Val ValueNode
   533  }
   534  
   535  // NewMessageFieldNode creates a new *MessageFieldNode. All args except sep
   536  // must be non-nil.
   537  func NewMessageFieldNode(name *FieldReferenceNode, sep *RuneNode, val ValueNode) *MessageFieldNode {
   538  	if name == nil {
   539  		panic("name is nil")
   540  	}
   541  	if val == nil {
   542  		panic("val is nil")
   543  	}
   544  	numChildren := 2
   545  	if sep != nil {
   546  		numChildren++
   547  	}
   548  	children := make([]Node, 0, numChildren)
   549  	children = append(children, name)
   550  	if sep != nil {
   551  		children = append(children, sep)
   552  	}
   553  	children = append(children, val)
   554  
   555  	return &MessageFieldNode{
   556  		compositeNode: compositeNode{
   557  			children: children,
   558  		},
   559  		Name: name,
   560  		Sep:  sep,
   561  		Val:  val,
   562  	}
   563  }