source: proto/JSON/json_prototype.py @ 766

Last change on this file since 766 was 766, checked in by ksherdy, 8 years ago

Initial working JSON compilable and executable.

File size: 23.7 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
22import bitutil
23import byteclass
24import u8u16
25import math
26import sys
27
28debug = False
29filename = "json_prototype.py"
30
31# Globals
32#
33# Bitstream function definitions input/output *only* bitstream type variables.
34#
35# Global declarations allow debug blocks in bitstream processing definitions.
36#
37# Do not shadow the global variables 'u8data' or 'lgth' with local variable declartions.
38
39u8data = ""
40lgth = 0
41
42def simd_const_4(hexdigit, EOF_mask):
43        r"""
44        IDISA library function.
45        """
46        lgth = bitutil.count_leading_zeroes(~EOF_mask)/4
47        return int(hexdigit*(lgth+1),16)&EOF_mask
48       
49def parse_escape(Lex, EOF_mask):
50        r"""
51        We translate stream abtraction logic to native block-by-block implementation logic.
52       
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)  # little endian
58        even = simd_const_4('5',EOF_mask) # little endian               
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        We translate stream abtraction logic to native block-by-block implementation logic.
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))-1] for each bit position k, 1 <= k <= n.
102       
103        Base Case: Pk,0 = bitstream at position k, for all k, n >= k >= 1.
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 >= 1.
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        Escape = parse_escape(Lex, EOF_mask)
187       
188        UnescapedDQuotes = (Lex.DQuote &~ Escape)
189       
190        ParityMask = parallel_prefix_parity(UnescapedDQuotes) # TODO - Solve EOF_mask problem, if final position is 1 then the final DQUOTE is not matched.
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(TrueStarts, Lex):
206        r"""
207        RFC 4627 - JavaScript Object Notation (JSON) 
208       
209        true  = %x74.72.75.65      ; true
210       
211        """     
212        Scope1 = bitutil.Advance(TrueStarts)
213        Scope2 = bitutil.Advance(Scope1)
214        Scope3 = bitutil.Advance(Scope2)
215       
216        TrueErrors = Scope1 &~ Lex.r
217        TrueErrors |= Scope2 &~ Lex.u
218        TrueErrors |= Scope3 &~ Lex.e
219       
220        Follows = bitutil.Advance(Scope3)
221        TrueSpans = Follows - TrueStarts
222
223        return (TrueErrors, TrueSpans)
224
225def validate_false(FalseStarts, Lex):
226        r"""
227        RFC 4627 - JavaScript Object Notation (JSON) 
228       
229        false = %x66.61.6c.73.65   ; false
230       
231        """     
232        Scope1 = bitutil.Advance(FalseStarts)
233        Scope2 = bitutil.Advance(Scope1)
234        Scope3 = bitutil.Advance(Scope2)
235        Scope4 = bitutil.Advance(Scope3)
236       
237        FalseErrors = Scope1 &~ Lex.a
238        FalseErrors |= Scope2 &~ Lex.l
239        FalseErrors |= Scope3 &~ Lex.s
240        FalseErrors |= Scope4 &~ Lex.e
241
242        Follows = bitutil.Advance(Scope4)
243        FalseSpans = Follows - FalseStarts
244       
245        return (FalseErrors, FalseSpans)
246
247def validate_null(NullStarts, Lex):
248        r"""
249        RFC 4627 - JavaScript Object Notation (JSON) 
250       
251        null  = %x6e.75.6c.6c      ; null
252       
253        """
254        Scope1 = bitutil.Advance(NullStarts)
255        Scope2 = bitutil.Advance(Scope1)
256        Scope3 = bitutil.Advance(Scope2)
257       
258        NullErrors = Scope1 &~ Lex.u
259        NullErrors |= Scope2 &~ Lex.l
260        NullErrors |= Scope3 &~ Lex.l
261       
262        Follows = bitutil.Advance(Scope3)
263        NullSpans = Follows - NullStarts
264
265        return (NullErrors, NullSpans)
266
267def validate_number(NumberStarts, Lex, EOF_mask):
268        r"""   
269        RFC 4627 - JavaScript Object Notation (JSON) 
270        RFC 5234 - Augmented BNF for Syntax Specifications: ABNF
271
272        number = [ minus ] int [ frac ] [ exp ]
273        decimal-point = %x2E       ; .
274        digit1-9 = %x31-39         ; 1-9
275        e = %x65 / %x45            ; e E
276        exp = e [ minus / plus ] 1*DIGIT
277        frac = decimal-point 1*DIGIT
278        int = zero / ( digit1-9 *DIGIT )
279        minus = %x2D               ; -
280        plus = %x2B                ; +
281        zero = %x30                ; 0 
282
283        NOTE - Does not validate number follow characters. Hence leading zero errors are not reported.
284
285        """     
286        global lgth
287       
288        M0 = NumberStarts                                               # 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        NumberErrors = 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                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
350                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
351                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth+1))])               
352       
353        return (NumberErrors, 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        NumberErrors: __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        NumberErrors: _____________________________________________________________________________________________________________________________
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        NumberErrors: ___________________________
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        Escape = parse_escape(Lex, EOF_mask)
406        UnescapedDQuotes = (Lex.DQuote &~ Escape)
407       
408        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
409        StringMask = ParityMask & bitutil.Advance(ParityMask)   
410        StringSpans = StringMask | UnescapedDQuotes
411       
412        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)       
413       
414        (NumberErrors, 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                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth+1)),
426                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
427
428def validate_string(StringStarts, Lex, Ctrl, StringMask, Escape, 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 = Escape & StringMask
457        StringErrors = (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        StringErrors |= uScope1 &~ Lex.HexDigit
467        StringErrors |= uScope2 &~ Lex.HexDigit
468        StringErrors |= uScope3 &~ Lex.HexDigit
469        StringErrors |= 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
475        StringNotEscapedChars = (~(Escape | Lex.RSolidus)) & StringMask # TODO - Verify logic.
476        StringErrors |= (StringNotEscapedChars & Ctrl.x00_x1F)
477       
478        # (3) Validate all strings are terminated with an unescaped "
479        StringCursor = bitutil.Advance(StringStarts)
480        StringEnds = bitutil.ScanThru(StringCursor, StringMask)
481        StringErrors |= StringEnds &~ UnescapedDQuotes
482        StringSpans = (StringEnds - StringStarts) | StringEnds
483       
484        if debug:
485                bitutil.print_aligned_streams([('Input Data', u8data), 
486                              ('Escape', bitutil.bitstream2string(Escape, lgth)),
487                              ('StringEscapeChars', bitutil.bitstream2string(StringEscapeChars, lgth)),
488                              ('u', bitutil.bitstream2string(u, lgth)),
489                              ('uScope1', bitutil.bitstream2string(uScope1, lgth)),
490                              ('uScope2', bitutil.bitstream2string(uScope2, lgth)),
491                              ('uScope3', bitutil.bitstream2string(uScope3, lgth)),
492                              ('uScope4', bitutil.bitstream2string(uScope4, lgth)),
493                              ('StringNotEscapedChars', bitutil.bitstream2string(StringNotEscapedChars, lgth)),
494                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
495                              ('StringEnds', bitutil.bitstream2string(StringEnds, lgth)),
496                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
497                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth+1))])         
498        return (StringErrors, StringSpans)
499
500def demo_validate_string(u8data):
501        r"""
502        >>> demo_validate_string('["\u abcd", "\u1___", "\u12__", "\u123_"]')
503        Input Data      : ["\u abcd", "\u1___", "\u12__", "\u123_"]
504        Escape          : ___1__________1_________1_________1______
505        UnescapedDQuotes: _1_______1__1______1__1______1__1______1_
506        ParityMask      : _11111111___1111111___1111111___1111111__
507        StringMask      : __1111111____111111____111111____111111__
508        StringStarts    : _1__________1_________1_________1________
509        StringSpans     : _111111111__11111111__11111111__11111111_
510        StringErrors    : ____1___________111________11_________1___
511        EOF_Mask        : 11111111111111111111111111111111111111111_
512        <BLANKLINE>
513        """ 
514        global lgth
515        lgth = len(u8data)
516       
517        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
518        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
519
520        # Construct string interiors mask (1),(2),(3)
521        # (1) Mark all escaped characters
522        Escape = parse_escape(Lex, EOF_mask)
523
524        # (2) Mark all unescaped "
525        UnescapedDQuotes = (Lex.DQuote &~ Escape)
526
527        # (3) Construct string interiors mask
528        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
529        StringMask = ParityMask & bitutil.Advance(ParityMask)
530        StringSpans = StringMask | UnescapedDQuotes
531
532        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)                               
533       
534        (StringErrors, StringSpans) = validate_string(StringStarts, Lex,Ctrl,StringMask,Escape,UnescapedDQuotes)
535       
536        bitutil.print_aligned_streams([('Input Data', u8data), 
537                              ('Escape', bitutil.bitstream2string(Escape, lgth)),
538                              ('UnescapedDQuotes', bitutil.bitstream2string(UnescapedDQuotes, lgth)),
539                              ('ParityMask', bitutil.bitstream2string(ParityMask, lgth)),
540                              ('StringMask', bitutil.bitstream2string(StringMask, lgth)),
541                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
542                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
543                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth+1)),
544                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
545                             
546        return
547
548def validate_json_atoms(u8data):
549               
550        Errors = 0       
551               
552        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
553       
554        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
555       
556        Escape = parse_escape(Lex, EOF_mask)
557        UnescapedDQuotes = (Lex.DQuote &~ Escape)
558        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
559        StringMask = ParityMask & bitutil.Advance(ParityMask)   
560        StringSpans = StringMask | UnescapedDQuotes
561       
562        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
563       
564        (StringErrors, StringSpans) = validate_string(StringStarts, Lex, Ctrl, StringMask, Escape, UnescapedDQuotes)
565       
566        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
567       
568        (TrueErrors, TrueSpans) = validate_true(TrueStarts, Lex)
569       
570        (FalseErrors, FalseSpans) = validate_false(FalseStarts, Lex)
571       
572        (NullErrors, NullSpans) = validate_null(NullStarts, Lex)
573
574        return (StringStarts, StringSpans, StringErrors, 
575                NumberStarts, NumberSpans, NumberErrors, 
576                TrueStarts, TrueSpans, TrueErrors, 
577                FalseStarts, FalseSpans, FalseErrors, 
578                NullStarts, NullSpans, NullErrors)
579 
580def demo_validate_json_atoms(u8data):
581        global lgth
582        lgth = len(u8data)
583
584        (StringStarts, StringSpans, StringErrors,
585        NumberStarts, NumberSpans, NumberErrors, 
586        TrueStarts, TrueSpans, TrueErrors, 
587        FalseStarts, FalseSpans, FalseErrors, 
588        NullStarts, NullSpans, NullErrors) = validate_json_atoms(u8data)
589
590        AtomSpans = (StringSpans|NumberSpans|TrueSpans|FalseSpans|NullSpans)
591
592        bitutil.print_aligned_streams([('Input Data', u8data), 
593                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
594                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
595                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
596                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
597                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
598                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
599                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
600                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
601                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
602                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
603                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
604                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
605                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
606                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
607                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth)),
608                              ('AtomSpans', bitutil.bitstream2string(AtomSpans, lgth))])
609
610        return
611
612if __name__ == "__main__":
613        import doctest
614        doctest.testmod()
615
616        if len(sys.argv) < 2:
617                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
618                sys.exit(2)
619
620        u8data = bitutil.readfile(sys.argv[1]) 
621
622#       demo_parse_escape(u8data)
623#       demo_parallel_prefix_parity(u8data)
624#       demo_atom_starts(u8data)
625#       demo_validate_number(u8data)
626#       demo_validate_string(u8data)
627        demo_validate_json_atoms(u8data)
Note: See TracBrowser for help on using the repository browser.