2004-12-06 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / Commons.Xml.Relaxng / Commons.Xml.Relaxng.Derivative / RdpPatterns.cs
1 //\r
2 // Commons.Xml.Relaxng.Derivative.RdpPatterns.cs\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>\r
6 //\r
7 // 2003 Atsushi Enomoto "No rights reserved."\r
8 //\r
9 // Copyright (c) 2004 Novell Inc.\r
10 // All rights reserved\r
11 //\r
12
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 \r
34 using System;\r
35 using System.Collections;\r
36 using System.Xml;\r
37 using Commons.Xml.Relaxng;\r
38 \r
39 using LabelList = System.Collections.Hashtable;\r
40 \r
41 \r
42 namespace Commons.Xml.Relaxng.Derivative\r
43 {\r
44         public delegate RdpPattern RdpApplyAfterHandler (RdpPattern p);\r
45 \r
46         // abstract Pattern\r
47         public abstract class RdpPattern\r
48         {\r
49                 internal bool nullableComputed;\r
50                 internal bool isNullable;\r
51                 Hashtable patternPool;\r
52 \r
53                 internal string debug ()\r
54                 {\r
55                         return RdpUtil.DebugRdpPattern (this, new Hashtable ());\r
56                 }\r
57 \r
58                 public abstract RelaxngPatternType PatternType { get; }\r
59 \r
60                 public abstract RdpContentType ContentType { get; }\r
61 \r
62                 private Hashtable setupTable (Type type, RdpPattern p)\r
63                 {\r
64                         // Why?\r
65                         if (patternPool == null) {\r
66                                 patternPool = new Hashtable ();\r
67                         }\r
68 \r
69                         Hashtable typePool = (Hashtable) patternPool [type];\r
70                         if (typePool == null) {\r
71                                 typePool = new Hashtable ();\r
72                                 patternPool [type] = typePool;\r
73                         }\r
74                         Hashtable pTable = (Hashtable) typePool [p];\r
75                         if (pTable == null) {\r
76                                 pTable = new Hashtable ();\r
77                                 typePool [p] = pTable;\r
78                         }\r
79                         return pTable;\r
80                 }\r
81 \r
82                 public RdpChoice MakeChoice (RdpPattern p1, RdpPattern p2)\r
83                 {\r
84                         Hashtable p1Table = setupTable (typeof (RdpChoice), p1);\r
85                         if (p1Table [p2] == null) {\r
86                                 RdpChoice c = new RdpChoice (p1, p2);\r
87                                 c.setInternTable (this.patternPool);\r
88                                 p1Table [p2] = c;\r
89                         }\r
90                         return (RdpChoice) p1Table [p2];\r
91                 }\r
92 \r
93                 public RdpPattern MakeGroup (RdpPattern p1, RdpPattern p2)\r
94                 {\r
95                         Hashtable p1Table = setupTable (typeof (RdpGroup), p1);\r
96                         if (p1Table [p2] == null) {\r
97                                 RdpGroup g = new RdpGroup (p1, p2);\r
98                                 g.setInternTable (this.patternPool);\r
99                                 p1Table [p2] = g;\r
100                         }\r
101                         return (RdpGroup) p1Table [p2];\r
102                 }\r
103 \r
104                 public RdpInterleave MakeInterleave (RdpPattern p1, RdpPattern p2)\r
105                 {\r
106                         Hashtable p1Table = setupTable (typeof (RdpInterleave), p1);\r
107                         if (p1Table [p2] == null) {\r
108                                 RdpInterleave i = new RdpInterleave (p1, p2);\r
109                                 i.setInternTable (this.patternPool);\r
110                                 p1Table [p2] = i;\r
111                         }\r
112                         return (RdpInterleave) p1Table [p2];\r
113                 }\r
114 \r
115                 public RdpAfter MakeAfter (RdpPattern p1, RdpPattern p2)\r
116                 {\r
117                         Hashtable p1Table = setupTable (typeof (RdpAfter), p1);\r
118                         if (p1Table [p2] == null) {\r
119                                 RdpAfter a = new RdpAfter (p1, p2);\r
120                                 a.setInternTable (this.patternPool);\r
121                                 p1Table [p2] = a;\r
122                         }\r
123                         return (RdpAfter) p1Table [p2];\r
124                 }\r
125 \r
126                 public RdpOneOrMore MakeOneOrMore (RdpPattern p)\r
127                 {\r
128                         Hashtable pTable = (Hashtable) patternPool [RelaxngPatternType.OneOrMore];\r
129                         if (pTable == null) {\r
130                                 pTable = new Hashtable ();\r
131                                 patternPool [RelaxngPatternType.OneOrMore] = pTable;\r
132                         }\r
133                         if (pTable [p] == null)\r
134                                 pTable [p] = new RdpOneOrMore (p);\r
135                         return (RdpOneOrMore) pTable [p];\r
136                 }\r
137 \r
138                 internal void setInternTable (Hashtable ht)\r
139                 {\r
140                         this.patternPool = ht;\r
141 \r
142                         Hashtable pt = ht [PatternType] as Hashtable;\r
143                         if (pt == null) {\r
144                                 pt = new Hashtable ();\r
145                                 ht [PatternType] = pt;\r
146                         }\r
147 \r
148                         RdpAbstractSingleContent single =\r
149                                 this as RdpAbstractSingleContent;\r
150                         if (single != null) {\r
151                                 if (pt [single.Child] == null) {\r
152                                         pt [single.Child] = this;\r
153                                         single.Child.setInternTable (ht);\r
154                                 }\r
155                                 return;\r
156                         }\r
157 \r
158                         RdpAbstractBinary binary =\r
159                                 this as RdpAbstractBinary;\r
160                         if (binary != null) {\r
161                                 Hashtable lTable = setupTable (GetType (), binary.LValue);\r
162                                 if (lTable [binary.RValue] == null) {\r
163                                         lTable [binary.RValue] = this;\r
164                                         binary.LValue.setInternTable (ht);\r
165                                         binary.RValue.setInternTable (ht);\r
166                                 }\r
167                                 return;\r
168                         }\r
169 \r
170                         // For rest patterns, only check recursively, without pooling.\r
171                         RdpAttribute attr = this as RdpAttribute;\r
172                         if (attr != null) {\r
173                                 attr.Children.setInternTable (ht);\r
174                                 return;\r
175                         }\r
176                         RdpElement el = this as RdpElement;\r
177                         if (el != null) {\r
178                                 el.Children.setInternTable (ht);\r
179                                 return;\r
180                         }\r
181                         RdpDataExcept dex= this as RdpDataExcept;\r
182                         if (dex != null) {\r
183                                 dex.Except.setInternTable (ht);\r
184                                 return;\r
185                         }\r
186 \r
187                         switch (PatternType) {\r
188                         case RelaxngPatternType.Empty:\r
189                         case RelaxngPatternType.NotAllowed:\r
190                         case RelaxngPatternType.Text:\r
191                         case RelaxngPatternType.Data:\r
192                         case RelaxngPatternType.Value:\r
193                                 return;\r
194                         }\r
195 \r
196 #if REPLACE_IN_ADVANCE\r
197                         throw new InvalidOperationException ();\r
198 #endif\r
199                 }\r
200 \r
201                 internal abstract void MarkReachableDefs ();\r
202 \r
203                 internal abstract void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept);\r
204 \r
205                 internal abstract bool ContainsText ();\r
206 \r
207                 internal virtual RdpPattern ExpandRef (Hashtable defs)\r
208                 {\r
209                         return this;\r
210                 }\r
211 \r
212                 internal virtual RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
213                 {\r
214                         return this;\r
215                 }\r
216 \r
217                 public abstract bool Nullable { get; }\r
218 \r
219                 // fills QName collection\r
220                 public abstract void GetLabels (LabelList elements, LabelList attributes);\r
221 \r
222                 internal void AddNameLabel (LabelList names, RdpNameClass nc)\r
223                 {\r
224                         RdpName name = nc as RdpName;\r
225                         if (name != null) {\r
226                                 XmlQualifiedName qname = new XmlQualifiedName (\r
227                                         name.LocalName, name.NamespaceURI);\r
228                                 names [qname] = qname;\r
229                                 return;\r
230                         }\r
231                         RdpNameClassChoice choice = nc as RdpNameClassChoice;\r
232                         if (choice != null) {\r
233                                 AddNameLabel (names, choice.LValue);\r
234                                 AddNameLabel (names, choice.RValue);\r
235                                 return;\r
236                         }\r
237                         // For NsName and AnyName, do nothing.\r
238                 }\r
239 \r
240                 #region Derivative\r
241                 public virtual RdpPattern TextDeriv (string s, XmlReader reader)\r
242                 {\r
243                         // This is an extension to JJC algorithm.\r
244                         // Whitespace text are allowed except for Data and Value\r
245                         // (their TextDeriv are overridden)\r
246                         return Util.IsWhitespace (s) ? this : RdpNotAllowed.Instance;\r
247                 }\r
248 \r
249 /*\r
250                 public RdpPattern ChildDeriv (RdpChildNode child)\r
251                 {\r
252                         RdpTextChild tc = child as RdpTextChild;\r
253 //                      RdpElementChild ec = child as RdpElementChild;\r
254                         if (tc != null) {\r
255                                 return TextDeriv (tc.Text);\r
256                         } else {\r
257                                 // complex stuff;-(\r
258                                 return StartTagOpenDeriv (ec.LocalName, ec.NamespaceURI)\r
259                                                 .AttsDeriv (ec.Attributes)\r
260                                                 .StartTagCloseDeriv ()\r
261                                         .ChildrenDeriv (ec.ChildNodes)\r
262                                         .EndTagDeriv ();\r
263                         }\r
264                 }\r
265 */\r
266 \r
267                 public RdpPattern ListDeriv (string [] list, int index, XmlReader reader)\r
268                 {\r
269                         return listDerivInternal (list, 0, reader);\r
270                 }\r
271 \r
272                 private RdpPattern listDerivInternal (string [] list, int start, XmlReader reader)\r
273                 {\r
274                         if (list.Length <= start)\r
275                                 return this;\r
276                         else\r
277                                 return this.TextDeriv (list [start], reader).listDerivInternal (list, start + 1, reader);\r
278                 }\r
279 \r
280                 // Choice(this, p)\r
281                 public virtual RdpPattern Choice (RdpPattern p)\r
282                 {\r
283                         if (p is RdpNotAllowed)\r
284                                 return this;\r
285                         else if (this is RdpNotAllowed)\r
286                                 return p;\r
287                         else\r
288                                 return MakeChoice (this, p);\r
289                 }\r
290 \r
291                 // Group(this, p)\r
292                 public virtual RdpPattern Group (RdpPattern p)\r
293                 {\r
294                         if (p is RdpNotAllowed || this is RdpNotAllowed)\r
295                                 return RdpNotAllowed.Instance;\r
296                         else if (p is RdpEmpty)\r
297                                 return this;\r
298                         else if (this is RdpEmpty)\r
299                                 return p;\r
300                         else\r
301                                 return MakeGroup (this, p);\r
302                 }\r
303 \r
304                 // Interleave(this, p)\r
305                 public virtual RdpPattern Interleave (RdpPattern p)\r
306                 {\r
307                         if (p is RdpNotAllowed || this is RdpNotAllowed)\r
308                                 return RdpNotAllowed.Instance;\r
309                         else if (p is RdpEmpty)\r
310                                 return this;\r
311                         else if (this is RdpEmpty)\r
312                                 return p;\r
313                         else\r
314                                 return MakeInterleave (this, p);\r
315                 }\r
316 \r
317                 // After(this, p)\r
318                 public virtual RdpPattern After (RdpPattern p)\r
319                 {\r
320                         if (this is RdpNotAllowed || p is RdpNotAllowed)\r
321                                 return RdpNotAllowed.Instance;\r
322                         else\r
323                                 return MakeAfter (this, p);\r
324                 }\r
325 \r
326 \r
327                 // applyAfter((f, p1=this), p2)\r
328                 public virtual RdpPattern ApplyAfter (RdpApplyAfterHandler h)\r
329                 {\r
330                         return RdpNotAllowed.Instance;\r
331                 }\r
332 \r
333                 // startTagOpenDeriv (this, qname)\r
334                 // startTagOpenDeriv _ qn = NotAllowed (default)\r
335                 public virtual RdpPattern StartTagOpenDeriv (string name, string ns)\r
336                 {\r
337                         return RdpNotAllowed.Instance;\r
338                 }\r
339 \r
340                 // attDeriv(ctx, this, att)\r
341                 // attDeriv _ _ _ = NotAllowed\r
342                 public virtual RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
343                 {\r
344                         return RdpNotAllowed.Instance;\r
345                 }\r
346 \r
347                 public bool ValueMatch (string s, XmlReader reader)\r
348                 {\r
349                         return (Nullable && RdpUtil.Whitespace (s)) ||\r
350                                 TextDeriv (s, reader).Nullable;\r
351                 }\r
352 \r
353                 public virtual RdpPattern StartTagCloseDeriv ()\r
354                 {\r
355                         return this;\r
356                 }\r
357 \r
358                 /*\r
359                 public RdpPattern ChildrenDeriv (RdpChildNodes children)\r
360                 {\r
361                         return childrenDerivInternal (children, 0);\r
362                 }\r
363 \r
364                 RdpPattern childrenDerivInternal (RdpChildNodes children, int start)\r
365                 {\r
366                         if (children.Count == 0) {\r
367                                 // childrenDeriv cx p []\r
368                                 RdpChildNodes c = new RdpChildNodes ();\r
369                                 c.Add (new RdpTextChild (String.Empty));\r
370                                 return ChildrenDeriv (c);\r
371                         } else if (children.Count == 1 && children [0] is RdpTextChild) {\r
372                                 // childrenDeriv cx p [(TextNode s)]\r
373                                 RdpTextChild tc = children [0] as RdpTextChild;\r
374                                 RdpPattern p1 = ChildDeriv (tc);\r
375                                 return RdpUtil.Whitespace (tc.Text) ?\r
376                                         RdpUtil.Choice (this, p1) : p1;\r
377                         } else\r
378                                 // childrenDeriv cx p children\r
379                                 return stripChildrenDerivInternal (children, start);\r
380                 }\r
381 \r
382                 RdpPattern stripChildrenDerivInternal (RdpChildNodes children, int start)\r
383                 {\r
384                         if (children.Count == start)\r
385                                 return this;\r
386                         else {\r
387                                 RdpChildNode firstChild =\r
388                                         children [start] as RdpChildNode;\r
389                                 RdpPattern p =\r
390                                         (firstChild.IsNonWhitespaceText) ?\r
391                                         this : ChildDeriv (firstChild);\r
392                                 return p.childrenDerivInternal (children, start + 1);\r
393                         }\r
394                 }\r
395                 */\r
396 \r
397                 public RdpPattern OneOrMore ()\r
398                 {\r
399                         if (PatternType == RelaxngPatternType.NotAllowed)\r
400                                 return RdpNotAllowed.Instance;\r
401                         else\r
402                                 return MakeOneOrMore (this);\r
403                 }\r
404 \r
405                 public virtual RdpPattern EndTagDeriv ()\r
406                 {\r
407                         return RdpNotAllowed.Instance;\r
408                 }\r
409                 #endregion\r
410         }\r
411 \r
412         // Empty\r
413         public class RdpEmpty : RdpPattern\r
414         {\r
415                 public RdpEmpty () {}\r
416                 static RdpEmpty ()\r
417                 {\r
418                         instance = new RdpEmpty ();\r
419                 }\r
420 \r
421                 public override bool Nullable {\r
422                         get { return true; }\r
423                 }\r
424 \r
425                 static RdpEmpty instance;\r
426                 public static RdpEmpty Instance {\r
427                         get { return instance; }\r
428                 }\r
429 \r
430                 public override RelaxngPatternType PatternType {\r
431                         get { return RelaxngPatternType.Empty; }\r
432                 }\r
433 \r
434                 public override RdpContentType ContentType {\r
435                         get { return RdpContentType.Empty; }\r
436                 }\r
437 \r
438                 public override void GetLabels (LabelList elements, LabelList attributes)\r
439                 {\r
440                         // do nothing\r
441                 }\r
442 \r
443                 internal override void MarkReachableDefs () \r
444                 {\r
445                         // do nothing\r
446                 }\r
447 \r
448                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
449                 {\r
450                         if (dataExcept)\r
451                                 throw new RelaxngException ("empty cannot appear under except of a data pattern.");\r
452                 }\r
453 \r
454                 internal override bool ContainsText()\r
455                 {\r
456                         return false;\r
457                 }\r
458         }\r
459 \r
460         // NotAllowed\r
461         public class RdpNotAllowed : RdpPattern\r
462         {\r
463                 public RdpNotAllowed () {}\r
464                 static RdpNotAllowed ()\r
465                 {\r
466                         instance = new RdpNotAllowed ();\r
467                 }\r
468 \r
469                 static RdpNotAllowed instance;\r
470                 public static RdpNotAllowed Instance {\r
471                         get { return instance; }\r
472                 }\r
473 \r
474                 public override bool Nullable {\r
475                         get { return false; }\r
476                 }\r
477 \r
478                 public override RdpPattern ApplyAfter (RdpApplyAfterHandler h)\r
479                 {\r
480                         return RdpNotAllowed.Instance;\r
481                 }\r
482 \r
483                 public override RelaxngPatternType PatternType {\r
484                         get { return RelaxngPatternType.NotAllowed; }\r
485                 }\r
486 \r
487                 public override RdpContentType ContentType {\r
488                         get { return RdpContentType.Empty; }\r
489                 }\r
490 \r
491                 internal override void MarkReachableDefs () \r
492                 {\r
493                         // do nothing\r
494                 }\r
495 \r
496                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
497                 {\r
498                         // do nothing\r
499                 }\r
500 \r
501                 internal override bool ContainsText()\r
502                 {\r
503                         return false;\r
504                 }\r
505 \r
506                 public override void GetLabels (LabelList elements, LabelList attributes)\r
507                 {\r
508                         // FIXME: Supposed to clear something here?\r
509                 }\r
510         }\r
511 \r
512         // Text\r
513         public class RdpText : RdpPattern\r
514         {\r
515                 static RdpText instance;\r
516                 public static RdpText Instance {\r
517                         get { return instance; }\r
518                 }\r
519 \r
520                 public RdpText () {}\r
521                 static RdpText ()\r
522                 {\r
523                         instance = new RdpText ();\r
524                 }\r
525 \r
526                 public override bool Nullable {\r
527                         get { return true; }\r
528                 }\r
529 \r
530                 public override RelaxngPatternType PatternType {\r
531                         get { return RelaxngPatternType.Text; }\r
532                 }\r
533 \r
534                 public override RdpContentType ContentType {\r
535                         get { return RdpContentType.Complex; }\r
536                 }\r
537 \r
538                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
539                 {\r
540                         return this;\r
541                 }\r
542 \r
543                 internal override void MarkReachableDefs () \r
544                 {\r
545                         // do nothing\r
546                 }\r
547 \r
548                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
549                 {\r
550                         if (list)\r
551                                 throw new RelaxngException ("text is not allowed under a list.");\r
552                         if (dataExcept)\r
553                                 throw new RelaxngException ("text is not allowed under except of a list.");\r
554                 }\r
555 \r
556                 internal override bool ContainsText()\r
557                 {\r
558                         return true;\r
559                 }\r
560 \r
561                 public override void GetLabels (LabelList elements, LabelList attributes)\r
562                 {\r
563                         // do nothing\r
564                 }\r
565         }\r
566 \r
567         // AbstractBinary\r
568         public abstract class RdpAbstractBinary : RdpPattern\r
569         {\r
570                 public RdpAbstractBinary (RdpPattern l, RdpPattern r)\r
571                 {\r
572                         this.l = l;\r
573                         this.r = r;\r
574                 }\r
575 \r
576                 RdpPattern l;\r
577                 public RdpPattern LValue {\r
578                         get { return l; }\r
579                         set { l = value; }\r
580                 }\r
581 \r
582                 RdpPattern r;\r
583                 public RdpPattern RValue {\r
584                         get { return r; }\r
585                         set { r = value; }\r
586                 }\r
587 \r
588                 public override RdpContentType ContentType {\r
589                         get {\r
590                                 if (l.ContentType == RdpContentType.Empty)\r
591                                         return r.ContentType;\r
592                                 if (r.ContentType == RdpContentType.Empty)\r
593                                         return l.ContentType;\r
594 \r
595                                 if ((l.ContentType & RdpContentType.Simple) != 0 || ((r.ContentType & RdpContentType.Simple) != 0))\r
596                                         throw new RelaxngException ("The content type of this group is invalid.");\r
597                                 return RdpContentType.Complex;\r
598                         }\r
599                 }\r
600 \r
601                 bool expanded;\r
602                 internal override RdpPattern ExpandRef (Hashtable defs)\r
603                 {\r
604                         if (!expanded) {\r
605                                 l = l.ExpandRef (defs);\r
606                                 r = r.ExpandRef (defs);\r
607                         }\r
608                         return this;\r
609                 }\r
610 \r
611                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
612                 {\r
613                         if (visited.Contains (this))\r
614                                 return this;\r
615                         visited.Add (this, this);\r
616 \r
617                         if (LValue.PatternType == RelaxngPatternType.NotAllowed ||\r
618                                 RValue.PatternType == RelaxngPatternType.NotAllowed) {\r
619                                 result = true;\r
620                                 return RdpNotAllowed.Instance;\r
621                         } else if (LValue.PatternType == RelaxngPatternType.Empty) {\r
622                                 result = true;\r
623                                 return RValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
624                         } else if (RValue.PatternType == RelaxngPatternType.Empty) {\r
625                                 result = true;\r
626                                 return LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
627                         } else {\r
628                                 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
629                                 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
630                                 return this;\r
631                         }\r
632                 }\r
633 \r
634                 internal override void MarkReachableDefs () \r
635                 {\r
636                         l.MarkReachableDefs ();\r
637                         r.MarkReachableDefs ();\r
638                 }\r
639 \r
640                 internal override bool ContainsText()\r
641                 {\r
642                         return l.ContainsText () || r.ContainsText ();\r
643                 }\r
644         }\r
645 \r
646         // Choice\r
647         public class RdpChoice : RdpAbstractBinary\r
648         {\r
649                 public RdpChoice (RdpPattern l, RdpPattern r) : base (l, r)\r
650                 {\r
651                 }\r
652 \r
653                 public override bool Nullable {\r
654                         get {\r
655                                 if (!nullableComputed) {\r
656                                         isNullable =\r
657                                                 LValue.Nullable || RValue.Nullable;\r
658                                         nullableComputed = true;\r
659                                 }\r
660                                 return isNullable;\r
661                         }\r
662                 }\r
663 \r
664                 public override RelaxngPatternType PatternType {\r
665                         get { return RelaxngPatternType.Choice; }\r
666                 }\r
667 \r
668                 public override RdpContentType ContentType {\r
669                         get {\r
670                                 if (LValue.ContentType == RdpContentType.Simple ||\r
671                                         RValue.ContentType == RdpContentType.Simple)\r
672                                         return RdpContentType.Simple;\r
673                                 return base.ContentType;\r
674                         }\r
675                 }\r
676 \r
677                 public override void GetLabels (LabelList elements, LabelList attributes)\r
678                 {\r
679                         LValue.GetLabels (elements, attributes);\r
680                         RValue.GetLabels (elements, attributes);\r
681                 }\r
682 \r
683 \r
684                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
685                 {\r
686                         if (visited.Contains (this))\r
687                                 return this;\r
688                         visited.Add (this, this);\r
689 \r
690                         if (LValue.PatternType == RelaxngPatternType.NotAllowed &&\r
691                                 RValue.PatternType == RelaxngPatternType.NotAllowed) {\r
692                                 result = true;\r
693                                 return RdpNotAllowed.Instance;\r
694                         } else if (LValue.PatternType == RelaxngPatternType.NotAllowed) {\r
695                                 result = true;\r
696                                 return RValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
697                         } else if (RValue.PatternType == RelaxngPatternType.NotAllowed) {\r
698                                 result = true;\r
699                                 return LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
700                         } else if (LValue.PatternType == RelaxngPatternType.Empty &&\r
701                                 RValue.PatternType == RelaxngPatternType.Empty) {\r
702                                 result = true;\r
703                                 return RdpEmpty.Instance;\r
704                         } else if (RValue.PatternType == RelaxngPatternType.Empty) {\r
705                                 result = true;\r
706                                 RValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
707                                 LValue = RdpEmpty.Instance;\r
708                                 return this;\r
709                         } else {\r
710                                 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
711                                 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
712                                 return this;\r
713                         }\r
714                 }\r
715 \r
716                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
717                 {\r
718                         return LValue.TextDeriv (s, reader).Choice (RValue.TextDeriv (s, reader));\r
719                 }\r
720 \r
721                 public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)\r
722                 {\r
723 //                      return handler (LValue).Choice (handler (RValue));\r
724                         return LValue.ApplyAfter (handler).Choice (RValue.ApplyAfter (handler));\r
725                 }\r
726 \r
727                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
728                 {\r
729 #if UseStatic\r
730                         return RdpUtil.Choice (\r
731                                 RdpUtil.StartTagOpenDeriv (LValue, qname),\r
732                                 RdpUtil.StartTagOpenDeriv (RValue, qname));\r
733 #else\r
734                         RdpPattern lDeriv = LValue.StartTagOpenDeriv (name, ns);\r
735                         return lDeriv.Choice (RValue.StartTagOpenDeriv (name, ns));\r
736 #endif\r
737                 }\r
738 \r
739                 // attDeriv cx (Choice p1 p2) att =\r
740                 //  choice (attDeriv cx p1 att) (attDeriv cx p2 att)\r
741                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
742                 {\r
743                         return LValue.AttDeriv (name, ns, value, reader)\r
744                                 .Choice (RValue.AttDeriv (name, ns, value, reader));\r
745                 }\r
746 \r
747                 // startTagCloseDeriv (Choice p1 p2) =\r
748                 //  choice (startTagCloseDeriv p1) (startTagCloseDeriv p2)\r
749                 public override RdpPattern StartTagCloseDeriv ()\r
750                 {\r
751                         return LValue.StartTagCloseDeriv ()\r
752                                 .Choice (RValue.StartTagCloseDeriv ());\r
753                 }\r
754 \r
755                 public override RdpPattern EndTagDeriv ()\r
756                 {\r
757                         return LValue.EndTagDeriv ().Choice (RValue.EndTagDeriv ());\r
758                 }\r
759 \r
760                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
761                 {\r
762                         LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);\r
763                         RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);\r
764                 }\r
765         }\r
766 \r
767         // Interleave\r
768         public class RdpInterleave : RdpAbstractBinary\r
769         {\r
770                 public RdpInterleave (RdpPattern l, RdpPattern r) : base (l, r)\r
771                 {\r
772                 }\r
773 \r
774                 public override bool Nullable {\r
775                         get {\r
776                                 if (!nullableComputed) {\r
777                                         isNullable =\r
778                                                 LValue.Nullable && RValue.Nullable;\r
779                                         nullableComputed = true;\r
780                                 }\r
781                                 return isNullable;\r
782                         }\r
783                 }\r
784 \r
785                 public override void GetLabels (LabelList elements, LabelList attributes)\r
786                 {\r
787                         LValue.GetLabels (elements, attributes);\r
788                         RValue.GetLabels (elements, attributes);\r
789                 }\r
790 \r
791                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
792                 {\r
793                         if (visited.Contains (this))\r
794                                 return this;\r
795                         visited.Add (this, this);\r
796 \r
797                         if (LValue.PatternType == RelaxngPatternType.NotAllowed ||\r
798                                 RValue.PatternType == RelaxngPatternType.NotAllowed) {\r
799                                 result = true;\r
800                                 return RdpNotAllowed.Instance;\r
801                         } else {\r
802                                 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
803                                 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);\r
804                                 return this;\r
805                         }\r
806                 }\r
807 \r
808                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
809                 {\r
810                         return LValue.TextDeriv (s, reader).Interleave (RValue)\r
811                                 .Choice (LValue.Interleave (RValue.TextDeriv (s, reader)));\r
812                 }\r
813 \r
814                 // => choice (applyAfter (flip interleave p2) (startTagOpenDeriv p1 qn)) (applyAfter (interleave p1) (startTagOpenDeriv p2 qn)\r
815                 // => p1.startTagOpenDeriv(qn).applyAfter (flip interleave p2).choice (p2.startTagOpenDeriv(qn).applyAfter (interleave p1) )\r
816                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
817                 {\r
818                         RdpPattern handledL = LValue.StartTagOpenDeriv (name, ns);\r
819                         RdpPattern handledR = RValue.StartTagOpenDeriv (name, ns);\r
820                         RdpFlip flipL = new RdpFlip (new RdpBinaryFunction (RdpUtil.Interleave), RValue);\r
821                         RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));\r
822                         RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));\r
823                         return choiceL.Choice (choiceR);\r
824                 }\r
825 \r
826                 // attDeriv cx (Interleave p1 p2) att =\r
827                 //  choice (interleave (attDeriv cx p1 att) p2)\r
828                 //         (interleave p1 (attDeriv cx p2 att))\r
829                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
830                 {\r
831                         return LValue.AttDeriv (name, ns, value, reader)\r
832                                 .Interleave (RValue)\r
833                                 .Choice (LValue.Interleave (\r
834                                         RValue.AttDeriv (name, ns, value, reader)));\r
835                 }\r
836 \r
837                 // startTagCloseDeriv (Interleave p1 p2) =\r
838                 //  interleave (startTagCloseDeriv p1) (startTagCloseDeriv p2)\r
839                 public override RdpPattern StartTagCloseDeriv ()\r
840                 {\r
841                         return LValue.StartTagCloseDeriv ()\r
842                                 .Interleave (RValue.StartTagCloseDeriv ());\r
843                 }\r
844 \r
845                 /*\r
846                 // FIXME: This is not specified in James Clark's algorithm, so\r
847                 // this may raise unstable behaviour!!\r
848                 // I think this is right but not confident.\r
849                 \r
850                 // ... then I reminded to include it.\r
851                 public override RdpPattern EndTagDeriv ()\r
852                 {\r
853                         return LValue.Nullable ? RValue : RdpNotAllowed.Instance;\r
854                 }\r
855                 */\r
856 \r
857                 public override RelaxngPatternType PatternType {\r
858                         get { return RelaxngPatternType.Interleave; }\r
859                 }\r
860 \r
861                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
862                 {\r
863                         if (list)\r
864                                 throw new RelaxngException ("interleave is not allowed under a list.");\r
865                         if (dataExcept)\r
866                                 throw new RelaxngException ("interleave is not allowed under except of a data.");\r
867 \r
868                         // 7.1\r
869                         LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);\r
870                         RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);\r
871 \r
872                         // 7.4\r
873                         // TODO: (1) unique name analysis\r
874                         // (2) text/text prohibited\r
875                         if (LValue.PatternType == RelaxngPatternType.Text && RValue.PatternType == RelaxngPatternType.Text)\r
876                                 throw new RelaxngException ("Both branches of the interleave contains a text pattern.");\r
877                 }\r
878         }\r
879 \r
880         // Group\r
881         public class RdpGroup : RdpAbstractBinary\r
882         {\r
883                 public RdpGroup (RdpPattern l, RdpPattern r) : base (l, r)\r
884                 {\r
885                 }\r
886 \r
887                 public override bool Nullable {\r
888                         get {\r
889                                 if (!nullableComputed) {\r
890                                         isNullable =\r
891                                                 LValue.Nullable && RValue.Nullable;\r
892                                         nullableComputed = true;\r
893                                 }\r
894                                 return isNullable;\r
895                         }\r
896                 }\r
897 \r
898                 public override void GetLabels (LabelList elements, LabelList attributes)\r
899                 {\r
900                         LValue.GetLabels (elements, attributes);\r
901                         if (LValue.Nullable)\r
902                                 RValue.GetLabels (elements, attributes);\r
903                 }\r
904 \r
905                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
906                 {\r
907                         RdpPattern p = LValue.TextDeriv (s, reader).Group (RValue);\r
908                         return p.Nullable ?\r
909                                 p.Choice (RValue.TextDeriv(s, reader)) : p;\r
910                 }\r
911 \r
912                 // startTagOpenDeriv (Group p1 p2) qn =\r
913                 //  let x = applyAfter (flip group p2) (startTagOpenDeriv p1 qn)\r
914                 //  in if nullable p1 then\r
915                 //       choice x (startTagOpenDeriv p2 qn)\r
916                 //     else\r
917                 //       x\r
918                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
919                 {\r
920                         RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);\r
921                         RdpFlip f = new RdpFlip (new RdpBinaryFunction (RdpUtil.Group), RValue);\r
922                         RdpPattern x = handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));\r
923                         if (LValue.Nullable)\r
924                                 return x.Choice (RValue.StartTagOpenDeriv (name, ns));\r
925                         else\r
926                                 return x;\r
927                 }\r
928 \r
929                 // attDeriv cx (Group p1 p2) att =\r
930                 //  choice (group (attDeriv cx p1 att) p2)\r
931                 //         (group p1 (attDeriv cx p2 att))\r
932                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
933                 {\r
934                         return LValue.AttDeriv (name, ns, value, reader).Group (RValue)\r
935                                 .Choice (LValue.Group (\r
936                                         RValue.AttDeriv (name, ns, value, reader)));\r
937                 }\r
938 \r
939                 // startTagCloseDeriv (Group p1 p2) =\r
940                 //  group (startTagCloseDeriv p1) (startTagCloseDeriv p2)\r
941                 public override RdpPattern StartTagCloseDeriv ()\r
942                 {\r
943                         return LValue.StartTagCloseDeriv ()\r
944                                 .Group (RValue.StartTagCloseDeriv ());\r
945                 }\r
946 \r
947                 public override RelaxngPatternType PatternType {\r
948                         get { return RelaxngPatternType.Group; }\r
949                 }\r
950 \r
951                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
952                 {\r
953                         if (dataExcept)\r
954                                 throw new RelaxngException ("interleave is not allowed under except of a data.");\r
955 \r
956                         LValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);\r
957                         RValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);\r
958                 }\r
959         }\r
960 \r
961         public abstract class RdpAbstractSingleContent : RdpPattern\r
962         {\r
963                 RdpPattern child;\r
964                 bool isExpanded;\r
965 \r
966                 internal override RdpPattern ExpandRef (Hashtable defs)\r
967                 {\r
968                         if (!isExpanded)\r
969                                 child = child.ExpandRef (defs);\r
970                         return this;\r
971                 }\r
972 \r
973                 public RdpAbstractSingleContent (RdpPattern p)\r
974                 {\r
975                         this.child = p;\r
976                 }\r
977 \r
978                 public RdpPattern Child {\r
979                         get { return child; }\r
980                         set { child = value; }\r
981                 }\r
982 \r
983                 internal override void MarkReachableDefs () \r
984                 {\r
985                         child.MarkReachableDefs ();\r
986                 }\r
987 \r
988                 internal override bool ContainsText()\r
989                 {\r
990                         return child.ContainsText ();\r
991                 }\r
992         }\r
993 \r
994         // OneOrMore\r
995         public class RdpOneOrMore : RdpAbstractSingleContent\r
996         {\r
997                 public RdpOneOrMore (RdpPattern p) : base (p)\r
998                 {\r
999                 }\r
1000 \r
1001                 public override RelaxngPatternType PatternType {\r
1002                         get { return RelaxngPatternType.OneOrMore; }\r
1003                 }\r
1004 \r
1005                 public override RdpContentType ContentType {\r
1006                         get {\r
1007                                 if (Child.ContentType == RdpContentType.Simple)\r
1008                                         throw new RelaxngException ("Invalid content type was found.");\r
1009                                 return Child.ContentType;\r
1010                         }\r
1011                 }\r
1012 \r
1013                 public override bool Nullable {\r
1014                         get { return Child.Nullable; }\r
1015                 }\r
1016 \r
1017                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1018                 {\r
1019                         Child.GetLabels (elements, attributes);\r
1020                 }\r
1021 \r
1022                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
1023                 {\r
1024                         if (visited.Contains (this))\r
1025                                 return this;\r
1026                         visited.Add (this, this);\r
1027 \r
1028                         if (Child.PatternType == RelaxngPatternType.NotAllowed) {\r
1029                                 result = true;\r
1030                                 return RdpNotAllowed.Instance;\r
1031                         } else if (Child.PatternType == RelaxngPatternType.Empty)\r
1032                                 return RdpEmpty.Instance;\r
1033                         else {\r
1034                                 Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);\r
1035                                 return this;\r
1036                         }\r
1037                 }\r
1038 \r
1039                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1040                 {\r
1041                         return Child.TextDeriv (s, reader).Group (Choice (RdpEmpty.Instance));\r
1042                 }\r
1043 \r
1044                 // attDeriv cx (OneOrMore p) att =\r
1045                 //  group (attDeriv cx p att) (choice (OneOrMore p) Empty)\r
1046                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
1047                 {\r
1048 #if UseStatic\r
1049                         return RdpUtil.Group (\r
1050                                 RdpUtil.AttDeriv (ctx, children, att),\r
1051                                 RdpUtil.Choice (RdpUtil.OneOrMore (children), RdpEmpty.Instance));\r
1052 #else\r
1053                         return Child.AttDeriv (name, ns, value, reader)\r
1054                                 .Group (Choice (RdpEmpty.Instance));\r
1055 #endif\r
1056                 }\r
1057 \r
1058                 // startTagOpenDeriv (OneOrMore p) qn =\r
1059                 //  applyAfter (flip group (choice (OneOrMore p) Empty))\r
1060                 //             (startTagOpenDeriv p qn)\r
1061                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
1062                 {\r
1063                         RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());\r
1064                         RdpPattern handled = Child.StartTagOpenDeriv (name, ns);\r
1065                         RdpFlip f = new RdpFlip (new RdpBinaryFunction (RdpUtil.Group), rest);\r
1066                         return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));\r
1067                 }\r
1068 \r
1069                 // startTagCloseDeriv (OneOrMore p) =\r
1070                 //  oneOrMore (startTagCloseDeriv p)\r
1071                 public override RdpPattern StartTagCloseDeriv ()\r
1072                 {\r
1073 #if UseStatic\r
1074                         return RdpUtil.OneOrMore (\r
1075                                 RdpUtil.StartTagCloseDeriv (children));\r
1076 #else\r
1077                         return Child.StartTagCloseDeriv ().OneOrMore ();\r
1078 #endif\r
1079                 }\r
1080 \r
1081                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
1082                 {\r
1083                         if (dataExcept)\r
1084                                 throw new RelaxngException ("oneOrMore is not allowed under except of a data.");\r
1085                         this.Child.CheckConstraints (attribute, true, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);\r
1086                 }\r
1087 \r
1088         }\r
1089 \r
1090         // List\r
1091         public class RdpList : RdpAbstractSingleContent\r
1092         {\r
1093                 public RdpList (RdpPattern p) : base (p)\r
1094                 {\r
1095                 }\r
1096 \r
1097                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
1098                 {\r
1099                         if (visited.Contains (this))\r
1100                                 return this;\r
1101                         visited.Add (this, this);\r
1102 \r
1103                         if (Child.PatternType == RelaxngPatternType.NotAllowed) {\r
1104                                 result = true;\r
1105                                 return RdpNotAllowed.Instance;\r
1106                         } else {\r
1107                                 Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);\r
1108                                 return this;\r
1109                         }\r
1110                 }\r
1111 \r
1112 /*\r
1113                 // This is not written in James Clark's derivative algorithm\r
1114                 // ( http://www.thaiopensource.com/relaxng/derivative.html ),\r
1115                 // but it looks required.\r
1116                 public override bool Nullable {\r
1117                         get { return this.Child.Nullable; }\r
1118                 }\r
1119                 \r
1120                 // ... but it also causes different error:\r
1121                 // <list><group><data .../><data .../></group></list>\r
1122 */\r
1123                 public override bool Nullable {\r
1124                         get { return false; }\r
1125                 }\r
1126 \r
1127                 public override RelaxngPatternType PatternType {\r
1128                         get { return RelaxngPatternType.List; }\r
1129                 }\r
1130 \r
1131                 public override RdpContentType ContentType {\r
1132                         get { return RdpContentType.Simple; }\r
1133                 }\r
1134 \r
1135                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1136                 {\r
1137                         Child.GetLabels (elements, attributes);\r
1138                 }\r
1139 \r
1140                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1141                 {\r
1142                         RdpPattern p = Child.ListDeriv (Util.NormalizeWhitespace (s).Split (RdpUtil.WhitespaceChars), 0, reader);                       \r
1143                         if (p.Nullable)\r
1144                                 return RdpEmpty.Instance;\r
1145                         else\r
1146                                 return RdpNotAllowed.Instance;\r
1147                 }\r
1148 \r
1149                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
1150                 {\r
1151                         if (list)\r
1152                                 throw new RelaxngException ("list is not allowed uner another list.");\r
1153                         if (dataExcept)\r
1154                                 throw new RelaxngException ("list is not allowed under except of a data.");\r
1155                         this.Child.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, true, dataExcept);\r
1156                 }\r
1157         }\r
1158 \r
1159         // Data\r
1160         public class RdpData : RdpPattern\r
1161         {\r
1162                 public RdpData (RdpDatatype dt)\r
1163                 {\r
1164                         this.dt = dt;\r
1165                 }\r
1166 \r
1167                 RdpDatatype dt;\r
1168                 public RdpDatatype Datatype {\r
1169                         get { return dt; }\r
1170                 }\r
1171 \r
1172                 // This is not written in James Clark's derivative algorithm\r
1173                 // ( http://www.thaiopensource.com/relaxng/derivative.html ),\r
1174                 // but it looks required.\r
1175                 public override bool Nullable {\r
1176                         get {\r
1177                                 if (dt.NamespaceURI.Length == 0)\r
1178                                         return true;\r
1179                                 return false; \r
1180                         }\r
1181                 }\r
1182 \r
1183                 public override RelaxngPatternType PatternType {\r
1184                         get { return RelaxngPatternType.Data; }\r
1185                 }\r
1186 \r
1187                 public override RdpContentType ContentType {\r
1188                         get { return RdpContentType.Simple; }\r
1189                 }\r
1190 \r
1191                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1192                 {\r
1193                         // do nothing.\r
1194                 }\r
1195 \r
1196                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1197                 {\r
1198                         if (dt.IsAllowed (s, reader))\r
1199                                 return RdpEmpty.Instance;\r
1200                         else\r
1201                                 return RdpNotAllowed.Instance;\r
1202                 }\r
1203 \r
1204                 internal override void MarkReachableDefs () \r
1205                 {\r
1206                         // do nothing\r
1207                 }\r
1208 \r
1209                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
1210                 {\r
1211                         // do nothing\r
1212                 }\r
1213 \r
1214                 internal override bool ContainsText()\r
1215                 {\r
1216                         return false;\r
1217                 }\r
1218         }\r
1219 \r
1220         // DataExcept\r
1221         public class RdpDataExcept : RdpData\r
1222         {\r
1223                 public RdpDataExcept (RdpDatatype dt, RdpPattern except)\r
1224                         : base (dt)\r
1225                 {\r
1226                         this.except = except;\r
1227                 }\r
1228 \r
1229                 RdpPattern except;\r
1230                 public RdpPattern Except {\r
1231                         get { return except; }\r
1232                         set { except = value; }\r
1233                 }\r
1234 \r
1235                 public override RelaxngPatternType PatternType {\r
1236                         get { return RelaxngPatternType.DataExcept; }\r
1237                 }\r
1238 \r
1239                 public override RdpContentType ContentType {\r
1240                         get {\r
1241                                 RdpContentType c = except.ContentType; // conformance required for except pattern.\r
1242                                 return RdpContentType.Simple;\r
1243                         }\r
1244                 }\r
1245 \r
1246                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
1247                 {\r
1248                         if (visited.Contains (this))\r
1249                                 return this;\r
1250                         visited.Add (this, this);\r
1251 \r
1252                         if (except.PatternType == RelaxngPatternType.NotAllowed) {\r
1253                                 result = true;\r
1254                                 return new RdpData (this.Datatype);\r
1255                         } else {\r
1256                                 except = except.ReduceEmptyAndNotAllowed (ref result, visited);\r
1257                                 return this;\r
1258                         }\r
1259                 }\r
1260 \r
1261                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1262                 {\r
1263                         if (Datatype.IsAllowed (s, reader) && !except.TextDeriv (s, reader).Nullable)\r
1264                                 return RdpEmpty.Instance;\r
1265                         else\r
1266                                 return RdpNotAllowed.Instance;\r
1267                 }\r
1268 \r
1269                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)\r
1270                 {\r
1271                         this.except.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, true);\r
1272                 }\r
1273 \r
1274                 internal override bool ContainsText()\r
1275                 {\r
1276                         return except.ContainsText ();\r
1277                 }\r
1278         }\r
1279 \r
1280         // Value\r
1281         public class RdpValue : RdpPattern\r
1282         {\r
1283                 public RdpValue (RdpDatatype dt, string value)\r
1284                 {\r
1285                         this.dt = dt;\r
1286                         this.value = value;\r
1287                 }\r
1288 \r
1289                 RdpDatatype dt;\r
1290                 public RdpDatatype Datatype {\r
1291                         get { return dt; }\r
1292                 }\r
1293 \r
1294                 string value;\r
1295                 public string Value {\r
1296                         get { return value; }\r
1297                 }\r
1298 \r
1299                 // This is not written in James Clark's derivative algorithm\r
1300                 // ( http://www.thaiopensource.com/relaxng/derivative.html ),\r
1301                 // but it looks required.\r
1302                 public override bool Nullable {\r
1303                         get {\r
1304                                 if (dt.NamespaceURI.Length == 0 && value.Length == 0)\r
1305                                         return true;\r
1306                                 return false; \r
1307                         }\r
1308                 }\r
1309 \r
1310                 public override RelaxngPatternType PatternType {\r
1311                         get { return RelaxngPatternType.Value; }\r
1312                 }\r
1313 \r
1314                 public override RdpContentType ContentType {\r
1315                         get { return RdpContentType.Simple; }\r
1316                 }\r
1317 \r
1318                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1319                 {\r
1320                         // do nothing\r
1321                 }\r
1322 \r
1323                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1324                 {\r
1325                         if (dt.IsTypeEqual (value, s, reader))\r
1326                                 return RdpEmpty.Instance;\r
1327                         else\r
1328                                 return RdpNotAllowed.Instance;\r
1329                 }\r
1330 \r
1331                 internal override void MarkReachableDefs () \r
1332                 {\r
1333                         // do nothing\r
1334                 }\r
1335 \r
1336                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept) \r
1337                 {\r
1338                         // nothing to be checked\r
1339                 }\r
1340 \r
1341                 internal override bool ContainsText()\r
1342                 {\r
1343                         return false;\r
1344                 }\r
1345         }\r
1346 \r
1347         // Attribute\r
1348         public class RdpAttribute : RdpPattern\r
1349         {\r
1350                 public RdpAttribute (RdpNameClass nameClass, RdpPattern p)\r
1351                 {\r
1352                         this.nameClass = nameClass;\r
1353                         this.children = p;\r
1354                 }\r
1355 \r
1356                 RdpNameClass nameClass;\r
1357                 public RdpNameClass NameClass {\r
1358                         get { return nameClass; }\r
1359                 }\r
1360 \r
1361                 RdpPattern children;\r
1362                 public RdpPattern Children {\r
1363                         get { return children; }\r
1364                         set { children = value; }\r
1365                 }\r
1366 \r
1367                 public override bool Nullable {\r
1368                         get { return false; }\r
1369                 }\r
1370 \r
1371                 public override RelaxngPatternType PatternType {\r
1372                         get { return RelaxngPatternType.Attribute; }\r
1373                 }\r
1374 \r
1375                 public override RdpContentType ContentType {\r
1376                         get { return RdpContentType.Empty; }\r
1377                 }\r
1378 \r
1379                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1380                 {\r
1381                         AddNameLabel (attributes, NameClass);\r
1382                 }\r
1383 \r
1384                 bool isExpanded;\r
1385                 internal override RdpPattern ExpandRef (Hashtable defs)\r
1386                 {\r
1387                         if (!isExpanded) {\r
1388                                 isExpanded = true;\r
1389                                 children = children.ExpandRef (defs);\r
1390                         }\r
1391                         return this;\r
1392                 }\r
1393 \r
1394                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
1395                 {\r
1396                         if (visited.Contains (this))\r
1397                                 return this;\r
1398                         visited.Add (this, this);\r
1399 \r
1400                         if (children.PatternType == RelaxngPatternType.NotAllowed) {\r
1401                                 result = true;\r
1402                                 return RdpNotAllowed.Instance;\r
1403                         } else {\r
1404                                 children = children.ReduceEmptyAndNotAllowed (ref result, visited);\r
1405                                 return this;\r
1406                         }\r
1407                 }\r
1408 \r
1409                 // attDeriv cx (Attribute nc p) (AttributeNode qn s) =\r
1410                 //  if contains nc qn && valueMatch cx p s then Empty else NotAllowed\r
1411                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
1412                 {\r
1413                         // If value is null, then does not check ValueMatch.\r
1414 #if UseStatic\r
1415                         if (RdpUtil.Contains (this.nameClass, att.QName)\r
1416                                 && (value == null || RdpUtil.ValueMatch (ctx, this.children, att.Value)))\r
1417                                 return RdpEmpty.Instance;\r
1418                         else\r
1419                                 return RdpNotAllowed.Instance;\r
1420 #else\r
1421                         if (nameClass.Contains (name, ns) &&\r
1422                                 (value == null || children.ValueMatch (value, reader)))\r
1423                                 return RdpEmpty.Instance;\r
1424                         else\r
1425                                 return RdpNotAllowed.Instance;\r
1426 #endif\r
1427                 }\r
1428 \r
1429                 // startTagCloseDeriv (Attribute _ _) = NotAllowed\r
1430                 public override RdpPattern StartTagCloseDeriv ()\r
1431                 {\r
1432                         return RdpNotAllowed.Instance;\r
1433                 }\r
1434 \r
1435                 internal override void MarkReachableDefs () \r
1436                 {\r
1437                         children.MarkReachableDefs ();\r
1438                 }\r
1439 \r
1440                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept) \r
1441                 {\r
1442                         if (attribute || oneOrMoreGroup || oneOrMoreInterleave || list || dataExcept)\r
1443                                 throw new RelaxngException ("Not allowed attribute occurence was specified in the pattern.");\r
1444                         this.Children.CheckConstraints (true, oneOrMore, false, false, false, false);\r
1445                 }\r
1446 \r
1447                 internal override bool ContainsText()\r
1448                 {\r
1449                         return children.ContainsText ();\r
1450                 }\r
1451         }\r
1452 \r
1453         // Element\r
1454         public class RdpElement : RdpPattern\r
1455         {\r
1456                 public RdpElement (RdpNameClass nameClass, RdpPattern p)\r
1457                 {\r
1458                         this.nameClass = nameClass;\r
1459                         this.children = p;\r
1460                 }\r
1461 \r
1462                 RdpNameClass nameClass;\r
1463                 public RdpNameClass NameClass {\r
1464                         get { return nameClass; }\r
1465                 }\r
1466 \r
1467                 RdpPattern children;\r
1468                 public RdpPattern Children {\r
1469                         get { return children; }\r
1470                         set { children = value; }\r
1471                 }\r
1472 \r
1473                 public override bool Nullable {\r
1474                         get { return false; }\r
1475                 }\r
1476 \r
1477                 public override RelaxngPatternType PatternType {\r
1478                         get { return RelaxngPatternType.Element; }\r
1479                 }\r
1480 \r
1481                 bool contentTypeCheckDone;\r
1482                 public override RdpContentType ContentType {\r
1483                         get {\r
1484                                 if (!contentTypeCheckDone) {\r
1485                                         contentTypeCheckDone = true;\r
1486                                         RdpContentType ct = children.ContentType; // conformance required.\r
1487                                 }\r
1488                                 return RdpContentType.Complex;\r
1489                         }\r
1490                 }\r
1491 \r
1492                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1493                 {\r
1494                         AddNameLabel (elements, NameClass);\r
1495                 }\r
1496 \r
1497 \r
1498                 bool isExpanded;\r
1499                 short expanding; // FIXME: It is totally not required, but there is\r
1500                 // some bugs in simplification and without it it causes infinite loop.\r
1501                 internal override RdpPattern ExpandRef (Hashtable defs)\r
1502                 {\r
1503                         if (!isExpanded) {\r
1504                                 isExpanded = true;\r
1505                                 if (expanding == 100)\r
1506                                         throw new RelaxngException (String.Format ("Invalid recursion was found. Name is {0}", nameClass));\r
1507                                 expanding++;\r
1508                                 children = children.ExpandRef (defs);\r
1509                                 expanding--;\r
1510                         }\r
1511                         return this;\r
1512                 }\r
1513 \r
1514                 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)\r
1515                 {\r
1516                         if (visited.Contains (this))\r
1517                                 return this;\r
1518                         visited.Add (this, this);\r
1519 \r
1520                         children = children.ReduceEmptyAndNotAllowed (ref result, visited);\r
1521                         return this;\r
1522                 }\r
1523 \r
1524                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
1525                 {\r
1526 #if UseStatic\r
1527                         if (RdpUtil.Contains (this.nameClass, qname))\r
1528                                 return RdpUtil.After (this.Children, RdpEmpty.Instance);\r
1529                         else\r
1530                                 return RdpNotAllowed.Instance;\r
1531 #else\r
1532                         return nameClass.Contains (name, ns) ?\r
1533                                 children.After (RdpEmpty.Instance) :\r
1534                                 RdpNotAllowed.Instance;\r
1535 #endif\r
1536                 }\r
1537 \r
1538                 internal override void MarkReachableDefs () \r
1539                 {\r
1540                         children.MarkReachableDefs ();\r
1541                 }\r
1542 \r
1543                 bool constraintsChecked;\r
1544                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept) \r
1545                 {\r
1546                         if (constraintsChecked)\r
1547                                 return;\r
1548                         constraintsChecked = true;\r
1549                         if (attribute || list || dataExcept)\r
1550                                 throw new RelaxngException ("Not allowed element occurence was specified in the pattern.");\r
1551                         this.Children.CheckConstraints (false, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, false, false);\r
1552                 }\r
1553 \r
1554                 internal override bool ContainsText()\r
1555                 {\r
1556                         return children.ContainsText ();\r
1557                 }\r
1558         }\r
1559 \r
1560         // After\r
1561         public class RdpAfter : RdpAbstractBinary\r
1562         {\r
1563                 public RdpAfter (RdpPattern l, RdpPattern r) : base (l, r)\r
1564                 {\r
1565                 }\r
1566 \r
1567                 public override bool Nullable {\r
1568                         get { return false; }\r
1569                 }\r
1570 \r
1571                 public override void GetLabels (LabelList elements, LabelList attributes)\r
1572                 {\r
1573                         LValue.GetLabels (elements, attributes);\r
1574                 }\r
1575 \r
1576                 public override RdpPattern TextDeriv (string s, XmlReader reader)\r
1577                 {\r
1578                         return LValue.TextDeriv (s, reader).After (RValue);\r
1579                 }\r
1580 \r
1581                 // startTagOpenDeriv (After p1 p2) qn =\r
1582                 //   applyAfter (flip after p2) (startTagOpenDeriv p1 qn)\r
1583                 public override RdpPattern StartTagOpenDeriv (string name, string ns)\r
1584                 {\r
1585                         RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);\r
1586                         RdpFlip f = new RdpFlip (new RdpBinaryFunction (RdpUtil.After), RValue);\r
1587                         return handled.ApplyAfter (new RdpApplyAfterHandler (\r
1588                                 f.Apply));\r
1589                 }\r
1590 \r
1591                 public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)\r
1592                 {\r
1593                         return LValue.After (handler (RValue));\r
1594                 }\r
1595 \r
1596                 // attDeriv cx (After p1 p2) att =\r
1597                 //  after (attDeriv cx p1 att) p2\r
1598                 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)\r
1599                 {\r
1600                         return LValue.AttDeriv (name, ns, value, reader).After (RValue);\r
1601                 }\r
1602 \r
1603                 public override RdpPattern StartTagCloseDeriv ()\r
1604                 {\r
1605                         return LValue.StartTagCloseDeriv ().After (RValue);\r
1606                 }\r
1607 \r
1608                 public override RdpPattern EndTagDeriv ()\r
1609                 {\r
1610                         return LValue.Nullable ? RValue : RdpNotAllowed.Instance;\r
1611                 }\r
1612 \r
1613                 public override RelaxngPatternType PatternType {\r
1614                         get { return RelaxngPatternType.After; }\r
1615                 }\r
1616 \r
1617                 internal override void MarkReachableDefs () \r
1618                 {\r
1619                         throw new InvalidOperationException ();\r
1620                 }\r
1621 \r
1622                 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept) \r
1623                 {\r
1624                         throw new InvalidOperationException ();\r
1625                 }\r
1626 \r
1627                 internal override bool ContainsText ()\r
1628                 {\r
1629                         throw new InvalidOperationException ();\r
1630                 }\r
1631         }\r
1632 }\r
1633 \r