source: proto/JSON/json_prototype.py @ 715

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

Do not report leading zero errors.

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 = False
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
106        t1 = strm
107        for i in range(0,int(math.ceil(math.log(lgth,2)))):
108                t2 = t1 ^ (t1 << pow(2,i))
109                t1 = t2
110        return t2 
111
112def demo_parallel_prefix_parity(u8data):
113        r"""
114        >>> demo_parallel_prefix_parity('"data" "data""data" "data" "data')
115        Input Data: "data" "data""data" "data" "data
116        Lex.DQuote: 1____1_1____11____1_1____1_1____
117        Parity    : 11111__11111_11111__11111__11111
118        EOF_Mask  : 11111111111111111111111111111111_
119        <BLANKLINE>
120        """     
121        global lgth
122        lgth = len(u8data)
123
124        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
125        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
126        ParityMask = parallel_prefix_parity(Lex.DQuote)
127       
128        bitutil.print_aligned_streams([('Input Data', u8data), 
129                              ('Lex.DQuote', bitutil.bitstream2string(Lex.DQuote, lgth)),
130                              ('Parity', bitutil.bitstream2string(ParityMask, lgth)),   
131                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
132        return
133
134def atom_starts(Lex,StringSpans):
135        r"""
136        This function returns multi-cursor start positions for each JSON value type.
137       
138        Define JSON atoms as 'String', 'Number', 'true', 'false', and 'null' types.
139       
140        Error cases are postponed for the post-processing stage as expect() cases in
141        a recursive descent parser.
142        """
143        global lgth
144       
145        AtomSpans = (Lex.True | Lex.False | Lex.Null | Lex.Number | StringSpans)
146        AtomStarts = AtomSpans &~ bitutil.Advance(AtomSpans)
147               
148        StringStarts = AtomStarts & (Lex.DQuote)       
149        NumberStarts = AtomStarts & (Lex.Minus|Lex.Digit0_9)
150        TrueStarts = AtomStarts & (Lex.t)
151        FalseStarts = AtomStarts & (Lex.f)
152        NullStarts = AtomStarts & (Lex.n)
153
154        if debug:
155                bitutil.print_aligned_streams([('Input Data', u8data), 
156                              ('AtomSpans', bitutil.bitstream2string(AtomSpans, lgth)),
157                              ('AtomStarts', bitutil.bitstream2string(AtomStarts, lgth)),
158                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
159                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
160                              ('Lex.True', bitutil.bitstream2string(Lex.True, lgth)),
161                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
162                              ('Lex.False', bitutil.bitstream2string(Lex.False, lgth)),
163                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
164                              ('Lex.Null', bitutil.bitstream2string(Lex.Null, lgth)),
165                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
166                              ('Lex.Number', bitutil.bitstream2string(Lex.Number, lgth)),
167                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth))])
168
169        return (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts)
170
171
172def demo_atom_starts(u8data):
173        global lgth     
174        lgth = len(u8data)
175               
176        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
177        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
178       
179        EscapeChars = parse_escape(Lex, EOF_mask)
180       
181        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
182       
183        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve EOF_mask problem
184        StringMask = ParityMask & bitutil.Advance(ParityMask)   
185        StringSpans = StringMask | UnescapedDQuotes
186       
187        (StringStarts, NumberStarts,TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
188        bitutil.print_aligned_streams([('Input Data', u8data), 
189                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
190                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
191                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
192                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
193                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
194                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
195        return
196
197
198def validate_true(Starts, Lex):
199        r"""
200        RFC 4627 - JavaScript Object Notation (JSON) 
201       
202        true  = %x74.72.75.65      ; true
203       
204        """
205        Errors = 0
206       
207        Scope1 = bitutil.Advance(Starts)
208        Scope2 = bitutil.Advance(Scope1)
209        Scope3 = bitutil.Advance(Scope2)
210       
211        Errors |= Scope1 &~ Lex.r
212        Errors |= Scope2 &~ Lex.u
213        Errors |= Scope3 &~ Lex.e
214       
215        Follows = bitutil.Advance(Scope3)
216        Spans = Follows - Starts
217
218        return (Errors, Spans)
219
220def validate_false(Starts, Lex):
221        r"""
222        RFC 4627 - JavaScript Object Notation (JSON) 
223       
224        false = %x66.61.6c.73.65   ; false
225       
226        """
227        Errors = 0
228       
229        Scope1 = bitutil.Advance(Starts)
230        Scope2 = bitutil.Advance(Scope1)
231        Scope3 = bitutil.Advance(Scope2)
232        Scope4 = bitutil.Advance(Scope3)
233       
234        Errors |= Scope1 &~ Lex.a
235        Errors |= Scope2 &~ Lex.l
236        Errors |= Scope3 &~ Lex.s
237        Errors |= Scope4 &~ Lex.e
238
239        Follows = bitutil.Advance(Scope4)
240        Spans = Follows - Starts
241       
242        return (Errors, Spans)
243
244def validate_null(Starts, Lex):
245        r"""
246        RFC 4627 - JavaScript Object Notation (JSON) 
247       
248        null  = %x6e.75.6c.6c      ; null
249       
250        """
251        Errors = 0
252
253        Scope1 = bitutil.Advance(Starts)
254        Scope2 = bitutil.Advance(Scope1)
255        Scope3 = bitutil.Advance(Scope2)
256       
257        Errors |= Scope1 &~ Lex.u
258        Errors |= Scope2 &~ Lex.l
259        Errors |= Scope3 &~ Lex.l
260       
261        Follows = bitutil.Advance(Scope3)
262        Spans = Follows - Starts
263
264        return (Errors, Spans)
265
266def validate_number(Starts, Lex, EOF_mask):
267        r"""   
268        RFC 4627 - JavaScript Object Notation (JSON) 
269        RFC 5234 - Augmented BNF for Syntax Specifications: ABNF
270
271        number = [ minus ] int [ frac ] [ exp ]
272        decimal-point = %x2E       ; .
273        digit1-9 = %x31-39         ; 1-9
274        e = %x65 / %x45            ; e E
275        exp = e [ minus / plus ] 1*DIGIT
276        frac = decimal-point 1*DIGIT
277        int = zero / ( digit1-9 *DIGIT )
278        minus = %x2D               ; -
279        plus = %x2B                ; +
280        zero = %x30                ; 0 
281
282        NOTE - Does not validate number follow characters. Hence leading zero errors are not reported.
283
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        M1 = M1 &~ E1                                           # Remove cursors at error positions so as to report a single error position
293
294        M1a = M1 & Lex.Zero                                     # Split
295        M1b = M1 & Lex.Digit1_9                         
296        M2a = bitutil.Advance(M1a)
297        M2b = bitutil.Advance(M1b)
298        M3b = bitutil.ScanThru(M2b,Lex.Digit0_9)
299        M4 =  M2a | M3b                                         # Join
300       
301        M4a = M4 &~(Lex.DecimalPoint)                           # Split
302        M4b = M4 & (Lex.DecimalPoint)
303        M5b = bitutil.Advance(M4b)
304        E5b = M5b &~(Lex.Digit0_9)                              # + [0-9]+
305        M5b = M5b &~E5b                                         # Remove cursors at error positions so as to report a single error position
306       
307        M6 = bitutil.ScanThru(M5b,Lex.Digit0_9)
308        M7 = M4a | M6                                           # Join
309       
310        M7a = M7 &~(Lex.Ee)                                     # Split
311        M7b = M7 &(Lex.Ee)
312        M8b = bitutil.Advance(M7b)
313        M9b = bitutil.ScanThru(M8b, Lex.PlusMinus & M8b)        # ? Optional character class [+-]               
314        E9b  = M9b &~(Lex.Digit0_9)                             # + [0-9]+
315        M9b = M9b &~ E9b                                        # Remove cursors at error positions so as to report a single error position
316        M10b = bitutil.ScanThru(M9b,Lex.Digit0_9)
317
318        M11 = M7a | M10b                                       
319       
320        Errors = E1 | E5b | E9b
321       
322        NumberSpans = M11 - M0
323       
324        if debug:
325                bitutil.print_aligned_streams([('Input Data', u8data), 
326                              ('M0', bitutil.bitstream2string(M0, lgth)),
327                              ('M1', bitutil.bitstream2string(M1, lgth)),
328                              ('E1', bitutil.bitstream2string(E1, lgth+1)),
329                              ('M1a', bitutil.bitstream2string(M1a, lgth)),
330                              ('M2a', bitutil.bitstream2string(M2a, lgth)),
331                              ('M2b', bitutil.bitstream2string(M2b, lgth)),
332                              ('M3b', bitutil.bitstream2string(M3b, lgth)),
333                              ('M4', bitutil.bitstream2string(M4, lgth)),
334                              ('M4a', bitutil.bitstream2string(M4a, lgth)),
335                              ('M4b', bitutil.bitstream2string(M4b, lgth)),
336                              ('M5b', bitutil.bitstream2string(M5b, lgth)),
337                              ('E5b', bitutil.bitstream2string(E5b, lgth+1)),         
338                              ('M6', bitutil.bitstream2string(M6, lgth)),
339                              ('M7', bitutil.bitstream2string(M7, lgth)),
340                              ('M7a', bitutil.bitstream2string(M7a, lgth)),
341                              #('E7a', bitutil.bitstream2string(E7a, lgth+1)),       
342                              ('M7b', bitutil.bitstream2string(M7b, lgth)),
343                              ('M8b', bitutil.bitstream2string(M8b, lgth)),
344                              ('M9b', bitutil.bitstream2string(M9b, lgth)),           
345                              ('E9b', bitutil.bitstream2string(E9b, lgth+1)),         
346                              ('M10b', bitutil.bitstream2string(M10b, lgth)),
347                              #('E10b', bitutil.bitstream2string(E10b, lgth)),
348                              ('M11', bitutil.bitstream2string(M11, lgth+1)),
349                              ('Starts', bitutil.bitstream2string(Starts, lgth)),
350                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
351                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])           
352       
353        return (Errors, NumberSpans)
354
355def demo_validate_number(u8data):
356        r"""
357        >>> demo_validate_number('[-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]')
358        Input Data  : [-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]
359        Minus       : _1_11_1_____1___1___1____1_______1_______1_________________________
360        Zero        : _________11__11__1___1____1___11___________1______1__1__1__________
361        Digit1_9    : __________________________________111_111____111____1____111111111_
362        Digit0_9    : _________11__11__1___1____1___11__111_111__1_111__1_11__1111111111_
363        DecimalPoint: __________________1___1____1_________1______1______________________
364        Ee          : _______________________1____1______________________1_______________
365        PlusMinus   : _1_11_1_____1___1___1____1_______1_______1______1_____1____________
366        NumberSpans : _11_11_11___11__1111_1111_1111___11111111__11111__1111__1__________
367        Errors      : __1_1__1___________1___1____1_______________________________________
368        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111_
369        <BLANKLINE>
370
371        >>> 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]')
372        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]
373        Minus       : _________________________________1_______________1______________1________________________1__________________________________
374        Zero        : _1_______________1_______1____________11____11____11__________1____________1_1_________________________1_____________1______
375        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_
376        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_
377        DecimalPoint: __1____1____1_____________1__________________________________________1________1_______________1_____________________________
378        Ee          : ______________________1_____1___1____1____1_____1_______________________________________1_______________1_______________1___
379        PlusMinus   : _________________________________1_________1_____1______________1________________________1_______________1__________________
380        NumberSpans : _111_1111_11111_1111_111_11111_1111_1111_11111_11111_1111111111_111111111111_111111111111111_111111111111111_11111111111111_
381        Errors      : _____________________________________________________________________________________________________________________________
382        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_
383        <BLANKLINE>
384
385        >>> demo_validate_number('[012345,12345,0,00,-0,-00]')
386        Input Data  : [012345,12345,0,00,-0,-00]
387        Minus       : ___________________1__1___
388        Zero        : _1____________1_11__1__11_
389        Digit1_9    : __11111_11111_____________
390        Digit0_9    : _111111_11111_1_11__1__11_
391        DecimalPoint: __________________________
392        Ee          : __________________________
393        PlusMinus   : ___________________1__1___
394        NumberSpans : _1______11111_1_1__11_11__
395        Errors      : ___________________________
396        EOF_Mask    : 11111111111111111111111111_
397        <BLANKLINE>
398        """ 
399        global lgth
400        lgth = len(u8data)
401       
402        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
403        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
404       
405        EscapeChars = parse_escape(Lex, EOF_mask)
406        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
407       
408        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask
409        StringMask = ParityMask & bitutil.Advance(ParityMask)   
410        StringSpans = StringMask | UnescapedDQuotes
411       
412        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)       
413       
414        (Errors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
415
416        bitutil.print_aligned_streams([('Input Data', u8data), 
417                              ('Minus', bitutil.bitstream2string(Lex.Minus, lgth)),
418                              ('Zero', bitutil.bitstream2string(Lex.Zero, lgth)),
419                              ('Digit1_9', bitutil.bitstream2string(Lex.Digit1_9, lgth)),
420                              ('Digit0_9', bitutil.bitstream2string(Lex.Digit0_9, lgth)),
421                              ('DecimalPoint', bitutil.bitstream2string(Lex.DecimalPoint, lgth)),
422                              ('Ee', bitutil.bitstream2string(Lex.Ee, lgth)),
423                              ('PlusMinus', bitutil.bitstream2string(Lex.PlusMinus, lgth)),
424                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
425                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
426                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
427
428def validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes):
429        r"""
430        RFC 4627 - JavaScript Object Notation (JSON) 
431
432        string = quotation-mark *char quotation-mark
433        char = unescaped /
434              escape (
435                  %x22 /          ; "    quotation mark  U+0022
436                  %x5C /          ; \    reverse solidus U+005C
437                  %x2F /          ; /    solidus         U+002F
438                  %x62 /          ; b    backspace       U+0008
439                  %x66 /          ; f    form feed       U+000C
440                  %x6E /          ; n    line feed       U+000A
441                  %x72 /          ; r    carriage return U+000D
442                  %x74 /          ; t    tab             U+0009
443                  %x75 4HEXDIG )  ; uXXXX                U+XXXX
444
445        escape = %x5C              ; \
446        quotation-mark = %x22      ; "
447        unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
448
449        JSON string validation requires both:
450        (1) validation of escape characters,
451        (2) validation of unescaped characters.
452        """
453        global lgth
454       
455        # (1) Validate escape characters
456        StringEscapeChars = EscapeChars & StringMask
457        Errors = (StringEscapeChars &~ Lex.Escape)
458       
459        u = StringEscapeChars & Lex.u
460       
461        uScope1 = bitutil.Advance(u)
462        uScope2 = bitutil.Advance(uScope1)
463        uScope3 = bitutil.Advance(uScope2)
464        uScope4 = bitutil.Advance(uScope3)
465       
466        Errors |= uScope1 &~ Lex.HexDigit
467        Errors |= uScope2 &~ Lex.HexDigit
468        Errors |= uScope3 &~ Lex.HexDigit
469        Errors |= uScope4 &~ Lex.HexDigit
470       
471        # (2) Validation of unescaped characters
472        # (2.1) StringMask construction ensures all '"' are escaped.
473        # (2.2) '\' are either correctly escaped or the character following an odd length run is escaped.
474        # (2.3) validate_utf8(u8) ensures valid UTF8 encodings in the code point range U+0000 - U+01FFFF. TODO - Validate this final large.
475
476        StringNotEscapedChars = (~(EscapeChars | Lex.RSolidus)) & StringMask # TODO - Verify logic.
477        Errors |= (StringNotEscapedChars & Ctrl.x00_x1F)
478       
479        # (3) Validate all strings are terminated with an unescaped "
480        StringCursor = bitutil.Advance(StringStarts)
481        StringEnds = bitutil.ScanThru(StringCursor, StringMask)
482        Errors |= StringEnds &~ UnescapedDQuotes
483        StringSpans = (StringEnds - StringStarts) | StringEnds
484       
485        if debug:
486                bitutil.print_aligned_streams([('Input Data', u8data), 
487                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, lgth)),
488                              ('StringEscapeChars', bitutil.bitstream2string(StringEscapeChars, lgth)),
489                              ('u', bitutil.bitstream2string(u, lgth)),
490                              ('uScope1', bitutil.bitstream2string(uScope1, lgth)),
491                              ('uScope2', bitutil.bitstream2string(uScope2, lgth)),
492                              ('uScope3', bitutil.bitstream2string(uScope3, lgth)),
493                              ('uScope4', bitutil.bitstream2string(uScope4, lgth)),
494                              ('StringNotEscapedChars', bitutil.bitstream2string(StringNotEscapedChars, lgth)),
495                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
496                              ('StringEnds', bitutil.bitstream2string(StringEnds, lgth)),
497                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
498                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])     
499        return (Errors, StringSpans)
500
501def demo_validate_string(u8data):
502        r"""
503        >>> demo_validate_string('["\u abcd", "\u1___", "\u12__", "\u123_"]')
504        Input Data      : ["\u abcd", "\u1___", "\u12__", "\u123_"]
505        EscapeChars     : ___1__________1_________1_________1______
506        UnescapedDQuotes: _1_______1__1______1__1______1__1______1_
507        ParityMask      : _11111111___1111111___1111111___1111111__
508        StringMask      : __1111111____111111____111111____111111__
509        StringStarts    : _1__________1_________1_________1________
510        StringSpans     : _111111111__11111111__11111111__11111111_
511        Errors          : ____1___________111________11_________1___
512        EOF_Mask        : 11111111111111111111111111111111111111111_
513        <BLANKLINE>
514        """ 
515        global lgth
516        lgth = len(u8data)
517       
518        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
519        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
520
521        # Construct string interiors mask (1),(2),(3)
522        # (1) Mark all escaped characters
523        EscapeChars = parse_escape(Lex, EOF_mask)
524
525        # (2) Mark all unescaped "
526        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
527
528        # (3) Construct string interiors mask
529        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve parity EOF_mask problem
530        StringMask = ParityMask & bitutil.Advance(ParityMask)
531        StringSpans = StringMask | UnescapedDQuotes
532
533        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)                               
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        StringSpans = StringMask | UnescapedDQuotes
562       
563        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
564       
565        (StringErrors, StringSpans) = validate_string(StringStarts, Lex, Ctrl, StringMask, EscapeChars, UnescapedDQuotes)
566       
567        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
568       
569        (TrueErrors, TrueSpans) = validate_true(TrueStarts, Lex)
570       
571        (FalseErrors, FalseSpans) = validate_false(FalseStarts, Lex)
572       
573        (NullErrors, NullSpans) = validate_null(NullStarts, Lex)
574
575        return (StringStarts, StringSpans, StringErrors, 
576                NumberStarts, NumberSpans, NumberErrors, 
577                TrueStarts, TrueSpans, TrueErrors, 
578                FalseStarts, FalseSpans, FalseErrors, 
579                NullStarts, NullSpans, NullErrors)
580 
581def demo_validate_json_atoms(u8data):
582        global lgth
583        lgth = len(u8data)
584
585        (StringStarts, StringSpans, StringErrors,
586        NumberStarts, NumberSpans, NumberErrors, 
587        TrueStarts, TrueSpans, TrueErrors, 
588        FalseStarts, FalseSpans, FalseErrors, 
589        NullStarts, NullSpans, NullErrors) = validate_json_atoms(u8data)
590
591        bitutil.print_aligned_streams([('Input Data', u8data), 
592                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
593                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
594                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
595                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
596                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
597                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
598                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
599                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
600                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
601                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
602                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
603                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
604                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
605                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
606                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth))])
607
608        return
609
610if __name__ == "__main__":
611        import doctest
612        doctest.testmod()
613
614        if len(sys.argv) < 2:
615                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
616                sys.exit(2)
617
618        u8data = bitutil.readfile(sys.argv[1]) 
619
620#       demo_parse_escape(u8data)
621#       demo_parallel_prefix_parity(u8data)
622#       demo_atom_starts(u8data)
623        demo_validate_number(u8data)
624#       demo_validate_string(u8data)
625#       demo_validate_json_atoms(u8data)
Note: See TracBrowser for help on using the repository browser.