// Dec will decrement a variable. // args[0] - variable name // args[1] - quantum of value to decrement // if variable name is present in local scope it will be used, // otherwise variable name from global scope is used. func Dec(scope common.Scope, args ...interface{}) interface{} { name, by := args[0].(string), int64(1) if len(args) > 1 { by = args[1].(int64) } vali, g, ok := scope.Get(name) if ok { scope.Set(name, vali.(int64)-by, g) } return "" }
// Rangef will randomly pick a value from args[0] to args[1] // and return the same. // args... are expected to be in float64 func Rangef(scope common.Scope, args ...interface{}) interface{} { rnd := scope.GetRandom() if len(args) == 2 { min, max := args[0].(float64), args[1].(float64) f := (rnd.Float64() * (max - min)) + min return f } else if len(args) == 1 { max := args[0].(float64) return rnd.Float64() * max } panic(fmt.Errorf("atleast one argument expected for range-form\n")) }
// Ranget will randomly pick a value from args[0] to args[1] // and return the same. // args... are expected to be in time.RFC3339 format func Ranget(scope common.Scope, args ...interface{}) interface{} { rnd := scope.GetRandom() start, err := time.Parse(time.RFC3339, args[0].(string)) if err != nil { panic(fmt.Errorf("parsing first argument %v: %v\n", args[0], err)) } end, err := time.Parse(time.RFC3339, args[1].(string)) if err != nil { panic(fmt.Errorf("parsing second argument %v: %v\n", args[0], err)) } t := start.Add(time.Duration(rnd.Int63n(int64(end.Sub(start))))) return t.Format(time.RFC3339) }
// Range will randomly pick a value from args[0] to args[1] // and return the same. // args... are expected to be in int64 func Range(scope common.Scope, args ...interface{}) interface{} { var min, max int64 var err error rnd := scope.GetRandom() if len(args) == 2 { min, max = args[0].(int64), args[1].(int64) if err != nil { panic(fmt.Errorf("parsing argument %v\n", args[1])) } } else if len(args) == 1 { max = args[0].(int64) } else { panic(fmt.Errorf("atleast one argument expected for range-form\n")) } return rnd.Int63n(max-min) + min }
// Bag will fetch a random line from file and return it. // args[0] - filename. func Bag(scope common.Scope, args ...interface{}) interface{} { var err error filename := args[0].(string) if !filepath.IsAbs(filename) { if bagdir, _, ok := scope.GetString("_bagdir"); ok { filename = filepath.Join(bagdir, filename) } else if prodfile, _, ok := scope.GetString("_prodfile"); ok { dirpath := filepath.Dir(prodfile) filename = filepath.Join(dirpath, filename) } } if filename, err = filepath.Abs(filename); err != nil { panic(fmt.Errorf("bad filepath: %v\n", filename)) } bagrw.RLock() records, ok := cacheBagRecords[filename] bagrw.RUnlock() if !ok { records = readBag(filename) bagrw.Lock() cacheBagRecords[filename] = records bagrw.Unlock() } if len(records) > 0 { rnd := scope.GetRandom() record := records[rnd.Intn(len(records))] if len(record) > 0 { return record[0] } } return "" }
// BuildContext to initialize a new scope for evaluating // production grammars. The scope contains the following // elements, // // _globalForms: list of top-level S-expression definitions // _nonterminals: list of top-level non-terminals in production // _weights: running weights for each non-terminal rule // _globals: global scope // _bagdir: absolute path to directory containing bags of data // _prodfile: absolute path to production file // _random: reference to seeded *math.rand.Rand object func BuildContext( scope common.Scope, seed uint64, bagdir, prodfile string) common.Scope { scope["_prodfile"] = prodfile scope.SetBagdir(bagdir) if seed != 0 { scope.SetRandom(rand.New(rand.NewSource(int64(seed)))) } else { now := time.Now().UnixNano() scope.SetRandom(rand.New(rand.NewSource(int64(now)))) } // verify conflicts between user provided form-names // and builtin form-names. for name := range scope["_nonterminals"].(common.NTForms) { if _, ok := builtins[name]; ok { log.Printf("warn: `%v` non-terminal is defined as builtin\n", name) } } return scope.RebuildContext() }
// Choice will randomly pick one of the passed argument // and return back. func Choice(scope common.Scope, args ...interface{}) interface{} { rnd := scope.GetRandom() return args[rnd.Intn(len(args))] }
// Let will define a set of one or more variables in // local scope. // args[0], args[2] ... args[N-1] - variable name // args[1], args[3] ... args[N] - variable value func Let(scope common.Scope, args ...interface{}) interface{} { for i := 0; i < len(args); i += 2 { scope.Set(args[i].(string), args[i+1], false /*global*/) } return "" }