Fixed.
[mono.git] / mcs / class / Commons.Xml.Relaxng / Commons.Xml.Relaxng / RelaxngGrammar.cs
index 41115e62745bea4859ff23766caee128622fd933..938a8a69393e0be0d21d16c8138e4eba1003a5ff 100644 (file)
@@ -1,14 +1,14 @@
-//\r
-// Commons.Xml.Relaxng.RelaxngGrammar.cs\r
-//\r
-// Author:\r
-//     Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>\r
-//\r
-// 2003 Atsushi Enomoto "No rights reserved."\r
-//\r
-// Copyright (c) 2004 Novell Inc.\r
-// All rights reserved\r
-//\r
+//
+// Commons.Xml.Relaxng.RelaxngGrammar.cs
+//
+// Author:
+//     Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
+//
+// 2003 Atsushi Enomoto "No rights reserved."
+//
+// Copyright (c) 2004 Novell Inc.
+// All rights reserved
+//
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-using System;\r
-using System.Collections;\r
-using System.IO;\r
-using System.Net;\r
-using System.Xml;\r
-using Commons.Xml.Relaxng.Derivative;\r
-\r
-namespace Commons.Xml.Relaxng\r
-{\r
-       public class RelaxngGrammar : RelaxngPattern\r
-       {\r
-               // field\r
-               public static string NamespaceURI =\r
-                       "http://relaxng.org/ns/structure/1.0";\r
-\r
-               // object model fields\r
-               RelaxngGrammarContentList starts = new RelaxngGrammarContentList ();\r
-               RelaxngGrammarContentList defs = new RelaxngGrammarContentList ();\r
-               RelaxngGrammarContentList includes = new RelaxngGrammarContentList ();\r
-               RelaxngGrammarContentList divs = new RelaxngGrammarContentList ();\r
-\r
-               RelaxngDatatypeProvider provider;\r
-\r
-               // compiled fields.\r
-               RdpPattern startPattern;\r
-\r
-               // compile cache fields.\r
-               Hashtable assembledDefs = new Hashtable (); // [defName] = RelaxngDefine\r
-               RelaxngPattern assembledStart;\r
-               RdpPattern compiledStart;\r
-               Hashtable elementReplacedDefs = new Hashtable ();\r
-\r
-               Hashtable includedUris = new Hashtable ();\r
-               RelaxngGrammar parentGrammar;\r
-               Hashtable refPatterns = new Hashtable (); // key = RdpPattern of assembledDefs\r
-\r
-               // only for checkRecursion()\r
-               Hashtable checkedDefs = new Hashtable ();\r
-\r
-               // this should be checked after its compilation finished to complete\r
-               // missing-at-the-tracking patterns (especially of parent grammars).\r
-               // key = RdpPattern, value = ArrayList of unresolvedPatterns.\r
-               ArrayList unresolvedPatterns = new ArrayList ();\r
-\r
-               // contents key = RdpElement and value = name of the parent define.\r
-               private Hashtable ElementDefMap = new Hashtable ();\r
-\r
-               // Public\r
-\r
-               public RelaxngGrammar ()\r
-               {\r
-               }\r
-\r
-               private void ResetCompileState ()\r
-               {\r
-                       startPattern = null;\r
-                       assembledDefs.Clear ();\r
-                       assembledStart = null;\r
-                       compiledStart = null;\r
-                       elementReplacedDefs.Clear ();\r
-                       includedUris.Clear ();\r
-                       parentGrammar = null;\r
-                       refPatterns.Clear ();\r
-                       checkedDefs.Clear ();\r
-                       unresolvedPatterns.Clear ();\r
-                       ElementDefMap.Clear ();\r
-               }\r
-\r
-               internal RelaxngGrammar ParentGrammar {\r
-                       get { return parentGrammar; }\r
-                       set { parentGrammar = value; }\r
-               }\r
-\r
-               internal RelaxngDatatypeProvider Provider {\r
-                       get { return parentGrammar != null ? parentGrammar.Provider : provider; }\r
-                       set { provider = value; }\r
-               }\r
-\r
-               public override RelaxngPatternType PatternType {\r
-                       get { return RelaxngPatternType.Grammar; }\r
-               }\r
-\r
-               public RelaxngGrammarContentList Starts {\r
-                       get { return starts; }\r
-               }\r
-\r
-               public RelaxngGrammarContentList Defines {\r
-                       get { return defs; }\r
-               }\r
-\r
-               public RelaxngGrammarContentList Includes {\r
-                       get { return includes; }\r
-               }\r
-\r
-               public RelaxngGrammarContentList Divs {\r
-                       get { return divs; }\r
-               }\r
-\r
-               public override void Write (XmlWriter writer)\r
-               {\r
-                       writer.WriteStartElement ("", "grammar", RelaxngGrammar.NamespaceURI);\r
-                       foreach (RelaxngStart start in Starts)\r
-                               start.Write (writer);\r
-                       foreach (RelaxngDefine define in Defines)\r
-                               define.Write (writer);\r
-                       foreach (RelaxngInclude include in Includes)\r
-                               include.Write (writer);\r
-                       foreach (RelaxngDiv div in Divs)\r
-                               div.Write (writer);\r
-                       writer.WriteEndElement ();\r
-               }\r
-\r
-               internal Hashtable IncludedUris {\r
-                       get { return includedUris; }\r
-               }\r
-\r
-               // Internal\r
-               internal override void CheckConstraints ()\r
-               {\r
-                       // do nothing here.\r
-               }\r
-\r
-               internal void CheckIncludeRecursion (string href)\r
-               {\r
-                       if (this.includedUris [href] != null)\r
-                               throw new RelaxngException ("Include recursion found. href: " + href);\r
-                       if (parentGrammar != null)\r
-                               parentGrammar.CheckIncludeRecursion (href);\r
-               }\r
-\r
-               // Compile from this simplified syntax to derivatives.\r
-               internal override RdpPattern Compile (RelaxngGrammar grammar)\r
-               {\r
-                       ResetCompileState ();\r
-\r
-                       parentGrammar = grammar;\r
-\r
-                       // First, process includes and divs. RELAX NG 4.1 - 4.15.\r
-                       ArrayList compiledDivs = new ArrayList ();\r
-                       foreach (RelaxngInclude inc in includes)\r
-                               compiledDivs.Add (inc.Compile (this));\r
-                       compiledDivs.AddRange (divs);\r
-                       foreach (RelaxngDiv div in compiledDivs)\r
-                               div.Compile (this);\r
-\r
-                       // Check constraints. RELAX NG 4.16\r
-                       foreach (RelaxngStart start in starts)\r
-                               start.Pattern.CheckConstraints ();\r
-                       foreach (RelaxngDefine define in defs)\r
-                               foreach (RelaxngPattern p in define.Patterns)\r
-                                       p.CheckConstraints ();\r
-\r
-                       // Assemble combine into the same name defines/start.\r
-                       // see RELAX NG 4.17.\r
-                       AssembleCombine ();\r
-\r
-                       // FIXME: It should not return NotAllowed\r
-                       if (assembledStart != null)\r
-                               compiledStart = assembledStart.Compile (this);\r
-                       else\r
-                               return RdpNotAllowed.Instance;\r
-\r
-                       // Assemble all define components into top grammar and\r
-                       // return start patterns for descendant grammars.\r
-                       // see RELAX NG 4.18.\r
-                       CollectGrammars ();\r
-                       if (parentGrammar != null)\r
-                               return compiledStart;\r
-                       assembledStart = null; // no use anymore\r
-\r
-                       // 4.19 (a) remove non-reachable defines\r
-/*\r
-                       compiledStart.MarkReachableDefs ();\r
-                       ArrayList tmp = new ArrayList ();\r
-                       foreach (DictionaryEntry entry in this.assembledDefs)\r
-                               if (!reachableDefines.ContainsKey (entry.Key))\r
-                                       tmp.Add (entry.Key);\r
-                       foreach (string key in tmp)\r
-                               assembledDefs.Remove (key);\r
-*/\r
-                       // 4.19 (b) check illegal recursion\r
-                       CheckRecursion (compiledStart, 0);\r
-                       // here we collected element-replaced definitions\r
-                       foreach (DictionaryEntry entry in elementReplacedDefs)\r
-                               assembledDefs.Add (entry.Key, entry.Value);\r
-                       startPattern = compiledStart;\r
-                       // 4.20,21 reduce notAllowed and empty.\r
-                       bool b;\r
-                       do {\r
-                               b = false;\r
-                               startPattern = startPattern.ReduceEmptyAndNotAllowed (ref b, new Hashtable ());\r
-                       } while (b);\r
-\r
-                       Hashtable ht = new Hashtable ();\r
-                       startPattern.setInternTable (ht);\r
-                       RdpNotAllowed.Instance.setInternTable (ht);\r
-                       RdpEmpty.Instance.setInternTable (ht);\r
-                       RdpText.Instance.setInternTable (ht);\r
-\r
-                       // Check Constraints: RELAX NG spec 7\r
-                       // 7.1.1-4 & 7.4\r
-                       startPattern.CheckConstraints (false, false, false, false, false, false);\r
-                       // 7.1.5\r
-                       CheckStartPatternContent (startPattern);\r
-\r
-                       // 7.2\r
-                       RdpContentType ct = startPattern.ContentType;\r
-\r
-                       // TODO: 7.3\r
-\r
-                       // 4.19 (c) expandRef - actual replacement\r
-                       startPattern = compiledStart.ExpandRef (assembledDefs);\r
-\r
-                       // return its start pattern.\r
-                       IsCompiled = true;\r
-                       return startPattern;\r
-               }\r
-\r
-               private void CheckStartPatternContent (RdpPattern p)\r
-               {\r
-                       switch (p.PatternType) {\r
-                       case RelaxngPatternType.Ref:\r
-                               CheckStartPatternContent (((RdpUnresolvedRef) p).RefPattern);\r
-                               break;\r
-                       case RelaxngPatternType.Element:\r
-                               break;\r
-                       case RelaxngPatternType.Choice:\r
-                               RdpChoice c = p as RdpChoice;\r
-                               CheckStartPatternContent (c.LValue);\r
-                               CheckStartPatternContent (c.RValue);\r
-                               break;\r
-                       case RelaxngPatternType.NotAllowed:\r
-                               break;\r
-                       default:\r
-                               throw new RelaxngException ("Start pattern contains an invalid content pattern.");\r
-                       }\r
-               }\r
-\r
-               Hashtable reachableDefines = new Hashtable ();\r
-\r
-               // for step 4.19\r
-               internal void MarkReacheableDefine (string name)\r
-               {\r
-                       if (reachableDefines.ContainsKey (name))\r
-                               return;\r
-                       RdpPattern p = assembledDefs [name] as RdpPattern;\r
-                       reachableDefines.Add (name, p);\r
-                       p.MarkReachableDefs ();\r
-               }\r
-\r
-               // 4.19 (b)\r
-               private void CheckRecursion (RdpPattern p, int depth)\r
-               {\r
-\r
-                       RdpAbstractBinary binary = p as RdpAbstractBinary;\r
-                       if (binary != null) {\r
-                               // choice, interleave, group\r
-                               CheckRecursion (binary.LValue, depth);\r
-                               CheckRecursion (binary.RValue, depth);\r
-                               return;\r
-                       }\r
-                       RdpAbstractSingleContent single = p as RdpAbstractSingleContent;\r
-                       if (single != null) {\r
-                               CheckRecursion (single.Child, depth);\r
-                               return;\r
-                       }\r
-\r
-                       switch (p.PatternType) {\r
-                       case RelaxngPatternType.Ref:\r
-                               // get checkRecursionDepth from table.\r
-                               int checkRecursionDepth = -1;\r
-                               object checkedDepth = checkedDefs [p];\r
-                               if (checkedDepth != null)\r
-                                       checkRecursionDepth = (int) checkedDepth;\r
-                               // get refPattern\r
-                               RdpUnresolvedRef pref = p as RdpUnresolvedRef;\r
-                               RelaxngGrammar target = pref.TargetGrammar;\r
-                               RdpPattern refPattern = pref.RefPattern;\r
-                               if (refPattern == null)\r
-                                       throw new RelaxngException ("No matching define found for " + pref.Name);\r
-\r
-                               if (checkRecursionDepth == -1) {\r
-                                       checkedDefs [p] = depth;\r
-/*test*/                                       if (refPattern.PatternType != RelaxngPatternType.Element)\r
-                                               CheckRecursion (refPattern, depth);\r
-                                       checkedDefs [p] = -2;\r
-                               }\r
-                               else if (depth == checkRecursionDepth)\r
-                                       throw new RelaxngException (String.Format ("Detected illegal recursion. Ref name is {0}.", pref.Name));\r
-\r
-                               break;\r
-\r
-                       case RelaxngPatternType.Attribute:\r
-                               CheckRecursion (((RdpAttribute) p).Children, depth);\r
-                               break;\r
-\r
-                       case RelaxngPatternType.DataExcept:\r
-                               CheckRecursion (((RdpDataExcept) p).Except, depth);\r
-                               break;\r
-\r
-                       case RelaxngPatternType.Element:\r
-                               RdpElement el = p as RdpElement;\r
-                               CheckRecursion (el.Children, depth + 1);        // +1\r
-                               break;\r
-                       case RelaxngPatternType.List:\r
-                               CheckRecursion (((RdpList) p).Child, depth);\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               // 4.18\r
-               private void CollectGrammars ()\r
-               {\r
-                       // collect ref and parentRef for each define.\r
-\r
-                       // FIXME: This should be assembledStart.\r
-                       CheckReferences (compiledStart);\r
-                       FixupReference ();\r
-\r
-                       foreach (string name in assembledDefs.Keys) {\r
-                               RdpPattern p = (RdpPattern) assembledDefs [name];\r
-                               CheckReferences (p);\r
-                               FixupReference ();\r
-                       }\r
-\r
-                       // If it is child of any other pattern:\r
-                       // * Remove all definitions under descendant grammars,\r
-                       //   replacing ref names, and\r
-                       // * Then return its start pattern.\r
-                       if (parentGrammar != null) {\r
-                               // TODO: reachable check is incomplete.\r
-                               foreach (string name in assembledDefs.Keys) {\r
-                                       ArrayList al = \r
-                                               refPatterns [assembledDefs [name] ] as ArrayList;\r
-                                       if (al == null)\r
-                                               continue; // Not referenced.\r
-\r
-                                       // At this point, parent grammar doesn't \r
-                                       // collect assembledDefs as yet\r
-                                       string uname = GetUniqueName (name, parentGrammar);\r
-                                       parentGrammar.assembledDefs [uname] = assembledDefs [name];\r
-                               }\r
-                       }\r
-               }\r
-\r
-               private static string GetUniqueName (string name, RelaxngGrammar grammar)\r
-               {\r
-                       foreach (RelaxngDefine def in grammar.Defines)\r
-                               if (def.Name == name)\r
-                                       return GetUniqueName (name + '_', grammar);\r
-                       return name;\r
-               }\r
-\r
-               private void FixupReference ()\r
-               {\r
-                       foreach (RdpUnresolvedRef pref in this.unresolvedPatterns) {\r
-                               RdpPattern defP = assembledDefs [pref.Name] as RdpPattern;\r
-                               if (defP == null)\r
-                                       throw new RelaxngException (String.Format ("Target definition was not found: {0}", pref.Name));\r
-                               ArrayList al = refPatterns [defP] as ArrayList;\r
-                               if (al == null) {\r
-                                       al = new ArrayList ();\r
-                                       refPatterns [defP] = al;\r
-                               }\r
-                               al.Add (pref);\r
-                       }\r
-                       this.unresolvedPatterns.Clear ();\r
-               }\r
-\r
-               private void replaceDefines (string name, ArrayList al)\r
-               {\r
-                       int idx = 0;\r
-                       while (true) {\r
-                               string newName = "define" + idx;\r
-                               if (parentGrammar.assembledDefs [newName] == null) {\r
-                                       parentGrammar.assembledDefs [newName] = \r
-                                               assembledDefs [name];\r
-                                       foreach (RdpUnresolvedRef pref in al)\r
-                                               pref.Name = newName;\r
-                                       break;\r
-                               }\r
-                               idx++;\r
-                       }\r
-               }\r
-\r
-               // remove ref and parentRef.\r
-               // add new defines for each elements.\r
-               private void CheckReferences (RdpPattern p)\r
-               {\r
-                       RdpAbstractBinary binary = p as RdpAbstractBinary;\r
-                       if (binary != null) {\r
-                               // choice, interleave, group\r
-                               CheckReferences (binary.LValue);\r
-                               CheckReferences (binary.RValue);\r
-                               return;\r
-                       }\r
-                       RdpAbstractSingleContent single = p as RdpAbstractSingleContent;\r
-                       if (single != null) {\r
-                               CheckReferences (single.Child);\r
-                               return;\r
-                       }\r
-\r
-                       switch (p.PatternType) {\r
-                       case RelaxngPatternType.Ref:\r
-                               // FIXME: This should not re-expand ref\r
-                               RdpUnresolvedRef pref = p as RdpUnresolvedRef;\r
-                               if (pref.RefPattern != null)\r
-                                       break;\r
-\r
-                               RelaxngGrammar target = pref.TargetGrammar;\r
-                               if (target == null)\r
-                                       throw new RelaxngException ("Referenced definition was not found.");\r
-                               RdpPattern defP = target.assembledDefs [pref.Name] as RdpPattern;\r
-                               if (defP == null)\r
-                                       target.unresolvedPatterns.Add (p);\r
-                               else {\r
-                                       ArrayList al = target.refPatterns [defP] as ArrayList;\r
-                                       if (al == null) {\r
-                                               al = new ArrayList ();\r
-                                               target.refPatterns [defP] = al;\r
-                                       }\r
-                                       al.Add (p);\r
-                                       pref.RefPattern = defP;\r
-                               }\r
-                               break;\r
-\r
-                       case RelaxngPatternType.Attribute:\r
-                               CheckReferences (((RdpAttribute) p).Children);\r
-                               break;\r
-\r
-                       case RelaxngPatternType.DataExcept:\r
-                               CheckReferences (((RdpDataExcept) p).Except);\r
-                               break;\r
-\r
-                       case RelaxngPatternType.Element:\r
-                               RdpElement el = p as RdpElement;\r
-                               CheckReferences (el.Children);\r
-                               string name = ElementDefMap [el] as string;\r
-                               if (name == null) {\r
-                                       // add new define\r
-                                       int idx = 0;\r
-                                       string newName = "element0";\r
-                                       if (el.NameClass is RdpName)\r
-                                               newName = ((RdpName) el.NameClass).LocalName;\r
-                                       while (true) {\r
-                                                if (assembledDefs [newName] == null) {\r
-                                                       elementReplacedDefs [newName] = el.Children;\r
-                                                       break;\r
-                                               }\r
-                                               newName = "element" + ++idx;\r
-                                       }\r
-                                       ElementDefMap [el] = newName;\r
-                               }\r
-                               // Even though the element is replaced with ref,\r
-                               // derivative of ref is RdpElement in fact...\r
-                               break;\r
-\r
-                       case RelaxngPatternType.List:\r
-                               CheckReferences (((RdpList) p).Child);\r
-                               break;\r
-\r
-                       case RelaxngPatternType.Empty:\r
-                       case RelaxngPatternType.NotAllowed:\r
-                       case RelaxngPatternType.Text:\r
-                       case RelaxngPatternType.Value:\r
-                               break;\r
-\r
-                       //case RelaxngPatternType.ExternalRef:\r
-                       //case RelaxngPatternType.Include:\r
-                       // Mixed, Optional, ZeroOrMore are already removed.\r
-                       // Choice, Group, Interleave, OneOrMore are already proceeded.\r
-                       }\r
-               }\r
-\r
-               #region 4.17 - Combine\r
-               private void AssembleCombine ()\r
-               {\r
-                       // calculate combines.\r
-                       bool haveHeadStart = false;\r
-                       string combineStart = null;\r
-                       Hashtable haveHeadDefs = new Hashtable ();\r
-                       Hashtable combineDefs = new Hashtable ();\r
-\r
-                       // 1.calculate combine for starts.\r
-                       foreach (RelaxngStart start in starts)\r
-                               CheckCombine (ref haveHeadStart, \r
-                                       ref combineStart, start.Combine, "start");\r
-                       // 2.calculate combine for defines.\r
-                       foreach (RelaxngDefine def in defs) {\r
-                               bool haveHead = \r
-                                       haveHeadDefs.ContainsKey (def.Name) ?\r
-                                       haveHead = (bool) haveHeadDefs [def.Name]\r
-                                       : false;\r
-                               string combine = combineDefs [def.Name] as string;\r
-                               CheckCombine (ref haveHead, ref combine,\r
-                                       def.Combine, String.Format ("define name={0}", def.Name));\r
-                               haveHeadDefs [def.Name] = haveHead;\r
-                               combineDefs [def.Name] = combine;\r
-                               continue;\r
-                       }\r
-\r
-                       // assemble starts and defines with "combine" attribute.\r
-\r
-                       // 3.assemble starts.\r
-                       if (starts.Count == 0) {\r
-                               if (ParentGrammar == null)\r
-                                       throw new RelaxngException ("grammar must have at least one start component.");\r
-                       } else {\r
-                               assembledStart = ((RelaxngStart)starts [0]).Pattern;\r
-                               for (int i=1; i<starts.Count; i++) {\r
-                                       RelaxngPattern p2 = ((RelaxngStart) starts [i]).Pattern;;\r
-                                       if (combineStart == "interleave") {\r
-                                               RelaxngInterleave intlv = new RelaxngInterleave ();\r
-                                               intlv.Patterns.Add (assembledStart);\r
-                                               intlv.Patterns.Add (p2);\r
-                                               assembledStart = intlv;\r
-                                       } else {\r
-                                               RelaxngChoice c = new RelaxngChoice ();\r
-                                               c.Patterns.Add (assembledStart);\r
-                                               c.Patterns.Add (p2);\r
-                                               assembledStart = c;\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       // 4.assemble defines\r
-                       foreach (RelaxngDefine def in defs) {\r
-                               string combine = combineDefs [def.Name] as string;\r
-                               RdpPattern p1 = \r
-                                       assembledDefs [def.Name] as RdpPattern;\r
-                               RdpPattern p2 = def.Compile (this);\r
-                               if (p1 != null) {\r
-                                       if (combine == "interleave") {\r
-                                               assembledDefs [def.Name] =\r
-                                                       new RdpInterleave (p1, p2);\r
-                                       } else {\r
-                                               assembledDefs [def.Name] =\r
-                                                       new RdpChoice (p1, p2);\r
-                                       }\r
-                               } else {\r
-                                       assembledDefs [def.Name] = p2;\r
-                               }\r
-                       }\r
-\r
-               }\r
-\r
-               // check combine attributes.\r
-               private void CheckCombine (ref bool haveHead, ref string combine, string newCombine, string targetSpec)\r
-               {\r
-                       switch (newCombine) {\r
-                       case "interleave":\r
-                               if (combine == "choice")\r
-                                       throw new RelaxngException ("\"combine\" was already specified \"choice\"");\r
-                               else\r
-                                       combine = "interleave";\r
-                               break;\r
-                       case "choice":\r
-                               if (combine == "interleave")\r
-                                       throw new RelaxngException ("\"combine\" was already specified \"interleave\"");\r
-                               else\r
-                                       combine = "choice";\r
-                               break;\r
-                       case null:\r
-                               if (haveHead)\r
-                                       throw new RelaxngException (String.Format ("There was already \"{0}\" element without \"combine\" attribute.", targetSpec));\r
-                               haveHead = true;\r
-                               break;\r
-                       }\r
-               }\r
-               #endregion\r
-       }\r
-}\r
+using System;
+using System.Collections;
+using System.IO;
+using System.Net;
+using System.Xml;
+using Commons.Xml.Relaxng.Derivative;
+using Commons.Xml.Relaxng.Rnc;
+
+namespace Commons.Xml.Relaxng
+{
+       public class RelaxngGrammar : RelaxngPattern
+       {
+               // field
+               public static string NamespaceURI =
+                       "http://relaxng.org/ns/structure/1.0";
+
+               // Parser condition: it is used to resolve "included" source
+               bool isSourceRnc;
+
+               // object model fields
+               string defaultNamespace;
+               RelaxngGrammarContentList starts = new RelaxngGrammarContentList ();
+               RelaxngGrammarContentList defs = new RelaxngGrammarContentList ();
+               RelaxngGrammarContentList includes = new RelaxngGrammarContentList ();
+               RelaxngGrammarContentList divs = new RelaxngGrammarContentList ();
+
+               // compiled fields.
+               RdpPattern startPattern;
+
+               // compile cache fields.
+               Hashtable assembledDefs = new Hashtable (); // [defName] = RelaxngDefine
+               RelaxngPattern assembledStart;
+               RdpPattern compiledStart;
+               Hashtable elementReplacedDefs = new Hashtable ();
+
+               Hashtable includedUris = new Hashtable ();
+               RelaxngGrammar parentGrammar;
+               Hashtable refPatterns = new Hashtable (); // key = RdpPattern of assembledDefs
+
+               // only for checkRecursion()
+               Hashtable checkedDefs = new Hashtable ();
+
+               // this should be checked after its compilation finished to complete
+               // missing-at-the-tracking patterns (especially of parent grammars).
+               // key = RdpPattern, value = ArrayList of unresolvedPatterns.
+               ArrayList unresolvedPatterns = new ArrayList ();
+
+               // contents key = RdpElement and value = name of the parent define.
+               private Hashtable ElementDefMap = new Hashtable ();
+
+               // Public
+
+               public RelaxngGrammar ()
+               {
+               }
+
+               private void ResetCompileState ()
+               {
+                       startPattern = null;
+                       assembledDefs.Clear ();
+                       assembledStart = null;
+                       compiledStart = null;
+                       elementReplacedDefs.Clear ();
+                       includedUris.Clear ();
+                       parentGrammar = null;
+                       refPatterns.Clear ();
+                       checkedDefs.Clear ();
+                       unresolvedPatterns.Clear ();
+                       ElementDefMap.Clear ();
+               }
+
+               internal bool IsSourceCompactSyntax {
+                       get { return isSourceRnc; }
+                       set { isSourceRnc = value; }
+               }
+
+               internal RelaxngGrammar ParentGrammar {
+                       get { return parentGrammar; }
+                       set { parentGrammar = value; }
+               }
+
+               internal RelaxngDatatypeProvider Provider {
+                       get { return (base.DataProvider == null) ? (parentGrammar != null ? parentGrammar.Provider : base.DataProvider) : base.DataProvider; }
+                       set { base.DataProvider = value; }
+               }
+
+               public override RelaxngPatternType PatternType {
+                       get { return RelaxngPatternType.Grammar; }
+               }
+
+               public string DefaultNamespace {
+                       get { return defaultNamespace; }
+                       set { defaultNamespace = value; }
+               }
+
+               public RelaxngGrammarContentList Starts {
+                       get { return starts; }
+               }
+
+               public RelaxngGrammarContentList Defines {
+                       get { return defs; }
+               }
+
+               public RelaxngGrammarContentList Includes {
+                       get { return includes; }
+               }
+
+               public RelaxngGrammarContentList Divs {
+                       get { return divs; }
+               }
+
+               public override void Write (XmlWriter writer)
+               {
+                       writer.WriteStartElement ("", "grammar", RelaxngGrammar.NamespaceURI);
+                       if (defaultNamespace != null)
+                               writer.WriteAttributeString ("ns", defaultNamespace);
+                       foreach (RelaxngStart start in Starts)
+                               start.Write (writer);
+                       foreach (RelaxngDefine define in Defines)
+                               define.Write (writer);
+                       foreach (RelaxngInclude include in Includes)
+                               include.Write (writer);
+                       foreach (RelaxngDiv div in Divs)
+                               div.Write (writer);
+                       writer.WriteEndElement ();
+               }
+
+               internal override void WriteRnc (RncWriter writer)
+               {
+                       writer.WriteGrammar (this);
+               }
+
+               internal Hashtable IncludedUris {
+                       get { return includedUris; }
+               }
+
+               // Internal
+               internal override void CheckConstraints ()
+               {
+                       // do nothing here.
+               }
+
+               internal void CheckIncludeRecursion (string href)
+               {
+                       if (this.includedUris [href] != null)
+                               // FIXME: fill line info
+                               throw new RelaxngException ("Include recursion found. href: " + href);
+                       if (parentGrammar != null)
+                               parentGrammar.CheckIncludeRecursion (href);
+               }
+
+               // Compile from this simplified syntax to derivatives.
+               internal override RdpPattern Compile (RelaxngGrammar grammar)
+               {
+                       ResetCompileState ();
+
+                       parentGrammar = grammar;
+
+                       // First, process includes and divs. RELAX NG 4.1 - 4.15.
+                       ArrayList compiledDivs = new ArrayList ();
+                       foreach (RelaxngInclude inc in includes)
+                               compiledDivs.Add (inc.Compile (this));
+                       compiledDivs.AddRange (divs);
+                       foreach (RelaxngDiv div in compiledDivs)
+                               div.Compile (this);
+
+                       // Check constraints. RELAX NG 4.16
+                       foreach (RelaxngStart start in starts)
+                               start.Pattern.CheckConstraints ();
+                       foreach (RelaxngDefine define in defs)
+                               foreach (RelaxngPattern p in define.Patterns)
+                                       p.CheckConstraints ();
+
+                       // Assemble combine into the same name defines/start.
+                       // see RELAX NG 4.17.
+                       AssembleCombine ();
+
+                       // 4.18 : <grammar> must have at least one <start>.
+                       if (assembledStart == null)
+                               throw new RelaxngException ("A grammar elements must contain at least one start element.");
+                       compiledStart = assembledStart.Compile (this);
+
+                       // Assemble all define components into top grammar and
+                       // return start patterns for descendant grammars.
+                       // see RELAX NG 4.18.
+                       CollectGrammars ();
+                       if (parentGrammar != null)
+                               return compiledStart;
+                       assembledStart = null; // no use anymore
+
+                       // 4.19 (a) remove non-reachable defines
+/*
+                       compiledStart.MarkReachableDefs ();
+                       ArrayList tmp = new ArrayList ();
+                       foreach (DictionaryEntry entry in this.assembledDefs)
+                               if (!reachableDefines.ContainsKey (entry.Key))
+                                       tmp.Add (entry.Key);
+                       foreach (string key in tmp)
+                               assembledDefs.Remove (key);
+*/
+                       // 4.19 (b) check illegal recursion
+                       CheckRecursion (compiledStart, 0);
+                       // here we collected element-replaced definitions
+                       foreach (DictionaryEntry entry in elementReplacedDefs)
+                               assembledDefs.Add (entry.Key, entry.Value);
+                       startPattern = compiledStart;
+                       // 4.20,21 reduce notAllowed and empty.
+                       bool b;
+                       do {
+                               b = false;
+                               startPattern = startPattern.ReduceEmptyAndNotAllowed (ref b, new Hashtable ());
+                       } while (b);
+
+                       Hashtable ht = new Hashtable ();
+                       startPattern.setInternTable (ht);
+
+                       // Check Constraints: RELAX NG spec 7
+                       // 7.1.1-4, 7.3, 7.4
+                       startPattern.CheckConstraints (false, false, false, false, false, false);
+                       // 7.1.5
+                       CheckStartPatternContent (startPattern);
+
+                       // 4.19 (c) expandRef - actual replacement
+                       startPattern = compiledStart.ExpandRef (assembledDefs);
+
+                       // 7.2
+                       RdpContentType ct = startPattern.ContentType;
+
+                       // return its start pattern.
+                       IsCompiled = true;
+                       return startPattern;
+               }
+
+               private void CheckStartPatternContent (RdpPattern p)
+               {
+                       switch (p.PatternType) {
+                       case RelaxngPatternType.Ref:
+                               CheckStartPatternContent (((RdpUnresolvedRef) p).RefPattern);
+                               break;
+                       case RelaxngPatternType.Element:
+                               break;
+                       case RelaxngPatternType.Choice:
+                               RdpChoice c = p as RdpChoice;
+                               CheckStartPatternContent (c.LValue);
+                               CheckStartPatternContent (c.RValue);
+                               break;
+                       case RelaxngPatternType.NotAllowed:
+                               break;
+                       default:
+                               // FIXME: fill line info
+                               throw new RelaxngException ("Start pattern contains an invalid content pattern.");
+                       }
+               }
+
+               Hashtable reachableDefines = new Hashtable ();
+
+               // for step 4.19
+               internal void MarkReacheableDefine (string name)
+               {
+                       if (reachableDefines.ContainsKey (name))
+                               return;
+                       RdpPattern p = assembledDefs [name] as RdpPattern;
+                       reachableDefines.Add (name, p);
+                       p.MarkReachableDefs ();
+               }
+
+               // 4.19 (b)
+               private void CheckRecursion (RdpPattern p, int depth)
+               {
+
+                       RdpAbstractBinary binary = p as RdpAbstractBinary;
+                       if (binary != null) {
+                               // choice, interleave, group
+                               CheckRecursion (binary.LValue, depth);
+                               CheckRecursion (binary.RValue, depth);
+                               return;
+                       }
+                       RdpAbstractSingleContent single = p as RdpAbstractSingleContent;
+                       if (single != null) {
+                               CheckRecursion (single.Child, depth);
+                               return;
+                       }
+
+                       switch (p.PatternType) {
+                       case RelaxngPatternType.Ref:
+                               // get checkRecursionDepth from table.
+                               int checkRecursionDepth = -1;
+                               object checkedDepth = checkedDefs [p];
+                               if (checkedDepth != null)
+                                       checkRecursionDepth = (int) checkedDepth;
+                               // get refPattern
+                               RdpUnresolvedRef pref = p as RdpUnresolvedRef;
+                               RelaxngGrammar target = pref.TargetGrammar;
+                               RdpPattern refPattern = pref.RefPattern;
+                               if (refPattern == null)
+                                       // FIXME: fill line info
+                                       throw new RelaxngException ("No matching define found for " + pref.Name);
+
+                               if (checkRecursionDepth == -1) {
+                                       checkedDefs [p] = depth;
+/*test*/                                       if (refPattern.PatternType != RelaxngPatternType.Element)
+                                               CheckRecursion (refPattern, depth);
+                                       checkedDefs [p] = -2;
+                               }
+                               else if (depth == checkRecursionDepth)
+                                       // FIXME: fill line info
+                                       throw new RelaxngException (String.Format ("Detected illegal recursion. Ref name is {0}.", pref.Name));
+
+                               break;
+
+                       case RelaxngPatternType.Attribute:
+                               CheckRecursion (((RdpAttribute) p).Children, depth);
+                               break;
+
+                       case RelaxngPatternType.DataExcept:
+                               CheckRecursion (((RdpDataExcept) p).Except, depth);
+                               break;
+
+                       case RelaxngPatternType.Element:
+                               RdpElement el = p as RdpElement;
+                               CheckRecursion (el.Children, depth + 1);        // +1
+                               break;
+                       case RelaxngPatternType.List:
+                               CheckRecursion (((RdpList) p).Child, depth);
+                               break;
+                       }
+               }
+
+               // 4.18
+               private void CollectGrammars ()
+               {
+                       // collect ref and parentRef for each define.
+
+                       // FIXME: This should be assembledStart.
+                       CheckReferences (compiledStart);
+                       FixupReference ();
+
+                       foreach (string name in assembledDefs.Keys) {
+                               RdpPattern p = (RdpPattern) assembledDefs [name];
+                               CheckReferences (p);
+                               FixupReference ();
+                       }
+
+                       // If it is child of any other pattern:
+                       // * Remove all definitions under descendant grammars,
+                       //   replacing ref names, and
+                       // * Then return its start pattern.
+                       if (parentGrammar != null) {
+                               // TODO: reachable check is incomplete.
+                               foreach (string name in assembledDefs.Keys) {
+                                       ArrayList al = 
+                                               refPatterns [assembledDefs [name] ] as ArrayList;
+                                       if (al == null)
+                                               continue; // Not referenced.
+
+                                       // At this point, parent grammar doesn't 
+                                       // collect assembledDefs as yet
+                                       string uname = GetUniqueName (name, parentGrammar);
+                                       parentGrammar.assembledDefs [uname] = assembledDefs [name];
+                               }
+                       }
+               }
+
+               private static string GetUniqueName (string name, RelaxngGrammar grammar)
+               {
+                       foreach (RelaxngDefine def in grammar.Defines)
+                               if (def.Name == name)
+                                       return GetUniqueName (name + '_', grammar);
+                       return name;
+               }
+
+               private void FixupReference ()
+               {
+                       foreach (RdpUnresolvedRef pref in this.unresolvedPatterns) {
+                               RdpPattern defP = assembledDefs [pref.Name] as RdpPattern;
+                               if (defP == null)
+                                       // FIXME: fill line info
+                                       throw new RelaxngException (String.Format ("Target definition was not found: {0}", pref.Name));
+                               ArrayList al = refPatterns [defP] as ArrayList;
+                               if (al == null) {
+                                       al = new ArrayList ();
+                                       refPatterns [defP] = al;
+                               }
+                               al.Add (pref);
+                       }
+                       this.unresolvedPatterns.Clear ();
+               }
+
+               private void replaceDefines (string name, ArrayList al)
+               {
+                       int idx = 0;
+                       while (true) {
+                               string newName = "define" + idx;
+                               if (parentGrammar.assembledDefs [newName] == null) {
+                                       parentGrammar.assembledDefs [newName] = 
+                                               assembledDefs [name];
+                                       foreach (RdpUnresolvedRef pref in al)
+                                               pref.Name = newName;
+                                       break;
+                               }
+                               idx++;
+                       }
+               }
+
+               // remove ref and parentRef.
+               // add new defines for each elements.
+               private void CheckReferences (RdpPattern p)
+               {
+                       RdpAbstractBinary binary = p as RdpAbstractBinary;
+                       if (binary != null) {
+                               // choice, interleave, group
+                               CheckReferences (binary.LValue);
+                               CheckReferences (binary.RValue);
+                               return;
+                       }
+                       RdpAbstractSingleContent single = p as RdpAbstractSingleContent;
+                       if (single != null) {
+                               CheckReferences (single.Child);
+                               return;
+                       }
+
+                       switch (p.PatternType) {
+                       case RelaxngPatternType.Ref:
+                               // FIXME: This should not re-expand ref
+                               RdpUnresolvedRef pref = p as RdpUnresolvedRef;
+                               if (pref.RefPattern != null)
+                                       break;
+
+                               RelaxngGrammar target = pref.TargetGrammar;
+                               if (target == null)
+                                       // FIXME: fill line info
+                                       throw new RelaxngException ("Referenced definition was not found.");
+                               RdpPattern defP = target.assembledDefs [pref.Name] as RdpPattern;
+                               if (defP == null)
+                                       target.unresolvedPatterns.Add (p);
+                               else {
+                                       ArrayList al = target.refPatterns [defP] as ArrayList;
+                                       if (al == null) {
+                                               al = new ArrayList ();
+                                               target.refPatterns [defP] = al;
+                                       }
+                                       al.Add (p);
+                                       pref.RefPattern = defP;
+                               }
+                               break;
+
+                       case RelaxngPatternType.Attribute:
+                               CheckReferences (((RdpAttribute) p).Children);
+                               break;
+
+                       case RelaxngPatternType.DataExcept:
+                               CheckReferences (((RdpDataExcept) p).Except);
+                               break;
+
+                       case RelaxngPatternType.Element:
+                               RdpElement el = p as RdpElement;
+                               CheckReferences (el.Children);
+                               string name = ElementDefMap [el] as string;
+                               if (name == null) {
+                                       // add new define
+                                       int idx = 0;
+                                       string newName = "element0";
+                                       if (el.NameClass is RdpName)
+                                               newName = ((RdpName) el.NameClass).LocalName;
+                                       while (true) {
+                                                if (assembledDefs [newName] == null) {
+                                                       elementReplacedDefs [newName] = el.Children;
+                                                       break;
+                                               }
+                                               newName = "element" + ++idx;
+                                       }
+                                       ElementDefMap [el] = newName;
+                               }
+                               // Even though the element is replaced with ref,
+                               // derivative of ref is RdpElement in fact...
+                               break;
+
+                       case RelaxngPatternType.List:
+                               CheckReferences (((RdpList) p).Child);
+                               break;
+
+                       case RelaxngPatternType.Empty:
+                       case RelaxngPatternType.NotAllowed:
+                       case RelaxngPatternType.Text:
+                       case RelaxngPatternType.Value:
+                               break;
+
+                       //case RelaxngPatternType.ExternalRef:
+                       //case RelaxngPatternType.Include:
+                       // Mixed, Optional, ZeroOrMore are already removed.
+                       // Choice, Group, Interleave, OneOrMore are already proceeded.
+                       }
+               }
+
+               #region 4.17 - Combine
+               private void AssembleCombine ()
+               {
+                       // calculate combines.
+                       bool haveHeadStart = false;
+                       string combineStart = null;
+                       Hashtable haveHeadDefs = new Hashtable ();
+                       Hashtable combineDefs = new Hashtable ();
+
+                       // 1.calculate combine for starts.
+                       foreach (RelaxngStart start in starts)
+                               CheckCombine (ref haveHeadStart, 
+                                       ref combineStart, start.Combine, "start");
+                       // 2.calculate combine for defines.
+                       foreach (RelaxngDefine def in defs) {
+                               bool haveHead = 
+                                       haveHeadDefs.ContainsKey (def.Name) ?
+                                       haveHead = (bool) haveHeadDefs [def.Name]
+                                       : false;
+                               string combine = combineDefs [def.Name] as string;
+                               CheckCombine (ref haveHead, ref combine,
+                                       def.Combine, String.Format ("define name={0}", def.Name));
+                               haveHeadDefs [def.Name] = haveHead;
+                               combineDefs [def.Name] = combine;
+                               continue;
+                       }
+
+                       // assemble starts and defines with "combine" attribute.
+
+                       // 3.assemble starts.
+                       if (starts.Count == 0) {
+                               if (ParentGrammar == null)
+                                       throw new RelaxngException (this, "grammar must have at least one start component.");
+                       } else {
+                               assembledStart = ((RelaxngStart)starts [0]).Pattern;
+                               for (int i=1; i<starts.Count; i++) {
+                                       RelaxngPattern p2 = ((RelaxngStart) starts [i]).Pattern;;
+                                       if (combineStart == "interleave") {
+                                               RelaxngInterleave intlv = new RelaxngInterleave ();
+                                               intlv.Patterns.Add (assembledStart);
+                                               intlv.Patterns.Add (p2);
+                                               assembledStart = intlv;
+                                       } else {
+                                               RelaxngChoice c = new RelaxngChoice ();
+                                               c.Patterns.Add (assembledStart);
+                                               c.Patterns.Add (p2);
+                                               assembledStart = c;
+                                       }
+                               }
+                       }
+
+                       // 4.assemble defines
+                       foreach (RelaxngDefine def in defs) {
+                               string combine = combineDefs [def.Name] as string;
+                               RdpPattern p1 = 
+                                       assembledDefs [def.Name] as RdpPattern;
+                               RdpPattern p2 = def.Compile (this);
+                               if (p1 != null) {
+                                       if (combine == "interleave") {
+                                               assembledDefs [def.Name] =
+                                                       new RdpInterleave (p1, p2);
+                                       } else {
+                                               assembledDefs [def.Name] =
+                                                       new RdpChoice (p1, p2);
+                                       }
+                               } else {
+                                       assembledDefs [def.Name] = p2;
+                               }
+                       }
+
+               }
+
+               // check combine attributes.
+               private void CheckCombine (ref bool haveHead, ref string combine, string newCombine, string targetSpec)
+               {
+                       switch (newCombine) {
+                       case "interleave":
+                               if (combine == "choice")
+                                       throw new RelaxngException (this, "\"combine\" was already specified \"choice\"");
+                               else
+                                       combine = "interleave";
+                               break;
+                       case "choice":
+                               if (combine == "interleave")
+                                       throw new RelaxngException (this, "\"combine\" was already specified \"interleave\"");
+                               else
+                                       combine = "choice";
+                               break;
+                       case null:
+                               if (haveHead)
+                                       throw new RelaxngException (this, String.Format ("There was already \"{0}\" element without \"combine\" attribute.", targetSpec));
+                               haveHead = true;
+                               break;
+                       }
+               }
+               #endregion
+       }
+}