package jdr import( "log" "errors" "strings" "strconv" "regexp" ) var regexp_d = regexp.MustCompile(`^[1-9][0-9]*d([468]|1[02]|20|100)$`) type VariableType interface { Name() string Validate(s string) bool } type VariableType_badType struct {} func (*VariableType_badType) Name() string { return "unknown type" } func (*VariableType_badType) Validate(s string) bool { return false } type VariableType_bool struct {} 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 (self *VariableType_bool) Validate(value string) bool { _, err := self.ToBool(value) return err == nil } type VariableType_int struct {} 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) Validate(value string) bool { _, err := self.ToInt(value) return err == nil } type VariableType_float struct {} func (*VariableType_float) Name() string { return "float" } func (*VariableType_float) ToFloat(value string) (float64, error) { return strconv.ParseFloat(value, 64) } func (self *VariableType_float) Validate(value string) bool { _, err := self.ToFloat(value) return err == nil } type VariableType_string struct {} func (*VariableType_string) Name() string { return "string" } func (*VariableType_string) Validate(s string) bool { return true } type VariableType_d struct {} func (*VariableType_d) Name() string { return "d" } func (*VariableType_d) Validate(s string) bool { return regexp_d.MatchString(s) } func makeVariableType(s string) VariableType { switch(strings.ToLower(s)) { case "bool": return &VariableType_bool{} case "int": return &VariableType_int{} case "float": return &VariableType_float{} case "string": return &VariableType_string{} case "d": return &VariableType_d{} default: log.Println("Unknown type:", s) return &VariableType_badType{} } } type CustomEnum struct { name string BaseType VariableType Values []string } func (self *CustomEnum) Name() string { return self.name } func (self *CustomEnum) Validate(s string) bool { if !self.BaseType.Validate(s) { return false } for i := 0; i < len(self.Values); i++ { if self.Values[i] == s { return true } } return false } type CustomStruct struct { name string Variables []Variable } func (self *CustomStruct) Name() string { return self.name } func (self *CustomStruct) Validate(s string) bool { //FIXME log.Println("Custom struct Validate is not (yet) implemented") return false } 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 switch attrName { 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") } } } return &customEnum, nil } func parseCustomStruct(root xmlNode) (*CustomStruct, error) { customType := CustomStruct{} nameOk := false for i := 0; i < len(root.Attrs); i++ { attrName := root.Attrs[i].Name.Local attrVal := root.Attrs[i].Value switch attrName { case "name": nameOk = true customType.name = attrVal } } if !nameOk { return nil, errors.New("Unnamed custom type") } return &customType, nil } func parseCustomTypes(root xmlNode) ([]VariableType, error) { types := []VariableType{} for i := 0; i < len(root.Nodes); i++ { node := root.Nodes[i] switch node.XMLName.Local { case "enum": customEnum, err := parseCustomEnum(node) if err != nil { return []VariableType{}, err } types = append(types, customEnum) case "type": customType, err := parseCustomStruct(node) if err != nil { return []VariableType{}, err } types = append(types, customType) default: return []VariableType{}, errors.New("Unknown CustomType: " + root.Nodes[i].XMLName.Local) } } return types, nil }