source: proto/JSON/json_prototype.py @ 714

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

Update character set defs.

File size: 23.4 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 definitions input/output *only* bitstream type variables.
29#
30# Global declarations allow debug blocks in bitstream processing definitions.
31#
32# Do not shadow the global variables 'u8data' or 'lgth' with local variable declartions.
33
34u8data = ""
35lgth = 0
36
37def simd_const_4(hexdigit,EOF_mask):
38        r"""
39        IDISA library function.
40        """
41        lgth = bitutil.count_leading_zeroes(~EOF_mask)/4
42        return int(hexdigit*(lgth+1),16)&EOF_mask
43       
44def parse_escape(Lex, EOF_mask):
45        r"""
46        Marks escaped characters.
47        Does not mark escaped '\' characters.
48        '\' characters are either escaped and unmarked or the following character in an odd length run is marked.
49        """
50        odd = simd_const_4('a',EOF_mask)
51        even = simd_const_4('5',EOF_mask)
52       
53        start = Lex.RSolidus &~ bitutil.Advance(Lex.RSolidus)
54       
55        even_start = start & even
56        even_final = (even_start + Lex.RSolidus) & ~Lex.RSolidus
57        even_escape = even_final & odd
58       
59        odd_start = start & odd
60        odd_final = (odd_start + Lex.RSolidus) & ~Lex.RSolidus
61        odd_escape = (odd_final & even)
62
63        escape = (even_escape | odd_escape) 
64       
65        return escape
66       
67def demo_parse_escape(u8data):
68        global lgth
69        lgth = len(u8data)
70       
71        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
72        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
73        (escape) = parse_escape(Lex,EOF_mask)
74
75        bitutil.print_aligned_streams([('Input Data', u8data), 
76                              ('Lex.RSolidus', bitutil.bitstream2string(Lex.RSolidus, lgth)),   
77                              ('escape', bitutil.bitstream2string(escape, lgth)),       
78                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
79        return
80
81def parallel_prefix_parity(strm):
82        r"""
83        Translate to library function.
84       
85        x y  x XOR y
86        ------------
87        0 0   0
88        0 1   1
89        1 0   1
90        0 0   0
91
92        Let n = length(bitstream).
93
94        Define Pk,i as the parity of the bit range [k-(k+2^i),k] for bit positions n >= k >= 1.
95       
96        Base Case: Pk,0 = bitstream at position k, for all k, n >= k >= 0.
97        Inductive Step: Pk,i+1 = (Pk,i << 2^i) XOR Pk,i.
98       
99        Pk,ceil(log(n) denotes the parity of the bit position k, n >= k >= 0.
100       
101        bitstream[k] = 1 --> odd parity
102        bitstream[k] = 0 --> even parity
103        """
104        global lgth
105#       lgth = len(u8data)
106
107        t1 = strm
108        for i in range(0,int(math.ceil(math.log(lgth,2)))):
109                t2 = t1 ^ (t1 << pow(2,i))
110                t1 = t2
111        return t2 
112
113def demo_parallel_prefix_parity(u8data):
114        r"""
115        >>> demo_parallel_prefix_parity('"data" "data""data" "data" "data')
116        Input Data: "data" "data""data" "data" "data
117        Lex.DQuote: 1____1_1____11____1_1____1_1____
118        Parity    : 11111__11111_11111__11111__11111
119        EOF_Mask  : 11111111111111111111111111111111_
120        <BLANKLINE>
121        """     
122        global lgth
123        lgth = len(u8data)
124
125        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
126        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
127        ParityMask = parallel_prefix_parity(Lex.DQuote)
128       
129        bitutil.print_aligned_streams([('Input Data', u8data), 
130                              ('Lex.DQuote', bitutil.bitstream2string(Lex.DQuote, lgth)),
131                              ('Parity', bitutil.bitstream2string(ParityMask, lgth)),   
132                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
133        return
134
135def atom_starts(Lex,StringSpans):
136        r"""
137        This function returns multi-cursor start positions for each JSON value type.
138       
139        Define JSON atoms as 'String', 'Number', 'true', 'false', and 'null' types.
140       
141        Error cases are postponed for the post-processing stage as expect() cases in
142        a recursive descent parser.
143        """
144        global lgth
145       
146        AtomSpans = (Lex.True | Lex.False | Lex.Null | Lex.Number | StringSpans)
147        AtomStarts = AtomSpans &~ bitutil.Advance(AtomSpans)
148               
149        StringStarts = AtomStarts & (Lex.DQuote)       
150        NumberStarts = AtomStarts & (Lex.Minus|Lex.Digit0_9)
151        TrueStarts = AtomStarts & (Lex.t)
152        FalseStarts = AtomStarts & (Lex.f)
153        NullStarts = AtomStarts & (Lex.n)
154
155        if debug:
156                bitutil.print_aligned_streams([('Input Data', u8data), 
157                              ('AtomSpans', bitutil.bitstream2string(AtomSpans, lgth)),
158                              ('AtomStarts', bitutil.bitstream2string(AtomStarts, lgth)),
159                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
160                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
161                              ('Lex.True', bitutil.bitstream2string(Lex.True, lgth)),
162                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
163                              ('Lex.False', bitutil.bitstream2string(Lex.False, lgth)),
164                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
165                              ('Lex.Null', bitutil.bitstream2string(Lex.Null, lgth)),
166                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
167                              ('Lex.Number', bitutil.bitstream2string(Lex.Number, lgth)),
168                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth))])
169
170        return (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts)
171
172
173def demo_atom_starts(u8data):
174        global lgth     
175        lgth = len(u8data)
176               
177        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
178        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit) 
179       
180        EscapeChars = parse_escape(Lex, EOF_mask)
181       
182        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
183       
184        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve EOF_mask problem
185        StringMask = ParityMask & bitutil.Advance(ParityMask)   
186        StringSpans = StringMask | UnescapedDQuotes
187       
188        (StringStarts, NumberStarts,TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)
189        bitutil.print_aligned_streams([('Input Data', u8data), 
190                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
191                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
192                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
193                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
194                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
195                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])       
196        return
197
198
199def validate_true(Starts, Lex):
200        r"""
201        RFC 4627 - JavaScript Object Notation (JSON) 
202       
203        true  = %x74.72.75.65      ; true
204       
205        """
206        Errors = 0
207       
208        Scope1 = bitutil.Advance(Starts)
209        Scope2 = bitutil.Advance(Scope1)
210        Scope3 = bitutil.Advance(Scope2)
211       
212        Errors |= Scope1 &~ Lex.r
213        Errors |= Scope2 &~ Lex.u
214        Errors |= Scope3 &~ Lex.e
215       
216        Follows = bitutil.Advance(Scope3)
217        Spans = Follows - Starts
218
219        return (Errors, Spans)
220
221def validate_false(Starts, Lex):
222        r"""
223        RFC 4627 - JavaScript Object Notation (JSON) 
224       
225        false = %x66.61.6c.73.65   ; false
226       
227        """
228        Errors = 0
229       
230        Scope1 = bitutil.Advance(Starts)
231        Scope2 = bitutil.Advance(Scope1)
232        Scope3 = bitutil.Advance(Scope2)
233        Scope4 = bitutil.Advance(Scope3)
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(Scope4)
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        global lgth
284       
285        Errors = 0
286        M0 = Starts                                             # Initialize marker stream     
287       
288        M1 = bitutil.ScanThru(M0, Lex.Minus & M0)               # ? Optional character class [-]
289        E1 = M1 &~(Lex.Zero|Lex.Digit1_9)
290        M1 = M1 &~ E1                                           # Remove cursors at error positions so as to report a single error position
291
292        M1a = M1 & Lex.Zero                                     # Split
293        M1b = M1 & Lex.Digit1_9                         
294        M2a = bitutil.Advance(M1a)
295        M2b = bitutil.Advance(M1b)
296        M3b = bitutil.ScanThru(M2b,Lex.Digit0_9)
297        M4 =  M2a | M3b                                         # Join
298       
299        M4a = M4 &~(Lex.DecimalPoint)                           # Split
300        M4b = M4 & (Lex.DecimalPoint)
301        M5b = bitutil.Advance(M4b)
302        E5b = M5b &~(Lex.Digit0_9)                              # + [0-9]+
303        M5b = M5b &~E5b                                         # Remove cursors at error positions so as to report a single error position
304       
305        M6 = bitutil.ScanThru(M5b,Lex.Digit0_9)
306        M7 = M4a | M6                                           # Join
307       
308        M7a = M7 &~(Lex.Ee)                                     # Split
309        M7b = M7 &(Lex.Ee)
310        M8b = bitutil.Advance(M7b)
311        M9b = bitutil.ScanThru(M8b, Lex.PlusMinus & M8b)        # ? Optional character class [+-]               
312        E9b  = M9b &~(Lex.Digit0_9)                             # + [0-9]+
313        M9b = M9b &~ E9b                                        # Remove cursors at error positions so as to report a single error position
314        M10b = bitutil.ScanThru(M9b,Lex.Digit0_9)
315
316        M11 = M7a | M10b                                       
317       
318        # NOTE - Number Follow Set logic occurs at the final step after the final cursor join   
319        NumberFollowErrors = (M7a | M10b) &~(Lex.RSquareBracket | Lex.RCurlyBrace | Lex.Comma | Lex.WS)
320       
321        Errors = E1 | E5b | E9b | NumberFollowErrors
322       
323        NumberSpans = M11 - Starts
324       
325        if debug:
326                bitutil.print_aligned_streams([('Input Data', u8data), 
327                              ('M0', bitutil.bitstream2string(M0, lgth)),
328                              ('M1', bitutil.bitstream2string(M1, lgth)),
329                              ('E1', bitutil.bitstream2string(E1, lgth+1)),
330                              ('M1a', bitutil.bitstream2string(M1a, lgth)),
331                              ('M2a', bitutil.bitstream2string(M2a, lgth)),
332                              ('M2b', bitutil.bitstream2string(M2b, lgth)),
333                              ('M3b', bitutil.bitstream2string(M3b, lgth)),
334                              ('M4', bitutil.bitstream2string(M4, lgth)),
335                              ('M4a', bitutil.bitstream2string(M4a, lgth)),
336                              ('M4b', bitutil.bitstream2string(M4b, lgth)),
337                              ('M5b', bitutil.bitstream2string(M5b, lgth)),
338                              ('E5b', bitutil.bitstream2string(E5b, lgth+1)),         
339                              ('M6', bitutil.bitstream2string(M6, lgth)),
340                              ('M7', bitutil.bitstream2string(M7, lgth)),
341                              ('M7a', bitutil.bitstream2string(M7a, lgth)),
342                              #('E7a', bitutil.bitstream2string(E7a, lgth+1)),       
343                              ('M7b', bitutil.bitstream2string(M7b, lgth)),
344                              ('M8b', bitutil.bitstream2string(M8b, lgth)),
345                              ('M9b', bitutil.bitstream2string(M9b, lgth)),           
346                              ('E9b', bitutil.bitstream2string(E9b, lgth+1)),         
347                              ('M10b', bitutil.bitstream2string(M10b, lgth)),
348                              #('E10b', bitutil.bitstream2string(E10b, lgth)),
349                              ('M11', bitutil.bitstream2string(M11, lgth+1)),
350                              ('Starts', bitutil.bitstream2string(Starts, lgth)),
351                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
352                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])           
353       
354        return (Errors, NumberSpans)
355
356def demo_validate_number(u8data):
357        r"""
358        >>> demo_validate_number('[-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]')
359        Input Data  : [-,--,-a,00,-00,-0.,-0.e,-0.E,00,-123.456-,0.456+,0e10+,0123456789]
360        Minus       : _1_11_1_____1___1___1____1_______1_______1_________________________
361        Zero        : _________11__11__1___1____1___11___________1______1__1__1__________
362        Digit1_9    : __________________________________111_111____111____1____111111111_
363        Digit0_9    : _________11__11__1___1____1___11__111_111__1_111__1_11__1111111111_
364        DecimalPoint: __________________1___1____1_________1______1______________________
365        Ee          : _______________________1____1______________________1_______________
366        PlusMinus   : _1_11_1_____1___1___1____1_______1_______1______1_____1____________
367        NumberSpans : _11_11_11___11__1111_1111_1111___11111111__11111__1111__1__________
368        Errors      : __1_1__1__1___1____1___1____1__1_________1______1_____1__1__________
369        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111_
370        <BLANKLINE>
371
372        >>> 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]')
373        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]
374        Minus       : _________________________________1_______________1______________1________________________1__________________________________
375        Zero        : _1_______________1_______1____________11____11____11__________1____________1_1_________________________1_____________1______
376        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_
377        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_
378        DecimalPoint: __1____1____1_____________1__________________________________________1________1_______________1_____________________________
379        Ee          : ______________________1_____1___1____1____1_____1_______________________________________1_______________1_______________1___
380        PlusMinus   : _________________________________1_________1_____1______________1________________________1_______________1__________________
381        NumberSpans : _111_1111_11111_1111_111_11111_1111_1111_11111_11111_1111111111_111111111111_111111111111111_111111111111111_11111111111111_
382        Errors      : _____________________________________________________________________________________________________________________________
383        EOF_Mask    : 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_
384        <BLANKLINE>
385
386        >>> demo_validate_number('[012345,12345,0,00,-0,-00]')
387        Input Data  : [012345,12345,0,00,-0,-00]
388        Minus       : ___________________1__1___
389        Zero        : _1____________1_11__1__11_
390        Digit1_9    : __11111_11111_____________
391        Digit0_9    : _111111_11111_1_11__1__11_
392        DecimalPoint: __________________________
393        Ee          : __________________________
394        PlusMinus   : ___________________1__1___
395        NumberSpans : _1______11111_1_1__11_11__
396        Errors      : __1______________1______1__
397        EOF_Mask    : 11111111111111111111111111_
398        <BLANKLINE>
399        """ 
400        global lgth
401        lgth = len(u8data)
402       
403        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
404        (u8, Lex, Ctrl) = byteclass.classify_bytes(bit)
405       
406        EscapeChars = parse_escape(Lex, EOF_mask)
407        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
408       
409        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask
410        StringMask = ParityMask & bitutil.Advance(ParityMask)   
411        StringSpans = StringMask | UnescapedDQuotes
412       
413        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)       
414       
415        (Errors, NumberSpans) = validate_number(NumberStarts, Lex, EOF_mask)
416
417        bitutil.print_aligned_streams([('Input Data', u8data), 
418                              ('Minus', bitutil.bitstream2string(Lex.Minus, lgth)),
419                              ('Zero', bitutil.bitstream2string(Lex.Zero, lgth)),
420                              ('Digit1_9', bitutil.bitstream2string(Lex.Digit1_9, lgth)),
421                              ('Digit0_9', bitutil.bitstream2string(Lex.Digit0_9, lgth)),
422                              ('DecimalPoint', bitutil.bitstream2string(Lex.DecimalPoint, lgth)),
423                              ('Ee', bitutil.bitstream2string(Lex.Ee, lgth)),
424                              ('PlusMinus', bitutil.bitstream2string(Lex.PlusMinus, lgth)),
425                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
426                              ('Errors', bitutil.bitstream2string(Errors, lgth+1)),
427                              ('EOF_Mask', bitutil.bitstream2string(EOF_mask, lgth+1))])
428
429def validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes):
430        r"""
431        RFC 4627 - JavaScript Object Notation (JSON) 
432
433        string = quotation-mark *char quotation-mark
434        char = unescaped /
435              escape (
436                  %x22 /          ; "    quotation mark  U+0022
437                  %x5C /          ; \    reverse solidus U+005C
438                  %x2F /          ; /    solidus         U+002F
439                  %x62 /          ; b    backspace       U+0008
440                  %x66 /          ; f    form feed       U+000C
441                  %x6E /          ; n    line feed       U+000A
442                  %x72 /          ; r    carriage return U+000D
443                  %x74 /          ; t    tab             U+0009
444                  %x75 4HEXDIG )  ; uXXXX                U+XXXX
445
446        escape = %x5C              ; \
447        quotation-mark = %x22      ; "
448        unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
449
450        JSON string validation requires both:
451        (1) validation of escape characters,
452        (2) validation of unescaped characters.
453        """
454        global lgth
455       
456        # (1) Validate escape characters
457        StringEscapeChars = EscapeChars & StringMask
458        Errors = (StringEscapeChars &~ Lex.Escape)
459       
460        u = StringEscapeChars & Lex.u
461       
462        uScope1 = bitutil.Advance(u)
463        uScope2 = bitutil.Advance(uScope1)
464        uScope3 = bitutil.Advance(uScope2)
465        uScope4 = bitutil.Advance(uScope3)
466       
467        Errors |= uScope1 &~ Lex.HexDigit
468        Errors |= uScope2 &~ Lex.HexDigit
469        Errors |= uScope3 &~ Lex.HexDigit
470        Errors |= uScope4 &~ Lex.HexDigit
471       
472        # (2) Validation of unescaped characters
473        # (2.1) StringMask construction ensures all '"' are escaped.
474        # (2.2) '\' are either correctly escaped or the character following an odd length run is escaped.
475        # (2.3) validate_utf8(u8) ensures valid UTF8 encodings in the code point range U+0000 - U+01FFFF. TODO - Validate this final large.
476
477        StringNotEscapedChars = (~(EscapeChars | Lex.RSolidus)) & StringMask # TODO - Verify logic.
478        Errors |= (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        Errors |= StringEnds &~ UnescapedDQuotes
484        StringSpans = (StringEnds - StringStarts) | StringEnds
485       
486        if debug:
487                bitutil.print_aligned_streams([('Input Data', u8data), 
488                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, 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                              ('Errors', bitutil.bitstream2string(Errors, lgth+1))])     
500        return (Errors, 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        EscapeChars     : ___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        Errors          : ____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        EscapeChars = parse_escape(Lex, EOF_mask)
525
526        # (2) Mark all unescaped "
527        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
528
529        # (3) Construct string interiors mask
530        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve parity EOF_mask problem
531        StringMask = ParityMask & bitutil.Advance(ParityMask)
532        StringSpans = StringMask | UnescapedDQuotes
533
534        (StringStarts, NumberStarts, TrueStarts, FalseStarts, NullStarts) = atom_starts(Lex, StringSpans)                               
535       
536        (Errors, StringSpans) = validate_string(StringStarts, Lex,Ctrl,StringMask,EscapeChars,UnescapedDQuotes)
537       
538        bitutil.print_aligned_streams([('Input Data', u8data), 
539                              ('EscapeChars', bitutil.bitstream2string(EscapeChars, 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                              ('Errors', bitutil.bitstream2string(Errors, 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        EscapeChars = parse_escape(Lex, EOF_mask)
559        UnescapedDQuotes = (Lex.DQuote &~ EscapeChars)
560        ParityMask = parallel_prefix_parity(UnescapedDQuotes) & EOF_mask # TODO - Solve parity EOF_mask problem
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, EscapeChars, 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        bitutil.print_aligned_streams([('Input Data', u8data), 
593                              ('StringStarts', bitutil.bitstream2string(StringStarts, lgth)),
594                              ('StringSpans', bitutil.bitstream2string(StringSpans, lgth)),
595                              ('StringErrors', bitutil.bitstream2string(StringErrors, lgth)),                         
596                              ('NumberStarts', bitutil.bitstream2string(NumberStarts, lgth)),
597                              ('NumberSpans', bitutil.bitstream2string(NumberSpans, lgth)),
598                              ('NumberErrors', bitutil.bitstream2string(NumberErrors, lgth)),                         
599                              ('TrueStarts', bitutil.bitstream2string(TrueStarts, lgth)),
600                              ('TrueSpans', bitutil.bitstream2string(TrueSpans, lgth)),
601                              ('TrueErrors', bitutil.bitstream2string(TrueErrors, lgth)),                             
602                              ('FalseStarts', bitutil.bitstream2string(FalseStarts, lgth)),
603                              ('FalseSpans', bitutil.bitstream2string(FalseSpans, lgth)),
604                              ('FalseErrors', bitutil.bitstream2string(FalseErrors, lgth)),                           
605                              ('NullStarts', bitutil.bitstream2string(NullStarts, lgth)),
606                              ('NullSpans', bitutil.bitstream2string(NullSpans, lgth)),
607                              ('NullErrors', bitutil.bitstream2string(NullErrors, lgth))])
608
609        return
610
611if __name__ == "__main__":
612        import doctest
613        doctest.testmod()
614
615        if len(sys.argv) < 2:
616                sys.stderr.write("Usage: python " + filename + " <filename>" "\n")
617                sys.exit(2)
618
619        u8data = bitutil.readfile(sys.argv[1]) 
620
621#       demo_parse_escape(u8data)
622#       demo_parallel_prefix_parity(u8data)
623        demo_atom_starts(u8data)
624#       demo_validate_number(u8data)
625#       demo_validate_string(u8data)
626#       demo_validate_json_atoms(u8data)
Note: See TracBrowser for help on using the repository browser.