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