diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..41278f4 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module gitea.cozeon.cloud/anand.ekka-ext/jaeson + +go 1.22.3 + +require github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 + +require gitea.cozeon.cloud/anand.ekka-ext/parser v0.0.0-20260929115114-8ff7130c8636 diff --git a/jayson.go b/jayson.go new file mode 100644 index 0000000..c2184b8 --- /dev/null +++ b/jayson.go @@ -0,0 +1,623 @@ +package jaeson + +import ( + "errors" + "sort" + "strconv" + "strings" +) + +var ( + JSON_VAL_TYPE_STRING = "str" + JSON_VAL_TYPE_INT = "int" + JSON_VAL_TYPE_FLOAT = "float" + JSON_VAL_TYPE_BOOL = "jsbln" + JSON_VAL_TYPE_OBJECT = "jsobj" + JSON_VAL_TYPE_ARRAY = "jsarr" +) + +type JSONObject struct { + + ms map[string]string + mo map[string]*JSONObject + marr map[string]*JSONArray + mn map[string]int + mbln map[string]bool + mflt64 map[string]float64 + + //contains all valid keys + mAllkeys map[string]string + + ctms int + ctmo int + ctmarr int + ctmn int + ctmbln int + ctmflt64 int + + hasVal bool + //isSorted bool +} + +func NewJSONObject() *JSONObject { + jsObj := new(JSONObject) + jsObj.Init() + return jsObj +} +func NewJSONArray() *JSONArray { + jsArr := new(JSONArray) + jsArr.Init() + return jsArr +} + +func (v *JSONObject) Init() { + v.ctms = 0 + v.ctmo = 0 + v.ctmarr = 0 + v.ctmn = 0 + v.ctmbln = 0 + v.ctmflt64 = 0 + + v.ms = make(map[string]string, 0) + v.mo = make(map[string]*JSONObject, 0) + v.marr = make(map[string]*JSONArray, 0) + v.mn = make(map[string]int, 0) + v.mbln = make(map[string]bool, 0) + v.mflt64 = make(map[string]float64, 0) + + v.hasVal = false + //v.isSorted = false + + v.mAllkeys = make(map[string]string, 0) + +} + +func (v *JSONObject) KeySetSize() int { + return v.ctms + v.ctmo + v.ctmarr + v.ctmn + v.ctmbln +} + +func (v *JSONObject) Map() map[string]string { + return v.mAllkeys +} + +//---------- PUT ----------// + +func (v *JSONObject) PutString(key string, value string) { + if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { + v.RemoveJSONObject(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { + v.RemoveJSONArray(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { + v.RemoveInt(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { + v.RemoveBool(key) + } + v.ms[key] = value + v.ctms += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_STRING +} + +func (v *JSONObject) PutJSONObject(key string, value *JSONObject) { + if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { + v.RemoveJSONArray(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { + v.RemoveInt(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { + v.RemoveString(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { + v.RemoveBool(key) + } + v.mo[key] = value + v.ctmo += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_OBJECT +} + +func (v *JSONObject) PutJSONArray(key string, value *JSONArray) { + if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { + v.RemoveJSONObject(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { + v.RemoveInt(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { + v.RemoveString(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { + v.RemoveBool(key) + } + v.marr[key] = value + v.ctmarr += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_ARRAY +} + +func (v *JSONObject) PutInt(key string, value int) { + if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { + v.RemoveJSONObject(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { + v.RemoveJSONArray(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { + v.RemoveString(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { + v.RemoveBool(key) + } + v.mn[key] = value + v.ctmn += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_INT +} + +func (v *JSONObject) PutNumber(key string, value int) { + v.PutInt(key, value) +} + +func (v *JSONObject) PutBool(key string, value bool) { + if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { + v.RemoveJSONObject(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { + v.RemoveJSONArray(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { + v.RemoveString(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { + v.RemoveInt(key) + } + v.mbln[key] = value + v.ctmbln += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_BOOL +} + +func (v *JSONObject) PutFloat(key string, value float64) { + + if v.mAllkeys[key] == JSON_VAL_TYPE_OBJECT { + v.RemoveJSONObject(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_ARRAY { + v.RemoveJSONArray(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_STRING { + v.RemoveString(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_INT { + v.RemoveInt(key) + } else if v.mAllkeys[key] == JSON_VAL_TYPE_BOOL { + v.RemoveBool(key) + } + v.mflt64[key] = value + v.ctmflt64 += 1 + v.hasVal = true + + v.mAllkeys[key] = JSON_VAL_TYPE_FLOAT +} + +//---------- ACCUMULATE ----------// +func (v *JSONObject) AccumulateJSONObject(key string, value *JSONObject) { + + jsArr, err := v.GetJSONArray(key) + if err != nil { + v.RemoveString(key) + v.RemoveJSONObject(key) + + jsArr := NewJSONArray() + jsArr.AddJSONObject(value) + + v.PutJSONArray(key, jsArr) + + } else { + + jsArr.AddJSONObject(value) + } +} + +//---------- GET ----------// +func (v *JSONObject) GethasVal() bool { + return v.hasVal +} + +func (v *JSONObject) GetString(key string) (string, error) { + if v.ctms > 0 { + val, isContainsKey := v.ms[key] + if isContainsKey { + return val, nil + }else{ + _, err := v.GetValType(key) + if err != nil { + return "", err + } else { + return "", errors.New("value not a string") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return "", err + } else { + return "", errors.New("value not an string") + } + } +} + +func (v *JSONObject) GetJSONObject(key string) (*JSONObject, error) { + if v.ctmo > 0 { + val, isContainsKey := v.mo[key] + if isContainsKey { + return val, nil + }else{ + _, err := v.GetValType(key) + if err != nil { + return nil, err + } else { + return nil, errors.New("value not a JSONObject") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return nil, err + } else { + return nil, errors.New("value not an JSONObject") + } + } +} + +func (v *JSONObject) GetJSONArray(key string) (*JSONArray, error) { + if v.ctmarr > 0 { + val, isContainsKey := v.marr[key] + if isContainsKey { + return val, nil + }else{ + _, err := v.GetValType(key) + if err != nil { + return nil, err + } else { + return nil, errors.New("value not a JSONArray") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return nil, err + } else { + return nil, errors.New("value not an JSONArray") + } + } +} + +func (v *JSONObject) GetInt(key string) (int, error) { + if v.ctmn > 0 { + val, isContainsKey := v.mn[key] + if isContainsKey { + return val, nil + + }else{ + _, err := v.GetValType(key) + if err != nil { + return -1, err + } else { + return -1, errors.New("value not an int") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return -1, err + } else { + return -1, errors.New("value not an int") + } + } +} + +func (v *JSONObject) GetNumber(key string) (int, error) { + return v.GetInt(key) +} + +func (v *JSONObject) GetBool(key string) (bool, error) { + if v.ctmbln > 0 { + val, isContainsKey := v.mbln[key] + if isContainsKey { + return val, nil + }else{ + _, err := v.GetValType(key) + if err != nil { + return false, err + } else { + return false, errors.New("value not a bool") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return false, err + } else { + return false, errors.New("value not a bool") + } + } +} + +func (v *JSONObject) GetFloat(key string) (float64, error) { + if v.ctmflt64 > 0 { + val, isContainsKey := v.mflt64[key] + if isContainsKey { + return val, nil + }else{ + _, err := v.GetValType(key) + if err != nil { + return -1, err + } else { + return -1, errors.New("value not a float") + } + } + } else { + _, err := v.GetValType(key) + if err != nil { + return -1, err + } else { + return -1, errors.New("value not a float") + } + } +} + +func (v *JSONObject) GetValType(key string) (string, error) { + + if len(v.mAllkeys) > 0 { + valType := v.mAllkeys[key] + if len(valType) == 0 { + return "", errors.New("key not found") + } else { + return valType, nil + } + } else { + return "", errors.New("key not found") + } +} + +//---------- func REMOVE ----------// +func (v *JSONObject) RemoveString(key string) (error) { + if v.ctms > 0 { + _, isContainsKey := v.ms[key] + if isContainsKey { + delete(v.ms, key) + delete(v.mAllkeys, key) + v.ctms = len(v.ms) + + }else{ + return v.genericRemove(key, "string") + } + } else { + return v.genericRemove(key, "string") + } + return nil +} + +func (v *JSONObject) RemoveJSONObject(key string) (error) { + if v.ctmo > 0 { + _, isContainsKey := v.mo[key] + if isContainsKey { + delete(v.mo, key) + delete(v.mAllkeys, key) + v.ctmo = len(v.mo) + + }else{ + return v.genericRemove(key, "JSONObject") + } + } else { + return v.genericRemove(key, "JSONObject") + } + return nil +} + +func (v *JSONObject) RemoveJSONArray(key string) (error) { + if v.ctmarr > 0 { + _, isContainsKey := v.marr[key] + if isContainsKey { + delete(v.marr, key) + delete(v.mAllkeys, key) + v.ctmarr = len(v.marr) + + }else{ + return v.genericRemove(key, "JSONArray") + } + } else { + return v.genericRemove(key, "JSONArray") + } + return nil +} + +func (v *JSONObject) RemoveInt(key string) (error){ + if v.ctmn > 0 { + _, isContainsKey := v.mn[key] + if isContainsKey { + delete(v.mn, key) + delete(v.mAllkeys, key) + v.ctmn = len(v.mn) + + }else{ + return v.genericRemove(key, "int") + } + } else { + return v.genericRemove(key, "int") + } + return nil +} + +func (v *JSONObject) RemoveBool(key string) (error){ + if v.ctmbln > 0 { + _, isContainsKey := v.mbln[key] + if isContainsKey { + delete(v.mbln, key) + delete(v.mAllkeys, key) + v.ctmbln = len(v.mbln) + + }else{ + return v.genericRemove(key, "bool") + } + } else { + return v.genericRemove(key, "bool") + } + return nil +} + +func (v *JSONObject) RemoveFloat(key string) (error){ + if v.ctmflt64 > 0 { + _, isContainsKey := v.mflt64[key] + if isContainsKey { + delete(v.mflt64, key) + delete(v.mAllkeys, key) + v.ctmflt64 = len(v.mflt64) + + }else{ + return v.genericRemove(key, "float") + } + } else { + return v.genericRemove(key, "float") + } + return nil +} + +func (v *JSONObject) RemoveAny(key string) (error){ + _, isContainsKey := v.mAllkeys[key] + if isContainsKey { + valType, err := v.GetValType(key) + if err != nil { + return err + } else { + // delete appropriate collection + switch valType { + case JSON_VAL_TYPE_STRING: + delete(v.ms, key) + delete(v.mAllkeys, key) + v.ctms = len(v.ms) + case JSON_VAL_TYPE_BOOL: + delete(v.mbln, key) + delete(v.mAllkeys, key) + v.ctmbln = len(v.mbln) + case JSON_VAL_TYPE_INT: + delete(v.mn, key) + delete(v.mAllkeys, key) + v.ctmn = len(v.mn) + case JSON_VAL_TYPE_FLOAT: + delete(v.mflt64, key) + delete(v.mAllkeys, key) + v.ctmflt64 = len(v.mflt64) + case JSON_VAL_TYPE_OBJECT: + delete(v.mo, key) + delete(v.mAllkeys, key) + v.ctmo = len(v.mo) + case JSON_VAL_TYPE_ARRAY: + delete(v.marr, key) + delete(v.mAllkeys, key) + v.ctmarr = len(v.marr) + default: + return errors.New("Invalid date type: " + valType) + } + } + }else{ + return errors.New("key not found") + } + + return nil +} + +func (v *JSONObject) genericRemove(key string, msgSuffx string) (error){ + _, err := v.GetValType(key) + if err != nil { + return err + } else { + return errors.New("value not a "+msgSuffx) + } +} + +//---------- PRINT STRING----------// +func (v *JSONObject) String() string { + + var out string = "{" + + if v.ctms > 0 { + for keyms, _ := range v.ms { + out += "\"" + keyms + "\":\"" + v.ms[keyms] + "\"," + } + } + + if v.ctmn > 0 { + for keymn, _ := range v.mn { + out += "\"" + keymn + "\":" + strconv.Itoa(v.mn[keymn]) + "," + } + } + + if v.ctmo > 0 { + for keymo, _ := range v.mo { + jsObj := v.mo[keymo] + out += "\"" + keymo + "\":" + jsObj.String() + "," + } + } + + if v.ctmarr > 0 { + for keymarr, _ := range v.marr { + jsArr := v.marr[keymarr] + out += "\"" + keymarr + "\":" + jsArr.String() + "," + } + } + + if v.ctmbln > 0 { + for keymbln, _ := range v.mbln { + if v.mbln[keymbln] { + out += "\"" + keymbln + "\":true," + }else{ + out += "\"" + keymbln + "\":false," + } + } + } + + if v.ctmflt64 > 0 { + for keymflt64, _ := range v.mflt64 { + out += "\"" + keymflt64 + "\":" + strconv.FormatFloat(v.mflt64[keymflt64], 'f', -1, 64 ) + "," + } + } + + if strings.HasSuffix(out, ",") { + out = out[0 : len(out)-1] + } + out += "}" + return out +} + +func (v *JSONObject) StringJCS() string { + + var out string = "{" + var keys []string + + keys = make([]string, 0, len(v.mAllkeys)) + for k := range v.mAllkeys { + keys = append(keys, k) + } + sort.Strings(keys) + + iLenKeys := len(keys) + for idx := 0; idx < iLenKeys; idx++ { + key := keys[idx] + tmpVal := v.mAllkeys[key] + + switch tmpVal { + case JSON_VAL_TYPE_OBJECT: + jsObj := v.mo[key] + out += "\"" + key + "\":\"" + jsObj.StringJCS() + "\"," + case JSON_VAL_TYPE_ARRAY: + jsArr := v.marr[key] + out += "\"" + key + "\":" + jsArr.String() + "," + case JSON_VAL_TYPE_BOOL: + out += "\"" + key + "\":" + strconv.FormatBool(v.mbln[key]) + "," + case JSON_VAL_TYPE_INT: + out += "\"" + key + "\":" + strconv.Itoa(v.mn[key]) + "," + case JSON_VAL_TYPE_FLOAT: + out += "\"" + key + "\":" + strconv.FormatFloat(v.mflt64[key], 'f', -1, 64 ) + "," + default: + out += "\"" + key + "\":\"" + v.ms[key] + "\"," + } + } + if strings.HasSuffix(out, ",") { + out = out[0 : len(out)-1] + } + out += "}" + return out +} diff --git a/jaysonArr.go b/jaysonArr.go new file mode 100644 index 0000000..8cb46fe --- /dev/null +++ b/jaysonArr.go @@ -0,0 +1,257 @@ +package jaeson + +import ( + "errors" + "strconv" + "strings" +) + +type JSONArray struct { + sarr []string + oarr []*JSONObject + aarr []*JSONArray + narr []int + blnarr []bool + flt64arr []float64 + + ctsarr int + ctoarr int + ctaarr int + ctnarr int + ctblnarr int + ctflt64arr int + + hasVal bool +} + +func (v *JSONArray) Init() { + v.ctsarr = 0 + v.ctoarr = 0 + v.ctaarr = 0 + v.ctnarr = 0 + v.ctblnarr = 0 + v.ctflt64arr = 0 + + v.sarr = make([]string, 0) + v.oarr = make([]*JSONObject, 0) + v.aarr = make([]*JSONArray, 0) + v.narr = make([]int, 0) + v.blnarr = make([]bool, 0) + v.flt64arr = make([]float64, 0) + + v.hasVal = false +} + +func (v *JSONArray) Size() int { + return v.ctsarr + v.ctoarr + v.ctaarr + v.ctnarr +} + +//---------- ADD ----------// + +func (v *JSONArray) AddString(value string) error { + v.sarr = append(v.sarr, value) + v.ctsarr += 1 + v.hasVal = true + return nil +} + +func (v *JSONArray) AddJSONObject(value *JSONObject) error { + v.oarr = append(v.oarr, value) + v.ctoarr += 1 + v.hasVal = true + return nil +} + +func (v *JSONArray) AddJSONArray(value *JSONArray) error { + v.aarr = append(v.aarr, value) + v.ctaarr += 1 + v.hasVal = true + return nil +} + +func (v *JSONArray) AddInt(value int) error { + v.narr = append(v.narr, value) + v.ctnarr += 1 + v.hasVal = true + return nil +} + +func (v *JSONArray) AddBool(value bool) error { + v.blnarr = append(v.blnarr, value) + v.ctblnarr += 1 + v.hasVal = true + return nil +} + +func (v *JSONArray) AddFloat(value float64) error { + v.flt64arr = append(v.flt64arr, value) + v.ctflt64arr += 1 + v.hasVal = true + return nil +} + +//---------- PUT ----------// + +func (v *JSONArray) PutJSONObject(value *JSONObject) error { + return v.AddJSONObject(value) +} + +func (v *JSONArray) PutString(value string) error { + + return v.AddString(value) +} + +func (v *JSONArray) PutJSONArray(value *JSONArray) error { + return v.AddJSONArray(value) +} + +func (v *JSONArray) PutInt(value int) error { + + return v.AddInt(value) +} + +func (v *JSONArray) PutBool(value bool) error { + + return v.AddBool(value) +} + +func (v *JSONArray) PutFloat(value float64) error { + return v.AddFloat(value) +} + +//---------- GET ----------// + +func (v *JSONArray) GethasVal() bool { + return v.hasVal +} + +func (v *JSONArray) GetString(index int) string { + return v.sarr[index] +} + +func (v *JSONArray) GetStringArray() []string { + return v.sarr +} + +func (v *JSONArray) FromStringArray(pArr []string) { + v.sarr = pArr +} + +func (v *JSONArray) GetJSONObject(index int) (*JSONObject, error) { + if index > -1 { + if v.ctoarr > 0 { + return v.oarr[index], nil + } else { + return nil, errors.New("index out of range: " + strconv.Itoa(index)) + } + } else { + return nil, errors.New("index out of range: " + strconv.Itoa(index)) + } +} + +func (v *JSONArray) GetJSONArray(index int) (*JSONArray, error) { + if index > -1 { + if v.ctaarr > 0 { + return v.aarr[index], nil + } else { + return nil, errors.New("index out of range: " + strconv.Itoa(index)) + } + } else { + return nil, errors.New("index out of range: " + strconv.Itoa(index)) + } +} + +func (v *JSONArray) GetInt(index int) int { + return v.narr[index] +} + +func (v *JSONArray) GetNumber(index int) int { + return v.narr[index] +} + +func (v *JSONArray) GetBool(index int) bool { + return v.blnarr[index] +} + +func (v *JSONArray) GetFloat(index int) float64 { + return v.flt64arr[index] +} + +func (v *JSONArray) RemoveLastElem() { + if v.ctaarr > 0 { + v.aarr = v.aarr[:len(v.aarr)-1] + v.ctaarr -= 1 + + }else if v.ctoarr > 0 { + v.oarr = v.oarr[:len(v.oarr)-1] + v.ctoarr -= 1 + + }else if v.ctsarr > 0 { + v.sarr = v.sarr[:len(v.sarr)-1] + v.ctsarr -= 1 + + }else if v.ctnarr > 0 { + v.narr = v.narr[:len(v.narr)-1] + v.ctnarr -= 1 + } +} + +//---------- PRINT STRING----------// +func (v *JSONArray) String() string { + + var out string = "[" + + if v.ctsarr > 0 { + for idx := range v.sarr { + out += "\"" + v.sarr[idx] + "\"," + } + } + + if v.ctoarr > 0 { + for idx, _ := range v.oarr { + jsObj := v.oarr[idx] + out += jsObj.String() + "," + } + } + + if v.ctaarr > 0 { + for idx, _ := range v.aarr { + jsArr := v.aarr[idx] + out += jsArr.String() + "," + } + } + + if v.ctnarr > 0 { + for idx, _ := range v.narr { + out += strconv.Itoa(v.narr[idx]) + "," + } + } + + if v.ctblnarr > 0 { + for idx, _ := range v.blnarr { + out += strconv.FormatBool(v.blnarr[idx]) + "," + } + } + + if v.ctflt64arr > 0 { + for idx, _ := range v.flt64arr { + out += strconv.FormatFloat(v.flt64arr[idx], 'f', -1, 64 ) + "," + } + } + + if strings.HasSuffix(out, ",") { + out = out[0 : len(out)-1] + } + out += "]" + return out +} + +//---------- PRINT STRING----------// +// JSON Canonicalisation Scheme (JCS) +func (v *JSONArray) StringJCS() string { + var out string = "[" + + // TO BE IMPLEMENTED + out += "]" + return out +} diff --git a/jsonParse.go b/jsonParse.go new file mode 100644 index 0000000..2b9aafc --- /dev/null +++ b/jsonParse.go @@ -0,0 +1,320 @@ +package jaeson + +import ( + "strconv" + "gitea.cozeon.cloud/anand.ekka-ext/parser" + "github.com/antlr/antlr4/runtime/Go/antlr" +) + +type stackElem struct { + jsObj *JSONObject + jsArr *JSONArray + hasJsObj bool + hasJsArr bool +} + +func (v *stackElem) Init() { + v.hasJsObj = false + v.hasJsArr = false +} + +func (v *stackElem) GetJsObj() *JSONObject { + return v.jsObj +} +func (v *stackElem) GetJsArr() *JSONArray { + return v.jsArr +} + +func (v *stackElem) GetHasJsObj() bool { + return v.hasJsObj +} +func (v *stackElem) GetHasJsArr() bool { + return v.hasJsArr +} + +func (v *stackElem) PutJSONObject(jsnObj *JSONObject) { + v.hasJsObj = true + v.hasJsArr = false + v.jsObj = jsnObj +} + +func (v *stackElem) PutJSONArray(jsnArr *JSONArray) { + v.hasJsObj = false + v.hasJsArr = true + v.jsArr = jsnArr +} + +type jsonListener struct { + *parser.BaseJSONListener + + topJsObj *JSONObject + + currJsObj *JSONObject + currJsArr *JSONArray + currKey string + + childJsObj *JSONObject + childJsArr *JSONArray + + foundKeyOfPair bool + jsonStartFound bool + topObjCreated bool + arrStart bool + + parentObjStack []*stackElem + + stckElemPointer int + + topJsArr *JSONArray + topArrCreated bool +} + +func (s *jsonListener) GetLastElem() *stackElem { + return s.parentObjStack[s.stckElemPointer-1] +} + +func (s *jsonListener) DeleteLastElem() { + s.parentObjStack[s.stckElemPointer-1] = nil + s.stckElemPointer -= 1 +} + +func (s *jsonListener) AddJSONObjToStack(jsObj *JSONObject) { + tmpStckElem := new(stackElem) + tmpStckElem.Init() + s.stckElemPointer += 1 + + if s.stckElemPointer > len(s.parentObjStack) { + s.parentObjStack = append(s.parentObjStack, tmpStckElem) + } else { + s.parentObjStack[s.stckElemPointer-1] = tmpStckElem + } + + tmpStckElem.PutJSONObject(jsObj) +} + +func (s *jsonListener) AddJSONArrToStack(jsArr *JSONArray) { + tmpStckElem := new(stackElem) + tmpStckElem.Init() + s.stckElemPointer += 1 + + if s.stckElemPointer > len(s.parentObjStack) { + s.parentObjStack = append(s.parentObjStack, tmpStckElem) + } else { + s.parentObjStack[s.stckElemPointer-1] = tmpStckElem + } + + tmpStckElem.PutJSONArray(jsArr) +} + +//--------------- Json Enter-Exit ---------------// +func (s *jsonListener) EnterJson(ctx *parser.JsonContext) { + s.jsonStartFound = true + s.topObjCreated = false + s.stckElemPointer = 0 +} + +func (s *jsonListener) ExitJson(ctx *parser.JsonContext) { + // nothing needs to be implemented +} + +//--------------- Obj Enter-Exit ---------------// +func (s *jsonListener) EnterObj(ctx *parser.ObjContext) { + + if !s.topObjCreated && !s.topArrCreated { + s.topJsObj = new(JSONObject) + s.topJsObj.Init() + s.currJsObj = s.topJsObj + s.foundKeyOfPair = false + + s.topObjCreated = true + s.arrStart = false + + //initialize stack + s.parentObjStack = make([]*stackElem, 0) + + //Add topJsObj to stack + s.AddJSONObjToStack(s.topJsObj) + + } else { + + s.childJsObj = new(JSONObject) + s.childJsObj.Init() + + if s.arrStart { + s.currJsArr.PutJSONObject(s.childJsObj) + s.AddJSONArrToStack(s.currJsArr) + s.currJsObj = s.childJsObj + s.arrStart = false + + } else { + s.currJsObj.PutJSONObject(s.currKey, s.childJsObj) + + // might need stack up or append curr object in a LIFO stack, + // before takig on the new child object + s.AddJSONObjToStack(s.currJsObj) + + s.currJsObj = s.childJsObj + } + } +} + +func (s *jsonListener) ExitObj(ctx *parser.ObjContext) { + + tmpPrevStckElem := s.GetLastElem() + + if tmpPrevStckElem != nil { + if tmpPrevStckElem.GetHasJsObj() { + s.currJsObj = tmpPrevStckElem.GetJsObj() + s.arrStart = false + + } else { + s.currJsArr = tmpPrevStckElem.GetJsArr() + s.arrStart = true + } + s.DeleteLastElem() + + } //else { + // nothing needs to be implemented + //} + +} + +//--------------- Arr Enter-Exit ---------------// + +// EnterArr is called when production arr is entered. +func (s *jsonListener) EnterArr(ctx *parser.ArrContext) { + + if !s.topObjCreated && !s.topArrCreated { + + s.topJsArr = new(JSONArray) + s.topJsArr.Init() + s.currJsArr = s.topJsArr + + s.topArrCreated = true + s.arrStart = true + + //initialize stack + s.parentObjStack = make([]*stackElem, 0) + + //Add topJsArr to stack + s.AddJSONArrToStack(s.topJsArr) + + } else { + + if s.arrStart { + + s.childJsArr = new(JSONArray) + s.childJsArr.Init() + + //add currJsArr to stack + s.AddJSONArrToStack(s.currJsArr) + s.currJsArr.PutJSONArray(s.childJsArr) + s.currJsArr = s.childJsArr + + } else { + + s.currJsArr = new(JSONArray) + s.currJsArr.Init() + s.currJsObj.PutJSONArray(s.currKey, s.currJsArr) + s.AddJSONObjToStack(s.currJsObj) + } + } + s.arrStart = true +} + +// ExitArr is called when production arr is exited. +func (s *jsonListener) ExitArr(ctx *parser.ArrContext) { + s.arrStart = false + + tmpPrevStckElem := s.GetLastElem() + if tmpPrevStckElem.GetHasJsObj() { + s.currJsObj = tmpPrevStckElem.GetJsObj() + s.arrStart = false + + } else { + s.currJsArr = tmpPrevStckElem.GetJsArr() + s.arrStart = true + } + s.DeleteLastElem() +} + +//--------------- Pair Enter-Exit ---------------// + +func (s *jsonListener) EnterPair(ctx *parser.PairContext) { + s.foundKeyOfPair = true + s.currKey = ctx.STRING().GetSymbol().GetText() + s.currKey = s.currKey[1 : len(s.currKey)-1] +} + +func (s *jsonListener) ExitPair(ctx *parser.PairContext) { + s.foundKeyOfPair = false +} + +//--------------- Value Enter-Exit ---------------// + +func (s *jsonListener) EnterValue(ctx *parser.ValueContext) { + + if ctx.STRING() != nil { + val0 := ctx.STRING().GetSymbol().GetText() + val1 := val0[1 : len(val0)-1] + + if s.arrStart { + s.currJsArr.PutString(val1) + } else { + s.currJsObj.PutString(s.currKey, val1) + } + + }else if ctx.NUMBER() != nil { + val0 := ctx.NUMBER().GetSymbol().GetText() + vali, erri := strconv.ParseInt(val0, 10, 64) + if erri != nil { + valf, errf := strconv.ParseFloat(val0, 64) + if errf == nil { + s.currJsObj.PutFloat(s.currKey, valf) + } else { + // neither int nor float. then what is it ? + } + }else{ + s.currJsObj.PutInt(s.currKey, int(vali)) + } + + //s.currJsObj.PutInt(s.currKey, val1) + + }else if ctx.Obj() != nil { + // nothing needs to be implemented + + }else if ctx.BOOLEAN() != nil { + + val0 := ctx.BOOLEAN().GetSymbol().GetText() + val1, _ := strconv.ParseBool(val0) + s.currJsObj.PutBool(s.currKey, val1) + } + s.foundKeyOfPair = false +} + +func (s *jsonListener) ExitValue(ctx *parser.ValueContext) { + // nothing needs to be implemented +} + +func UnmarshalJSON(jsonstr string) (*JSONObject, *JSONArray) { + + is := antlr.NewInputStream(jsonstr) + + // Create the Lexer + lexer := parser.NewJSONLexer(is) + stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) + + // Create the Parser + p := parser.NewJSONParser(stream) + + // Finally parse the expression + var jsonLstnr *jsonListener = new(jsonListener) + antlr.ParseTreeWalkerDefault.Walk(jsonLstnr, p.Json()) + + if jsonLstnr.topObjCreated { + return jsonLstnr.topJsObj, nil + + } else { + return nil, jsonLstnr.topJsArr + } +}