mirror of
https://github.com/vishapoberon/vipak.git
synced 2026-04-05 20:42:26 +00:00
304 lines
No EOL
9 KiB
Modula-2
304 lines
No EOL
9 KiB
Modula-2
MODULE JsonParser;
|
|
IMPORT Logger, CharacterStack, Strings, Out, strutils, Settings;
|
|
CONST
|
|
ArrayMaxNumber = 30;
|
|
ArrayMaxNumberChar = 1000;
|
|
(* Const *)
|
|
symbolBracketStart = "{";
|
|
symbolBracketEnd = "}";
|
|
(* TODO: Reverse " and ' *)
|
|
quote = Settings.quote;
|
|
coma = ",";
|
|
TYPE
|
|
TString* = ARRAY ArrayMaxNumberChar OF CHAR;
|
|
|
|
JsonTypePointer* = POINTER TO JsonType;
|
|
|
|
JsonType* = RECORD
|
|
GetTerminal* : PROCEDURE(self : JsonTypePointer; string : ARRAY OF CHAR; VAR returnValue : ARRAY OF CHAR): BOOLEAN;
|
|
GetNonTerminal* : PROCEDURE(self : JsonTypePointer; key : ARRAY OF CHAR): JsonTypePointer;
|
|
HasKey* : PROCEDURE(self : JsonTypePointer; key : ARRAY OF CHAR): BOOLEAN;
|
|
TypeOfTheKey* : PROCEDURE(self : JsonTypePointer; key : ARRAY OF CHAR; VAR returnValue : ARRAY OF CHAR);
|
|
GetTerminalKeys* : PROCEDURE(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
GetTerminalValues* : PROCEDURE(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
GetNoneTerminalKeys* : PROCEDURE(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
GetTerminalNumber* : PROCEDURE(self : JsonTypePointer): LONGINT;
|
|
GetNonTerminalNumber* : PROCEDURE(self : JsonTypePointer): LONGINT;
|
|
|
|
TerminalKeys : ARRAY ArrayMaxNumber OF TString;
|
|
TerminalValues : ARRAY ArrayMaxNumber OF TString;
|
|
TerminalNumber* : LONGINT;
|
|
|
|
NonTerminalKeys : ARRAY ArrayMaxNumber OF TString;
|
|
NonTerminalValues : POINTER TO ARRAY OF JsonTypePointer;
|
|
NonTerminalNumber* : LONGINT;
|
|
END;
|
|
|
|
VAR
|
|
jsonRecord: JsonTypePointer;
|
|
testValue: ARRAY ArrayMaxNumber OF CHAR;
|
|
keyFound: BOOLEAN;
|
|
|
|
PROCEDURE GetTerminalNumber*(self : JsonTypePointer): LONGINT;
|
|
BEGIN RETURN self.TerminalNumber END GetTerminalNumber;
|
|
|
|
PROCEDURE GetNonTerminalNumber*(self : JsonTypePointer): LONGINT;
|
|
BEGIN RETURN self.NonTerminalNumber END GetNonTerminalNumber;
|
|
|
|
PROCEDURE GetNonTerminal(self : JsonTypePointer; key : ARRAY OF CHAR): JsonTypePointer;
|
|
VAR
|
|
i: LONGINT;
|
|
BEGIN
|
|
FOR i := 0 TO self.NonTerminalNumber - 1 DO
|
|
IF Strings.Match(key, self.NonTerminalKeys[i]) THEN RETURN self.NonTerminalValues[i] END;
|
|
END;
|
|
|
|
RETURN NIL;
|
|
END GetNonTerminal;
|
|
|
|
PROCEDURE Empty *(VAR string: ARRAY OF CHAR);
|
|
VAR
|
|
i : LONGINT;
|
|
BEGIN
|
|
FOR i := 0 TO LEN(string) - 1 DO string[i] := 0X END;
|
|
COPY("", string);
|
|
END Empty;
|
|
|
|
PROCEDURE GetTerminal *(self: JsonTypePointer; key: ARRAY OF CHAR; VAR returnValue: ARRAY OF CHAR): BOOLEAN;
|
|
VAR
|
|
i: LONGINT;
|
|
noneTerminal: JsonTypePointer;
|
|
strings: strutils.strings;
|
|
parent, children: ARRAY ArrayMaxNumber OF CHAR;
|
|
BEGIN
|
|
|
|
FOR i := 0 TO self.TerminalNumber DO
|
|
IF Strings.Match(key, self.TerminalKeys[i]) THEN COPY(self.TerminalValues[i], returnValue); RETURN TRUE END;
|
|
END;
|
|
|
|
strings := strutils.tokenize(key, '.');
|
|
|
|
IF LEN(strings^) < 1 THEN RETURN FALSE END;
|
|
|
|
COPY(strings^[0], parent);
|
|
|
|
IF Strings.Length(parent) < 1 THEN RETURN FALSE END;
|
|
|
|
noneTerminal := self.GetNonTerminal(self, parent);
|
|
|
|
IF noneTerminal = NIL THEN RETURN FALSE END;
|
|
|
|
FOR i := 1 TO LEN(strings^) - 1 DO
|
|
Strings.Append(strings[i], children);
|
|
IF i < LEN(strings^) - 1 THEN
|
|
Strings.Append(".", children);
|
|
END;
|
|
END;
|
|
|
|
RETURN noneTerminal.GetTerminal(noneTerminal, children, returnValue);
|
|
|
|
RETURN FALSE;
|
|
END GetTerminal;
|
|
|
|
PROCEDURE GetTerminalKeys(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
VAR
|
|
i: LONGINT;
|
|
BEGIN
|
|
FOR i := 0 TO self.TerminalNumber DO
|
|
COPY(self.TerminalKeys[i], destination[i]);
|
|
END;
|
|
END GetTerminalKeys;
|
|
|
|
PROCEDURE GetTerminalValues(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
VAR
|
|
i: LONGINT;
|
|
BEGIN
|
|
FOR i := 0 TO LEN(self.TerminalValues) - 1 DO
|
|
Empty(destination[i]);
|
|
COPY(self.TerminalValues[i], destination[i]);
|
|
END;
|
|
END GetTerminalValues;
|
|
|
|
PROCEDURE GetNoneTerminalKeys(self : JsonTypePointer; VAR destination : ARRAY OF TString);
|
|
VAR
|
|
i: LONGINT;
|
|
BEGIN
|
|
FOR i := 0 TO LEN(self.NonTerminalKeys) - 1 DO
|
|
destination[i] := self.NonTerminalKeys[i];
|
|
END;
|
|
END GetNoneTerminalKeys;
|
|
(*
|
|
TODO:
|
|
Create a good validation for comas
|
|
Create a good validation for name repetition
|
|
*)
|
|
|
|
PROCEDURE PushDownString(
|
|
string: ARRAY OF CHAR;
|
|
startCharacter: CHAR;
|
|
endCharacter: CHAR;
|
|
i: LONGINT;
|
|
VAR returnString: ARRAY OF CHAR): LONGINT;
|
|
VAR
|
|
characterStack: CharacterStack.CharacterStackType;
|
|
j , k: LONGINT;
|
|
BEGIN
|
|
NEW(characterStack);
|
|
j := i;
|
|
characterStack := CharacterStack.Create();
|
|
Empty(returnString);
|
|
REPEAT
|
|
IF (characterStack.Count > 1) & (string[j] = endCharacter) THEN
|
|
REPEAT UNTIL characterStack.pop(characterStack) = startCharacter;
|
|
ELSE
|
|
characterStack.push(characterStack, string[j]);
|
|
INC(j);
|
|
END;
|
|
UNTIL characterStack.Count = 0; (* do not trust top it btings OAX on EOL*)
|
|
|
|
IF j >= LEN(returnString) THEN
|
|
Logger.Log('ERROR string out of range in JSON parser');
|
|
END;
|
|
ASSERT(j < LEN(returnString));
|
|
|
|
FOR k := i TO j DO
|
|
returnString[k - i] := string[k];
|
|
END;
|
|
|
|
RETURN j; (* returning next symbol of quote *)
|
|
END PushDownString;
|
|
|
|
PROCEDURE deQuote(text: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
|
|
VAR
|
|
i, j: LONGINT;
|
|
BEGIN
|
|
j := 0;
|
|
FOR i := 0 TO Strings.Length(text) DO
|
|
IF text[i] # quote THEN
|
|
result[j] := text[i];
|
|
INC(j);
|
|
END;
|
|
END;
|
|
END deQuote;
|
|
|
|
PROCEDURE Create*(text: ARRAY OF CHAR): JsonTypePointer;
|
|
VAR
|
|
self: JsonTypePointer;
|
|
i, j, terminalIterator, noneTerminalIterator: LONGINT;
|
|
characterStack: CharacterStack.CharacterStackType;
|
|
key, val, nonTerminalVal, string: ARRAY ArrayMaxNumberChar OF CHAR;
|
|
symbol: CHAR;
|
|
symbolStart: CHAR;
|
|
quoteStart: BOOLEAN;
|
|
BEGIN
|
|
NEW(self);
|
|
NEW(self.NonTerminalValues, ArrayMaxNumber);
|
|
self.GetTerminal := GetTerminal;
|
|
self.GetNonTerminal := GetNonTerminal;
|
|
self.GetTerminalKeys := GetTerminalKeys;
|
|
self.GetNoneTerminalKeys := GetNoneTerminalKeys;
|
|
NEW(characterStack);
|
|
characterStack := CharacterStack.Create();
|
|
|
|
i := 0;
|
|
j := 0;
|
|
terminalIterator := 0;
|
|
noneTerminalIterator := 0;
|
|
|
|
Empty(key);
|
|
Empty(val);
|
|
Empty(nonTerminalVal);
|
|
Empty(string);
|
|
|
|
quoteStart := FALSE;
|
|
|
|
REPEAT
|
|
IF (text[i] = symbolBracketStart) & (i = 0) THEN
|
|
INC(i);
|
|
(* Logger.Log("Starting Parse Json"); *)
|
|
END;
|
|
|
|
IF symbol = symbolBracketStart THEN
|
|
(* Logger.Log("End Parsing Json"); *)
|
|
END;
|
|
symbol := text[i];
|
|
|
|
(* Logger.LogIntLn(i); *)
|
|
(* IF i > 508 THEN
|
|
Logger.Log(text);
|
|
END; *)
|
|
(* terminals *)
|
|
IF symbol = quote THEN
|
|
i := PushDownString(text, quote, quote, i, string);
|
|
END;
|
|
|
|
IF (Strings.Length(string) > 0) & (symbol = quote) THEN
|
|
IF Strings.Length(key) > 0 THEN
|
|
COPY(string, val);
|
|
ELSE
|
|
COPY(string, key);
|
|
END;
|
|
|
|
Empty(string);
|
|
END;
|
|
|
|
IF (Strings.Length(key) > 0) & (Strings.Length(val) > 0) THEN
|
|
deQuote(key, self.TerminalKeys[terminalIterator]);
|
|
deQuote(val, self.TerminalValues[terminalIterator]);
|
|
|
|
INC(terminalIterator);
|
|
|
|
Empty(key);
|
|
Empty(val);
|
|
END;
|
|
|
|
(* none terminals *)
|
|
IF symbol = symbolBracketStart THEN
|
|
i := PushDownString(text, symbolBracketStart, symbolBracketEnd, i, string);
|
|
END;
|
|
|
|
IF (Strings.Length(string) > 0) & (symbol = symbolBracketStart) THEN
|
|
IF Strings.Length(key) > 0 THEN
|
|
COPY(string, nonTerminalVal);
|
|
END;
|
|
|
|
Empty(string);
|
|
END;
|
|
|
|
IF (Strings.Length(key) > 0) & (Strings.Length(nonTerminalVal) > 0) THEN
|
|
deQuote(key, self.NonTerminalKeys[noneTerminalIterator]);
|
|
self.NonTerminalValues[noneTerminalIterator] := Create(nonTerminalVal);
|
|
|
|
INC(noneTerminalIterator);
|
|
|
|
Empty(key);
|
|
Empty(nonTerminalVal);
|
|
END;
|
|
|
|
INC(i);
|
|
UNTIL (i >= LEN(text) - 1) OR (text[i] = 0X);
|
|
|
|
self.NonTerminalNumber := noneTerminalIterator;
|
|
self.TerminalNumber := terminalIterator;
|
|
|
|
RETURN self;
|
|
END Create;
|
|
|
|
BEGIN
|
|
(* NEW(jsonRecord);
|
|
jsonRecord := Create("{'foo': 'bar', 'test': 'test1', 'test2': {'sub': 'dub'}}");
|
|
|
|
keyFound := jsonRecord.GetTerminal(jsonRecord, "foo", testValue);
|
|
|
|
IF keyFound THEN
|
|
Logger.Log('found KEY');
|
|
Logger.Log(testValue);
|
|
ELSE Logger.Log('Value for the Key is not found') END;
|
|
|
|
keyFound := jsonRecord.GetTerminal(jsonRecord, "test2.sub", testValue);
|
|
|
|
IF keyFound THEN
|
|
Logger.Log('found KEY');
|
|
Logger.Log(testValue);
|
|
ELSE Logger.Log('Value for the Key is not found') END; *)
|
|
END JsonParser. |