github.com/go-graphite/carbonapi@v0.17.0/pkg/parser/parser.go (about) 1 package parser 2 3 import ( 4 "bytes" 5 "fmt" 6 "regexp" 7 "strconv" 8 "strings" 9 "time" 10 "unicode" 11 "unicode/utf8" 12 13 "github.com/go-graphite/carbonapi/expr/holtwinters" 14 15 "github.com/ansel1/merry" 16 ) 17 18 // expression parser 19 20 type expr struct { 21 target string 22 etype ExprType 23 val float64 24 valStr string 25 args []*expr // positional 26 namedArgs map[string]*expr 27 argString string 28 } 29 30 func (e *expr) IsName() bool { 31 return e.etype == EtName 32 } 33 34 func (e *expr) IsFunc() bool { 35 return e.etype == EtFunc 36 } 37 38 func (e *expr) IsConst() bool { 39 return e.etype == EtConst 40 } 41 42 func (e *expr) IsString() bool { 43 return e.etype == EtString 44 } 45 46 func (e *expr) IsBool() bool { 47 return e.etype == EtBool 48 } 49 50 func (e *expr) Type() ExprType { 51 return e.etype 52 } 53 54 func (e *expr) ToString() string { 55 switch e.etype { 56 case EtFunc: 57 return e.target + "(" + e.argString + ")" 58 case EtConst: 59 return e.valStr 60 case EtString: 61 s := e.valStr 62 s = strings.ReplaceAll(s, `\`, `\\`) 63 s = strings.ReplaceAll(s, `'`, `\'`) 64 return "'" + s + "'" 65 case EtBool: 66 return fmt.Sprint(e.val) 67 } 68 69 return e.target 70 } 71 72 func (e *expr) SetTarget(target string) { 73 e.target = target 74 } 75 76 func (e *expr) MutateTarget(target string) Expr { 77 e.SetTarget(target) 78 return e 79 } 80 81 func (e *expr) Target() string { 82 return e.target 83 } 84 85 func (e *expr) FloatValue() float64 { 86 return e.val 87 } 88 89 func (e *expr) StringValue() string { 90 return e.valStr 91 } 92 93 func (e *expr) SetValString(value string) { 94 e.valStr = value 95 } 96 97 func (e *expr) MutateValString(value string) Expr { 98 e.SetValString(value) 99 return e 100 } 101 102 func (e *expr) RawArgs() string { 103 return e.argString 104 } 105 106 func (e *expr) SetRawArgs(args string) { 107 e.argString = args 108 } 109 110 func (e *expr) MutateRawArgs(args string) Expr { 111 e.SetRawArgs(args) 112 return e 113 } 114 115 func (e *expr) Args() []Expr { 116 ret := make([]Expr, len(e.args)) 117 for i := 0; i < len(e.args); i++ { 118 ret[i] = e.args[i] 119 } 120 return ret 121 } 122 123 func (e *expr) Arg(i int) Expr { 124 return e.args[i] 125 } 126 127 func (e *expr) ArgsLen() int { 128 return len(e.args) 129 } 130 131 func (e *expr) NamedArgs() map[string]Expr { 132 ret := make(map[string]Expr) 133 for k, v := range e.namedArgs { 134 ret[k] = v 135 } 136 return ret 137 } 138 139 func (e *expr) NamedArg(name string) (Expr, bool) { 140 expr, exist := e.namedArgs[name] 141 return expr, exist 142 } 143 144 func (e *expr) Metrics(from, until int64) []MetricRequest { 145 switch e.etype { 146 case EtName: 147 return []MetricRequest{{Metric: e.target, From: from, Until: until}} 148 case EtConst, EtString: 149 return nil 150 case EtFunc: 151 var r []MetricRequest 152 for _, a := range e.args { 153 r = append(r, a.Metrics(from, until)...) 154 } 155 156 switch e.target { 157 case "transformNull": 158 referenceSeriesExpr := e.GetNamedArg("referenceSeries") 159 if !referenceSeriesExpr.IsInterfaceNil() { 160 r = append(r, referenceSeriesExpr.Metrics(from, until)...) 161 } 162 case "consolidateBy": 163 function, err := e.GetStringArg(1) 164 if err != nil { 165 break 166 } 167 for i := range r { 168 r[i].ConsolidationFunc = function 169 } 170 case "timeShift": 171 offs, err := e.GetIntervalArg(1, -1) 172 if err != nil { 173 return nil 174 } 175 for i := range r { 176 r[i].From += int64(offs) 177 r[i].Until += int64(offs) 178 } 179 case "timeStack": 180 offs, err := e.GetIntervalArg(1, -1) 181 if err != nil { 182 return nil 183 } 184 185 start, err := e.GetIntArg(2) 186 if err != nil { 187 return nil 188 } 189 190 end, err := e.GetIntArg(3) 191 if err != nil { 192 return nil 193 } 194 195 var r2 []MetricRequest 196 for _, v := range r { 197 for i := int64(start); i < int64(end); i++ { 198 fromNew := v.From + i*int64(offs) 199 untilNew := v.Until + i*int64(offs) 200 r2 = append(r2, MetricRequest{ 201 Metric: v.Metric, 202 From: fromNew, 203 Until: untilNew, 204 }) 205 } 206 } 207 208 return r2 209 case "holtWintersForecast": 210 bootstrapInterval, err := e.GetIntervalNamedOrPosArgDefault("bootstrapInterval", 1, 1, holtwinters.DefaultBootstrapInterval) 211 if err != nil { 212 return nil 213 } 214 215 for i := range r { 216 r[i].From -= bootstrapInterval 217 } 218 case "holtWintersConfidenceBands", "holtWintersConfidenceArea": 219 bootstrapInterval, err := e.GetIntervalNamedOrPosArgDefault("bootstrapInterval", 2, 1, holtwinters.DefaultBootstrapInterval) 220 if err != nil { 221 return nil 222 } 223 224 for i := range r { 225 r[i].From -= bootstrapInterval 226 } 227 case "holtWintersAberration": 228 bootstrapInterval, err := e.GetIntervalNamedOrPosArgDefault("bootstrapInterval", 2, 1, holtwinters.DefaultBootstrapInterval) 229 if err != nil { 230 return nil 231 } 232 233 // For this function, we also need to pull data with an adjusted From time, 234 // so additional requests are added with the adjusted start time based on the 235 // bootstrapInterval 236 for i := range r { 237 adjustedReq := MetricRequest{ 238 Metric: r[i].Metric, 239 From: r[i].From - bootstrapInterval, 240 Until: r[i].Until, 241 } 242 r = append(r, adjustedReq) 243 } 244 case "movingAverage", "movingMedian", "movingMin", "movingMax", "movingSum", "movingWindow", "exponentialMovingAverage": 245 if len(e.args) < 2 { 246 return nil 247 } 248 if e.args[1].etype == EtString { 249 offs, err := e.GetIntervalArg(1, 1) 250 if err != nil { 251 return nil 252 } 253 for i := range r { 254 fromNew := r[i].From - int64(offs) 255 r[i].From = fromNew 256 } 257 } 258 case "hitcount": 259 if len(e.args) < 2 { 260 return nil 261 } 262 263 alignToInterval, err := e.GetBoolNamedOrPosArgDefault("alignToInterval", 2, false) 264 if err != nil { 265 return nil 266 } 267 if alignToInterval { 268 bucketSizeInt32, err := e.GetIntervalArg(1, 1) 269 if err != nil { 270 return nil 271 } 272 273 interval := int64(bucketSizeInt32) 274 // This is done in order to replicate the behavior in Graphite web when alignToInterval is set, 275 // in which new data is fetched with the adjusted start time. 276 for i, _ := range r { 277 start := r[i].From 278 for _, v := range []int64{86400, 3600, 60} { 279 if interval >= v { 280 start -= start % v 281 break 282 } 283 } 284 285 r[i].From = start 286 } 287 } 288 case "smartSummarize": 289 if len(e.args) < 2 { 290 return nil 291 } 292 293 alignToInterval, err := e.GetStringNamedOrPosArgDefault("alignTo", 3, "") 294 if err != nil { 295 return nil 296 } 297 298 if alignToInterval != "" { 299 for i, _ := range r { 300 newStart, err := StartAlignTo(r[i].From, alignToInterval) 301 if err != nil { 302 return nil 303 } 304 r[i].From = newStart 305 } 306 } 307 } 308 return r 309 } 310 311 return nil 312 } 313 314 func (e *expr) GetIntervalArg(n, defaultSign int) (int32, error) { 315 if len(e.args) <= n { 316 return 0, ErrMissingArgument 317 } 318 319 if e.args[n].etype != EtString { 320 return 0, ErrBadType 321 } 322 323 seconds, err := IntervalString(e.args[n].valStr, defaultSign) 324 if err != nil { 325 return 0, ErrBadType 326 } 327 328 return seconds, nil 329 } 330 331 func (e *expr) GetIntervalNamedOrPosArgDefault(k string, n, defaultSign int, v int64) (int64, error) { 332 var val string 333 var err error 334 if a := e.getNamedArg(k); a != nil { 335 val, err = a.doGetStringArg() 336 if err != nil { 337 return 0, ErrBadType 338 } 339 } else { 340 if len(e.args) <= n { 341 return v, nil 342 } 343 344 if e.args[n].etype != EtString { 345 return 0, ErrBadType 346 } 347 val = e.args[n].valStr 348 } 349 350 seconds, err := IntervalString(val, defaultSign) 351 if err != nil { 352 return 0, ErrBadType 353 } 354 355 return int64(seconds), nil 356 } 357 358 func (e *expr) GetStringArg(n int) (string, error) { 359 if len(e.args) <= n { 360 return "", ErrMissingArgument 361 } 362 363 return e.args[n].doGetStringArg() 364 } 365 366 func (e *expr) GetStringArgs(n int) ([]string, error) { 367 if len(e.args) <= n { 368 return nil, ErrMissingArgument 369 } 370 371 strs := make([]string, 0, len(e.args)-n) 372 373 for i := n; i < len(e.args); i++ { 374 a, err := e.GetStringArg(i) 375 if err != nil { 376 return nil, err 377 } 378 strs = append(strs, a) 379 } 380 381 return strs, nil 382 } 383 384 func (e *expr) GetStringArgDefault(n int, s string) (string, error) { 385 if len(e.args) <= n { 386 return s, nil 387 } 388 389 return e.args[n].doGetStringArg() 390 } 391 392 func (e *expr) GetStringNamedOrPosArgDefault(k string, n int, s string) (string, error) { 393 if a := e.getNamedArg(k); a != nil { 394 return a.doGetStringArg() 395 } 396 397 return e.GetStringArgDefault(n, s) 398 } 399 400 func (e *expr) GetFloatArg(n int) (float64, error) { 401 if len(e.args) <= n { 402 return 0, ErrMissingArgument 403 } 404 405 return e.args[n].doGetFloatArg() 406 } 407 408 func (e *expr) GetFloatArgDefault(n int, v float64) (float64, error) { 409 if len(e.args) <= n { 410 return v, nil 411 } 412 413 return e.args[n].doGetFloatArg() 414 } 415 416 func (e *expr) GetFloatNamedOrPosArgDefault(k string, n int, v float64) (float64, error) { 417 if a := e.getNamedArg(k); a != nil { 418 return a.doGetFloatArg() 419 } 420 421 return e.GetFloatArgDefault(n, v) 422 } 423 424 func (e *expr) GetIntArg(n int) (int, error) { 425 if len(e.args) <= n { 426 return 0, ErrMissingArgument 427 } 428 429 return e.args[n].doGetIntArg() 430 } 431 432 func (e *expr) GetIntArgs(n int) ([]int, error) { 433 if len(e.args) < n { 434 return nil, ErrMissingArgument 435 } 436 437 ints := make([]int, 0, len(e.args)-n) 438 439 for i := n; i < len(e.args); i++ { 440 a, err := e.GetIntArg(i) 441 if err != nil { 442 return nil, err 443 } 444 ints = append(ints, a) 445 } 446 447 return ints, nil 448 } 449 450 func (e *expr) GetIntArgDefault(n, d int) (int, error) { 451 if len(e.args) <= n { 452 return d, nil 453 } 454 455 return e.args[n].doGetIntArg() 456 } 457 458 func (e *expr) GetIntArgWithIndication(n int) (int, bool, error) { 459 if len(e.args) <= n { 460 return 0, false, nil 461 } 462 463 v, err := e.args[n].doGetIntArg() 464 return v, true, err 465 } 466 467 func (e *expr) GetIntNamedOrPosArgWithIndication(k string, n int) (int, bool, error) { 468 if a := e.getNamedArg(k); a != nil { 469 v, err := a.doGetIntArg() 470 return v, true, err 471 } 472 473 return e.GetIntArgWithIndication(n) 474 } 475 476 func (e *expr) GetIntNamedOrPosArgDefault(k string, n, d int) (int, error) { 477 if a := e.getNamedArg(k); a != nil { 478 return a.doGetIntArg() 479 } 480 481 return e.GetIntArgDefault(n, d) 482 } 483 484 func (e *expr) GetIntOrInfArg(n int) (IntOrInf, error) { 485 if len(e.args) <= n { 486 return IntOrInf{}, ErrMissingArgument 487 } 488 489 return e.args[n].doGetIntOrInfArg() 490 } 491 492 func (e *expr) GetIntOrInfArgDefault(n int, d IntOrInf) (IntOrInf, error) { 493 if len(e.args) <= n { 494 return d, nil 495 } 496 497 return e.args[n].doGetIntOrInfArg() 498 } 499 500 func (e *expr) GetIntOrInfNamedOrPosArgDefault(k string, n int, d IntOrInf) (IntOrInf, error) { 501 if a := e.getNamedArg(k); a != nil { 502 return a.doGetIntOrInfArg() 503 } 504 505 return e.GetIntOrInfArgDefault(n, d) 506 } 507 508 func (e *expr) GetNamedArg(name string) Expr { 509 return e.getNamedArg(name) 510 } 511 512 func (e *expr) GetBoolNamedOrPosArgDefault(k string, n int, b bool) (bool, error) { 513 if a := e.getNamedArg(k); a != nil { 514 return a.doGetBoolArg() 515 } 516 517 return e.GetBoolArgDefault(n, b) 518 } 519 520 func (e *expr) GetBoolArgDefault(n int, b bool) (bool, error) { 521 if len(e.args) <= n { 522 return b, nil 523 } 524 525 return e.args[n].doGetBoolArg() 526 } 527 528 func (e *expr) GetNodeOrTagArgs(n int, single bool) ([]NodeOrTag, error) { 529 // if single==false, zero nodes is OK 530 if single && len(e.args) <= n || len(e.args) < n { 531 return nil, ErrMissingArgument 532 } 533 534 nodeTags := make([]NodeOrTag, 0, len(e.args)-n) 535 536 var err error 537 until := len(e.args) 538 if single { 539 until = n + 1 540 } 541 for i := n; i < until; i++ { 542 var nodeTag NodeOrTag 543 nodeTag.Value, err = e.GetIntArg(i) 544 if err != nil { 545 // Try to parse it as String 546 nodeTag.Value, err = e.GetStringArg(i) 547 if err != nil { 548 return nil, err 549 } 550 nodeTag.IsTag = true 551 } 552 nodeTags = append(nodeTags, nodeTag) 553 } 554 555 return nodeTags, nil 556 } 557 558 func (e *expr) IsInterfaceNil() bool { 559 return e == nil 560 } 561 562 func (e *expr) insertFirstArg(exp *expr) error { 563 if e.etype != EtFunc { 564 return fmt.Errorf("pipe to not a function") 565 } 566 567 newArgs := []*expr{exp} 568 e.args = append(newArgs, e.args...) 569 570 if e.argString == "" { 571 e.argString = exp.ToString() 572 } else { 573 e.argString = exp.ToString() + "," + e.argString 574 } 575 576 return nil 577 } 578 579 func skipWhitespace(e string) string { 580 skipTo := len(e) 581 for i, r := range e { 582 if !unicode.IsSpace(r) { 583 skipTo = i 584 break 585 } 586 } 587 return e[skipTo:] 588 } 589 590 func parseExprWithoutPipe(e string) (Expr, string, error) { 591 e = skipWhitespace(e) 592 593 if e == "" { 594 return nil, "", ErrMissingExpr 595 } 596 597 if '0' <= e[0] && e[0] <= '9' || e[0] == '-' || e[0] == '+' { 598 val, valStr, e, err := parseConst(e) 599 r, _ := utf8.DecodeRuneInString(e) 600 if !unicode.IsLetter(r) { 601 return &expr{val: val, etype: EtConst, valStr: valStr}, e, err 602 } 603 } 604 605 if e[0] == '\'' || e[0] == '"' { 606 val, e, err := parseString(e) 607 return &expr{valStr: val, etype: EtString}, e, err 608 } 609 610 name, e := parseName(e) 611 612 if name == "" { 613 return nil, e, ErrMissingArgument 614 } 615 616 nameLower := strings.ToLower(name) 617 if nameLower == "false" || nameLower == "true" { 618 return &expr{valStr: nameLower, etype: EtBool, target: nameLower}, e, nil 619 } 620 621 if e != "" && e[0] == '(' { 622 // TODO(civil): Tags: make it a proper Expression 623 if name == "seriesByTag" { 624 argString, _, _, e, err := parseArgList(e) 625 return &expr{target: name + "(" + argString + ")", etype: EtName}, e, err 626 } 627 exp := &expr{target: name, etype: EtFunc} 628 629 argString, posArgs, namedArgs, e, err := parseArgList(e) 630 exp.argString = argString 631 exp.args = posArgs 632 exp.namedArgs = namedArgs 633 634 return exp, e, err 635 } 636 637 return &expr{target: name}, e, nil 638 } 639 640 func parseExprInner(e string) (Expr, string, error) { 641 exp, e, err := parseExprWithoutPipe(e) 642 if err != nil { 643 return exp, e, err 644 } 645 return pipe(exp.(*expr), e) 646 } 647 648 // ParseExpr actually do all the parsing. It returns expression, original string and error (if any) 649 func ParseExpr(e string) (Expr, string, error) { 650 exp, e, err := parseExprInner(e) 651 if err != nil { 652 return exp, e, err 653 } 654 exp, err = defineMap.expandExpr(exp.(*expr)) 655 return exp, e, err 656 } 657 658 func pipe(exp *expr, e string) (*expr, string, error) { 659 e = skipWhitespace(e) 660 661 if e == "" || e[0] != '|' { 662 return exp, e, nil 663 } 664 665 wr, e, err := parseExprWithoutPipe(e[1:]) 666 if err != nil { 667 return exp, e, err 668 } 669 if wr == nil { 670 return exp, e, nil 671 } 672 673 err = wr.(*expr).insertFirstArg(exp) 674 if err != nil { 675 return exp, e, err 676 } 677 exp = wr.(*expr) 678 679 return pipe(exp, e) 680 } 681 682 // IsNameChar checks if specified char is actually a valid (from graphite's protocol point of view) 683 func IsNameChar(r byte) bool { 684 return false || 685 'a' <= r && r <= 'z' || 686 'A' <= r && r <= 'Z' || 687 '0' <= r && r <= '9' || 688 r == '.' || r == '_' || 689 r == '-' || r == '*' || 690 r == '?' || r == ':' || 691 r == '[' || r == ']' || 692 r == '^' || r == '$' || 693 r == '<' || r == '>' || 694 r == '&' || r == '#' || 695 r == '/' || r == '%' || 696 r == '@' 697 } 698 699 func IsDigit(r byte) bool { 700 return '0' <= r && r <= '9' 701 } 702 703 func parseArgList(e string) (string, []*expr, map[string]*expr, string, error) { 704 var ( 705 posArgs []*expr 706 namedArgs map[string]*expr 707 ) 708 eOrig := e 709 710 if e[0] != '(' { 711 panic("arg list should start with paren") 712 } 713 714 var argStringBuffer bytes.Buffer 715 716 e = e[1:] 717 718 // check for empty args 719 t := skipWhitespace(e) 720 if t != "" && t[0] == ')' { 721 return "", posArgs, namedArgs, t[1:], nil 722 } 723 724 charNum := 1 725 for { 726 var arg Expr 727 var err error 728 charNum++ 729 730 argString := e 731 arg, e, err = parseExprInner(e) 732 if err != nil { 733 return "", nil, nil, e, err 734 } 735 736 if e == "" { 737 return "", nil, nil, "", ErrMissingComma 738 } 739 740 // we now know we're parsing a key-value pair 741 if arg.IsName() && e[0] == '=' { 742 e = e[1:] 743 argCont, eCont, errCont := parseExprInner(e) 744 if errCont != nil { 745 return "", nil, nil, eCont, errCont 746 } 747 748 if eCont == "" { 749 return "", nil, nil, "", ErrMissingComma 750 } 751 752 if !argCont.IsConst() && !argCont.IsName() && !argCont.IsString() && !argCont.IsBool() { 753 return "", nil, nil, eCont, ErrBadType 754 } 755 756 if namedArgs == nil { 757 namedArgs = make(map[string]*expr) 758 } 759 760 exp := &expr{ 761 etype: argCont.Type(), 762 val: argCont.FloatValue(), 763 valStr: argCont.StringValue(), 764 target: argCont.Target(), 765 } 766 namedArgs[arg.Target()] = exp 767 768 e = eCont 769 if argStringBuffer.Len() > 0 { 770 argStringBuffer.WriteByte(',') 771 } 772 argStringBuffer.WriteString(argString[:len(argString)-len(e)]) 773 charNum += len(argString) - len(e) 774 } else { 775 exp := arg.toExpr().(*expr) 776 posArgs = append(posArgs, exp) 777 778 if argStringBuffer.Len() > 0 { 779 argStringBuffer.WriteByte(',') 780 } 781 if exp.IsFunc() { 782 expString := exp.ToString() 783 argStringBuffer.WriteString(expString) 784 charNum += len(expString) 785 } else { 786 argStringBuffer.WriteString(argString[:len(argString)-len(e)]) 787 charNum += len(argString) - len(e) 788 } 789 } 790 791 // after the argument, trim any trailing spaces 792 e = skipWhitespace(e) 793 794 if e[0] == ')' { 795 return argStringBuffer.String(), posArgs, namedArgs, e[1:], nil 796 } 797 798 if e[0] != ',' && e[0] != ' ' { 799 return "", nil, nil, "", merry.Wrap(ErrUnexpectedCharacter).WithUserMessagef("string_to_parse=`%v`, character_number=%v, character=`%v`", eOrig, charNum, string(e[0])) 800 } 801 802 e = e[1:] 803 } 804 } 805 806 func parseConst(s string) (float64, string, string, error) { 807 var i int 808 // All valid characters for a floating-point constant 809 // Just slurp them all in and let ParseFloat sort 'em out 810 for i < len(s) && (IsDigit(s[i]) || s[i] == '.' || s[i] == '+' || s[i] == '-' || s[i] == 'e' || s[i] == 'E') { 811 i++ 812 } 813 814 v, err := strconv.ParseFloat(s[:i], 64) 815 if err != nil { 816 return 0, "", "", err 817 } 818 819 return v, s[:i], s[i:], err 820 } 821 822 // RangeTables is an array of *unicode.RangeTable 823 var RangeTables []*unicode.RangeTable 824 825 var disallowedCharactersInMetricName = map[rune]struct{}{ 826 '(': struct{}{}, 827 ')': struct{}{}, 828 '"': struct{}{}, 829 '\'': struct{}{}, 830 ' ': struct{}{}, 831 '/': struct{}{}, 832 } 833 834 func unicodeRuneAllowedInName(r rune) bool { 835 if _, ok := disallowedCharactersInMetricName[r]; ok { 836 return false 837 } 838 839 return true 840 } 841 842 func parseName(s string) (string, string) { 843 var ( 844 braces, i, w int 845 r rune 846 isEscape bool 847 isDefault bool 848 ) 849 850 buf := bytes.NewBuffer(make([]byte, 0, len(s))) 851 852 FOR: 853 for braces, i, w = 0, 0, 0; i < len(s); i += w { 854 if s[i] != '\\' { 855 err := buf.WriteByte(s[i]) 856 if err != nil { 857 break FOR 858 } 859 } 860 isDefault = false 861 w = 1 862 if IsNameChar(s[i]) { 863 continue 864 } 865 866 switch s[i] { 867 case '\\': 868 if isEscape { 869 err := buf.WriteByte(s[i]) 870 if err != nil { 871 break FOR 872 } 873 isEscape = false 874 continue 875 } 876 isEscape = true 877 case '{': 878 if isEscape { 879 isDefault = true 880 } else { 881 braces++ 882 } 883 case '}': 884 if isEscape { 885 isDefault = true 886 } else { 887 if braces == 0 { 888 break FOR 889 } 890 braces-- 891 } 892 case ',': 893 if isEscape { 894 isDefault = true 895 } else if braces == 0 { 896 break FOR 897 } 898 /* */ 899 case '=': 900 // allow metric name to end with any amount of `=` without treating it as a named arg or tag 901 if !isEscape { 902 if len(s) < i+2 || s[i+1] == '=' || s[i+1] == ',' || s[i+1] == ')' { 903 continue 904 } 905 } 906 fallthrough 907 /* */ 908 default: 909 isDefault = true 910 } 911 if isDefault { 912 r, w = utf8.DecodeRuneInString(s[i:]) 913 if unicodeRuneAllowedInName(r) && unicode.In(r, RangeTables...) { 914 continue 915 } 916 if !isEscape { 917 break FOR 918 } 919 isEscape = false 920 continue 921 } 922 } 923 924 if i == len(s) { 925 return buf.String(), "" 926 } 927 928 return s[:i], s[i:] 929 } 930 931 func parseString(s string) (string, string, error) { 932 if s[0] != '\'' && s[0] != '"' { 933 panic("string should start with open quote") 934 } 935 936 match := s[0] 937 938 s = s[1:] 939 940 var i int 941 for i < len(s) && s[i] != match { 942 i++ 943 } 944 945 if i == len(s) { 946 return "", "", ErrMissingQuote 947 948 } 949 950 return s[:i], s[i+1:], nil 951 } 952 953 func StartAlignTo(start int64, alignTo string) (int64, error) { 954 var newDate time.Time 955 re := regexp.MustCompile(`^[0-9]+`) 956 alignTo = re.ReplaceAllString(alignTo, "") 957 958 startDate := time.Unix(start, 0).UTC() 959 switch { 960 case strings.HasPrefix(alignTo, "y"): 961 newDate = time.Date(startDate.Year(), 1, 1, 0, 0, 0, 0, time.UTC) 962 case strings.HasPrefix(alignTo, "mon"): 963 newDate = time.Date(startDate.Year(), startDate.Month(), 1, 0, 0, 0, 0, time.UTC) 964 case strings.HasPrefix(alignTo, "w"): 965 if !IsDigit(alignTo[len(alignTo)-1]) { 966 return start, ErrInvalidInterval 967 } 968 newDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), 0, 0, 0, 0, time.UTC) 969 dayOfWeek, err := strconv.Atoi(alignTo[len(alignTo)-1:]) 970 if err != nil { 971 return start, ErrInvalidInterval 972 } 973 974 startDayOfWeek := int(startDate.Weekday()) 975 daysToSubtract := startDayOfWeek - dayOfWeek 976 if daysToSubtract < 0 { 977 daysToSubtract += 7 978 } 979 newDate = newDate.AddDate(0, 0, -daysToSubtract) 980 case strings.HasPrefix(alignTo, "d"): 981 newDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), 0, 0, 0, 0, time.UTC) 982 case strings.HasPrefix(alignTo, "h"): 983 newDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), startDate.Hour(), 0, 0, 0, time.UTC) 984 case strings.HasPrefix(alignTo, "min"): 985 newDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), startDate.Hour(), startDate.Minute(), 0, 0, time.UTC) 986 case strings.HasPrefix(alignTo, "s"): 987 newDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), startDate.Hour(), startDate.Minute(), startDate.Second(), 0, time.UTC) 988 default: 989 return start, ErrInvalidInterval 990 } 991 return newDate.Unix(), nil 992 }