source: proto/JSON/json_prototype.py @ 768

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

Add fix to prototype and compilable.

File size: 24.1 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#True
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        StringStarts = StringSpans &~ bitutil.Advance(StringSpans)     
153
154        UnmaskedAtomSpans = (Lex.True | Lex.False | Lex.Null | Lex.Number) &~ StringSpans
155        UnmaskedAtomStarts = UnmaskedAtomSpans &~ bitutil.Advance(UnmaskedAtomSpans)
156
157        NumberStarts = UnmaskedAtomStarts & (Lex.Minus|Lex.Digit0_9)
158        TrueStarts = UnmaskedAtomStarts & (Lex.t)
159        FalseStarts = UnmaskedAtomStarts & (Lex.f)
160        NullStarts = UnmaskedAtomStarts & (Lex.n)
161
162        if debug:
163                bitutil.print_aligned_streams([('Input Data', u8data), 
164                              ('AtomSpans', bitutil.bitstream2string(AtomSpans, lgth)),
165                              ('AtomStarts', bitutil.bitstream2string(AtomStarts, lgth)),
166                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
167                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
168                              ('Lex.True', bitutil.bitstream2string(Lex.True, lgth)),
169                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
170                              ('Lex.False', bitutil.bitstream2string(Lex.False, lgth)),
171                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
172                              ('Lex.Null', bitutil.bitstream2string(Lex.Null, lgth)),
173                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
174                              ('Lex.Number', bitutil.bitstream2string(Lex.Number, lgth)),
175                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth))])
176
177        return (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts)
178
179
180def demo_atom_starts(u8data):
181        global lgth     
182        lgth = len(u8data)
183               
184        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
185        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
186       
187        Escape = parse_escape(Lex, EOF_mask)
188       
189        UnescapedDQuotes = (Lex.DQuote &~ Escape)
190       
191        ParityMask = parallel_prefix_parity(UnescapedDQuotes) # TODO - Solve EOF_mask problem, if final position is 1 then the final DQUOTE is not matched.
192        StringMask = ParityMask & bitutil.Advance(ParityMask)   
193        StringSpans = StringMask | UnescapedDQuotes
194       
195        (StringStarts, NumberStarts,TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
196        bitutil.print_aligned_streams([('Input Data', u8data), 
197                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
198                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
199                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
200                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
201                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
202                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
203        return
204
205
206def validate_true(TrueStarts, Lex):
207        r"""
208        RFC 4627 - JavaScript Object Notation (JSON) 
209       
210        true  = %x74.72.75.65      ; true
211       
212        """     
213        TrueScope1 = bitutil.Advance(TrueStarts)
214        TrueScope2 = bitutil.Advance(TrueScope1)
215        TrueScope3 = bitutil.Advance(TrueScope2)
216       
217        TrueErrors = TrueScope1 &~ Lex.r
218        TrueErrors |= TrueScope2 &~ Lex.u
219        TrueErrors |= TrueScope3 &~ Lex.e
220       
221        TrueFollows = bitutil.Advance(TrueScope3)
222        TrueSpans = TrueFollows - TrueStarts
223
224        return (TrueErrors, TrueSpans)
225
226def validate_false(FalseStarts, Lex):
227        r"""
228        RFC 4627 - JavaScript Object Notation (JSON) 
229       
230        false = %x66.61.6c.73.65   ; false
231       
232        """     
233        FalseScope1 = bitutil.Advance(FalseStarts)
234        FalseScope2 = bitutil.Advance(FalseScope1)
235        FalseScope3 = bitutil.Advance(FalseScope2)
236        FalseScope4 = bitutil.Advance(FalseScope3)
237       
238        FalseErrors = FalseScope1 &~ Lex.a
239        FalseErrors |= FalseScope2 &~ Lex.l
240        FalseErrors |= FalseScope3 &~ Lex.s
241        FalseErrors |= FalseScope4 &~ Lex.e
242
243        FalseFollows = bitutil.Advance(FalseScope4)
244        FalseSpans = FalseFollows - FalseStarts
245       
246        return (FalseErrors, FalseSpans)
247
248def validate_null(NullStarts, Lex):
249        r"""
250        RFC 4627 - JavaScript Object Notation (JSON) 
251       
252        null  = %x6e.75.6c.6c      ; null
253       
254        """
255        NullScope1 = bitutil.Advance(NullStarts)
256        NullScope2 = bitutil.Advance(NullScope1)
257        NullScope3 = bitutil.Advance(NullScope2)
258       
259        NullErrors = NullScope1 &~ Lex.u
260        NullErrors |= NullScope2 &~ Lex.l
261        NullErrors |= NullScope3 &~ Lex.l
262       
263        NullFollows = bitutil.Advance(NullScope3)
264        NullSpans = NullFollows - NullStarts
265
266        return (NullErrors, NullSpans)
267
268def validate_number(NumberStarts, Lex, EOF_mask):
269        r"""   
270        RFC 4627 - JavaScript Object Notation (JSON) 
271        RFC 5234 - Augmented BNF for Syntax Specifications: ABNF
272
273        number = [ minus ] int [ frac ] [ exp ]
274        decimal-point = %x2E       ; .
275        digit1-9 = %x31-39         ; 1-9
276        e = %x65 / %x45            ; e E
277        exp = e [ minus / plus ] 1*DIGIT
278        frac = decimal-point 1*DIGIT
279        int = zero / ( digit1-9 *DIGIT )
280        minus = %x2D               ; -
281        plus = %x2B                ; +
282        zero = %x30                ; 0 
283
284        NOTE - Does not validate number follow characters. Hence leading zero errors are not reported.
285
286        """     
287        global lgth
288       
289        M0 = NumberStarts                                       # Initialize marker stream     
290       
291        M1 = bitutil.ScanThru(M0, Lex.Minus & M0)               # ? Optional character class [-]
292        E1 = M1 &~(Lex.Zero|Lex.Digit1_9)
293        M1 = M1 &~ E1                                           # Remove cursors at error positions so as to report a single error position
294
295        M1a = M1 & Lex.Zero                                     # Split
296        M1b = M1 & Lex.Digit1_9                         
297        M2a = bitutil.Advance(M1a)
298        M2b = bitutil.Advance(M1b)
299        M3b = bitutil.ScanThru(M2b,Lex.Digit0_9)
300        M4 =  M2a | M3b                                         # Join
301       
302        M4a = M4 &~(Lex.DecimalPoint)                           # Split
303        M4b = M4 & (Lex.DecimalPoint)
304        M5b = bitutil.Advance(M4b)
305        E5b = M5b &~(Lex.Digit0_9)                              # + [0-9]+
306        M5b = M5b &~E5b                                         # Remove cursors at error positions so as to report a single error position
307       
308        M6 = bitutil.ScanThru(M5b,Lex.Digit0_9)
309        M7 = M4a | M6                                           # Join
310       
311        M7a = M7 &~(Lex.Ee)                                     # Split
312        M7b = M7 & (Lex.Ee)
313        M8b = bitutil.Advance(M7b)
314        M9b = bitutil.ScanThru(M8b, Lex.PlusMinus & M8b)        # ? Optional character class [+-]               
315        E9b  = M9b &~(Lex.Digit0_9)                             # + [0-9]+
316        M9b = M9b &~ E9b                                        # Remove cursors at error positions so as to report a single error position
317        M10b = bitutil.ScanThru(M9b,Lex.Digit0_9)
318
319        M11 = E1 | E5b | E9b | M7a | M10b                       # Record final marker positions,
320                                                                # At Advance(M11) this positions is either (1) a known error position or (2) an undetermined position to be checked
321       
322        NumberErrors = E1 | E5b | E9b
323       
324        NumberSpans = M11 - M0
325       
326        if debug:
327                bitutil.print_aligned_streams([('Input Data', u8data), 
328                              ('M0', bitutil.bitstream2string(M0, lgth)),
329                              ('M1', bitutil.bitstream2string(M1, lgth)),
330                              ('E1', bitutil.bitstream2string(E1, lgth+1)),
331                              ('M1a', bitutil.bitstream2string(M1a, lgth)),
332                              ('M2a', bitutil.bitstream2string(M2a, lgth)),
333                              ('M2b', bitutil.bitstream2string(M2b, lgth)),
334                              ('M3b', bitutil.bitstream2string(M3b, lgth)),
335                              ('M4', bitutil.bitstream2string(M4, lgth)),
336                              ('M4a', bitutil.bitstream2string(M4a, lgth)),
337                              ('M4b', bitutil.bitstream2string(M4b, lgth)),
338                              ('M5b', bitutil.bitstream2string(M5b, lgth)),
339                              ('E5b', bitutil.bitstream2string(E5b, lgth+1)),         
340                              ('M6', bitutil.bitstream2string(M6, lgth)),
341                              ('M7', bitutil.bitstream2string(M7, lgth)),
342                              ('M7a', bitutil.bitstream2string(M7a, lgth)),
343                              #('E7a', bitutil.bitstream2string(E7a, lgth+1)),       
344                              ('M7b', bitutil.bitstream2string(M7b, lgth)),
345                              ('M8b', bitutil.bitstream2string(M8b, lgth)),
346                              ('M9b', bitutil.bitstream2string(M9b, lgth)),           
347                              ('E9b', bitutil.bitstream2string(E9b, lgth+1)),         
348                              ('M10b', bitutil.bitstream2string(M10b, lgth)),
349                              #('E10b', bitutil.bitstream2string(E10b, lgth)),
350                              ('M11', bitutil.bitstream2string(M11, lgth+1)),
351                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
352                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
353                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth+1))])               
354       
355        return (NumberErrors, NumberSpans)
356
357def demo_validate_number(u8data):
358        r"""
359        >>> demo_validate_number('[-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]')
360        Input Data  : [-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]
361        Minus       : _1_11_1_____1___1___1____1_______1_______1_________________________
362        Zero        : _________11__11__1___1____1___11___________1______1__1__1__________
363        Digit1_9    : __________________________________111_111____111____1____111111111_
364        Digit0_9    : _________11__11__1___1____1___11__111_111__1_111__1_11__1111111111_
365        DecimalPoint: __________________1___1____1_________1______1______________________
366        Ee          : _______________________1____1______________________1_______________
367        PlusMinus   : _1_11_1_____1___1___1____1_______1_______1______1_____1____________
368        NumberSpans : _1_1__1__1__11__111_111__111__1__11111111__11111__1111__1__________
369        NumberErrors: __1_1__1___________1___1____1_______________________________________
370        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111_
371        <BLANKLINE>
372
373        >>> 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]')
374        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]
375        Minus       : _________________________________1_______________1______________1________________________1__________________________________
376        Zero        : _1_______________1_______1____________11____11____11__________1____________1_1_________________________1_____________1______
377        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_
378        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_
379        DecimalPoint: __1____1____1_____________1__________________________________________1________1_______________1_____________________________
380        Ee          : ______________________1_____1___1____1____1_____1_______________________________________1_______________1_______________1___
381        PlusMinus   : _________________________________1_________1_____1______________1________________________1_______________1__________________
382        NumberSpans : _111_1111_11111_1111_111_11111_1111_1111_11111_11111_1111111111_111111111111_111111111111111_111111111111111_11111111111111_
383        NumberErrors: _____________________________________________________________________________________________________________________________
384        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_
385        <BLANKLINE>
386
387        >>> demo_validate_number('[012345,12345,0,00,-0,-00]')
388        Input Data  : [012345,12345,0,00,-0,-00]
389        Minus       : ___________________1__1___
390        Zero        : _1____________1_11__1__11_
391        Digit1_9    : __11111_11111_____________
392        Digit0_9    : _111111_11111_1_11__1__11_
393        DecimalPoint: __________________________
394        Ee          : __________________________
395        PlusMinus   : ___________________1__1___
396        NumberSpans : _1______11111_1_1__11_11__
397        NumberErrors: ___________________________
398        EOF_Mask    : 11111111111111111111111111_
399        <BLANKLINE>
400        """ 
401        global lgth
402        lgth = len(u8data)
403       
404        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
405        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
406       
407        Escape = parse_escape(Lex, EOF_mask)
408        UnescapedDQuotes = (Lex.DQuote &~ Escape)
409       
410        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
411        StringMask = ParityMask & bitutil.Advance(ParityMask)   
412        StringSpans = StringMask | UnescapedDQuotes
413       
414        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)       
415       
416        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
417
418        bitutil.print_aligned_streams([('Input Data', u8data), 
419                              ('Minus', bitutil.bitstream2string(Lex.Minus, lgth)),
420                              ('Zero', bitutil.bitstream2string(Lex.Zero, lgth)),
421                              ('Digit1_9', bitutil.bitstream2string(Lex.Digit1_9, lgth)),
422                              ('Digit0_9', bitutil.bitstream2string(Lex.Digit0_9, lgth)),
423                              ('DecimalPoint', bitutil.bitstream2string(Lex.DecimalPoint, lgth)),
424                              ('Ee', bitutil.bitstream2string(Lex.Ee, lgth)),
425                              ('PlusMinus', bitutil.bitstream2string(Lex.PlusMinus, lgth)),
426                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
427                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth+1)),
428                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
429
430def validate_string(StringStarts, Lex, Ctrl, StringMask, Escape, UnescapedDQuotes):
431        r"""
432        RFC 4627 - JavaScript Object Notation (JSON) 
433
434        string = quotation-mark *char quotation-mark
435        char = unescaped /
436              escape (
437                  %x22 /          ; "    quotation mark  U+0022
438                  %x5C /          ; \    reverse solidus U+005C
439                  %x2F /          ; /    solidus         U+002F
440                  %x62 /          ; b    backspace       U+0008
441                  %x66 /          ; f    form feed       U+000C
442                  %x6E /          ; n    line feed       U+000A
443                  %x72 /          ; r    carriage return U+000D
444                  %x74 /          ; t    tab             U+0009
445                  %x75 4HEXDIG )  ; uXXXX                U+XXXX
446
447        escape = %x5C              ; \
448        quotation-mark = %x22      ; "
449        unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
450
451        JSON string validation requires both:
452        (1) validation of escape characters,
453        (2) validation of unescaped characters.
454        """
455        global lgth
456       
457        # (1) Validate escape characters
458        StringEscapeChars = Escape & StringMask
459        StringErrors = (StringEscapeChars &~ Lex.Escape)
460       
461        u = StringEscapeChars & Lex.u
462       
463        uScope1 = bitutil.Advance(u)
464        uScope2 = bitutil.Advance(uScope1)
465        uScope3 = bitutil.Advance(uScope2)
466        uScope4 = bitutil.Advance(uScope3)
467       
468        StringErrors |= uScope1 &~ Lex.HexDigit
469        StringErrors |= uScope2 &~ Lex.HexDigit
470        StringErrors |= uScope3 &~ Lex.HexDigit
471        StringErrors |= uScope4 &~ Lex.HexDigit
472       
473        # (2) Validation of unescaped characters
474        # (2.1) StringMask construction ensures all '"' are escaped.
475        # (2.2) '\' are either correctly escaped or the character following an odd length run is escaped.
476
477        StringNotEscapedChars = (~(Escape | Lex.RSolidus)) & StringMask # TODO - Verify logic.
478        StringErrors |= (StringNotEscapedChars & Ctrl.x00_x1F)
479       
480        # (3) Validate all strings are terminated with an unescaped "
481        StringCursor = bitutil.Advance(StringStarts)
482        StringEnds = bitutil.ScanThru(StringCursor, StringMask)
483        StringErrors |= StringEnds &~ UnescapedDQuotes
484        StringSpans = (StringEnds - StringStarts) | StringEnds
485       
486        if debug:
487                bitutil.print_aligned_streams([('Input Data', u8data), 
488                              ('Escape', bitutil.bitstream2string(Escape, lgth)),
489                              ('StringEscapeChars', bitutil.bitstream2string(StringEscapeChars, lgth)),
490                              ('u', bitutil.bitstream2string(u, lgth)),
491                              ('uScope1', bitutil.bitstream2string(uScope1, lgth)),
492                              ('uScope2', bitutil.bitstream2string(uScope2, lgth)),
493                              ('uScope3', bitutil.bitstream2string(uScope3, lgth)),
494                              ('uScope4', bitutil.bitstream2string(uScope4, lgth)),
495                              ('StringNotEscapedChars', bitutil.bitstream2string(StringNotEscapedChars, lgth)),
496                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
497                              ('StringEnds', bitutil.bitstream2string(StringEnds, lgth)),
498                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
499                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth+1))])         
500        return (StringErrors, StringSpans)
501
502def demo_validate_string(u8data):
503        r"""
504        >>> demo_validate_string('["\u abcd", "\u1___", "\u12__", "\u123_"]')
505        Input Data      : ["\u abcd", "\u1___", "\u12__", "\u123_"]
506        Escape          : ___1__________1_________1_________1______
507        UnescapedDQuotes: _1_______1__1______1__1______1__1______1_
508        ParityMask      : _11111111___1111111___1111111___1111111__
509        StringMask      : __1111111____111111____111111____111111__
510        StringStarts    : _1__________1_________1_________1________
511        StringSpans     : _111111111__11111111__11111111__11111111_
512        StringErrors    : ____1___________111________11_________1___
513        EOF_Mask        : 11111111111111111111111111111111111111111_
514        <BLANKLINE>
515        """ 
516        global lgth
517        lgth = len(u8data)
518       
519        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
520        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
521
522        # Construct string interiors mask (1),(2),(3)
523        # (1) Mark all escaped characters
524        Escape = parse_escape(Lex, EOF_mask)
525
526        # (2) Mark all unescaped "
527        UnescapedDQuotes = (Lex.DQuote &~ Escape)
528
529        # (3) Construct string interiors mask
530        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
531        StringMask = ParityMask & bitutil.Advance(ParityMask)
532        StringSpans = StringMask | UnescapedDQuotes
533
534        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)                               
535       
536        (StringErrors, StringSpans) = validate_string(StringStarts, Lex,Ctrl,StringMask,Escape,UnescapedDQuotes)
537       
538        bitutil.print_aligned_streams([('Input Data', u8data), 
539                              ('Escape', bitutil.bitstream2string(Escape, lgth)),
540                              ('UnescapedDQuotes', bitutil.bitstream2string(UnescapedDQuotes, lgth)),
541                              ('ParityMask', bitutil.bitstream2string(ParityMask, lgth)),
542                              ('StringMask', bitutil.bitstream2string(StringMask, lgth)),
543                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
544                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
545                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth+1)),
546                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
547                             
548        return
549
550def validate_json_atoms(u8data):
551               
552        Errors = 0       
553               
554        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
555       
556        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
557       
558        Escape = parse_escape(Lex, EOF_mask)
559        UnescapedDQuotes = (Lex.DQuote &~ Escape)
560        ParityMask = parallel_prefix_parity(UnescapedDQuotes)
561        StringMask = ParityMask & bitutil.Advance(ParityMask)   
562        StringSpans = StringMask | UnescapedDQuotes
563       
564        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
565       
566        (StringErrors, StringSpans) = validate_string(StringStarts, Lex, Ctrl, StringMask, Escape, UnescapedDQuotes)
567       
568        (NumberErrors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
569       
570        (TrueErrors, TrueSpans) = validate_true(TrueStarts, Lex)
571       
572        (FalseErrors, FalseSpans) = validate_false(FalseStarts, Lex)
573       
574        (NullErrors, NullSpans) = validate_null(NullStarts, Lex)
575
576        return (StringStarts, StringSpans, StringErrors, 
577                NumberStarts, NumberSpans, NumberErrors, 
578                TrueStarts, TrueSpans, TrueErrors, 
579                FalseStarts, FalseSpans, FalseErrors, 
580                NullStarts, NullSpans, NullErrors)
581 
582def demo_validate_json_atoms(u8data):
583        global lgth
584        lgth = len(u8data)
585
586        (StringStarts, StringSpans, StringErrors,
587        NumberStarts, NumberSpans, NumberErrors, 
588        TrueStarts, TrueSpans, TrueErrors, 
589        FalseStarts, FalseSpans, FalseErrors, 
590        NullStarts, NullSpans, NullErrors) = validate_json_atoms(u8data)
591
592        AtomSpans = (StringSpans|NumberSpans|TrueSpans|FalseSpans|NullSpans)
593
594        bitutil.print_aligned_streams([('Input Data', u8data), 
595                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
596                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
597                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
598                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
599                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
600                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
601                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
602                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
603                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
604                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
605                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
606                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
607                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
608                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
609                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth)),
610                              ('AtomSpans', bitutil.bitstream2string(AtomSpans, lgth))])
611
612        return
613
614if __name__ == "__main__":
615        import doctest
616        doctest.testmod()
617
618        if len(sys.argv) < 2:
619                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
620                sys.exit(2)
621
622        u8data = bitutil.readfile(sys.argv[1]) 
623
624#       demo_parse_escape(u8data)
625#       demo_parallel_prefix_parity(u8data)
626#       demo_atom_starts(u8data)
627#       demo_validate_number(u8data)
628#       demo_validate_string(u8data)
629        demo_validate_json_atoms(u8data)
Note: See TracBrowser for help on using the repository browser.