From 58aba161ac87922399a68d4a940ce205bac42e68 Mon Sep 17 00:00:00 2001 From: n0m1s Date: Wed, 18 Sep 2019 09:27:03 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20real=20go=20types=20instead=20of?= =?UTF-8?q?=20string=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jdr/type.go | 202 +++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/jdr/type.go b/jdr/type.go index 58ddf80..b4de5a3 100644 --- a/jdr/type.go +++ b/jdr/type.go @@ -8,16 +8,17 @@ import( "strings" "strconv" "regexp" - "encoding/json" ) var regexp_d = regexp.MustCompile(`^[1-9][0-9]*d([468]|1[02]|20|100)$`) +type JsonValue interface{} + type VariableType interface { Name() string - Validate(value string) bool - ToHTML(value string) (template.HTML, error) - DefaultValue() string + Validate(value JsonValue) bool + ToHTML(value JsonValue) (template.HTML, error) + DefaultValue() JsonValue } type VariableType_badType struct {} @@ -26,15 +27,15 @@ func (*VariableType_badType) Name() string { return "unknown type" } -func (*VariableType_badType) Validate(s string) bool { +func (*VariableType_badType) Validate(s JsonValue) bool { return false } -func (*VariableType_badType) ToHTML(value string) (template.HTML, error) { +func (*VariableType_badType) ToHTML(value JsonValue) (template.HTML, error) { return template.HTML(""), errors.New("unknown type") } -func (*VariableType_badType) DefaultValue() string { +func (*VariableType_badType) DefaultValue() JsonValue { return "" } @@ -44,23 +45,21 @@ func (*VariableType_bool) Name() string { return "bool" } -func (*VariableType_bool) ToBool(value string) (bool, error) { - switch strings.ToLower(value) { - case "true": - return true, nil - case "false": - return false, nil - default: - return false, errors.New("unknown bool value") +func (*VariableType_bool) ToBool(value JsonValue) (bool, error) { + val, isBool := value.(bool) + if !isBool { + return false, errors.New("Non boolean value") } + + return val, nil } -func (self *VariableType_bool) Validate(value string) bool { +func (self *VariableType_bool) Validate(value JsonValue) bool { _, err := self.ToBool(value) return err == nil } -func (self *VariableType_bool) ToHTML(value string) (template.HTML, error) { +func (self *VariableType_bool) ToHTML(value JsonValue) (template.HTML, error) { val, err := self.ToBool(value) if err != nil { return template.HTML(""), err @@ -75,8 +74,8 @@ func (self *VariableType_bool) ToHTML(value string) (template.HTML, error) { return template.HTML(ret), nil } -func (self *VariableType_bool) DefaultValue() string { - return "false" +func (self *VariableType_bool) DefaultValue() JsonValue { + return false } type VariableType_int struct {} @@ -85,16 +84,26 @@ func (*VariableType_int) Name() string { return "int" } -func (self *VariableType_int) ToInt(value string) (int64, error) { - return strconv.ParseInt(value, 10, 64) +func (self *VariableType_int) ToInt(value JsonValue) (int64, error) { + val, isInt := value.(int64) + if !isInt { + val2, isInt := value.(int) + if isInt { + val = int64(val2) + } else { + return 0, errors.New("Not int")) + } + } + + return val, nil } -func (self *VariableType_int) Validate(value string) bool { +func (self *VariableType_int) Validate(value JsonValue) bool { _, err := self.ToInt(value) return err == nil } -func (self *VariableType_int) ToHTML(value string) (template.HTML, error) { +func (self *VariableType_int) ToHTML(value JsonValue) (template.HTML, error) { val, err := self.ToInt(value) if err != nil { return template.HTML(""), err @@ -104,8 +113,8 @@ func (self *VariableType_int) ToHTML(value string) (template.HTML, error) { return template.HTML(ret), nil } -func (self *VariableType_int) DefaultValue() string { - return "0" +func (self *VariableType_int) DefaultValue() JsonValue { + return 0 } type VariableType_float struct {} @@ -114,16 +123,21 @@ func (*VariableType_float) Name() string { return "float" } -func (*VariableType_float) ToFloat(value string) (float64, error) { - return strconv.ParseFloat(value, 64) +func (*VariableType_float) ToFloat(value JsonValue) (float64, error) { + val, isFloat := value.(float64) + if !isFloat { + return 0.0, errors.New("Not a float") + } + + return val, nil } -func (self *VariableType_float) Validate(value string) bool { +func (self *VariableType_float) Validate(value JsonValue) bool { _, err := self.ToFloat(value) return err == nil } -func (self *VariableType_float) ToHTML(value string) (template.HTML, error) { +func (self *VariableType_float) ToHTML(value JsonValue) (template.HTML, error) { val, err := self.ToFloat(value) if err != nil { return template.HTML(""), err @@ -134,8 +148,8 @@ func (self *VariableType_float) ToHTML(value string) (template.HTML, error) { return template.HTML(ret), nil } -func (self *VariableType_float) DefaultValue() string { - return "0.0" +func (self *VariableType_float) DefaultValue() JsonValue { + return 0.0 } type VariableType_string struct {} @@ -144,16 +158,31 @@ func (*VariableType_string) Name() string { return "string" } -func (*VariableType_string) Validate(s string) bool { - return true +func (self *VariableType_string) ToString(value JsonValue) (string, error) { + val, isString := value.(string) + if !isString { + return "", errors.New("Not a string") + } + + return val, nil } -func (self *VariableType_string) ToHTML(value string) (template.HTML, error) { - ret := `` +func (self *VariableType_string) Validate(value JsonValue) bool { + _, err := self.ToString(value) + return err != nil +} + +func (self *VariableType_string) ToHTML(value JsonValue) (template.HTML, error) { + str, err := self.ToString(value) + if err != nil { + return template.HTML(""), err + } + + ret := `` return template.HTML(ret), nil } -func (self *VariableType_string) DefaultValue() string { +func (self *VariableType_string) DefaultValue() JsonValue { return "" } @@ -163,18 +192,19 @@ func (*VariableType_d) Name() string { return "d" } -func (*VariableType_d) Validate(s string) bool { - return regexp_d.MatchString(s) +func (*VariableType_d) Validate(value JsonValue) bool { + //FIXME + return false } -func (self *VariableType_d) ToHTML(value string) (template.HTML, error) { +func (self *VariableType_d) ToHTML(value JsonValue) (template.HTML, error) { //FIXME: non-generic version - ret := `` + ret := `` return template.HTML(ret), nil } -func (self *VariableType_d) DefaultValue() string { +func (self *VariableType_d) DefaultValue() JsonValue { //FIXME: non-generic version return "" } @@ -199,7 +229,6 @@ func makeVariableType(s string) VariableType { type CustomEnum struct { name string - BaseType VariableType Values []string } @@ -207,13 +236,14 @@ func (self *CustomEnum) Name() string { return self.name } -func (self *CustomEnum) ToId(value string) (int, error) { - if !self.BaseType.Validate(value) { - return 0, errors.New("Invalid value") +func (self *CustomEnum) ToId(value JsonValue) (int, error) { + val, isString := value.(string) + if !isString { + return 0, errors.New("Enum value not a string") } for i := 0; i < len(self.Values); i++ { - if self.Values[i] == value { + if self.Values[i] == val { return i, nil } } @@ -221,13 +251,17 @@ func (self *CustomEnum) ToId(value string) (int, error) { return 0, errors.New("No such element") } -func (self *CustomEnum) Validate(value string) bool { +func (self *CustomEnum) Validate(value JsonValue) bool { _, err := self.ToId(value) return err == nil } -func (self *CustomEnum) ToHTML(value string) (template.HTML, error) { - selectItem := value != "" +func (self *CustomEnum) ToHTML(value JsonValue) (template.HTML, error) { + val, isString := value.(string) + if !isString { + return template.HTML(""), errors.New("Bad enum value") + } + selectItem := val != "" value_id := 0 if selectItem { @@ -253,10 +287,12 @@ func (self *CustomEnum) ToHTML(value string) (template.HTML, error) { return template.HTML(ret), nil } -func (self *CustomEnum) DefaultValue() string { +func (self *CustomEnum) DefaultValue() JsonValue { return "" } +type JsonObject map[string]interface{} + type CustomStruct struct { name string Variables []*Variable @@ -266,17 +302,16 @@ func (self *CustomStruct) Name() string { return self.name } -func (self *CustomStruct) Validate(s string) bool { - var jsonValue map[string]interface{} - err := json.Unmarshal([]byte(s), &jsonValue) - if err != nil { - log.Fatal(err) +func (self *CustomStruct) Validate(value JsonValue) bool { + obj, isObj := value.(JsonObject) + if !isObj { + log.Println("Struct \"" + self.Name() + "\": value is not a JSON object") return false } for _, v := range self.Variables { - jsonVal, isString := jsonValue[v.Name()].(string) - if !isString || ! v.Type.Validate(jsonVal) { + if !v.Type.Validate(obj[v.Name()]) { + log.Println("Struct \"" + self.Name() + "\": value \"" + v.Name() + "\" was not validated") return false } } @@ -284,25 +319,19 @@ func (self *CustomStruct) Validate(s string) bool { return true } -func (self *CustomStruct) ToHTML(value string) (template.HTML, error) { - - var jsonValue map[string]interface{} - err := json.Unmarshal([]byte(value), &jsonValue) - if err != nil { - log.Fatal(err) - return template.HTML(""), errors.New("Cannot unmarshal JSON") +func (self *CustomStruct) ToHTML(value JsonValue) (template.HTML, error) { + if !self.Validate(value) { + return template.HTML(""), errors.New("Cannot validate struct") } + obj, _ := value.(JsonObject) + ret := template.HTML("") ret += `
` for _, v := range self.Variables { log.Println("variable:", v.Name()) - jsonVal, isString := jsonValue[v.Name()].(string) - if !isString { - return template.HTML(""), errors.New("Variable " + v.Name() + " is not a string") - } - html, err := v.Type.ToHTML(jsonVal) + html, err := v.Type.ToHTML(obj[v.Name()]) if err != nil { return template.HTML(""), err } @@ -314,19 +343,11 @@ func (self *CustomStruct) ToHTML(value string) (template.HTML, error) { return ret, nil } -func (self *CustomStruct) DefaultValue() string { - ret := `{` - for i, v := range self.Variables { - if i > 0 { - ret += "," - } - ret += `"` - ret += v.Name() - ret += `":"` - ret += v.Type.DefaultValue() - ret += `"` +func (self *CustomStruct) DefaultValue() JsonValue { + ret := make(JsonObject) + for _, v := range self.Variables { + ret[v.Name()] = v.Type.DefaultValue() } - ret += `}` return ret } @@ -334,7 +355,6 @@ func parseCustomEnum(root xmlNode) (*CustomEnum, error) { customEnum := CustomEnum {} nameOk := false; - typeOk := false; for i := 0; i < len(root.Attrs); i++ { attrName := root.Attrs[i].Name.Local attrVal := root.Attrs[i].Value @@ -343,35 +363,19 @@ func parseCustomEnum(root xmlNode) (*CustomEnum, error) { case "name": nameOk = true customEnum.name = attrVal - case "base-type": - typeOk = true - customEnum.BaseType = makeVariableType(attrVal) - switch customEnum.BaseType.(type) { - case *VariableType_badType: - typeOk = false - } } } if !nameOk { return nil, errors.New("Unnamed custom enum") } - if !typeOk { - return nil, errors.New("Bad base type for " + customEnum.Name()) - } for i := 0; i < len(root.Nodes); i++ { node := root.Nodes[i] switch node.XMLName.Local { case "value": - value := string(node.Content) - if customEnum.BaseType.Validate(value) { - customEnum.Values = append(customEnum.Values, value) - } else { - log.Println("Cannot validate value enum \"" + value + "\" with type \"" + - customEnum.BaseType.Name() + "\". Discarded") - } + customEnum.Values = append(customEnum.Values, string(node.Content)) } }