// 2. Контроль зацикливаний тега tTagIncludeCon func chekloop(tpls map[string]parser.Ttpl) { var ( key string mitem = []interface{}{} ) matrix := make(map[interface{}][]interface{}, len(tpls)) for key = range tpls { for _, item := range tpls[key] { switch v := item.(type) { case tTagIncludeVar: if key == v[0] { err.Panic(err.New("Error: loops detection: "+key+" - "+key, 0)) } mitem = append(mitem, v[0]) } } if len(mitem) > 0 { matrix[key] = mitem } } loop := tarjan.Connections(matrix) for i := range loop { if len(loop[i]) > 1 { err.Panic(err.New("Error: loops detection: "+fmt.Sprint(loop[i]), 0)) } } }
// parse plural tag func parseTagPlural(source []string) *tTagPlural { if len(source) < 2 { err.Panic(err.New("error parsing to Plural Tag: "+fmt.Sprint(source), 0)) } i, e := strconv.ParseUint(source[1], 10, 16) err.Panic(e) return &tTagPlural{uint16(i), []string{source[0]}} }
func (t *TGen) decode(val reflect.Type) { v, ok := t.stackName.Pop() if !ok { err.Panic(err.New("stack name empty", 0)) } name := v.(string) switch val.Kind() { case reflect.Uint8: t.decUint8(name) case reflect.Uint16: t.decUint16(name) case reflect.Uint32: t.decUint32(name) case reflect.Uint64: t.decUint64(name) case reflect.Uint: t.decUint(name) case reflect.Int8: t.decInt8(name) case reflect.Int16: t.decInt16(name) case reflect.Int32: t.decInt32(name) case reflect.Int64: t.decInt64(name) case reflect.Int: t.decInt(name) case reflect.Float32: t.decFloat32(name) case reflect.Float64: t.decFloat64(name) case reflect.Complex64: t.decComplex64(name) case reflect.Complex128: t.decComplex128(name) case reflect.Bool: t.decBool(name) case reflect.String: t.decString(name) case reflect.Slice: t.decSlice(name, val) case reflect.Array: t.decArray(name, val) case reflect.Ptr: t.decPtr(name, val) case reflect.Struct: t.decStruct(name, val) case reflect.Map: t.decMap(name, val) case reflect.Interface: err.Panic(err.New("interface type not supported, only strong typed", 0)) } }
// Add add to function map func (t FuncMap) Add(name string, f interface{}) { v := reflect.ValueOf(f) if v.Kind() != reflect.Func { err.Panic(err.New(errNotFunction, 0)) } t[name] = v }
func parseTag(source []byte) (tag interface{}) { defer func() { if e := recover(); e != nil { v := e.(*err.OpenErr) v.Text += "err parse tpl: " + string(source) err.Panic(v) } }() list := parser.SplitWord(source, 32) switch list[0] { // основные теги case "!": case "inc": tag = parseTagInclude(list[1:]) case "i18n": tag = parseTagi18n(list[1:]) case "for": tag = parseTagFor(list[1:]) default: // переменная контекста // либо функция (расширенные теги) slice := []byte(list[0]) if bytes.HasPrefix(slice, []byte(".")) { tag = tTagVar(list[0][1:]) } else if bytes.HasPrefix(slice, []byte("@.")) { tag = tTagVarHtmlEsc(list[0][2:]) } else { tag = parseTagFunc(list) } } return }
func (t *TReplaser) Replace(name string, v map[string]interface{}, writer io.Writer) { tpl := t.tpl.tpl[name] if tpl == nil { err.Panic(err.New("Err, tpl '"+name+"' not found", 0)) } t.replace(tpl, v, writer) }
// Call call function from a function map func (t FuncMap) Call(name string, params ...interface{}) []reflect.Value { f, e := t[name] if !e { err.Panic(err.New(errFunctionNotFound, 0)) } return call(f, params...) }
// Add add to function slice, return element id func (t *FuncSlice) Add(f interface{}) int { v := reflect.ValueOf(f) if v.Kind() != reflect.Func { err.Panic(err.New(errNotFunction, 0)) } *t = append(*t, v) return len(*t) - 1 }
// parse context var tag func parseTagVar(source []string) (v *tTagVar) { i, e := strconv.ParseUint(source[0], 10, 16) err.Panic(e) v = &tTagVar{id: uint16(i)} if len(source) > 1 { v.format = source[1] } return }
func call(f reflect.Value, params ...interface{}) []reflect.Value { if len(params) != f.Type().NumIn() { err.Panic(err.New(errNumberParamsNotAdapted, 0)) } in := make([]reflect.Value, len(params)) for k, param := range params { in[k] = reflect.ValueOf(param) } return f.Call(in) }
// Encode generate encode function from value func (t *TGen) Encode(val interface{}) { valType := reflect.TypeOf(val) t.src = "\nfunc Encode(buf IBuf, t " + TypeName(valType.String(), true) + ") {\n" t.stackName.Push("t") t.encode(valType) t.src += "}\n\n" t.stackName.Clear() t.tmpNameGen.Clear() _, e := t.f.Write([]byte(t.src)) err.Panic(e) }
// Decode generate decode function from value func (t *TGen) Decode(val interface{}) { valType := reflect.TypeOf(val) t.src = "\nfunc Decode(buf IBuf) (t " + TypeName(valType.String(), true) + ", e error) {\n" t.src += "var (\npart []byte\nbt byte\nln uint32\n)\n\n" t.stackName.Push("t") t.decode(valType) t.src += "return\n}\n\n" t.stackName.Clear() t.tmpNameGen.Clear() _, e := t.f.Write([]byte(t.src)) err.Panic(e) }
// parse user functions tag func parseTagFunc(source []string) (v *tTagFunction) { var ( i uint64 e error ) v = &tTagFunction{fname: source[0]} for _, val := range source[1:] { i, e = strconv.ParseUint(val, 10, 16) err.Panic(e) v.vars = append(v.vars, uint16(i)) } return }
// parseTagi18n func parseTagFor(source []string) interface{} { var m [2]string if len(source) < 3 { err.Panic(err.New("error parse tag 'For'", 0)) } if source[0][0] == 46 { if len(source[0]) > 1 { m[0] = source[0][1:] } else { m[0] = "." } return tTagi18nVar(m) } m[0] = source[0] return &tTagFor{} }
// 3. for a tTagIncludeCon init before use func (t *Ttpl) tagIncludeCon_Init() { for key, val := range t.tpl { for key1 := range val { switch v := val[key1].(type) { case tTagIncludeVar: // не полное имя и не имя переменной контекста - значит короткое имя if v[0][0] == 47 { tpl := t.tpl[v[0]] if tpl == nil { err.Panic(err.New("Err parse from tpl: '"+key+"' include tag. Not found tpl: '"+v[0]+"'", 0)) } val[key1] = &tTagIncludeCon{tpl: tpl, contextVar: v[1]} } } } } }
// Loade template func (t *Ttpl) Load(patch string) { var ( fileSource []byte ) base := "/" + filepath.Base(patch) + "/" toparse := new(parser.ToParse) toparse.Delimiter[0] = []byte("{{") toparse.Delimiter[1] = []byte("}}") toparse.ParseTag = parseTag toparse.ParseText = parseText fileList, e := ioutil.ReadDir(patch) err.Panic(e) for _, item := range fileList { fileSource, e = ioutil.ReadFile(patch + "/" + item.Name()) t.tpl[base+item.Name()] = parser.Parse(fileSource, toparse) } }
// New create new generator func New(outputFile string, imported ...string) *TGen { os.Remove(outputFile) f, e := os.Create(outputFile) err.Panic(e) outputFile = filepath.Base(outputFile) outputFile, _ = extfilepath.Ext(outputFile) f.Write([]byte("// It's file auto generate encodebinaryFast\n\n")) f.Write([]byte("package " + outputFile + "\n\n")) resultImport := ". \"github.com/Cergoo/gol/encode/binary/primitive\"\n" for i := range imported { resultImport += "\"" + imported[i] + "\"\n" } f.Write([]byte("import (\n" + resultImport + ")\n")) return &TGen{ stackName: make(stack.TStack, 0, 10), tmpNameGen: tmpName.New(), f: f, } }
func (t *TGen) encode(val reflect.Type) { v, ok := t.stackName.Pop() if !ok { err.Panic(err.New("stack name empty", 0)) } name := v.(string) // use json.Marshaler implement if val.Implements(MarshalerType) { tmpName := t.tmpNameGen.Get() // get tmp var name t.src += "tmpName, _ := " + name + ".MarshalJSON()\n" t.src += "buf = append(buf, " + tmpName + ")\n" return } switch val.Kind() { case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: t.genUint(name) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: t.genInt(name) case reflect.Float32, reflect.Float64: t.genFloat(name) case reflect.Bool: t.genBool(name) case reflect.String: t.genString(name) case reflect.Slice: t.genSlice(name, val) case reflect.Array: t.genArray(name, val) case reflect.Ptr: t.genPtr(name, val) case reflect.Struct: t.genStruct(name, val) case reflect.Map: t.genMap(name, val) case reflect.Interface: t.genInterface(name, val) } }
// Get phrase func (t *TReplacer) p(tpl *titem, context []interface{}) []byte { var ( varFloate float64 varBool bool varUint16 uint16 result []byte ) if int(tpl.contextCount) > len(context) { err.Panic(err.New("i18n Mismatch context len: ("+strconv.Itoa(int(tpl.contextCount))+" , "+strconv.Itoa(len(context))+") "+fmt.Sprintf("%#v", tpl.items), 0)) } for _, item := range tpl.items { switch v := item.(type) { case tTagText: result = append(result, v...) case *tTagVar: if len(v.format) > 0 { result = append(result, []byte(fmt.Sprintf(v.format, context[v.id]))...) } else { result = append(result, []byte(fmt.Sprint(context[v.id]))...) } case *tTagPlural: varFloate, varBool = refl.Floate(context[v.count]) if varBool { result = append(result, []byte(v.text[t.lang.PluralRule(varFloate)])...) } case *tTagFunction: var vars []interface{} for _, varUint16 = range v.vars { vars = append(vars, context[varUint16]) } result = append(result, v.f(vars)...) } } return result }
// Save config to json format file func Save(fromVar interface{}, toPath string) { data, e := json.Marshal(fromVar) err.Panic(e) e = ioutil.WriteFile(toPath, data, 0664) err.Panic(e) }
// Del delete session. func (t *TSession) Del(w http.ResponseWriter, r *http.Request) { vcoockie, e := r.Cookie(SID) err.Panic(e) t.Stor.Del(vcoockie.Value) cookie.DelCookie(w, SID) }
// Load load language resources func (t *Ti18n) Load(patch string) { type ( tmpLang struct { PluralRule string Plural map[string][]string Phrase map[string]string Lists map[string][]string } ) // создаётся временная структура и в неё парсится json tmpLangs := make(map[string]*tmpLang) fileList, e := ioutil.ReadDir(patch) err.Panic(e) var ( name string valPre map[string]string keyPre string ) for _, item := range fileList { vtmpLang := new(tmpLang) vtmpLang.Plural = make(map[string][]string) vtmpLang.Lists = make(map[string][]string) jsonConfig.Load(patch+string(filepath.Separator)+item.Name(), &vtmpLang) name, _ = gfilepath.Ext(item.Name()) tmpLangs[name] = vtmpLang } // chek equivalent all lang resurce for key, val := range tmpLangs { if valPre != nil && !refl.MapKeysEq(valPre, val.Phrase) { err.Panic(err.New("Lang phrase not equivalent: "+keyPre+", "+key, 0)) } valPre = val.Phrase keyPre = key } toparse := new(parser.ToParse) toparse.Delimiter[0] = []byte("{{") toparse.Delimiter[1] = []byte("}}") toparse.ParseTag = parseTag toparse.ParseText = parseText for key, item := range tmpLangs { lang := &Tlang{ items: make(map[string]*titem), Plural: item.Plural, Lists: item.Lists, PluralRule: plural.PluralRules[item.PluralRule], F: make(map[string]func([]interface{}) []byte), } if lang.PluralRule == nil && len(lang.Plural) > 0 { err.Panic(err.New("Not found plural rule: '"+item.PluralRule+"'", 0)) } for keyPhrase, itemPhrase := range item.Phrase { lang.items[keyPhrase] = &titem{items: parser.Parse([]byte(itemPhrase), toparse), contextCount: -1} } existLang := t.lang[key] if existLang == nil { t.lang[key] = lang } else { // add phrase for key, val := range lang.items { existLang.items[key] = val } // add plural for key, val := range lang.Plural { existLang.Plural[key] = val } // add lists for key, val := range lang.Lists { existLang.Lists[key] = val } } } }
// NewID generate random strind http compatible func (t HTTPGenID) NewID() string { val := make([]byte, t) _, e := rand.Read(val) err.Panic(e) return strings.TrimRight(base64.URLEncoding.EncodeToString(val), "=") }
// Load load & remove comments from source .json file func Load(fromPath string, toVar interface{}) { file, e := ioutil.ReadFile(fromPath) err.Panic(e) file = RemoveComment(file) err.Panic(json.Unmarshal(file, toVar)) }
// Call call function from a function slice func (t FuncSlice) Call(id int, params ...interface{}) []reflect.Value { if len(t) <= id { err.Panic(err.New(errFunctionNotFound, 0)) } return call(t[id], params...) }