package JsonParser import public Json import SeqWorker import LinkedList /** Provides functionality to parse JSON (JasSObjectNotation). It is a minimal format to save space and allow for better compression. A Json object is a collection of properties that have one letter as name and an int or a list of json objects as value. Examples: x1y2 // Two component vector a[x1y2]b[x2y1] // Two lists of vectors To parse toplevel properties use the #parse function. To parse a list of json objects use the #parseList function */ constant numbermap = "-0123456789" constant lettermap = "abcdefghijklmnopqrstuvwxyz" public enum TokenType NONE LETTER NUMBER OPEN_ARRAY CLOSE_ARRAY public class JsonParser BigString bigInput = null int currentPosition = 0 int propStartPosition = 0 int squareBracketLvl = 0 TokenType lastType = TokenType.NONE string currentToken = null Json output = new Json() LinkedList outputList = null BigSubString propName = null BigSubString propVal = null function setInput(BigString bs) this.bigInput = bs currentPosition = 0 propStartPosition = 0 squareBracketLvl = 0 lastType = TokenType.NONE currentToken = null /** Parses a list of objects. Example: [x1_x2_x3] -> parsed: x1, x2, x3 */ function parseList(PayloadCallback finalCallback) if outputList != null destroy outputList outputList = new LinkedList() if bigInput.getLength() <= 2 Log.debug("skip empty list") finalCallback.doStep() else doSeq() cb -> var continue = true if currentPosition < bigInput.getLength() parseListSeq() else continue = false Log.debug("parsed list") finalCallback.doStep() return continue private function parseListSeq() currentToken = bigInput.getString(currentPosition, 1) switch currentToken case JSON_OPEN_ARRAY.token squareBracketLvl++ if squareBracketLvl == 1 propStartPosition = currentPosition+1 case JSON_CLOSE_ARRAY.token squareBracketLvl-- if squareBracketLvl == 0 let bss = new BigSubString(bigInput, propStartPosition, currentPosition-propStartPosition) outputList.add(bss) propStartPosition = currentPosition+1 case JSON_SIGN_COMMA.token if squareBracketLvl == 1 let bss = new BigSubString(bigInput, propStartPosition, currentPosition-propStartPosition) outputList.add(bss) propStartPosition = currentPosition+1 default currentPosition++ /** Parses a toplevel json Example: a1b2c[a1b2] -> parsed: a = 1, b = 2, c = [a1b2] */ function parse(PayloadCallback callback) if bigInput == null or bigInput.getLength() <= 0 Log.debug("skip empty input") callback.doStep() return bigInput.debugPrint() output.reset() doSeq() cb -> var continue = true if currentPosition < bigInput.getLength() parseSeq() else continue = false if propStartPosition < currentPosition propVal = new BigSubString(bigInput, propStartPosition, currentPosition-propStartPosition) output.addProperty(new Property(propName, propVal)) callback.doStep() return continue private function parseSeq() currentToken = bigInput.getString(currentPosition, 1) switch currentToken case JSON_OPEN_ARRAY.token squareBracketLvl++ if squareBracketLvl == 1 propStartPosition = currentPosition lastType = TokenType.OPEN_ARRAY case JSON_CLOSE_ARRAY.token squareBracketLvl-- if squareBracketLvl == 0 propVal = new BigSubString(bigInput, propStartPosition, currentPosition-propStartPosition+1) output.addProperty(new Property(propName, propVal)) propStartPosition = currentPosition+1 lastType = TokenType.CLOSE_ARRAY default if squareBracketLvl == 0 if lettermap.contains(currentToken) onLetter() else if numbermap.contains(currentToken) onNumber() currentPosition++ private function onNumber() switch lastType case LETTER propStartPosition = currentPosition default lastType = TokenType.NUMBER private function onLetter() switch lastType case NONE propName = new BigSubString(bigInput, currentPosition, 1) propStartPosition = currentPosition+1 case NUMBER propVal = new BigSubString(bigInput, propStartPosition, currentPosition-propStartPosition) output.addProperty(new Property(propName, propVal)) propName = new BigSubString(bigInput, currentPosition, 1) propStartPosition = currentPosition+1 case CLOSE_ARRAY propName = new BigSubString(bigInput, currentPosition, 1) propStartPosition = currentPosition+1 default lastType = TokenType.LETTER ondestroy if bigInput != null destroy bigInput if output != null destroy output if outputList != null for bss from outputList.staticItr() destroy bss destroy outputList