source: proto/JSON/json_prototype.py @ 713

Last change on this file since 713 was 713, checked in by ksherdy, 9 years ago

Demo logic to validate JSON atoms.

File size: 23.2 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# json_prototype.py
4#
5# Ken Herdy
6# Oct. 13, 2010
7#
8#----------------------------------------------------------------------------
9#
10# We use python's unlimited precision integers for unbounded bit streams.
11# This permits simple logical operations on the entire stream.
12# Assumption: bitstreams are little-endian (e.g., as on x86).
13#
14#----------------------------------------------------------------------------
15#
16
17import bitutil
18import byteclass
19import u8u16
20import math
21import sys
22
23debug = True
24filename = "json_prototype.py"
25
26# Globals
27#
28# Bitstream function definitions input/output *only* bitstream type variables.
29#
30# Global declarations allow debug blocks in bitstream processing definitions.
31#
32# Do not shadow the global variables 'u8data' or 'lgth' with local variable declartions.
33
34u8data = ""
35lgth = 0
36
37def simd_const_4(hexdigit,EOF_mask):
38        r"""
39        IDISA library function.
40        """
41        lgth = bitutil.count_leading_zeroes(~EOF_mask)/4
42        return int(hexdigit*(lgth+1),16)&EOF_mask
43       
44def parse_escape(Lex, EOF_mask):
45        r"""
46        Marks escaped characters.
47        Does not mark escaped '\' characters.
48        '\' characters are either escaped and unmarked or the following character in an odd length run is marked.
49        """
50        odd = simd_const_4('a',EOF_mask)
51        even = simd_const_4('5',EOF_mask)
52       
53        start = Lex.RSolidus &~ bitutil.Advance(Lex.RSolidus)
54       
55        even_start = start & even
56        even_final = (even_start + Lex.RSolidus) & ~Lex.RSolidus
57        even_escape = even_final & odd
58       
59        odd_start = start & odd
60        odd_final = (odd_start + Lex.RSolidus) & ~Lex.RSolidus
61        odd_escape = (odd_final & even)
62
63        escape = (even_escape | odd_escape) 
64       
65        return escape
66       
67def demo_parse_escape(u8data):
68        global lgth
69        lgth = len(u8data)
70       
71        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
72        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
73        (escape) = parse_escape(Lex,EOF_mask)
74
75        bitutil.print_aligned_streams([('Input Data', u8data), 
76                              ('Lex.RSolidus', bitutil.bitstream2string(Lex.RSolidus, lgth)),   
77                              ('escape', bitutil.bitstream2string(escape, lgth)),       
78                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
79        return
80
81def parallel_prefix_parity(strm):
82        r"""
83        Translate to library function.
84       
85        x y  x XOR y
86        ------------
87        0 0   0
88        0 1   1
89        1 0   1
90        0 0   0
91
92        Let n = length(bitstream).
93
94        Define Pk,i as the parity of the bit range [k-(k+2^i),k] for bit positions n >= k >= 1.
95       
96        Base Case: Pk,0 = bitstream at position k, for all k, n >= k >= 0.
97        Inductive Step: Pk,i+1 = (Pk,i << 2^i) XOR Pk,i.
98       
99        Pk,ceil(log(n) denotes the parity of the bit position k, n >= k >= 0.
100       
101        bitstream[k] = 1 --> odd parity
102        bitstream[k] = 0 --> even parity
103        """
104        global lgth
105#       lgth = len(u8data)
106
107        t1 = strm
108        for i in range(0,int(math.ceil(math.log(lgth,2)))):
109                t2 = t1 ^ (t1 << pow(2,i))
110                t1 = t2
111        return t2 
112
113def demo_parallel_prefix_parity(u8data):
114        r"""
115        >>> demo_parallel_prefix_parity('"data" "data""data" "data" "data')
116        Input Data: "data" "data""data" "data" "data
117        Lex.DQuote: 1____1_1____11____1_1____1_1____
118        Parity    : 11111__11111_11111__11111__11111
119        EOF_Mask  : 11111111111111111111111111111111_
120        <BLANKLINE>
121        """     
122        global lgth
123        lgth = len(u8data)
124
125        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
126        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
127        ParityMask = parallel_prefix_parity(Lex.DQuote)
128       
129        bitutil.print_aligned_streams([('Input Data', u8data), 
130                              ('Lex.DQuote', bitutil.bitstream2string(Lex.DQuote, lgth)),
131                              ('Parity', bitutil.bitstream2string(ParityMask, lgth)),   
132                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
133        return
134
135
136#TODO - Review this function.
137def atom_starts(Lex,StringMask,EscapeChars):
138        r"""
139        This function returns multi-cursor start positions for each JSON value type.
140       
141        Define JSON atoms as 'String', 'Number', 'true', 'false', and 'null' types.
142        """
143        global lgth
144        StringEscapeCharMask = (StringMask | EscapeChars)               
145       
146        ObjectStarts = Lex.LCurlyBrace &~ StringEscapeCharMask
147        ArrayStarts = Lex.LSquareBracket &~ StringEscapeCharMask
148               
149        Comma = Lex.Comma &~ StringEscapeCharMask
150        Colon = Lex.Colon &~ StringEscapeCharMask
151       
152        NonStringSyncPoint = (ArrayStarts | Comma | Colon)
153        StringSyncPoint = (ObjectStarts | NonStringSyncPoint)
154       
155        StringSyncPointFollows = bitutil.Advance(StringSyncPoint)
156        StringStarts = (StringSyncPointFollows | bitutil.ScanThru(StringSyncPointFollows, Lex.WS)) & (Lex.DQuote &~ StringEscapeCharMask)
157
158        NonStringSyncPointFollows = bitutil.Advance(NonStringSyncPoint)
159        ValueCursors = (StringSyncPointFollows | bitutil.ScanThru(StringSyncPointFollows,Lex.WS))
160       
161        NumberStarts = ValueCursors & ((Lex.Minus|Lex.Digit0_9) &~ StringEscapeCharMask) 
162        TrueStarts = ValueCursors & (Lex.t &~ StringEscapeCharMask)
163        FalseStarts = ValueCursors & (Lex.f &~ StringEscapeCharMask)
164        NullStarts = ValueCursors & (Lex.n &~ StringEscapeCharMask)
165        ValueStarts = ValueCursors & (Lex.ValueStartsSet &~ StringEscapeCharMask)
166
167        if debug:
168                bitutil.print_aligned_streams([('Input Data', u8data), 
169                              ('StringEscapeCharMask', bitutil.bitstream2string(StringEscapeCharMask, lgth)),
170                              ('ObjectStarts', bitutil.bitstream2string(ObjectStarts, lgth)),
171                              ('ArrayStarts', bitutil.bitstream2string(ArrayStarts, lgth))])
172       
173        return (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts, ValueStarts)
174
175
176def demo_atom_starts(u8data):
177        global lgth     
178        lgth = len(u8data)
179               
180        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
181        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
182       
183        EscapeChars = parse_escape(Lex, EOF_mask)
184       
185        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
186       
187        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve EOF_mask problem
188        StringMask = ParityMask & bitutil.Advance(ParityMask)   
189       
190        (StringStarts, NumberStarts,TrueStarts, FalseStarts, NullStarts, ValueStarts) = atom_starts(Lex, StringMask, EscapeChars)
191        bitutil.print_aligned_streams([('Input Data', u8data), 
192                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
193                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
194                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
195                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
196                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
197                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
198        return
199
200
201def validate_true(Starts, Lex):
202        r"""
203        RFC 4627 - JavaScript Object Notation (JSON) 
204       
205        true  = %x74.72.75.65      ; true
206       
207        """
208        Errors = 0
209       
210        Scope1 = bitutil.Advance(Starts)
211        Scope2 = bitutil.Advance(Scope1)
212        Scope3 = bitutil.Advance(Scope2)
213       
214        Errors |= Scope1 &~ Lex.r
215        Errors |= Scope2 &~ Lex.u
216        Errors |= Scope3 &~ Lex.e
217       
218        Follows = bitutil.Advance(Scope3)
219        Spans = Follows - Starts
220
221        return (Errors, Spans)
222
223def validate_false(Starts, Lex):
224        r"""
225        RFC 4627 - JavaScript Object Notation (JSON) 
226       
227        false = %x66.61.6c.73.65   ; false
228       
229        """
230        Errors = 0
231       
232        Scope1 = bitutil.Advance(Starts)
233        Scope2 = bitutil.Advance(Scope1)
234        Scope3 = bitutil.Advance(Scope2)
235        Scope4 = bitutil.Advance(Scope3)
236       
237        Errors |= Scope1 &~ Lex.a
238        Errors |= Scope2 &~ Lex.l
239        Errors |= Scope3 &~ Lex.s
240        Errors |= Scope4 &~ Lex.e
241
242        Follows = bitutil.Advance(Scope4)
243        Spans = Follows - Starts
244       
245        return (Errors, Spans)
246
247def validate_null(Starts, Lex):
248        r"""
249        RFC 4627 - JavaScript Object Notation (JSON) 
250       
251        null  = %x6e.75.6c.6c      ; null
252       
253        """
254        Errors = 0
255
256        Scope1 = bitutil.Advance(Starts)
257        Scope2 = bitutil.Advance(Scope1)
258        Scope3 = bitutil.Advance(Scope2)
259       
260        Errors |= Scope1 &~ Lex.u
261        Errors |= Scope2 &~ Lex.l
262        Errors |= Scope3 &~ Lex.l
263       
264        Follows = bitutil.Advance(Scope3)
265        Spans = Follows - Starts
266
267        return (Errors, Spans)
268
269def validate_number(Starts, Lex, EOF_mask):
270        r"""   
271        RFC 4627 - JavaScript Object Notation (JSON) 
272        RFC 5234 - Augmented BNF for Syntax Specifications: ABNF
273
274        number = [ minus ] int [ frac ] [ exp ]
275        decimal-point = %x2E       ; .
276        digit1-9 = %x31-39         ; 1-9
277        e = %x65 / %x45            ; e E
278        exp = e [ minus / plus ] 1*DIGIT
279        frac = decimal-point 1*DIGIT
280        int = zero / ( digit1-9 *DIGIT )
281        minus = %x2D               ; -
282        plus = %x2B                ; +
283        zero = %x30                ; 0 
284        """     
285        global lgth
286       
287        Errors = 0
288        M0 = Starts                                     # Initialize marker stream     
289       
290        M1 = bitutil.ScanThru(M0, Lex.Minus & M0)               # ? Optional character class [-]
291        E1 = M1 &~(Lex.Zero|Lex.Digit1_9)
292
293        M1a = M1 & Lex.Zero                                     # Split
294        M1b = M1 & Lex.Digit0_9                         
295        M2a = bitutil.Advance(M1a)
296        M2b = bitutil.Advance(M1b)
297        M3b = bitutil.ScanThru(M2b,Lex.Digit0_9)
298        M4 = M2a | M3b                                          # Join
299       
300        M4a = M4 &~(Lex.DecimalPoint)                           # Split
301        M4b = M4 & (Lex.DecimalPoint)
302        M5b = bitutil.Advance(M4b)
303        E5b = M5b &~(Lex.Digit0_9)                              # + [0-9]+
304        M6 = bitutil.ScanThru(M5b,Lex.Digit0_9)
305        M7 = M4a | M6                                           # Join
306       
307        M7a = M7 &~(Lex.Ee)                                     # Split
308        # NOTE - Number Follow Set logic occurs at the final step after the final cursor join
309        # E7a = M7a &~(Lex.NumberFollowSet)
310        M7b = M7 &(Lex.Ee)
311        M8b = bitutil.Advance(M7b)
312        M9b = bitutil.ScanThru(M8b, Lex.PlusMinus & M8b)        # ? Optional character class [+-]               
313        E9b  = M9b &~(Lex.Digit0_9)                             # + [0-9]+
314        M10b = bitutil.ScanThru(M9b,Lex.Digit0_9)
315        # NOTE - Number Follow Set logic occurs at the final step after the final cursor join
316        # E10b = M10b &~(Lex.NumberFollowSet)
317        M11 = M7a | M10b                                        # Join
318
319        ValueFollowSetErrors = M11 &~ (Lex.ValueFollowsSet | Lex.WS)
320        ValueFollowSetErrors |= M11 &~ EOF_mask
321       
322        Errors = E1 | E5b | E9b | ValueFollowSetErrors # E7a | E10b
323       
324        NumberSpans = M11 - Starts
325       
326        if debug:
327                bitutil.print_aligned_streams([('Input Data', u8data), 
328                              ('M0', bitutil.bitstream2string(M0, lgth)),
329                              ('M1', bitutil.bitstream2string(M1, lgth)),
330                              ('E1', bitutil.bitstream2string(E1, lgth+1)),
331                              ('M1a', bitutil.bitstream2string(M1a, lgth)),
332                              ('M2a', bitutil.bitstream2string(M2a, lgth)),
333                              ('M2b', bitutil.bitstream2string(M2b, lgth)),
334                              ('M3b', bitutil.bitstream2string(M3b, lgth)),
335                              ('M4', bitutil.bitstream2string(M4, lgth)),
336                              ('M4a', bitutil.bitstream2string(M4a, lgth)),
337                              ('M4b', bitutil.bitstream2string(M4b, lgth)),
338                              ('M5b', bitutil.bitstream2string(M5b, lgth)),
339                              ('E5b', bitutil.bitstream2string(E5b, lgth+1)),         
340                              ('M6', bitutil.bitstream2string(M6, lgth)),
341                              ('M7', bitutil.bitstream2string(M7, lgth)),
342                              ('M7a', bitutil.bitstream2string(M7a, lgth)),
343                              #('E7a', bitutil.bitstream2string(E7a, lgth+1)),       
344                              ('M7b', bitutil.bitstream2string(M7b, lgth)),
345                              ('M8b', bitutil.bitstream2string(M8b, lgth)),
346                              ('M9b', bitutil.bitstream2string(M9b, lgth)),           
347                              ('E9b', bitutil.bitstream2string(E9b, lgth+1)),         
348                              ('M10b', bitutil.bitstream2string(M10b, lgth)),
349                              #('E10b', bitutil.bitstream2string(E10b, lgth)),
350                              ('M11', bitutil.bitstream2string(M11, lgth)),
351                              ('Starts', bitutil.bitstream2string(Starts, lgth)),
352                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
353                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])           
354       
355        return (Errors, NumberSpans)
356
357def demo_validate_number(u8data):
358        r"""
359        >>> demo_validate_number('[-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]')
360        Input Data  : [-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]
361        Minus       : _1_11_1_____1___1___1____1_______1_______1_________________________
362        Zero        : _________11__11__1___1____1___11___________1______1__1__1__________
363        Digit1_9    : __________________________________111_111____111____1____111111111_
364        Digit0_9    : _________11__11__1___1____1___11__111_111__1_111__1_11__1111111111_
365        DecimalPoint: __________________1___1____1_________1______1______________________
366        Ee          : _______________________1____1______________________1_______________
367        PlusMinus   : _1_11_1_____1___1___1____1_______1_______1______1_____1____________
368        NumberSpans : _11_11_11__111_1111_1111_1111_1_111111111__11111__1111__1_________1
369        Errors      : __1_1__1__1___1____1___11___11_1_________1______1_____1__1__________
370        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111_
371        <BLANKLINE>
372
373        >>> demo_validate_number('[0.5,98.6,99.44,1066,1e1,0.1e1,1e-1,1e00,2e+00,2e-00,1234567890,-9876.543210,0.123456789e-12,1.234567890E+34,23456789012E66]')
374        Input Data  : [0.5,98.6,99.44,1066,1e1,0.1e1,1e-1,1e00,2e+00,2e-00,1234567890,-9876.543210,0.123456789e-12,1.234567890E+34,23456789012E66]
375        Minus       : _________________________________1_______________1______________1________________________1__________________________________
376        Zero        : _1_______________1_______1____________11____11____11__________1____________1_1_________________________1_____________1______
377        Digit1_9    : ___1_11_1_11_11_1_11_1_1___1_1_1__1_1____1_____1_____111111111___1111_11111____111111111__11_1_11111111___11_11111111_11_11_
378        Digit0_9    : _1_1_11_1_11_11_1111_1_1_1_1_1_1__1_1_11_1__11_1__11_1111111111__1111_111111_1_111111111__11_1_111111111__11_11111111111_11_
379        DecimalPoint: __1____1____1_____________1__________________________________________1________1_______________1_____________________________
380        Ee          : ______________________1_____1___1____1____1_____1_______________________________________1_______________1_______________1___
381        PlusMinus   : _________________________________1_________1_____1______________1________________________1_______________1__________________
382        NumberSpans : _111_1111_11111_1111_111_11111_1111_1111_11111_11111_1111111111_111111111111_111111111111111_111111111111111_11111111111111_
383        Errors      : _____________________________________________________________________________________________________________________________
384        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_
385        <BLANKLINE>
386
387        >>> demo_validate_number('[012345,12345,0,00,-0,-00]')
388        Input Data  : [012345,12345,0,00,-0,-00]
389        Minus       : ___________________1__1___
390        Zero        : _1____________1_11__1__11_
391        Digit1_9    : __11111_11111_____________
392        Digit0_9    : _111111_11111_1_11__1__11_
393        DecimalPoint: __________________________
394        Ee          : __________________________
395        PlusMinus   : ___________________1__1___
396        NumberSpans : _1_____111111_1_1_111_11_1
397        Errors      : __1______________1______1__
398        EOF_Mask    : 11111111111111111111111111_
399        <BLANKLINE>
400        """ 
401        global lgth
402        lgth = len(u8data)
403       
404        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
405        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
406       
407        EscapeChars = parse_escape(Lex, EOF_mask)
408        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
409       
410        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask
411        StringMask = ParityMask & bitutil.Advance(ParityMask)   
412       
413        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts, ValueStarts) = atom_starts(Lex, StringMask, EscapeChars)     
414       
415        (Errors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
416
417        bitutil.print_aligned_streams([('Input Data', u8data), 
418                              ('Minus', bitutil.bitstream2string(Lex.Minus, lgth)),
419                              ('Zero', bitutil.bitstream2string(Lex.Zero, lgth)),
420                              ('Digit1_9', bitutil.bitstream2string(Lex.Digit1_9, lgth)),
421                              ('Digit0_9', bitutil.bitstream2string(Lex.Digit0_9, lgth)),
422                              ('DecimalPoint', bitutil.bitstream2string(Lex.DecimalPoint, lgth)),
423                              ('Ee', bitutil.bitstream2string(Lex.Ee, lgth)),
424                              ('PlusMinus', bitutil.bitstream2string(Lex.PlusMinus, lgth)),
425                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
426                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
427                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
428
429def validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes):
430        r"""
431        RFC 4627 - JavaScript Object Notation (JSON) 
432
433        string = quotation-mark *char quotation-mark
434        char = unescaped /
435              escape (
436                  %x22 /          ; "    quotation mark  U+0022
437                  %x5C /          ; \    reverse solidus U+005C
438                  %x2F /          ; /    solidus         U+002F
439                  %x62 /          ; b    backspace       U+0008
440                  %x66 /          ; f    form feed       U+000C
441                  %x6E /          ; n    line feed       U+000A
442                  %x72 /          ; r    carriage return U+000D
443                  %x74 /          ; t    tab             U+0009
444                  %x75 4HEXDIG )  ; uXXXX                U+XXXX
445
446        escape = %x5C              ; \
447        quotation-mark = %x22      ; "
448        unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
449
450        JSON string validation requires both:
451        (1) validation of escape characters,
452        (2) validation of unescaped characters.
453        """
454        global lgth
455       
456        # (1) Validate escape characters
457        StringEscapeChars = EscapeChars & StringMask
458        Errors = (StringEscapeChars &~ Lex.Escape)
459       
460        u = StringEscapeChars & Lex.u
461       
462        uScope1 = bitutil.Advance(u)
463        uScope2 = bitutil.Advance(uScope1)
464        uScope3 = bitutil.Advance(uScope2)
465        uScope4 = bitutil.Advance(uScope3)
466       
467        Errors |= uScope1 &~ Lex.HexDigit
468        Errors |= uScope2 &~ Lex.HexDigit
469        Errors |= uScope3 &~ Lex.HexDigit
470        Errors |= uScope4 &~ Lex.HexDigit
471       
472        # (2) Validation of unescaped characters
473        # (2.1) StringMask construction ensures all '"' are escaped.
474        # (2.2) '\' are either correctly escaped or the character following an odd length run is escaped.
475        # (2.3) validate_utf8(u8) ensures valid UTF8 encodings in the code point range U+0000 - U+01FFFF. TODO - Validate this final large.
476
477        StringNotEscapedChars = (~(EscapeChars | Lex.RSolidus)) & StringMask # TODO - Verify logic.
478        Errors |= (StringNotEscapedChars & Ctrl.x00_x1F)
479       
480        # (3) Validate all strings are terminated with an unescaped "
481        StringCursor = bitutil.Advance(StringStarts)
482        StringEnds = bitutil.ScanThru(StringCursor, StringMask)
483        Errors |= StringEnds &~ UnescapedDQuotes
484        StringSpans = (StringEnds - StringStarts) | StringEnds
485       
486        if debug:
487                bitutil.print_aligned_streams([('Input Data', u8data), 
488                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, lgth)),
489                              ('StringEscapeChars', bitutil.bitstream2string(StringEscapeChars, lgth)),
490                              ('u', bitutil.bitstream2string(u, lgth)),
491                              ('uScope1', bitutil.bitstream2string(uScope1, lgth)),
492                              ('uScope2', bitutil.bitstream2string(uScope2, lgth)),
493                              ('uScope3', bitutil.bitstream2string(uScope3, lgth)),
494                              ('uScope4', bitutil.bitstream2string(uScope4, lgth)),
495                              ('StringNotEscapedChars', bitutil.bitstream2string(StringNotEscapedChars, lgth)),
496                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
497                              ('StringEnds', bitutil.bitstream2string(StringEnds, lgth)),
498                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
499                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])     
500        return (Errors, StringSpans)
501
502def demo_validate_string(u8data):
503        r"""
504        >>> demo_validate_string('["\u abcd", "\u1___", "\u12__", "\u123_"]')
505        Input Data      : ["\u abcd", "\u1___", "\u12__", "\u123_"]
506        EscapeChars     : ___1__________1_________1_________1______
507        UnescapedDQuotes: _1_______1__1______1__1______1__1______1_
508        ParityMask      : _11111111___1111111___1111111___1111111__
509        StringMask      : __1111111____111111____111111____111111__
510        StringStarts    : _1__________1_________1_________1________
511        StringSpans     : _111111111__11111111__11111111__11111111_
512        Errors          : ____1___________111________11_________1___
513        EOF_Mask        : 11111111111111111111111111111111111111111_
514        <BLANKLINE>
515        """ 
516        global lgth
517        lgth = len(u8data)
518       
519        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
520        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
521
522        # Construct string interiors mask (1),(2),(3)
523        # (1) Mark all escaped characters
524        EscapeChars = parse_escape(Lex, EOF_mask)
525
526        # (2) Mark all unescaped "
527        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
528
529        # (3) Construct string interiors mask
530        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve parity EOF_mask problem
531        StringMask = ParityMask & bitutil.Advance(ParityMask)
532
533        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts, ValueStarts) = atom_starts(Lex, StringMask, EscapeChars)                             
534       
535        (Errors, StringSpans) = validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes)
536       
537        bitutil.print_aligned_streams([('Input Data', u8data), 
538                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, lgth)),
539                              ('UnescapedDQuotes', bitutil.bitstream2string(UnescapedDQuotes, lgth)),
540                              ('ParityMask', bitutil.bitstream2string(ParityMask, lgth)),
541                              ('StringMask', bitutil.bitstream2string(StringMask, lgth)),
542                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
543                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
544                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
545                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
546                             
547        return
548
549def validate_json_atoms(u8data):
550               
551        Errors = 0       
552               
553        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
554       
555        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
556       
557        EscapeChars = parse_escape(Lex, EOF_mask)
558        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
559        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve parity EOF_mask problem
560        StringMask = ParityMask & bitutil.Advance(ParityMask)   
561       
562        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts, ValueStarts) = atom_starts(Lex, StringMask, EscapeChars)
563       
564        (StringErrors, StringSpans) = validate_string(StringStarts, Lex, Ctrl, StringMask, EscapeChars, UnescapedDQuotes)
565       
566        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
567       
568        (TrueErrors, TrueSpans) = validate_true(TrueStarts, Lex)
569       
570        (FalseErrors, FalseSpans) = validate_false(FalseStarts, Lex)
571       
572        (NullErrors, NullSpans) = validate_null(NullStarts, Lex)
573
574        return (StringStarts, StringSpans, StringErrors, 
575                NumberStarts, NumberSpans, NumberErrors, 
576                TrueStarts, TrueSpans, TrueErrors, 
577                FalseStarts, FalseSpans, FalseErrors, 
578                NullStarts, NullSpans, NullErrors)
579 
580def demo_validate_json_atoms(u8data):
581        global lgth
582        lgth = len(u8data)
583
584        (StringStarts, StringSpans, StringErrors, 
585        NumberStarts, NumberSpans, NumberErrors, 
586        TrueStarts, TrueSpans, TrueErrors, 
587        FalseStarts, FalseSpans, FalseErrors, 
588        NullStarts, NullSpans, NullErrors) = validate_json_atoms(u8data)
589
590        bitutil.print_aligned_streams([('Input Data', u8data), 
591                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
592                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
593                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
594                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
595                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
596                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
597                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
598                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
599                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
600                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
601                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
602                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
603                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
604                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
605                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth))])
606
607        return
608
609if __name__ == "__main__":
610        import doctest
611        doctest.testmod()
612
613        if len(sys.argv) < 2:
614                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
615                sys.exit(2)
616
617        u8data = bitutil.readfile(sys.argv[1]) 
618
619#       demo_parse_escape(u8data)
620#       demo_parallel_prefix_parity(u8data)
621#       demo_atom_starts(u8data)
622#       demo_validate_number(u8data)
623#       demo_validate_string(u8data)
624        demo_validate_json_atoms(u8data)
Note: See TracBrowser for help on using the repository browser.