Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1671)

Unified Diff: appengine/cmd/dm/distributor/impl/jobsim/parser/grammar.peg

Issue 1537883002: Initial distributor implementation (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: work in progress Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/cmd/dm/distributor/impl/jobsim/parser/grammar.peg
diff --git a/appengine/cmd/dm/distributor/impl/jobsim/parser/grammar.peg b/appengine/cmd/dm/distributor/impl/jobsim/parser/grammar.peg
new file mode 100644
index 0000000000000000000000000000000000000000..0ca703206936fe23b358ab0f8db38488eaf1bc14
--- /dev/null
+++ b/appengine/cmd/dm/distributor/impl/jobsim/parser/grammar.peg
@@ -0,0 +1,197 @@
+// vim: syntax=go
+{
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package parser
+
+type retriesHolder uint64
+type identityHolder uint64
+
+var whitespaceRE = regexp.MustCompile("#[^\n]*\n|\\s+")
+
+// CleanPhrase removes all whitespace and comments from a phrase in preparation
+// for parsing it. The parsers defined in this package only operate on cleaned
+// phrases, and will fail to parse if you provide a phrase with whitespace.
+func CleanPhrase(p string) string {
+ return whitespaceRE.ReplaceAllLiteralString(p, "")
+}
+
+// ParsePhrase is a convenience function for the parser functions in this
+// package to return a typed Phrase object as the result of a string.
+func ParsePhrase(p string) (Phrase, error) {
+ ret, err := Parse("<string>", []byte(p))
+ if err != nil {
+ return nil, err
+ }
+ return ret.(Phrase), nil
+}
+}
+
+Overall = p:Phrase !. {
+ return p, nil
+} / p:Phrase ext:Extra {
+ return nil, fmt.Errorf("found extra: %q", ext.(string))
+} / !. {
+ return nil, fmt.Errorf("empty phrase")
+} / ext:Extra {
+ return nil, fmt.Errorf("expected phrase: %q", ext.(string))
+}
+
+Extra = .* {
+ return string(c.text), nil
+}
+
+Phrase = ret:ReturnStage {
+ return Phrase{ret.(Stage)}, nil
+} / first:Stage middleI:(',' Stage)* retI:(',' ReturnStage)? {
+ middle, _ := middleI.([]interface{})
+ retStage, _ := retI.([]interface{})
+
+ amt := 1
+ if middle != nil {
+ amt += len(middle)
+ }
+ if retStage != nil {
+ amt++
+ }
+
+ ret := make(Phrase, 0, amt)
+ ret = append(ret, first.(Stage))
+ for _, itm := range middle {
+ ret = append(ret, itm.([]interface{})[1].(Stage))
+ }
+ if retStage != nil {
+ ret = append(ret, retStage[1].(Stage))
+ }
+
+ return ret, nil
+} / ',' .* {
+ return nil, fmt.Errorf("expected stage in %q", string(c.text))
+}
+
+Stage = s:(FailureStage / StallStage / DepsStage) {
+ return s, nil
+}
+
+FailureStage = '%' num:Num {
+ return FailureStage(num.(uint64)), nil
+}
+
+StallStage = '@' amt:Duration {
+ return StallStage(amt.(time.Duration)), nil
+}
+
+ReturnStage = '=' val:Num exp:('<' Duration)? {
+ ret := &ReturnStage{Value: val.(uint64)}
+ if exp != nil {
+ ret.Expiration = exp.([]interface{})[1].(time.Duration)
+ }
+ return ret, nil
+}
+
+DepsStage = first:Dependency restI:('&' Dependency)* {
+ rest, _ := restI.([]interface{})
+
+ if rest == nil {
+ return DepsStage{first.(*Dependency)}, nil
+ }
+ ret := make(DepsStage, 0, 1+len(rest))
+ ret = append(ret, first.(*Dependency))
+ for _, itm := range rest{
+ ret = append(ret, itm.([]interface{})[1].(*Dependency))
+ }
+ return ret, nil
+} / '&' .* {
+ return nil, fmt.Errorf("expected dependency in %q", string(c.text))
+}
+
+Dependency = shards:Shards? attempts:Attempts? id:ID options:Option? subI:( '(' Phrase ')' )? {
+ ret := &Dependency{Name: id.(string)}
+
+ if shards != nil {
+ ret.ShardCount = shards.(uint64)
+ }
+
+ if attempts != nil {
+ ret.AttemptNums = attempts.(RangeSlice)
+ }
+
+ if options != nil {
+ switch x := options.(type) {
+ case retriesHolder:
+ if attempts != nil {
+ return nil, fmt.Errorf(
+ "in %q: retries are incompatible with specified Attempts",
+ string(c.text))
+ }
+ ret.Retries = uint64(x)
+
+ case identityHolder:
+ ret.Uniq = uint64(x)
+ }
+ }
+
+ sub, _ := subI.([]interface{})
+ if sub != nil {
+ ret.Substages = sub[1].(Phrase)
+ }
+
+ return ret, nil
+}
+
+Option = '+' num:Num {
+ return retriesHolder(num.(uint64)), nil
+} / '^' num:Num {
+ return identityHolder(num.(uint64)), nil
+}
+
+Shards = '{' num:Num '}' {
+ return num, nil
+}
+
+Attempts = '[' rs:RangeSlice ']' {
+ return rs, nil
+}
+
+RangeSlice = firstI:Range restI:(',' Range)* {
+ rest, _ := restI.([]interface{})
+
+ ret := make(RangeSlice, 0, 1+len(rest))
+ ret = append(ret, firstI.(Range))
+ for _, itm := range rest {
+ ret = append(ret, itm.([]interface{})[1].(Range))
+ }
+
+ return ret, nil
+}
+
+Range = loI:Num '-' hiI:Num {
+ lo := loI.(uint64)
+ hi := hiI.(uint64)
+
+ if lo >= hi {
+ return nil, fmt.Errorf("invalid range %q: lo >= hi", string(c.text))
+ }
+
+ return Range{lo, hi}, nil
+} / num:Num {
+ return Range{num.(uint64), 0}, nil
+}
+
+Duration = num:Num {
+ return time.Second * time.Duration(num.(uint64)), nil
+}
+
+Num = '0' {
+ return nil, fmt.Errorf("zero value not acceptable")
+} / [1-9][0-9]* {
+ return strconv.ParseUint(string(c.text), 10, 64)
+} / .* {
+ return nil, fmt.Errorf("expected number, got %q", string(c.text))
+}
+
+ID = [a-zA-Z'_]+ {
+ return string(c.text), nil
+}

Powered by Google App Engine
This is Rietveld 408576698