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 }