bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/expr/parse/node.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Parse nodes.
     6  
     7  package parse
     8  
     9  import (
    10  	"fmt"
    11  	"strconv"
    12  
    13  	"bosun.org/models"
    14  )
    15  
    16  var textFormat = "%s" // Changed to "%q" in tests for better error messages.
    17  
    18  // A Node is an element in the parse tree. The interface is trivial.
    19  // The interface contains an unexported method so that only
    20  // types local to this package can satisfy it.
    21  type Node interface {
    22  	Type() NodeType
    23  	String() string
    24  	StringAST() string
    25  	Position() Pos     // byte position of start of node in full original input string
    26  	Check(*Tree) error // performs type checking for itself and sub-nodes
    27  	Return() models.FuncType
    28  	Tags() (Tags, error)
    29  
    30  	// Make sure only functions in this package can create Nodes.
    31  	unexported()
    32  }
    33  
    34  // NodeType identifies the type of a parse tree node.
    35  type NodeType int
    36  
    37  // Pos represents a byte position in the original input text from which
    38  // this template was parsed.
    39  type Pos int
    40  
    41  func (p Pos) Position() Pos {
    42  	return p
    43  }
    44  
    45  // unexported keeps Node implementations local to the package.
    46  // All implementations embed Pos, so this takes care of it.
    47  func (Pos) unexported() {
    48  }
    49  
    50  // Type returns itself and provides an easy default implementation
    51  // for embedding in a Node. Embedded in all non-trivial Nodes.
    52  func (t NodeType) Type() NodeType {
    53  	return t
    54  }
    55  
    56  const (
    57  	NodeFunc   NodeType = iota // A function call.
    58  	NodeBinary                 // Binary operator: math, logical, compare
    59  	NodeUnary                  // Unary operator: !, -
    60  	NodeString                 // A string constant.
    61  	NodeNumber                 // A numerical constant.
    62  	NodeExpr                   // A sub expression
    63  	NodePrefix                 // A host prefix [""]
    64  )
    65  
    66  // Nodes.
    67  
    68  // FuncNode holds a function invocation.
    69  type FuncNode struct {
    70  	NodeType
    71  	Pos
    72  	Name   string
    73  	F      *Func
    74  	Args   []Node
    75  	Prefix string
    76  }
    77  
    78  func newFunc(pos Pos, name string, f Func) *FuncNode {
    79  	return &FuncNode{NodeType: NodeFunc, Pos: pos, Name: name, F: &f}
    80  }
    81  
    82  func (f *FuncNode) append(arg Node) {
    83  	f.Args = append(f.Args, arg)
    84  }
    85  
    86  func (f *FuncNode) String() string {
    87  	s := f.Name + "("
    88  	for i, arg := range f.Args {
    89  		if i > 0 {
    90  			s += ", "
    91  		}
    92  		s += arg.String()
    93  	}
    94  	s += ")"
    95  	return s
    96  }
    97  
    98  func (f *FuncNode) StringAST() string {
    99  	s := f.Name + "("
   100  	for i, arg := range f.Args {
   101  		if i > 0 {
   102  			s += ", "
   103  		}
   104  		s += arg.StringAST()
   105  	}
   106  	s += ")"
   107  	return s
   108  }
   109  
   110  func (f *FuncNode) Check(t *Tree) error {
   111  	if f.F.MapFunc && !t.mapExpr {
   112  		return fmt.Errorf("%v is only valid in a map expression", f.Name)
   113  	}
   114  	const errFuncType = "parse: bad argument type in %s, expected %s, got %s"
   115  	// For VArgs we make sure they are all of the expected type
   116  	if f.F.VArgs {
   117  		if len(f.Args) < len(f.F.Args) && !f.F.VArgsOmit {
   118  			return fmt.Errorf("parse: variable argument functions need at least one arg")
   119  		}
   120  	} else {
   121  		if len(f.Args) < len(f.F.Args) {
   122  			return fmt.Errorf("parse: not enough arguments for %s", f.Name)
   123  		} else if len(f.Args) > len(f.F.Args) {
   124  			return fmt.Errorf("parse: too many arguments for %s", f.Name)
   125  		}
   126  	}
   127  	for i, arg := range f.Args {
   128  		var funcType models.FuncType
   129  		if f.F.VArgs && i >= f.F.VArgsPos {
   130  			funcType = f.F.Args[f.F.VArgsPos]
   131  		} else {
   132  			funcType = f.F.Args[i]
   133  		}
   134  		argType := arg.Return()
   135  		if funcType == models.TypeNumberSet && argType == models.TypeScalar {
   136  			argType = models.TypeNumberSet // Scalars are promoted to NumberSets during execution.
   137  		}
   138  		if funcType == models.TypeVariantSet {
   139  			if !(argType == models.TypeNumberSet || argType == models.TypeSeriesSet || argType == models.TypeScalar) {
   140  				return fmt.Errorf("parse: expected %v or %v for argument %v, got %v", models.TypeNumberSet, models.TypeSeriesSet, i, argType)
   141  			}
   142  		} else if funcType != argType {
   143  			return fmt.Errorf("parse: expected %v, got %v for argument %v (%v)", funcType, argType, i, arg.String())
   144  		}
   145  		if err := arg.Check(t); err != nil {
   146  			return err
   147  		}
   148  	}
   149  
   150  	if f.F.Check != nil {
   151  		return f.F.Check(t, f)
   152  	}
   153  	return nil
   154  }
   155  
   156  func (f *FuncNode) Return() models.FuncType {
   157  	return f.F.Return
   158  }
   159  
   160  func (f *FuncNode) Tags() (Tags, error) {
   161  	if f.F.Tags == nil {
   162  		return nil, nil
   163  	}
   164  	return f.F.Tags(f.Args)
   165  }
   166  
   167  // NumberNode holds a number: signed or unsigned integer or float.
   168  // The value is parsed and stored under all the types that can represent the value.
   169  // This simulates in a small amount of code the behavior of Go's ideal constants.
   170  type NumberNode struct {
   171  	NodeType
   172  	Pos
   173  	IsUint  bool    // Number has an unsigned integral value.
   174  	IsFloat bool    // Number has a floating-point value.
   175  	Uint64  uint64  // The unsigned integer value.
   176  	Float64 float64 // The floating-point value.
   177  	Text    string  // The original textual representation from the input.
   178  }
   179  
   180  type ExprNode struct {
   181  	NodeType
   182  	Pos
   183  	Text string
   184  	Tree *Tree
   185  }
   186  
   187  func newExprNode(text string, pos Pos) (*ExprNode, error) {
   188  	return &ExprNode{
   189  		NodeType: NodeExpr,
   190  		Text:     text,
   191  		Pos:      pos,
   192  	}, nil
   193  }
   194  
   195  func (s *ExprNode) String() string {
   196  	return fmt.Sprintf("%v", s.Text)
   197  }
   198  
   199  func (s *ExprNode) StringAST() string {
   200  	return s.String()
   201  }
   202  
   203  func (s *ExprNode) Check(*Tree) error {
   204  	return nil
   205  }
   206  
   207  func (s *ExprNode) Return() models.FuncType {
   208  	switch s.Tree.Root.Return() {
   209  	case models.TypeNumberSet, models.TypeScalar:
   210  		return models.TypeNumberExpr
   211  	case models.TypeSeriesSet:
   212  		return models.TypeSeriesExpr
   213  	default:
   214  		return models.TypeUnexpected
   215  	}
   216  }
   217  
   218  func (s *ExprNode) Tags() (Tags, error) {
   219  	return nil, nil
   220  }
   221  
   222  func newNumber(pos Pos, text string) (*NumberNode, error) {
   223  	n := &NumberNode{NodeType: NodeNumber, Pos: pos, Text: text}
   224  	// Do integer test first so we get 0x123 etc.
   225  	u, err := strconv.ParseUint(text, 0, 64) // will fail for -0.
   226  	if err == nil {
   227  		n.IsUint = true
   228  		n.Uint64 = u
   229  	}
   230  	// If an integer extraction succeeded, promote the float.
   231  	if n.IsUint {
   232  		n.IsFloat = true
   233  		n.Float64 = float64(n.Uint64)
   234  	} else {
   235  		f, err := strconv.ParseFloat(text, 64)
   236  		if err == nil {
   237  			n.IsFloat = true
   238  			n.Float64 = f
   239  			// If a floating-point extraction succeeded, extract the int if needed.
   240  			if !n.IsUint && float64(uint64(f)) == f {
   241  				n.IsUint = true
   242  				n.Uint64 = uint64(f)
   243  			}
   244  		}
   245  	}
   246  	if !n.IsUint && !n.IsFloat {
   247  		return nil, fmt.Errorf("illegal number syntax: %q", text)
   248  	}
   249  	return n, nil
   250  }
   251  
   252  func (n *NumberNode) String() string {
   253  	return n.Text
   254  }
   255  
   256  func (n *NumberNode) StringAST() string {
   257  	return n.String()
   258  }
   259  
   260  func (n *NumberNode) Check(*Tree) error {
   261  	return nil
   262  }
   263  
   264  func (n *NumberNode) Return() models.FuncType {
   265  	return models.TypeScalar
   266  }
   267  
   268  func (n *NumberNode) Tags() (Tags, error) {
   269  	return nil, nil
   270  }
   271  
   272  // StringNode holds a string constant. The value has been "unquoted".
   273  type StringNode struct {
   274  	NodeType
   275  	Pos
   276  	Quoted string // The original text of the string, with quotes.
   277  	Text   string // The string, after quote processing.
   278  }
   279  
   280  func newString(pos Pos, orig, text string) *StringNode {
   281  	return &StringNode{NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
   282  }
   283  
   284  func (s *StringNode) String() string {
   285  	return s.Quoted
   286  }
   287  
   288  func (s *StringNode) StringAST() string {
   289  	return s.String()
   290  }
   291  
   292  func (s *StringNode) Check(*Tree) error {
   293  	return nil
   294  }
   295  
   296  func (s *StringNode) Return() models.FuncType {
   297  	return models.TypeString
   298  }
   299  
   300  func (s *StringNode) Tags() (Tags, error) {
   301  	return nil, nil
   302  }
   303  
   304  // Prefix holds a string constant.
   305  type PrefixNode struct {
   306  	NodeType
   307  	Pos
   308  	Arg  Node
   309  	Text string
   310  }
   311  
   312  func newPrefix(text string, pos Pos, arg Node) *PrefixNode {
   313  	return &PrefixNode{NodeType: NodePrefix, Text: text, Pos: pos, Arg: arg}
   314  }
   315  
   316  func (p *PrefixNode) String() string {
   317  	return fmt.Sprintf("%s%s", p.Text, p.Arg)
   318  }
   319  
   320  func (p *PrefixNode) StringAST() string {
   321  	return p.String()
   322  }
   323  
   324  func (p *PrefixNode) Check(t *Tree) error {
   325  	if p.Arg.Type() != NodeFunc {
   326  		return fmt.Errorf("parse: prefix on non-function")
   327  	}
   328  	if !p.Arg.(*FuncNode).F.PrefixEnabled {
   329  		return fmt.Errorf("func %v does not support a prefix", p.Arg.(*FuncNode).Name)
   330  	}
   331  	return p.Arg.Check(t)
   332  }
   333  
   334  func (p *PrefixNode) Return() models.FuncType {
   335  	return p.Arg.Return()
   336  }
   337  
   338  func (p *PrefixNode) Tags() (Tags, error) {
   339  	return p.Arg.Tags()
   340  }
   341  
   342  // BinaryNode holds two arguments and an operator.
   343  type BinaryNode struct {
   344  	NodeType
   345  	Pos
   346  	Args     [2]Node
   347  	Operator item
   348  	OpStr    string
   349  }
   350  
   351  func newBinary(operator item, arg1, arg2 Node) *BinaryNode {
   352  	return &BinaryNode{NodeType: NodeBinary, Pos: operator.pos, Args: [2]Node{arg1, arg2}, Operator: operator, OpStr: operator.val}
   353  }
   354  
   355  func (b *BinaryNode) String() string {
   356  	return fmt.Sprintf("%s %s %s", b.Args[0], b.Operator.val, b.Args[1])
   357  }
   358  
   359  func (b *BinaryNode) StringAST() string {
   360  	return fmt.Sprintf("%s(%s, %s)", b.Operator.val, b.Args[0], b.Args[1])
   361  }
   362  
   363  func (b *BinaryNode) Check(t *Tree) error {
   364  	t1 := b.Args[0].Return()
   365  	t2 := b.Args[1].Return()
   366  	if !(t1 == models.TypeSeriesSet || t1 == models.TypeNumberSet || t1 == models.TypeScalar) {
   367  		return fmt.Errorf("expected NumberSet, SeriesSet, or Scalar, got %v", t1)
   368  	}
   369  	if !(t2 == models.TypeSeriesSet || t2 == models.TypeNumberSet || t2 == models.TypeScalar) {
   370  		return fmt.Errorf("expected NumberSet, SeriesSet, or Scalar, got %v", t1)
   371  	}
   372  	if err := b.Args[0].Check(t); err != nil {
   373  		return err
   374  	}
   375  	if err := b.Args[1].Check(t); err != nil {
   376  		return err
   377  	}
   378  	g1, err := b.Args[0].Tags()
   379  	if err != nil {
   380  		return err
   381  	}
   382  	g2, err := b.Args[1].Tags()
   383  	if err != nil {
   384  		return err
   385  	}
   386  	if g1 != nil && g2 != nil && !g1.Subset(g2) && !g2.Subset(g1) {
   387  		return fmt.Errorf("parse: incompatible tags (%v and %v) in %s", g1, g2, b)
   388  	}
   389  	return nil
   390  }
   391  
   392  func (b *BinaryNode) Return() models.FuncType {
   393  	t0 := b.Args[0].Return()
   394  	t1 := b.Args[1].Return()
   395  	if t1 > t0 {
   396  		return t1
   397  	}
   398  	return t0
   399  }
   400  
   401  func (b *BinaryNode) Tags() (Tags, error) {
   402  	t, err := b.Args[0].Tags()
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	if t == nil {
   407  		return b.Args[1].Tags()
   408  	}
   409  	return t, nil
   410  }
   411  
   412  // UnaryNode holds one argument and an operator.
   413  type UnaryNode struct {
   414  	NodeType
   415  	Pos
   416  	Arg      Node
   417  	Operator item
   418  	OpStr    string
   419  }
   420  
   421  func newUnary(operator item, arg Node) *UnaryNode {
   422  	return &UnaryNode{NodeType: NodeUnary, Pos: operator.pos, Arg: arg, Operator: operator, OpStr: operator.val}
   423  }
   424  
   425  func (u *UnaryNode) String() string {
   426  	return fmt.Sprintf("%s%s", u.Operator.val, u.Arg)
   427  }
   428  
   429  func (u *UnaryNode) StringAST() string {
   430  	return fmt.Sprintf("%s(%s)", u.Operator.val, u.Arg)
   431  }
   432  
   433  func (u *UnaryNode) Check(t *Tree) error {
   434  	switch rt := u.Arg.Return(); rt {
   435  	case models.TypeNumberSet, models.TypeSeriesSet, models.TypeScalar:
   436  		return u.Arg.Check(t)
   437  	default:
   438  		return fmt.Errorf("parse: type error in %s, expected %s, got %s", u, "number", rt)
   439  	}
   440  }
   441  
   442  func (u *UnaryNode) Return() models.FuncType {
   443  	return u.Arg.Return()
   444  }
   445  
   446  func (u *UnaryNode) Tags() (Tags, error) {
   447  	return u.Arg.Tags()
   448  }
   449  
   450  // Walk invokes f on n and sub-nodes of n.
   451  func Walk(n Node, f func(Node)) {
   452  	f(n)
   453  	switch n := n.(type) {
   454  	case *BinaryNode:
   455  		Walk(n.Args[0], f)
   456  		Walk(n.Args[1], f)
   457  	case *FuncNode:
   458  		for _, a := range n.Args {
   459  			Walk(a, f)
   460  		}
   461  	case *NumberNode, *StringNode, *ExprNode:
   462  		// Ignore.
   463  	case *UnaryNode:
   464  		Walk(n.Arg, f)
   465  	default:
   466  		panic(fmt.Errorf("other type: %T", n))
   467  	}
   468  }