source: proto/JSON/json_prototype.py @ 717

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

Add TODO notes to handle Unicode escape sequences and UTF-8 validation.

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