source: proto/parabix2/parabix2.py @ 277

Last change on this file since 277 was 277, checked in by cameron, 10 years ago

New parabix2 prototype

File size: 22.2 KB
Line 
1#
2# parabix2.py
3#
4# Parallel XML Parsing with Bitstream Addition
5# - Complete prototype for all bitstream computations in Parabix2
6#
7# Robert D. Cameron
8# August 20, 2009
9#
10#----------------------------------------------------------------------------
11#
12# We use python's unlimited precision integers for unbounded bit streams.
13# This permits simple logical operations on the entire stream.
14# Assumption: bitstreams are little-endian (e.g., as on x86).
15#
16#----------------------------------------------------------------------------
17#
18
19
20import bitutil
21
22import byteclass
23
24def validate_utf8(bit):
25        u8.scope22 = bitutil.Advance(u8.prefix2)
26        u8.scope32 = bitutil.Advance(u8.prefix3)
27        u8.scope33 = bitutil.Advance(u8.scope32)
28        u8.scope42 = bitutil.Advance(u8.prefix4)
29        u8.scope43 = bitutil.Advance(u8.scope42)
30        u8.scope44 = bitutil.Advance(u8.scope43)
31        u8lastscope = u8.scope22 | u8.scope33 | u8.scope44
32        u8anyscope = u8lastscope | u8.scope32 | u8.scope42 | u8.scope43
33       
34        # C0-C1 and F5-FF are illegal
35        error_mask = u8.badprefix
36       
37        error_mask |= bitutil.Advance(u8.xE0) & u8.x80_x9F
38        error_mask |= bitutil.Advance(xED) & u8.xA0_xBF
39        error_mask |= bitutil.Advance(xF0) & u8.x80_x8F
40        error_mask |= bitutil.Advance(xF4) & u8.x90_xBF
41       
42        error_mask |= u8anyscope ^ u8.suffix
43        u8.error = error_mask
44        return u8
45
46def validate_xmlchar(u8, control, lex):
47        r"""Compute an error stream marking characters illegal in XML:
48        (1) Control characters in the range 0x00-0x1F except HT, LF, CR
49        (2) OxFFFF and OxFFFE, having UTF-8 encodings 0xEF 0xBF 0XBF and 0xEF 0xBF 0xBE.
50
51        >>> demo_validate_xmlchar('plaintext (good: \x09) (bad: \x03) (bad \xEF\xBF\xBF) (good \xEF\xBF\xBC)')
52        input high nybbles: 7666676772266663202226663202226662ebb22266662ebb2
53        input low nybbles : 0c19e4584087ff4a09908214a039082140fff9087ff40ffc9
54        illegal XML chars : __________________________1_________1____________
55"""
56        EF_BF_pending = bitutil.Advance(bitutil.Advance(u8.xEF) & u8.xBF)
57        return (EF_BF_pending & (u8.xBE | u8.xBF)) | (control.x00_x1F &~ lex.WS)
58
59
60def demo_validate_xmlchar(u8data):
61        lgth = len(u8data)
62        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
63        (u8, control, lex) = byteclass.classify_bytes(bit)
64        bitutil.print_aligned_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)), 
65                              ('input low nybbles', bitutil.low_nybble_stream(u8data)),
66                              ('illegal XML chars', bitutil.bitstream2string(validate_xmlchar(u8, control, lex), lgth))])
67
68def normalize_line_breaks(control, bit):
69        r"""Convert CRs to LFs and mark CRLF occurrences for deletion.
70
71        >>> demo_line_breaks('ab \r\n  cd \r  ef \r ')
72        input high nybbles: 662002266202266202
73        input low nybbles : 120da00340d00560d0
74        CR                : ___1______1_____1_
75        LF                : ____1_____________
76        CRLF              : ____1_____________
77"""
78        control.CRLF = bitutil.Advance(control.CR) & control.LF
79        # Convert CRs to LFs (flip bits 5, 6 and 7 with xor).
80        bit[5] ^= control.CR
81        bit[6] ^= control.CR
82        bit[7] ^= control.CR
83        return (control, bit)
84
85def demo_line_breaks(u8data):
86        lgth = len(u8data)
87        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
88        (u8, control, lex) = byteclass.classify_bytes(bit)
89        (control, bit) = normalize_line_breaks(control, bit)
90        bitutil.print_aligned_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)), 
91                              ('input low nybbles', bitutil.low_nybble_stream(u8data)),
92                              ('CR', bitutil.bitstream2string(control.CR, lgth)),
93                              ('LF', bitutil.bitstream2string(control.LF, lgth)),
94                              ('CRLF', bitutil.bitstream2string(control.CRLF, lgth))])
95
96
97
98
99
100def add_multiliterals(lex):
101        """Extend the byte-based lexical item streams for some important
102        multibyte literals.
103       
104        >>> demo_multiliterals("  <?php?>  <!--  -->  <![CDATA[  ]]> ")
105        input data  :   <?php?>  <!--  -->  <![CDATA[  ]]>
106        PI_start    : ___1_________________________________
107        CtCD_start  : ____________1__________1_____________
108        EndTag_start: _____________________________________
109        CD_end      : ___________________________________1_
110        DoubleHyphen: ______________1___1__________________
111        PI_end      : ________1____________________________
112        """
113
114        LAngleFollow = bitutil.Advance(lex.LAngle)
115        lex.PI_start = LAngleFollow & lex.QMark
116        lex.CtCD_start = LAngleFollow & lex.Exclam
117        lex.EndTag_start = LAngleFollow & lex.Slash
118        lex.CD_end = bitutil.Advance(bitutil.Advance(lex.RBracket) & lex.RBracket) & lex.RAngle
119        lex.DoubleHyphen = bitutil.Advance(lex.Hyphen) & lex.Hyphen
120        lex.PI_end = bitutil.Advance(lex.QMark) & lex.RAngle
121        return lex
122
123
124def demo_multiliterals(u8data):
125        lgth = len(u8data)
126        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
127        (u8, control, lex) = byteclass.classify_bytes(bit)
128        lex = add_multiliterals(lex)
129        bitutil.print_aligned_streams([('input data', u8data), 
130                              ('PI_start', bitutil.bitstream2string(lex.PI_start, lgth)),
131                              ('CtCD_start', bitutil.bitstream2string(lex.CtCD_start, lgth)),
132                              ('EndTag_start', bitutil.bitstream2string(lex.EndTag_start, lgth)),
133                              ('CD_end', bitutil.bitstream2string(lex.CD_end, lgth)),
134                              ('DoubleHyphen', bitutil.bitstream2string(lex.DoubleHyphen, lgth)),
135                              ('PI_end', bitutil.bitstream2string(lex.PI_end, lgth))])
136
137class CtCDPI_callouts:
138        CD_span = 0
139        Ct_span = 0
140        PI_mask = 0
141        CtCDPI_mask = 0
142        Error = 0
143       
144def parse_CtCDPI(lex, EOF_mask):
145        """Parse all comments, CDATA sections and processing instructions.
146       
147        Return bitstreams marking the extent of these markup items,
148        excluding initial and final bracketting.
149       
150        >>> demo_CtCDPI(' <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]> ')
151        input data :  <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]>
152        CD_span    : ______________________________11111111111111111111111__
153        Ct_span    : _____________111111111111______________________________
154        PI_span    : __11111________________________________________________
155        CtCDPI_mask: __111111___111111111111111___1111111111111111111111111_
156        Error      : ________________________________________________________
157       
158        Comments are terminated by double-hyphen; immediately require closing ">".
159       
160        >>> demo_CtCDPI(' <!--  <?php?>  --   <!-- -->')
161        input data :  <!--  <?php?>  --   <!-- -->
162        CD_span    : _____________________________
163        Ct_span    : ____11111111111111______1111_
164        PI_span    : _____________________________
165        CtCDPI_mask: __11111111111111111___1111111
166        Error      : __________________1___________
167
168"""
169        callouts = CtCDPI_callouts()
170        PI_starts = 0
171        PI_ends = 0
172        Ct_starts = 0
173        Ct_ends = 0
174        CD_starts = 0
175        CD_ends = 0
176        CtCDPI_starts = 0
177        # Scanning streams
178        CtCDPI_scan = ~(lex.CtCD_start | lex.PI_start) & EOF_mask
179        Ct_end_scan = ~lex.DoubleHyphen & EOF_mask
180        CD_end_scan = ~lex.CD_end & EOF_mask
181        PI_end_scan = ~lex.PI_end & EOF_mask
182        #
183        # Initiate the scan
184        CtCDPI_Cursor = 1
185        CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
186        CtCDPI_Cursor &= EOF_mask
187        while CtCDPI_Cursor > 0:
188                CtCDPI_starts |= CtCDPI_Cursor
189                PI_Cursor = CtCDPI_Cursor & lex.PI_start
190                CD_Ct_Cursor = bitutil.Advance(CtCDPI_Cursor & ~PI_Cursor)
191                CD_Cursor = CD_Ct_Cursor & lex.LBracket
192                Ct_Cursor = bitutil.Advance(CD_Ct_Cursor & lex.Hyphen) 
193                PI_starts |= PI_Cursor
194                CD_starts |= CD_Cursor
195                Ct_starts |= Ct_Cursor
196                Ct_Cursor = bitutil.Advance(Ct_Cursor)
197                PI_Cursor = bitutil.ScanThru(PI_Cursor, PI_end_scan)
198                CD_Cursor = bitutil.ScanThru(CD_Cursor, CD_end_scan)
199                Ct_Cursor = bitutil.Advance(bitutil.ScanThru(Ct_Cursor, Ct_end_scan))
200                PI_ends |= PI_Cursor
201                CD_ends |= CD_Cursor
202                Ct_ends |= Ct_Cursor
203                CtCDPI_Cursor = PI_Cursor | CD_Cursor | Ct_Cursor
204                CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
205                CtCDPI_Cursor &= EOF_mask
206        # End of loop: no remaining CtCDPI_Cursor
207        callouts.CD_span = CD_ends - CD_starts
208        callouts.Ct_span = Ct_ends - Ct_starts
209        callouts.PI_span = PI_ends - PI_starts
210       
211        callouts.CtCDPI_mask |= bitutil.Advance(CD_ends | Ct_ends | PI_ends) - CtCDPI_starts
212        callouts.Error = Ct_ends & ~lex.RAngle
213        # If any of the Comment, CDATA or PI markups are unterminated, it is an error.
214        callouts.Error |= callouts.CtCDPI_mask &~ EOF_mask
215        return callouts
216
217
218def demo_CtCDPI(u8data):
219        lgth = len(u8data)
220        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
221        (u8, control, lex) = byteclass.classify_bytes(bit)
222        lex = add_multiliterals(lex)
223        markup = parse_CtCDPI(lex, EOF_mask)
224        bitutil.print_aligned_streams([('input data', u8data), 
225                              ('CD_span', bitutil.bitstream2string(markup.CD_span, lgth)),
226                              ('Ct_span', bitutil.bitstream2string(markup.Ct_span, lgth)),
227                              ('PI_span', bitutil.bitstream2string(markup.PI_span, lgth)),
228                              ('CtCDPI_mask', bitutil.bitstream2string(markup.CtCDPI_mask, lgth)),
229                              ('Error', bitutil.bitstream2string(markup.Error, lgth+1))])
230
231
232class ref_callouts:
233        GenRefs = 0
234        DecRefs = 0
235        HexRefs = 0
236        delmask = 0
237        error = 0
238
239def ref_pass(lex, CtCDPI_mask):
240        """Parse and call out all general and character references.
241        Mark all but the closing semicolon for deletion.
242       
243        >>> demo_refs(" &gt;  &#13;  &#x0a;  ")
244        input data       :  &gt;  &#13;  &#x0a; 
245        entity refs      : __11__________________
246        decimal char refs: _________11___________
247        ref delmask      : _111___1111___11111___
248        errors           : _______________________
249
250        Empty numeric references are reported as errors.
251        >>> demo_refs(" &#;       &#x; ")
252        input data       :  &#;       &#x;
253        entity refs      : ________________
254        decimal char refs: ________________
255        ref delmask      : _11________111__
256        errors           : ___1__________1__
257
258        Improperly terminated or unterminated references (lacking ";") are also errors.
259        >>> demo_refs("  &gt:  &#456a;  &#xab:  &unterminated")
260        input data       :   &gt:  &#456a;  &#xab:  &unterminated
261        entity refs      : ___111____________________111111111111
262        decimal char refs: __________111_________________________
263        ref delmask      : __1111__11111____11111___1111111111111
264        errors           : ______1______1________1_______________1
265"""
266        CallOuts = ref_callouts()
267        Ref2 = bitutil.Advance(lex.RefStart &~ CtCDPI_mask)
268        NumRef2 = Ref2 & lex.Hash
269        GenRef2 = Ref2 &~ lex.Hash
270        NumRef3 = bitutil.Advance(NumRef2)
271        HexRef3 = NumRef3 & lex.x
272        DecRef3 = NumRef3 &~ lex.x
273        HexRef4 = bitutil.Advance(HexRef3) 
274        GenRefEnds = bitutil.ScanThru(GenRef2, lex.NameScan)
275        DecRefEnds = bitutil.ScanThru(DecRef3, lex.Digit)
276        HexRefEnds = bitutil.ScanThru(HexRef4, lex.Hex)
277        # Error checks
278        # At least one digit required for DecRef, one hex digit for HexRef.
279        Error = DecRef3 &~ lex.Digit
280        Error |= HexRef4 &~ lex.Hex
281        # Semicolon terminator required (also covers unterminated at EOF).
282        Error |= (GenRefEnds | DecRefEnds | HexRefEnds) &~ lex.Semicolon
283        CallOuts.GenRefs = GenRefEnds - GenRef2
284        CallOuts.DecRefs = DecRefEnds - DecRef3
285        CallOuts.HexRefs = HexRefEnds - HexRef4
286        # Mark references for deletion, but leave the trailing semicolon as
287        # the point for insertion of the "expansion" text (most often a
288        # single character).
289        CallOuts.delmask = (GenRefEnds | DecRefEnds | HexRefEnds) - lex.RefStart
290        CallOuts.error = Error
291        return CallOuts
292
293
294def demo_refs(u8data):
295        lgth = len(u8data)
296        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
297        (u8, control, lex) = byteclass.classify_bytes(bit)
298        callouts = ref_pass(lex, 0)
299        bitutil.print_aligned_streams([('input data', u8data), 
300                              ('entity refs', bitutil.bitstream2string(callouts.GenRefs, lgth)),
301                              ('decimal char refs', bitutil.bitstream2string(callouts.DecRefs, lgth)),
302                              ('ref delmask', bitutil.bitstream2string(callouts.delmask, lgth)),
303                              ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
304
305
306class tag_callouts:
307        ElemNames = 0
308        AttNames = 0
309        AttVals = 0
310        Tags = 0
311        EmptyTagEnds = 0
312        EndTags = 0
313        error = 0
314
315def parse_tags(lex, CtCDPI_mask, EOF_mask):
316        """Parse start, empty and end tags, calling out element names, attribute
317        names and values, empty tag positions, and tag extents.
318
319        >>> demo_tags("<root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>")
320        input data      : <root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>
321        element names   : _1111__11___________11_______________________________1111__________________
322        attribute names : _______________________11_______11________________________1111_____________
323        attribute values: __________________________11111______11111_____________________111_________
324        empty tag marks : ___________________________________________________________________1_______
325        end tags        : _______________111______________________________111__________________11111_
326        start/empty tags: _1111__11___________1111111111111111111111___________11111111111111________
327        errors          : ____________________________________________________________________________
328
329        Attributes can use double quotes.
330
331        >>> demo_tags('<dquote_atts a1="1234" attribute2="4321"/>')
332        input data      : <dquote_atts a1="1234" attribute2="4321"/>
333        element names   : _11111111111______________________________
334        attribute names : _____________11________1111111111_________
335        attribute values: ________________111111____________111111__
336        empty tag marks : _________________________________________1
337        end tags        : __________________________________________
338        start/empty tags: _1111111111111111111111111111111111111111_
339        errors          : ___________________________________________
340
341        Syntax errors of various types are identified with the error stream.
342
343        1. Element name missing errors.
344
345        >>> demo_tags("< noname='flawed'/> ")
346        input data      : < noname='flawed'/>
347        element names   : ____________________
348        attribute names : __111111____________
349        attribute values: _________11111111___
350        empty tag marks : __________________1_
351        end tags        : ____________________
352        start/empty tags: _11111111111111111__
353        errors          : _1___________________
354
355        2. Missing attribute names.
356
357        >>> demo_tags("<noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>")
358        input data      : <noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>
359        element names   : _11111_______________1111111___________________________________
360        attribute names : _____________________________11________________________________
361        attribute values: ________11111111________________111111___11111_________________
362        empty tag marks : _________________1_____________________________________________
363        end tags        : ______________________________________________________11111111_
364        start/empty tags: _1111111111111111____1111111111111111111111111_________________
365        errors          : _______1_______________________________1________________________
366
367        3. Missing or incorrect = sign.
368
369        >>> demo_tags('<errata plusforeq+"5678" noequals"90" />')
370        input data      : <errata plusforeq+"5678" noequals"90" />
371        element names   : _111111_________________________________
372        attribute names : ________111111111________11111111_______
373        attribute values: __________________111111__________111111
374        empty tag marks : ________________________________________
375        end tags        : ________________________________________
376        start/empty tags: _111111111111111111111111111111111111111
377        errors          : _________________1_______________11______
378
379        4.  Missing whitespace
380
381        >>> demo_tags("<jammed att='value'att2='v2' />")
382        input data      : <jammed att='value'att2='v2' />
383        element names   : _111111________________________
384        attribute names : ________111________1111________
385        attribute values: ____________1111111_____1111___
386        empty tag marks : ______________________________1
387        end tags        : _______________________________
388        start/empty tags: _11111111111111111111111111111_
389        errors          : ___________________1____________
390
391        5.  Extra whitespace in an empty tag.
392
393        >>> demo_tags("<extrawhite / >")
394        input data      : <extrawhite / >
395        element names   : _1111111111____
396        attribute names : _______________
397        attribute values: _______________
398        empty tag marks : _____________1_
399        end tags        : _______________
400        start/empty tags: _111111111111__
401        errors          : _____________1__
402
403        6.  Unterminated or incorrectly terminated attribute values
404
405        >>> demo_tags("<badattvalues a='blud<   b='455>   ")
406        input data      : <badattvalues a='blud<   b='455>   
407        element names   : _111111111111______________________
408        attribute names : ______________1__________1_________
409        attribute values: ________________111111_____11111111
410        empty tag marks : ___________________________________
411        end tags        : ___________________________________
412        start/empty tags: _111111111111111111111_111111111111
413        errors          : _____________________11____________1
414
415        7.  Unterminated tags
416
417        >>> demo_tags("<unterminated a='245'  ")
418        input data      : <unterminated a='245' 
419        element names   : _111111111111__________
420        attribute names : ______________1________
421        attribute values: ________________11111__
422        empty tag marks : _______________________
423        end tags        : _______________________
424        start/empty tags: _1111111111111111111111
425        errors          : _______________________1
426
427"""
428        callouts = tag_callouts()
429       
430        # Delimiters for scans.
431        DQuoteScan = ~(lex.DQuote | lex.LAngle) & EOF_mask
432        SQuoteScan = ~(lex.SQuote | lex.LAngle) & EOF_mask
433        AttListDelim = lex.Slash | lex.RAngle
434       
435        # Start the parallel parsing by inspecting the character
436        # after the opening "<" of a tag.
437        LAngleFollow = bitutil.Advance(lex.LAngle) &~ CtCDPI_mask
438        ElemNamePositions = LAngleFollow & ~lex.Slash
439        EndTagSeconds = LAngleFollow & lex.Slash
440       
441        # Start Tag/Empty Element Tag Parsing
442
443        # Advance all cursors by scanning through the tag name.
444        ElemNameFollows = bitutil.ScanThru(ElemNamePositions, lex.NameScan)
445        # Must have at least one name character for a legal start tag.
446        # Mark any occurrences of null names as errors.
447        ParseError = ElemNamePositions & ElemNameFollows
448        callouts.ElemNames = ElemNameFollows - ElemNamePositions
449       
450        # Initialize the accumulators for attribute name and value positions.
451        AttNameStarts = 0 
452        AttNameFollows = 0
453        EqToCheck = 0
454        AttValStarts = 0
455        AttValEnds = 0
456        AttValFollows = 0
457
458        # After the element name, there may or may not be an attlist.
459        AfterWS = bitutil.ScanThru(ElemNameFollows, lex.WS)
460        AttListEnd = AfterWS & AttListDelim
461        AttNameStart = AfterWS & ~AttListDelim
462        # At least one WS character is required between ElemNames and AttNames.
463        ParseError |= ElemNameFollows & AttNameStart
464
465        #
466        # The following loop iterates through attributes within a start tag.
467        # Because all start tags are processed in parallel, the number of
468        # iterations is the maximum number of attributes found in any one
469        # start tag, plus one.
470        while AttNameStart > 0:
471                AttNameStarts |= AttNameStart
472                AttNameFollow = bitutil.ScanThru(AttNameStart, lex.NameScan)
473                AttNameFollows |= AttNameFollow
474                # Scan through WS to the expected '=' delimiter.
475                EqExpected = bitutil.ScanThru(AttNameFollow, lex.WS)
476                EqToCheck |= EqExpected
477                AttValPos = bitutil.ScanThru(bitutil.Advance(EqExpected), lex.WS)
478                AttValStarts |= AttValPos
479                DQuoteAttVal = AttValPos & lex.DQuote
480                SQuoteAttVal = AttValPos & lex.SQuote
481                DQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(DQuoteAttVal), DQuoteScan)
482                SQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(SQuoteAttVal), SQuoteScan)
483                AttValEnd = DQuoteAttEnd | SQuoteAttEnd
484                AttValEnds |= AttValEnd
485                AttValFollow = bitutil.Advance(AttValEnd)
486                AttValFollows |= AttValFollow
487                AfterWS = bitutil.ScanThru(AttValFollow, lex.WS)
488                AttListEnd |= AfterWS & AttListDelim
489                AttNameStart = AfterWS & ~AttListDelim
490
491        # No more attribute values to process when AttNameStart == 0.
492
493        callouts.AttNames = AttNameFollows - AttNameStarts
494        callouts.AttVals = AttValFollows - AttValStarts
495        STagEnds = AttListEnd & lex.RAngle
496        # Mark any "/" characters found as the ends of empty element tags.
497        callouts.EmptyTagMarks = bitutil.Advance(AttListEnd & lex.Slash)
498        callouts.Tags = (STagEnds | callouts.EmptyTagMarks) - ElemNamePositions
499
500        # Check for errors.
501        ParseError |= AttValFollows & AttNameStarts # No intervening WS.
502        ParseError |= AttNameStarts & AttNameFollows # Null AttName
503        ParseError |= EqToCheck & ~lex.Equals # = not found where expected.
504        ParseError |= AttValStarts & ~ (lex.DQuote | lex.SQuote)
505        ParseError |= AttValEnds & ~ (lex.DQuote | lex.SQuote)
506        ParseError |= callouts.EmptyTagMarks & ~lex.RAngle
507
508        # End Tag Parsing
509        EndTagEnds = bitutil.ScanThru(bitutil.ScanThru(bitutil.Advance(EndTagSeconds), lex.NameScan), lex.WS)
510        ParseError |= EndTagEnds & ~lex.RAngle
511        callouts.EndTags = EndTagEnds - EndTagSeconds
512        callouts.error = ParseError
513       
514        return callouts
515
516
517def demo_tags(u8data):
518        lgth = len(u8data)
519        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
520        (u8, control, lex) = byteclass.classify_bytes(bit)
521        lex = add_multiliterals(lex)
522        markup1 = parse_CtCDPI(lex, EOF_mask)
523        callouts = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
524        bitutil.print_aligned_streams([('input data', u8data), 
525                              ('element names', bitutil.bitstream2string(callouts.ElemNames, lgth)),
526                              ('attribute names', bitutil.bitstream2string(callouts.AttNames, lgth)),
527                              ('attribute values', bitutil.bitstream2string(callouts.AttVals, lgth)),
528                              ('empty tag marks', bitutil.bitstream2string(callouts.EmptyTagMarks, lgth)),
529                              ('end tags', bitutil.bitstream2string(callouts.EndTags, lgth)),
530                              ('start/empty tags', bitutil.bitstream2string(callouts.Tags, lgth)),
531                              ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
532
533
534
535def validate_no_CD_end(lex, markup1, tags):
536        """Find illegal occurrences of ]]> in text (outside of markup).
537
538        >>> demo_validate_no_CD_end(' <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?> ')
539        input data :  <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?>
540        CtCDPI_mask: __1111111111111111__111111111111111_______________________________11111111111_
541        tags       : __________________________________________1111111111111111____________________
542        illegal ]]>: _______________________________________1______________________1_______________
543"""
544        return lex.CD_end & ~(markup1.CtCDPI_mask | tags.Tags)
545
546
547def demo_validate_no_CD_end(u8data):
548        lgth = len(u8data)
549        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
550        (u8, control, lex) = byteclass.classify_bytes(bit)
551        lex = add_multiliterals(lex)
552        markup1 = parse_CtCDPI(lex, EOF_mask)
553        tags = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
554        error = validate_no_CD_end(lex, markup1, tags)
555        bitutil.print_aligned_streams([('input data', u8data), 
556                              ('CtCDPI_mask', bitutil.bitstream2string(markup1.CtCDPI_mask, lgth)),
557                              ('tags', bitutil.bitstream2string(tags.Tags, lgth)),
558                              ('illegal ]]>', bitutil.bitstream2string(error, lgth))])
559
560
561
562if __name__ == "__main__":
563    import doctest
564    doctest.testmod()
Note: See TracBrowser for help on using the repository browser.