I am a fool and should have found a better way to break this into many commits shame... shame on the poor choices I have madepull/16/head
| @ -1,9 +0,0 @@ | |||||
| package config | |||||
| type BooleanValue struct { | |||||
| Name string | |||||
| Value bool | |||||
| } | |||||
| func (this BooleanValue) GetType() ConfigType { return BOOLEAN } | |||||
| func (this BooleanValue) GetValue() interface{} { return this.Value } | |||||
| @ -1,39 +0,0 @@ | |||||
| package config | |||||
| type ConfigType int | |||||
| const ( | |||||
| SECTION ConfigType = iota | |||||
| INTEGER | |||||
| BOOLEAN | |||||
| FLOAT | |||||
| STRING | |||||
| NULL | |||||
| ) | |||||
| var configTypes = [...]string{ | |||||
| SECTION: "SECTION", | |||||
| BOOLEAN: "BOOLEAN", | |||||
| INTEGER: "INTEGER", | |||||
| FLOAT: "FLOAT", | |||||
| STRING: "STRING", | |||||
| NULL: "NULL", | |||||
| } | |||||
| func (this ConfigType) String() string { | |||||
| s := "" | |||||
| if 0 <= this && this < ConfigType(len(configTypes)) { | |||||
| s = configTypes[this] | |||||
| } | |||||
| if s == "" { | |||||
| s = "UNKNOWN" | |||||
| } | |||||
| return s | |||||
| } | |||||
| type ConfigValue interface { | |||||
| GetType() ConfigType | |||||
| GetValue() interface{} | |||||
| } | |||||
| @ -1,9 +0,0 @@ | |||||
| package config | |||||
| type FloatValue struct { | |||||
| Name string | |||||
| Value float64 | |||||
| } | |||||
| func (this FloatValue) GetType() ConfigType { return INTEGER } | |||||
| func (this FloatValue) GetValue() interface{} { return this.Value } | |||||
| @ -1,9 +0,0 @@ | |||||
| package config | |||||
| type IntegerValue struct { | |||||
| Name string | |||||
| Value int64 | |||||
| } | |||||
| func (this IntegerValue) GetType() ConfigType { return INTEGER } | |||||
| func (this IntegerValue) GetValue() interface{} { return this.Value } | |||||
| @ -1,9 +0,0 @@ | |||||
| package config | |||||
| type NullValue struct { | |||||
| Name string | |||||
| Value interface{} | |||||
| } | |||||
| func (this NullValue) GetType() ConfigType { return NULL } | |||||
| func (this NullValue) GetValue() interface{} { return nil } | |||||
| @ -1,132 +0,0 @@ | |||||
| package config | |||||
| import ( | |||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "strings" | |||||
| ) | |||||
| type SectionValue struct { | |||||
| Name string | |||||
| Value map[string]ConfigValue | |||||
| Comments []string | |||||
| Includes []string | |||||
| } | |||||
| func NewNamedSection(name string) *SectionValue { | |||||
| return &SectionValue{ | |||||
| Name: name, | |||||
| Value: make(map[string]ConfigValue), | |||||
| Comments: make([]string, 0), | |||||
| Includes: make([]string, 0), | |||||
| } | |||||
| } | |||||
| func NewAnonymousSection() *SectionValue { | |||||
| return &SectionValue{ | |||||
| Value: make(map[string]ConfigValue), | |||||
| Comments: make([]string, 0), | |||||
| Includes: make([]string, 0), | |||||
| } | |||||
| } | |||||
| func (this SectionValue) GetType() ConfigType { return SECTION } | |||||
| func (this SectionValue) GetValue() interface{} { return this.Value } | |||||
| func (this *SectionValue) AddComment(comment string) { | |||||
| this.Comments = append(this.Comments, comment) | |||||
| } | |||||
| func (this *SectionValue) AddInclude(include string) { | |||||
| this.Includes = append(this.Includes, include) | |||||
| } | |||||
| func (this *SectionValue) Set(name string, value ConfigValue) { | |||||
| this.Value[name] = value | |||||
| } | |||||
| func (this *SectionValue) Get(name string) ConfigValue { | |||||
| return this.Value[name] | |||||
| } | |||||
| func (this *SectionValue) GetSection(name string) SectionValue { | |||||
| value := this.Value[name] | |||||
| return value.(SectionValue) | |||||
| } | |||||
| func (this *SectionValue) GetString(name string) StringValue { | |||||
| value := this.Value[name] | |||||
| return value.(StringValue) | |||||
| } | |||||
| func (this *SectionValue) GetInteger(name string) IntegerValue { | |||||
| value := this.Value[name] | |||||
| return value.(IntegerValue) | |||||
| } | |||||
| func (this *SectionValue) GetFloat(name string) FloatValue { | |||||
| value := this.Value[name] | |||||
| return value.(FloatValue) | |||||
| } | |||||
| func (this *SectionValue) Contains(name string) bool { | |||||
| _, ok := this.Value[name] | |||||
| return ok | |||||
| } | |||||
| func (this *SectionValue) Resolve(setting string) (ConfigValue, error) { | |||||
| parts := strings.Split(setting, ".") | |||||
| var reference ConfigValue | |||||
| reference = this | |||||
| visited := []string{} | |||||
| for { | |||||
| if len(parts) == 0 { | |||||
| break | |||||
| } | |||||
| if reference.GetType() != SECTION { | |||||
| name := strings.Join(visited, ".") | |||||
| return nil, errors.New(fmt.Sprintf("'%s' is a %s not a SECTION", name, reference.GetType())) | |||||
| } | |||||
| part := parts[0] | |||||
| parts = parts[1:] | |||||
| section := reference.(*SectionValue) | |||||
| if section.Contains(part) == false { | |||||
| name := strings.Join(visited, ".") | |||||
| if len(name) > 0 { | |||||
| return nil, errors.New(fmt.Sprintf("'%s' does not have setting '%s'", name, part)) | |||||
| } else { | |||||
| return nil, errors.New(fmt.Sprintf("setting '%s' does not exist", part)) | |||||
| } | |||||
| } | |||||
| reference = section.Get(part) | |||||
| visited = append(visited, part) | |||||
| } | |||||
| return reference, nil | |||||
| } | |||||
| func (this *SectionValue) ToJSON() ([]byte, error) { | |||||
| data, err := this.ToMap() | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return json.Marshal(data) | |||||
| } | |||||
| func (this *SectionValue) ToMap() (map[string]interface{}, error) { | |||||
| settings := make(map[string]interface{}) | |||||
| for name, value := range this.Value { | |||||
| if value.GetType() == SECTION { | |||||
| data, err := value.(*SectionValue).ToMap() | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| settings[name] = data | |||||
| } else { | |||||
| settings[name] = value.GetValue() | |||||
| } | |||||
| } | |||||
| return settings, nil | |||||
| } | |||||
| @ -1,9 +0,0 @@ | |||||
| package config | |||||
| type StringValue struct { | |||||
| Name string | |||||
| Value string | |||||
| } | |||||
| func (this StringValue) GetType() ConfigType { return STRING } | |||||
| func (this StringValue) GetValue() interface{} { return this.Value } | |||||
| @ -0,0 +1,88 @@ | |||||
| package forge | |||||
| import ( | |||||
| "errors" | |||||
| "fmt" | |||||
| "math" | |||||
| "strconv" | |||||
| ) | |||||
| func asBoolean(value interface{}) (bool, error) { | |||||
| switch val := value.(type) { | |||||
| case bool: | |||||
| return val, nil | |||||
| case float64: | |||||
| return val != 0, nil | |||||
| case int64: | |||||
| return val != 0, nil | |||||
| case nil: | |||||
| return false, nil | |||||
| case string: | |||||
| return val != "", nil | |||||
| } | |||||
| msg := fmt.Sprintf("Could not convert value %s to type BOOLEAN", value) | |||||
| return false, errors.New(msg) | |||||
| } | |||||
| func asFloat(value interface{}) (float64, error) { | |||||
| switch val := value.(type) { | |||||
| case bool: | |||||
| if val { | |||||
| return float64(1), nil | |||||
| } else { | |||||
| return float64(0), nil | |||||
| } | |||||
| case float64: | |||||
| return val, nil | |||||
| case int64: | |||||
| return float64(val), nil | |||||
| case string: | |||||
| return strconv.ParseFloat(val, 64) | |||||
| } | |||||
| msg := fmt.Sprintf("Could not convert value %s to type FLOAT", value) | |||||
| return 0, errors.New(msg) | |||||
| } | |||||
| func asInteger(value interface{}) (int64, error) { | |||||
| switch val := value.(type) { | |||||
| case bool: | |||||
| if val { | |||||
| return int64(1), nil | |||||
| } else { | |||||
| return int64(0), nil | |||||
| } | |||||
| case float64: | |||||
| return int64(math.Trunc(val)), nil | |||||
| case int64: | |||||
| return val, nil | |||||
| case string: | |||||
| return strconv.ParseInt(val, 10, 64) | |||||
| } | |||||
| msg := fmt.Sprintf("Could not convert value %s to type INTEGER", value) | |||||
| return 0, errors.New(msg) | |||||
| } | |||||
| func asString(value interface{}) (string, error) { | |||||
| switch val := value.(type) { | |||||
| case bool: | |||||
| if val { | |||||
| return "True", nil | |||||
| } else { | |||||
| return "False", nil | |||||
| } | |||||
| case float64: | |||||
| return strconv.FormatFloat(val, 10, -1, 64), nil | |||||
| case int64: | |||||
| return strconv.FormatInt(val, 10), nil | |||||
| case nil: | |||||
| return "Null", nil | |||||
| case string: | |||||
| return val, nil | |||||
| } | |||||
| msg := fmt.Sprintf("Could not convert value %s to type STRING", value) | |||||
| return "", errors.New(msg) | |||||
| } | |||||
| @ -0,0 +1,89 @@ | |||||
| package forge | |||||
| import ( | |||||
| "errors" | |||||
| "fmt" | |||||
| ) | |||||
| type Primative struct { | |||||
| valueType ValueType | |||||
| value interface{} | |||||
| } | |||||
| func NewPrimative(valueType ValueType, value interface{}) *Primative { | |||||
| return &Primative{ | |||||
| valueType: valueType, | |||||
| value: value, | |||||
| } | |||||
| } | |||||
| func NewBoolean(value bool) *Primative { | |||||
| return NewPrimative(BOOLEAN, value) | |||||
| } | |||||
| func NewFloat(value float64) *Primative { | |||||
| return NewPrimative(FLOAT, value) | |||||
| } | |||||
| func NewInteger(value int64) *Primative { | |||||
| return NewPrimative(INTEGER, value) | |||||
| } | |||||
| func NewNull() *Primative { | |||||
| return NewPrimative(NULL, nil) | |||||
| } | |||||
| func NewString(value string) *Primative { | |||||
| return NewPrimative(STRING, value) | |||||
| } | |||||
| func (this *Primative) GetType() ValueType { | |||||
| return this.valueType | |||||
| } | |||||
| func (this *Primative) GetValue() interface{} { | |||||
| return this.value | |||||
| } | |||||
| func (this *Primative) UpdateValue(value interface{}) error { | |||||
| // Valid types | |||||
| switch value.(type) { | |||||
| case bool: | |||||
| this.valueType = BOOLEAN | |||||
| case float64: | |||||
| this.valueType = FLOAT | |||||
| case int64: | |||||
| this.valueType = INTEGER | |||||
| case nil: | |||||
| this.valueType = NULL | |||||
| case string: | |||||
| this.valueType = STRING | |||||
| default: | |||||
| msg := fmt.Sprintf("Unsupported type, %s must be of (bool, float64, int64, nil, string)", value) | |||||
| return errors.New(msg) | |||||
| } | |||||
| this.value = value | |||||
| return nil | |||||
| } | |||||
| func (this *Primative) AsBoolean() (bool, error) { | |||||
| return asBoolean(this.value) | |||||
| } | |||||
| func (this *Primative) AsFloat() (float64, error) { | |||||
| return asFloat(this.value) | |||||
| } | |||||
| func (this *Primative) AsInteger() (int64, error) { | |||||
| return asInteger(this.value) | |||||
| } | |||||
| func (this *Primative) AsString() (string, error) { | |||||
| return asString(this.value) | |||||
| } | |||||
| func (this *Primative) String() string { | |||||
| str, _ := this.AsString() | |||||
| return str | |||||
| } | |||||
| @ -0,0 +1,244 @@ | |||||
| package forge | |||||
| import ( | |||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "strings" | |||||
| ) | |||||
| type Section struct { | |||||
| parent *Section | |||||
| values map[string]Value | |||||
| } | |||||
| func NewSection() *Section { | |||||
| return &Section{ | |||||
| values: make(map[string]Value), | |||||
| } | |||||
| } | |||||
| func NewChildSection(parent *Section) *Section { | |||||
| return &Section{ | |||||
| parent: parent, | |||||
| values: make(map[string]Value), | |||||
| } | |||||
| } | |||||
| func (this *Section) GetType() ValueType { | |||||
| return SECTION | |||||
| } | |||||
| func (this *Section) GetValue() interface{} { | |||||
| return this.values | |||||
| } | |||||
| func (this *Section) UpdateValue(value interface{}) error { | |||||
| switch value.(type) { | |||||
| case map[string]Value: | |||||
| this.values = value.(map[string]Value) | |||||
| return nil | |||||
| } | |||||
| msg := fmt.Sprintf("Unsupported type, %s must be of type `map[string]Value`", value) | |||||
| return errors.New(msg) | |||||
| } | |||||
| func (this *Section) AddSection(name string) *Section { | |||||
| section := NewChildSection(this) | |||||
| this.values[name] = section | |||||
| return section | |||||
| } | |||||
| func (this *Section) Exists(name string) bool { | |||||
| _, err := this.Get(name) | |||||
| return err == nil | |||||
| } | |||||
| func (this *Section) Get(name string) (Value, error) { | |||||
| value, ok := this.values[name] | |||||
| var err error | |||||
| if ok == false { | |||||
| err = errors.New("Value does not exist") | |||||
| } | |||||
| return value, err | |||||
| } | |||||
| func (this *Section) GetBoolean(name string) (bool, error) { | |||||
| value, err := this.Get(name) | |||||
| if err != nil { | |||||
| return false, err | |||||
| } | |||||
| switch value.(type) { | |||||
| case *Primative: | |||||
| return value.(*Primative).AsBoolean() | |||||
| case *Section: | |||||
| return true, nil | |||||
| } | |||||
| return false, errors.New("Could not convert unknown value to boolean") | |||||
| } | |||||
| func (this *Section) GetFloat(name string) (float64, error) { | |||||
| value, err := this.Get(name) | |||||
| if err != nil { | |||||
| return float64(0), err | |||||
| } | |||||
| switch value.(type) { | |||||
| case *Primative: | |||||
| return value.(*Primative).AsFloat() | |||||
| } | |||||
| return float64(0), errors.New("Could not convert non-primative value to float") | |||||
| } | |||||
| func (this *Section) GetInteger(name string) (int64, error) { | |||||
| value, err := this.Get(name) | |||||
| if err != nil { | |||||
| return int64(0), err | |||||
| } | |||||
| switch value.(type) { | |||||
| case *Primative: | |||||
| return value.(*Primative).AsInteger() | |||||
| } | |||||
| return int64(0), errors.New("Could not convert non-primative value to integer") | |||||
| } | |||||
| func (this *Section) GetSection(name string) (*Section, error) { | |||||
| value, err := this.Get(name) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if value.GetType() == SECTION { | |||||
| return value.(*Section), nil | |||||
| } | |||||
| return nil, errors.New("Could not fetch value as section") | |||||
| } | |||||
| func (this *Section) GetString(name string) (string, error) { | |||||
| value, err := this.Get(name) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| switch value.(type) { | |||||
| case *Primative: | |||||
| return value.(*Primative).AsString() | |||||
| } | |||||
| return "", errors.New("Could not convert non-primative value to string") | |||||
| } | |||||
| func (this *Section) GetParent() *Section { | |||||
| return this.parent | |||||
| } | |||||
| func (this *Section) HasParent() bool { | |||||
| return this.parent != nil | |||||
| } | |||||
| func (this *Section) Set(name string, value Value) { | |||||
| this.values[name] = value | |||||
| } | |||||
| func (this *Section) SetBoolean(name string, value bool) { | |||||
| current, err := this.Get(name) | |||||
| // Exists just update the value/type | |||||
| if err == nil { | |||||
| current.UpdateValue(value) | |||||
| } else { | |||||
| this.values[name] = NewBoolean(value) | |||||
| } | |||||
| } | |||||
| func (this *Section) SetFloat(name string, value float64) { | |||||
| current, err := this.Get(name) | |||||
| // Exists just update the value/type | |||||
| if err == nil { | |||||
| current.UpdateValue(value) | |||||
| } else { | |||||
| this.values[name] = NewFloat(value) | |||||
| } | |||||
| } | |||||
| func (this *Section) SetInteger(name string, value int64) { | |||||
| current, err := this.Get(name) | |||||
| // Exists just update the value/type | |||||
| if err == nil { | |||||
| current.UpdateValue(value) | |||||
| } else { | |||||
| this.values[name] = NewInteger(value) | |||||
| } | |||||
| } | |||||
| func (this *Section) SetNull(name string) { | |||||
| current, err := this.Get(name) | |||||
| // Already is a Null, nothing to do | |||||
| if err == nil && current.GetType() == NULL { | |||||
| return | |||||
| } | |||||
| this.Set(name, NewNull()) | |||||
| } | |||||
| func (this *Section) SetString(name string, value string) { | |||||
| current, err := this.Get(name) | |||||
| // Exists just update the value/type | |||||
| if err == nil { | |||||
| current.UpdateValue(value) | |||||
| } else { | |||||
| this.Set(name, NewString(value)) | |||||
| } | |||||
| } | |||||
| func (this *Section) Resolve(name string) (Value, error) { | |||||
| // Used only in error state return value | |||||
| var value Value | |||||
| parts := strings.Split(name, ".") | |||||
| if len(parts) == 0 { | |||||
| return value, errors.New("No name provided") | |||||
| } | |||||
| var current Value | |||||
| current = this | |||||
| for _, part := range parts { | |||||
| if current.GetType() != SECTION { | |||||
| return value, errors.New("Trying to resolve value from non-section") | |||||
| } | |||||
| next_current, err := current.(*Section).Get(part) | |||||
| if err != nil { | |||||
| return value, errors.New("Could not find value in section") | |||||
| } | |||||
| current = next_current | |||||
| } | |||||
| return current, nil | |||||
| } | |||||
| func (this *Section) ToJSON() ([]byte, error) { | |||||
| data := this.ToMap() | |||||
| return json.Marshal(data) | |||||
| } | |||||
| func (this *Section) ToMap() map[string]interface{} { | |||||
| output := make(map[string]interface{}) | |||||
| for key, value := range this.values { | |||||
| if value.GetType() == SECTION { | |||||
| output[key] = value.(*Section).ToMap() | |||||
| } else { | |||||
| output[key] = value.GetValue() | |||||
| } | |||||
| } | |||||
| return output | |||||
| } | |||||
| @ -1,54 +0,0 @@ | |||||
| package token | |||||
| type TokenID int | |||||
| const ( | |||||
| ILLEGAL TokenID = iota | |||||
| EOF | |||||
| LBRACKET | |||||
| RBRACKET | |||||
| EQUAL | |||||
| SEMICOLON | |||||
| PERIOD | |||||
| IDENTIFIER | |||||
| BOOLEAN | |||||
| INTEGER | |||||
| FLOAT | |||||
| STRING | |||||
| NULL | |||||
| COMMENT | |||||
| INCLUDE | |||||
| ) | |||||
| var tokenNames = [...]string{ | |||||
| ILLEGAL: "ILLEGAL", | |||||
| EOF: "EOF", | |||||
| LBRACKET: "LBRACKET", | |||||
| RBRACKET: "RBRACKET", | |||||
| EQUAL: "EQUAL", | |||||
| SEMICOLON: "SEMICOLON", | |||||
| PERIOD: "PERIOD", | |||||
| IDENTIFIER: "IDENTIFIER", | |||||
| BOOLEAN: "BOOLEAN", | |||||
| INTEGER: "INTEGER", | |||||
| FLOAT: "FLOAT", | |||||
| STRING: "STRING", | |||||
| NULL: "NULL", | |||||
| COMMENT: "COMMENT", | |||||
| INCLUDE: "INCLUDE", | |||||
| } | |||||
| func (this TokenID) String() string { | |||||
| s := "" | |||||
| if 0 <= this && this < TokenID(len(tokenNames)) { | |||||
| s = tokenNames[this] | |||||
| } | |||||
| if s == "" { | |||||
| s = "UNKNOWN" | |||||
| } | |||||
| return s | |||||
| } | |||||
| @ -0,0 +1,48 @@ | |||||
| package forge | |||||
| type ValueType int | |||||
| const ( | |||||
| UNKNOWN ValueType = iota | |||||
| // Primative values | |||||
| BOOLEAN | |||||
| FLOAT | |||||
| INTEGER | |||||
| NULL | |||||
| STRING | |||||
| // Complex values | |||||
| REFERENCE | |||||
| SECTION | |||||
| ) | |||||
| var valueTypes = [...]string{ | |||||
| BOOLEAN: "BOOLEAN", | |||||
| FLOAT: "FLOAT", | |||||
| INTEGER: "INTEGER", | |||||
| NULL: "NULL", | |||||
| STRING: "STRING", | |||||
| REFERENCE: "REFERENCE", | |||||
| SECTION: "SECTION", | |||||
| } | |||||
| func (this ValueType) String() string { | |||||
| str := "" | |||||
| if 0 <= this && this < ValueType(len(valueTypes)) { | |||||
| str = valueTypes[this] | |||||
| } | |||||
| if str == "" { | |||||
| str = "UNKNOWN" | |||||
| } | |||||
| return str | |||||
| } | |||||
| type Value interface { | |||||
| GetType() ValueType | |||||
| GetValue() interface{} | |||||
| UpdateValue(interface{}) error | |||||
| } | |||||