source: proto/JSON/json_prototype.py @ 704

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

Add support for string, number, true, false, null validation.

File size: 23.9 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(Starts, Lex):
199        r"""
200        RFC 4627 - JavaScript Object Notation (JSON) 
201       
202        true  = %x74.72.75.65      ; true
203       
204        """
205        Errors = 0
206       
207        Scope1 = bitutil.Advance(Starts)
208        Scope2 = bitutil.Advance(Scope1)
209        Scope3 = bitutil.Advance(Scope2)
210       
211        Errors |= Scope1 &~ Lex.r
212        Errors |= Scope2 &~ Lex.u
213        Errors |= Scope3 &~ Lex.e
214       
215        Follows = bitutil.Advance(Scope3)
216        Spans = Follows - Starts
217
218        return (Errors, Spans)
219
220def validate_false(Starts, Lex):
221        r"""
222        RFC 4627 - JavaScript Object Notation (JSON) 
223       
224        false = %x66.61.6c.73.65   ; false
225       
226        """
227        Errors = 0
228       
229        Scope1 = bitutil.Advance(Starts)
230        Scope2 = bitutil.Advance(Scope1)
231        Scope3 = bitutil.Advance(Scope2)
232        Scope4 = bitutil.Advance(Scope3)
233       
234       
235        Errors |= Scope1 &~ Lex.a
236        Errors |= Scope2 &~ Lex.l
237        Errors |= Scope3 &~ Lex.s
238        Errors |= Scope4 &~ Lex.e
239
240        Follows = bitutil.Advance(Scope3)
241        Spans = Follows - Starts
242       
243        return (Errors, Spans)
244
245def validate_null(Starts, Lex):
246        r"""
247        RFC 4627 - JavaScript Object Notation (JSON) 
248       
249        null  = %x6e.75.6c.6c      ; null
250       
251        """
252        Errors = 0
253
254        Scope1 = bitutil.Advance(Starts)
255        Scope2 = bitutil.Advance(Scope1)
256        Scope3 = bitutil.Advance(Scope2)
257       
258        Errors |= Scope1 &~ Lex.u
259        Errors |= Scope2 &~ Lex.l
260        Errors |= Scope3 &~ Lex.l
261       
262        Follows = bitutil.Advance(Scope3)
263        Spans = Follows - Starts
264
265        return (Errors, Spans)
266
267def validate_number(Starts, 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        Errors = 0
284        M0 = Starts                                     # Initialize marker stream     
285       
286        M1 = bitutil.ScanThru(M0, Lex.Minus & M0)               # ? Optional character class [-]
287        E1 = M1 &~(Lex.Zero|Lex.Digit1_9)
288
289        M1a = M1 & Lex.Zero                                     # Split
290        M1b = M1 & Lex.Digit0_9                         
291        M2a = bitutil.Advance(M1a)
292        M2b = bitutil.Advance(M1b)
293        M3b = bitutil.ScanThru(M2b,Lex.Digit0_9)
294        M4 = M2a | M3b                                          # Join
295       
296        M4a = M4 &~(Lex.DecimalPoint)                           # Split
297        M4b = M4 & (Lex.DecimalPoint)
298        M5b = bitutil.Advance(M4b)
299        E5b = M5b &~(Lex.Digit0_9)                              # + [0-9]+
300        M6 = bitutil.ScanThru(M5b,Lex.Digit0_9)
301        M7 = M4a | M6                                           # Join
302       
303        M7a = M7 &~(Lex.Ee)                                     # Split
304        # NOTE - Number Follow Set logic occurs at the final step after the final cursor join
305        # E7a = M7a &~(Lex.NumberFollowSet)
306        M7b = M7 &(Lex.Ee)
307        M8b = bitutil.Advance(M7b)
308        M9b = bitutil.ScanThru(M8b, Lex.PlusMinus & M8b)        # ? Optional character class [+-]               
309        E9b  = M9b &~(Lex.Digit0_9)                             # + [0-9]+
310        M10b = bitutil.ScanThru(M9b,Lex.Digit0_9)
311        # NOTE - Number Follow Set logic occurs at the final step after the final cursor join
312        # E10b = M10b &~(Lex.NumberFollowSet)
313        M11 = M7a | M10b                                        # Join
314
315        ValueFollowSetErrors = M11 &~ (Lex.ValueFollowSet | ~EOF_mask)
316       
317        Errors = E1 | E5b | E9b | ValueFollowSetErrors # E7a | E10b
318       
319        NumberSpans = M11 - Starts
320       
321        if debug:
322                bitutil.print_aligned_streams([('Input Data', u8data), 
323                              ('M0', bitutil.bitstream2string(M0, lgth)),
324                              ('M1', bitutil.bitstream2string(M1, lgth)),
325                              ('E1', bitutil.bitstream2string(E1, lgth+1)),
326                              ('M1a', bitutil.bitstream2string(M1a, lgth)),
327                              ('M2a', bitutil.bitstream2string(M2a, lgth)),
328                              ('M2b', bitutil.bitstream2string(M2b, lgth)),
329                              ('M3b', bitutil.bitstream2string(M3b, lgth)),
330                              ('M4', bitutil.bitstream2string(M4, lgth)),
331                              ('M4a', bitutil.bitstream2string(M4a, lgth)),
332                              ('M4b', bitutil.bitstream2string(M4b, lgth)),
333                              ('M5b', bitutil.bitstream2string(M5b, lgth)),
334                              ('E5b', bitutil.bitstream2string(E5b, lgth+1)),         
335                              ('M6', bitutil.bitstream2string(M6, lgth)),
336                              ('M7', bitutil.bitstream2string(M7, lgth)),
337                              ('M7a', bitutil.bitstream2string(M7a, lgth)),
338                              #('E7a', bitutil.bitstream2string(E7a, lgth+1)),       
339                              ('M7b', bitutil.bitstream2string(M7b, lgth)),
340                              ('M8b', bitutil.bitstream2string(M8b, lgth)),
341                              ('M9b', bitutil.bitstream2string(M9b, lgth)),           
342                              ('E9b', bitutil.bitstream2string(E9b, lgth+1)),         
343                              ('M10b', bitutil.bitstream2string(M10b, lgth)),
344                              #('E10b', bitutil.bitstream2string(E10b, lgth)),
345                              ('M11', bitutil.bitstream2string(M11, lgth)),
346                              ('Starts', bitutil.bitstream2string(Starts, lgth)),
347                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
348                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])           
349       
350        return (Errors, NumberSpans)
351
352def demo_validate_number(u8data):
353        r"""
354        >>> demo_validate_number('[-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]')
355        Input Data  : [-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]
356        Minus       : _1_11_1_____1___1___1____1_______1_______1_________________________
357        Zero        : _________11__11__1___1____1___11___________1______1__1__1__________
358        Digit1_9    : __________________________________111_111____111____1____111111111_
359        Digit0_9    : _________11__11__1___1____1___11__111_111__1_111__1_11__1111111111_
360        DecimalPoint: __________________1___1____1_________1______1______________________
361        Ee          : _______________________1____1______________________1_______________
362        PlusMinus   : _1_11_1_____1___1___1____1_______1_______1______1_____1____________
363        NumberSpans : _11_11_11__111_1111_1111_1111_1_111111111__11111__1111__1_________1
364        Errors      : __1_1__1__1___1____1___11___11_1_________1______1_____1__1__________
365        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111_
366        <BLANKLINE>
367
368        >>> 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]')
369        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]
370        Minus       : _________________________________1_______________1______________1________________________1__________________________________
371        Zero        : _1_______________1_______1____________11____11____11__________1____________1_1_________________________1_____________1______
372        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_
373        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_
374        DecimalPoint: __1____1____1_____________1__________________________________________1________1_______________1_____________________________
375        Ee          : ______________________1_____1___1____1____1_____1_______________________________________1_______________1_______________1___
376        PlusMinus   : _________________________________1_________1_____1______________1________________________1_______________1__________________
377        NumberSpans : _111_1111_11111_1111_111_11111_1111_1111_11111_11111_1111111111_111111111111_111111111111111_111111111111111_11111111111111_
378        Errors      : _____________________________________________________________________________________________________________________________
379        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_
380        <BLANKLINE>
381
382        >>> demo_validate_number('[012345,12345,0,00,-0,-00]')
383        Input Data  : [012345,12345,0,00,-0,-00]
384        Minus       : ___________________1__1___
385        Zero        : _1____________1_11__1__11_
386        Digit1_9    : __11111_11111_____________
387        Digit0_9    : _111111_11111_1_11__1__11_
388        DecimalPoint: __________________________
389        Ee          : __________________________
390        PlusMinus   : ___________________1__1___
391        NumberSpans : _1_____111111_1_1_111_11_1
392        Errors      : __1______________1______1__
393        EOF_Mask    : 11111111111111111111111111_
394        <BLANKLINE>
395        """ 
396       
397        global lgth
398        lgth = len(u8data)
399
400        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
401        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
402       
403        EscapeChars = parse_escape(Lex, EOF_mask)
404        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
405       
406        ParityMask = parallel_prefix_parity(UnescapedDQuotes, lgth) & EOF_mask
407        StringMask = ParityMask & bitutil.Advance(ParityMask)   
408       
409        (ObjectStarts, ArrayStarts, StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = value_starts(Lex, StringMask, EscapeChars,lgth) 
410       
411        (Errors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
412
413        bitutil.print_aligned_streams([('Input Data', u8data), 
414                              ('Minus', bitutil.bitstream2string(Lex.Minus, lgth)),
415                              ('Zero', bitutil.bitstream2string(Lex.Zero, lgth)),
416                              ('Digit1_9', bitutil.bitstream2string(Lex.Digit1_9, lgth)),
417                              ('Digit0_9', bitutil.bitstream2string(Lex.Digit0_9, lgth)),
418                              ('DecimalPoint', bitutil.bitstream2string(Lex.DecimalPoint, lgth)),
419                              ('Ee', bitutil.bitstream2string(Lex.Ee, lgth)),
420                              ('PlusMinus', bitutil.bitstream2string(Lex.PlusMinus, lgth)),
421                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
422                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
423                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
424
425def validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes, lgth):
426        r"""
427        RFC 4627 - JavaScript Object Notation (JSON) 
428
429        string = quotation-mark *char quotation-mark
430        char = unescaped /
431              escape (
432                  %x22 /          ; "    quotation mark  U+0022
433                  %x5C /          ; \    reverse solidus U+005C
434                  %x2F /          ; /    solidus         U+002F
435                  %x62 /          ; b    backspace       U+0008
436                  %x66 /          ; f    form feed       U+000C
437                  %x6E /          ; n    line feed       U+000A
438                  %x72 /          ; r    carriage return U+000D
439                  %x74 /          ; t    tab             U+0009
440                  %x75 4HEXDIG )  ; uXXXX                U+XXXX
441
442        escape = %x5C              ; \
443        quotation-mark = %x22      ; "
444        unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
445
446        JSON string validation requires both:
447        (1) validation of escape characters,
448        (2) validation of unescaped characters.
449        """
450       
451        # (1) Validate escape characters
452        StringEscapeChars = EscapeChars & StringMask
453        Errors = (StringEscapeChars &~ Lex.Escape)
454       
455        u = StringEscapeChars & Lex.u
456       
457        uScope1 = bitutil.Advance(u)
458        uScope2 = bitutil.Advance(uScope1)
459        uScope3 = bitutil.Advance(uScope2)
460        uScope4 = bitutil.Advance(uScope3)
461       
462        Errors |= uScope1 &~ Lex.HexDigit
463        Errors |= uScope2 &~ Lex.HexDigit
464        Errors |= uScope3 &~ Lex.HexDigit
465        Errors |= uScope4 &~ Lex.HexDigit
466       
467        # (2) Validation of unescaped characters
468        # (2.1) StringMask construction ensures all '"' are escaped.
469        # (2.2) '\' are either correctly escaped or the character following an odd length run is escaped.
470        # (2.3) validate_utf8(u8) ensures valid UTF8 encodings in the code point range U+0000 - U+01FFFF. TODO - Validate this final large.
471
472        StringNotEscapedChars = (~(EscapeChars | Lex.RSolidus)) & StringMask # TODO - Verify logic.
473        Errors |= (StringNotEscapedChars & Ctrl.x00_x1F)
474       
475        # (3) Validate all strings are terminated with an unescaped "
476        StringCursor = bitutil.Advance(StringStarts)
477        StringEnds = bitutil.ScanThru(StringCursor, StringMask)
478        Errors |= StringEnds &~ UnescapedDQuotes
479        StringSpans = (StringEnds - StringStarts) | StringEnds
480       
481        if debug:
482                bitutil.print_aligned_streams([('Input Data', u8data), 
483                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, lgth)),
484                              ('StringEscapeChars', bitutil.bitstream2string(StringEscapeChars, lgth)),
485                              ('u', bitutil.bitstream2string(u, lgth)),
486                              ('uScope1', bitutil.bitstream2string(uScope1, lgth)),
487                              ('uScope2', bitutil.bitstream2string(uScope2, lgth)),
488                              ('uScope3', bitutil.bitstream2string(uScope3, lgth)),
489                              ('uScope4', bitutil.bitstream2string(uScope4, lgth)),
490                              ('StringNotEscapedChars', bitutil.bitstream2string(StringNotEscapedChars, lgth)),
491                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
492                              ('StringEnds', bitutil.bitstream2string(StringEnds, lgth)),
493                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
494                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])     
495        return (Errors, StringSpans)
496
497def demo_validate_string(u8data):
498        r"""
499        >>> demo_validate_string('["\u abcd", "\u1___", "\u12__", "\u123_"]')
500        Input Data      : ["\u abcd", "\u1___", "\u12__", "\u123_"]
501        EscapeChars     : ___1__________1_________1_________1______
502        UnescapedDQuotes: _1_______1__1______1__1______1__1______1_
503        ParityMask      : _11111111___1111111___1111111___1111111__
504        StringMask      : __1111111____111111____111111____111111__
505        StringStarts    : _1__________1_________1_________1________
506        StringSpans     : _111111111__11111111__11111111__11111111_
507        Errors          : ____1___________111________11_________1___
508        EOF_Mask        : 11111111111111111111111111111111111111111_
509        <BLANKLINE>
510        """ 
511        global lgth
512        lgth = len(u8data)
513
514        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
515        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
516       
517        # Construct string interiors mask (1),(2),(3)
518        # (1) Mark all escaped characters
519        EscapeChars = parse_escape(Lex, EOF_mask)
520       
521        # (2) Mark all unescaped "
522        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
523       
524        # (3) Construct string interiors mask
525        ParityMask = parallel_prefix_parity(UnescapedDQuotes, lgth) & EOF_mask # TODO - Solve parity EOF_mask problem
526        StringMask = ParityMask & bitutil.Advance(ParityMask)
527                               
528        (ObjectStarts, ArrayStarts, StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = value_starts(Lex, StringMask, EscapeChars,lgth)                         
529                               
530        (Errors, StringSpans) = validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes,lgth)
531       
532        bitutil.print_aligned_streams([('Input Data', u8data), 
533                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, lgth)),
534                              ('UnescapedDQuotes', bitutil.bitstream2string(UnescapedDQuotes, lgth)),
535                              ('ParityMask', bitutil.bitstream2string(ParityMask, lgth)),
536                              ('StringMask', bitutil.bitstream2string(StringMask, lgth)),
537                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
538                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
539                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
540                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
541                             
542        return
543
544def validate_json(u8data,lgth):
545               
546        Errors = 0       
547               
548        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
549       
550        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
551       
552        EscapeChars = parse_escape(Lex, EOF_mask)
553        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
554        ParityMask = parallel_prefix_parity(UnescapedDQuotes, lgth) & EOF_mask # TODO - Solve parity EOF_mask problem
555        StringMask = ParityMask & bitutil.Advance(ParityMask)   
556       
557        (ObjectStarts, ArrayStarts, StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = value_starts(Lex, StringMask, EscapeChars,lgth)
558       
559        (StringErrors, StringSpans) = validate_string(StringStarts, Lex, Ctrl, StringMask, EscapeChars, UnescapedDQuotes, lgth)
560       
561        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
562       
563        (TrueErrors, TrueSpans) = validate_true(TrueStarts, Lex)
564       
565        (FalseErrors, FalseSpans) = validate_false(FalseStarts, Lex)
566       
567        (NullErrors, NullSpans) = validate_null(NullStarts, Lex)
568       
569        return (ObjectStarts, ArrayStarts, 
570                StringStarts, StringSpans, StringErrors, 
571                NumberStarts, NumberSpans, NumberErrors, 
572                TrueStarts, TrueSpans, TrueErrors, 
573                FalseStarts, FalseSpans, FalseErrors, 
574                NullStarts, NullSpans, NullErrors)
575 
576def demo_validate_json(u8data):
577 
578        global lgth
579        lgth = len(u8data)
580       
581        (ObjectStarts, ArrayStarts, 
582        StringStarts, StringSpans, StringErrors, 
583        NumberStarts, NumberSpans, NumberErrors, 
584        TrueStarts, TrueSpans, TrueErrors, 
585        FalseStarts, FalseSpans, FalseErrors, 
586        NullStarts, NullSpans, NullErrors) = validate_json(u8data,lgth)
587
588        bitutil.print_aligned_streams([('Input Data', u8data), 
589                              ('ObjectStarts', bitutil.bitstream2string(ObjectStarts, lgth)),
590                              ('ArrayStarts', bitutil.bitstream2string(ArrayStarts, lgth)),
591                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
592                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
593                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
594                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
595                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
596                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
597                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
598                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
599                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
600                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
601                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
602                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
603                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
604                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
605                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth))])
606
607        return
608
609if __name__ == "__main__":
610        import doctest
611        doctest.testmod()
612
613        if len(sys.argv) < 2:
614                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
615                sys.exit(2)
616
617        u8data = bitutil.readfile(sys.argv[1]) 
618#       demo_parse_escape(u8data)
619#       demo_parallel_prefix_parity(u8data)
620#       demo_value_starts(u8data)
621#       demo_validate_number(u8data)
622#       demo_validate_string(u8data)
623        demo_validate_json(u8data)
Note: See TracBrowser for help on using the repository browser.