source: proto/JSON/json_prototype.py @ 703

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

Update string type tests.

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