source: proto/JSON/json_prototype.py @ 1917

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

Update comments.

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