Formatter.cp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. MODULE JSonFormatter;
  2. (**
  3. project = "JSon"
  4. organization = ""
  5. contributors = ""
  6. version = "System/Rsrc/About"
  7. copyright = "Kushnir Piotr Michailovich"
  8. license = "Docu/BB-License"
  9. purpose = "генерация json вручную, этот способ полезен тем, кто не использует YSonModels, по каким-то причинам"
  10. changes = "
  11. - 20130112, pk, автогенерация заголовка
  12. - 20150204, pk, порт для fw
  13. "
  14. issues = ""
  15. **)
  16. IMPORT
  17. JSonGenerator,
  18. Str, Out;
  19. CONST
  20. objBegin* = 1;
  21. objEnd* = 2;
  22. arrBegin* = 3;
  23. arrEnd* = 4;
  24. name = 5;
  25. value = 6;
  26. stringVal* = 1;
  27. unicodeStringVal* = 10;
  28. intVal* = 2;
  29. realVal* =3;
  30. atomVal*= 4;
  31. errWrongSym* = -1;
  32. errUnexpected* = -2;
  33. TYPE
  34. Formatter* = POINTER TO ABSTRACT RECORD END;
  35. Directory* = POINTER TO ABSTRACT RECORD END;
  36. StdDir = POINTER TO RECORD (Directory) END;
  37. StdF = POINTER TO RECORD (Formatter)
  38. wr: JSonGenerator.Writer;
  39. this: StackItem;
  40. END;
  41. StackItem = POINTER TO RECORD
  42. depth: INTEGER;
  43. expect: SET;
  44. values: LONGINT;
  45. next: StackItem;
  46. END;
  47. VAR
  48. dir-, prev-, stdDir-: Directory;
  49. PROCEDURE (d: Directory) New* (wr: JSonGenerator.Writer): Formatter, NEW, ABSTRACT;
  50. PROCEDURE (f: Formatter) ConnectTo- (wr: JSonGenerator.Writer), NEW, ABSTRACT;
  51. PROCEDURE (f: Formatter) WriteSym* (sym: INTEGER; OUT res: INTEGER), NEW, ABSTRACT;
  52. PROCEDURE (f: Formatter) WriteName* (IN s: ARRAY OF CHAR; OUT res: INTEGER), NEW, ABSTRACT;
  53. PROCEDURE (f: Formatter) WriteValue* (type: INTEGER; IN val: ARRAY OF CHAR; OUT res: INTEGER), NEW, ABSTRACT;
  54. PROCEDURE NewStackItem(): StackItem;
  55. VAR s: StackItem;
  56. BEGIN
  57. NEW(s);
  58. s.depth:=1;
  59. s.expect:={};
  60. s.values:=0;
  61. RETURN s;
  62. END NewStackItem;
  63. PROCEDURE Push(VAR root: StackItem);
  64. VAR new: StackItem;
  65. BEGIN
  66. new:=NewStackItem();
  67. new.next:=root;
  68. root:=new;
  69. IF root.next#NIL THEN root.depth:=root.next.depth+1 END
  70. END Push;
  71. PROCEDURE Pop(VAR root: StackItem);
  72. VAR old: StackItem;
  73. BEGIN
  74. IF root#NIL THEN
  75. old:=root;
  76. root:=old.next;
  77. old:=NIL;
  78. END;
  79. END Pop;
  80. PROCEDURE (f: StdF) ConnectTo (wr: JSonGenerator.Writer);
  81. BEGIN
  82. ASSERT(wr#NIL, 20); ASSERT(wr.Base()#NIL, 21);
  83. f.wr:=wr;
  84. f.this:=NIL;
  85. END ConnectTo;
  86. PROCEDURE String (wr: JSonGenerator.Writer; IN s: ARRAY OF CHAR);
  87. VAR i: INTEGER;
  88. BEGIN
  89. i:=0;
  90. WHILE i<LEN(s$) DO
  91. CASE s[i] OF
  92. '"': wr.Char('\'); wr.Char('"');
  93. |'\': wr.Char('\'); wr.Char('\');
  94. |09X: wr.Char('\'); wr.Char('t');
  95. |0DX: wr.Char('\'); wr.Char('r');
  96. |0AX: wr.Char('\'); wr.Char('n');
  97. |0CX: wr.Char('\'); wr.Char('f');
  98. |08X: wr.Char('\'); wr.Char('b');
  99. ELSE wr.Char(s[i]) END;
  100. INC(i)
  101. END;
  102. END String;
  103. PROCEDURE UniString (wr: JSonGenerator.Writer; IN s: ARRAY OF CHAR);
  104. VAR i: INTEGER;
  105. BEGIN
  106. i:=0;
  107. WHILE i<LEN(s$) DO
  108. CASE s[i] OF
  109. '"': wr.Char('\'); wr.Char('"');
  110. |'\': wr.Char('\'); wr.Char('\');
  111. |09X: wr.Char('\'); wr.Char('t');
  112. |0DX: wr.Char('\'); wr.Char('r');
  113. |0AX: wr.Char('\'); wr.Char('n');
  114. |0CX: wr.Char('\'); wr.Char('f');
  115. |08X: wr.Char('\'); wr.Char('b');
  116. ELSE wr.UnicodeChar(s[i]) END;
  117. INC(i)
  118. END;
  119. END UniString;
  120. PROCEDURE (f: StdF) WriteName (IN s: ARRAY OF CHAR; OUT res: INTEGER);
  121. VAR i: INTEGER;
  122. BEGIN
  123. ASSERT(s$#'', 20);
  124. res:=0;
  125. IF (f.this#NIL) & (name IN f.this.expect) THEN
  126. IF (objEnd IN f.this.expect) THEN
  127. IF f.this.values > 0 THEN
  128. f.wr.Char(',');
  129. f.wr.Whitespace(0DX);
  130. END;
  131. FOR i:=1 TO f.this.depth DO f.wr.Whitespace(09X) END;
  132. END;
  133. f.wr.Char('"'); String(f.wr, s); f.wr.Char('"'); f.wr.Char(':'); f.wr.Whitespace(' '); f.this.expect:={value, arrBegin, objBegin};
  134. INC(f.this.values);
  135. ELSE
  136. res:=errUnexpected
  137. END;
  138. END WriteName;
  139. PROCEDURE (f: StdF) WriteValue (type: INTEGER; IN v: ARRAY OF CHAR; OUT res: INTEGER);
  140. VAR i: INTEGER; vs: ARRAY 20 OF CHAR;
  141. BEGIN
  142. ASSERT(type IN {stringVal, atomVal, intVal, realVal, unicodeStringVal}, 20);
  143. ASSERT((type IN {stringVal, unicodeStringVal}) OR (v$#''), 21);
  144. res:=0;
  145. IF (f.this#NIL) & (value IN f.this.expect) THEN
  146. IF (arrEnd IN f.this.expect) THEN
  147. IF f.this.values > 0 THEN
  148. f.wr.Char(',');
  149. f.wr.Whitespace(0DX);
  150. END;
  151. FOR i:=1 TO f.this.depth DO f.wr.Whitespace(09X) END;
  152. END;
  153. CASE type OF
  154. stringVal: f.wr.Char('"'); String(f.wr, v); f.wr.Char('"');
  155. |unicodeStringVal: f.wr.Char('"'); UniString(f.wr, v); f.wr.Char('"');
  156. |intVal, realVal: String(f.wr, v);
  157. |atomVal: Str.ToLower(v, vs); String(f.wr, vs); (* null, true, false точно поместятся в 20 символов *)
  158. ELSE HALT(100) END;
  159. INC(f.this.values);
  160. IF ~(arrEnd IN f.this.expect) THEN f.this.expect:={objEnd, name} END;
  161. ELSE
  162. res:=errUnexpected
  163. END;
  164. END WriteValue;
  165. PROCEDURE (f: StdF) WriteSym (sym: INTEGER; OUT res: INTEGER);
  166. VAR expect: SET; i: INTEGER;
  167. BEGIN
  168. res:=0;
  169. IF f.this#NIL THEN expect:=f.this.expect ELSE expect:={objBegin, arrBegin} END;
  170. IF (sym IN expect) THEN
  171. CASE sym OF
  172. objBegin:
  173. IF (f.this#NIL) THEN
  174. IF ~(arrEnd IN f.this.expect) THEN
  175. f.this.expect:={objEnd, name}
  176. ELSE
  177. IF f.this.values > 0 THEN
  178. f.wr.Char(',');
  179. f.wr.Whitespace(0DX);
  180. END;
  181. FOR i:=1 TO f.this.depth DO f.wr.Whitespace(09X) END;
  182. END;
  183. END;
  184. Push(f.this); f.wr.Char('{'); f.wr.Whitespace(0DX); f.this.expect:={objEnd, name}
  185. |arrBegin:
  186. IF (f.this#NIL) THEN
  187. IF ~(arrEnd IN f.this.expect) THEN f.this.expect:={objEnd, name}
  188. ELSE
  189. IF f.this.values > 0 THEN
  190. f.wr.Char(',');
  191. f.wr.Whitespace(0DX);
  192. END;
  193. FOR i:=1 TO f.this.depth DO f.wr.Whitespace(09X) END;
  194. END;
  195. END;
  196. Push(f.this); f.wr.Char('['); f.wr.Whitespace(0DX); f.this.expect:={arrEnd, objBegin, arrBegin, value}
  197. |objEnd:
  198. f.wr.Whitespace(0DX); FOR i:=1 TO f.this.depth-1 DO f.wr.Whitespace(09X) END;
  199. f.wr.Char('}'); Pop(f.this);
  200. |arrEnd:
  201. f.wr.Whitespace(0DX); FOR i:=1 TO f.this.depth-1 DO f.wr.Whitespace(09X) END;
  202. f.wr.Char(']'); Pop(f.this)
  203. ELSE HALT(101) END;
  204. ELSE
  205. res:=errWrongSym;
  206. HALT(100);
  207. END;
  208. END WriteSym;
  209. PROCEDURE (d: StdDir) New (wr: JSonGenerator.Writer): Formatter;
  210. VAR f: StdF;
  211. BEGIN
  212. ASSERT(wr#NIL, 20); ASSERT(wr.Base()#NIL, 21);
  213. NEW(f);
  214. f.ConnectTo(wr);
  215. RETURN f
  216. END New;
  217. PROCEDURE Install* (d: Directory);
  218. BEGIN
  219. ASSERT(d#NIL, 20);
  220. prev:=dir;
  221. dir:=d;
  222. END Install;
  223. PROCEDURE Init;
  224. VAR d: StdDir;
  225. BEGIN
  226. NEW(d);
  227. Install(d);
  228. stdDir:=d;
  229. END Init;
  230. BEGIN
  231. Init
  232. END JSonFormatter.