321 lines
6.7 KiB
Go
321 lines
6.7 KiB
Go
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
|
|
}
|
|
}
|