source: proto/parabix2/parabix2.py @ 278

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

Add u8u16 version consistent with parabix2

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