remove svn:executable from .cs files
[mono.git] / mcs / class / Commons.Xml.Relaxng / Commons.Xml.Nvdl / NvdlSimplified.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Specialized;
4 using System.Xml;
5
6 namespace Commons.Xml.Nvdl
7 {
8         internal class SimplifiedItem : IXmlLineInfo
9         {
10                 int line;
11                 int column;
12                 string sourceUri = String.Empty;
13
14                 public int LineNumber {
15                         get { return line; }
16                         set { line = value; }
17                 }
18
19                 public int LinePosition {
20                         get { return column; }
21                         set { column = value; }
22                 }
23
24                 public string SourceUri {
25                         get { return sourceUri; }
26                         set { sourceUri = value != null ? value : String.Empty; }
27                 }
28
29                 internal void FillLocation (NvdlElementBase e)
30                 {
31                         line = e.LineNumber;
32                         column = e.LinePosition;
33                         sourceUri = e.SourceUri;
34                 }
35
36                 public bool HasLineInfo ()
37                 {
38                         return line != 0;
39                 }
40
41                 public string Location {
42                         get { return line != 0 ? String.Format ("{0} ({1},{2})", sourceUri, line, column) : String.Empty; }
43                 }
44         }
45
46         internal class SimpleRules : SimplifiedItem
47         {
48                 SimpleMode startMode;
49                 XmlQualifiedName [] triggers;
50
51                 // FIXME: It is not used in validation step, so move it to
52                 // compile context
53                 SimpleMode [] modes;
54
55                 public SimpleRules (NvdlCompileContext context)
56                 {
57                         FillLocation (context.Rules);
58                         SimplifyPhase1 (context); // 6.4.1 - 10.
59                         SimplifyPhase2 (context); // 6.4.11 - 14.
60                         ResolveModes (context); // 6.4.15.
61                 }
62
63                 public SimpleMode StartMode {
64                         get { return startMode; }
65                 }
66
67                 public XmlQualifiedName [] Triggers {
68                         get { return triggers; }
69                 }
70
71                 #region Simplification
72                 private void SimplifyPhase1 (NvdlCompileContext ctx)
73                 {
74                         NvdlRules rules = ctx.Rules;
75                         // 6.4.1 : just ignore "Foreign" property.
76                         // 6.4.2 : already ignored on reading nvdl.
77                         // 6.4.3 : done in SOM
78                         // 6.4.4 : FIXME: must be done.
79                         // 6.4.5 : FIXME: considered in compiler.
80                         // 6.4.6 : FIXME: considered in compiler.
81                         // 6.4.7 : FIXME: considered in compiler.
82
83                         // 6.4.8 : here
84                         NvdlModeList list = rules.Modes;
85                         NvdlMode startMode = null;
86
87                         if (rules.Modes.Count > 0) {
88                                 if (rules.Rules.Count > 0)
89                                         throw new NvdlCompileException ("Modes and rules cannot coexist in 'rules' element.", rules);
90                                 else if (rules.StartMode == null)
91                                         throw new NvdlCompileException ("startMode is missing in 'rules' element when modes are specified.", rules);
92                                 foreach (NvdlMode m in rules.Modes) {
93                                         if (m.Name == rules.StartMode) {
94                                                 startMode = m;
95                                                 break;
96                                         }
97                                 }
98                                 if (startMode == null)
99                                         throw new NvdlCompileException ("Matching 'mode' element specified by 'startMode' does not exist.", rules);
100                         } else {
101                                 if (rules.Rules.Count == 0)
102                                         throw new NvdlCompileException ("Neither modes nor rules exists in 'rules' element.", rules);
103                                 list = new NvdlModeList ();
104                                 startMode = new NvdlMode ();
105                                 startMode.SourceUri = rules.SourceUri;
106                                 startMode.LineNumber = rules.LineNumber;
107                                 startMode.LinePosition = rules.LinePosition;
108                                 startMode.Name = "(startMode)";
109                                 list.Add (startMode);
110                                 foreach (NvdlRule rule in rules.Rules)
111                                         startMode.Rules.Add (rule);
112                         }
113
114                         // 6.4.9 : done in SimpleMode.ctor() and
115                         // SimpleRule.ctor(), using ctx.CompiledModes.
116                         foreach (NvdlMode m in list) {
117                                 SimpleMode sm = new SimpleMode (m, ctx);
118                                 ctx.AddCompiledMode (sm.Name, sm);
119                                 if (m == startMode)
120                                         this.startMode = sm;
121                         }
122
123                         // 6.4.10 : done in SimpleRule.Simplify
124
125                         triggers = new XmlQualifiedName [rules.Triggers.Count];
126                         for (int i = 0; i < triggers.Length; i++) {
127                                 NvdlTrigger t = rules.Triggers [i];
128                                 triggers [i] = new XmlQualifiedName (
129                                         t.Name, t.NS);
130                         }
131
132                         modes = (SimpleMode [])
133                                 new ArrayList (ctx.GetCompiledModes ())
134                                 .ToArray (typeof (SimpleMode));
135                 }
136
137                 private void SimplifyPhase2 (NvdlCompileContext ctx)
138                 {
139                         foreach (SimpleMode mode in modes)
140                                 mode.SimplifyPhase2 (ctx);
141                 }
142
143                 private void ResolveModes (NvdlCompileContext ctx)
144                 {
145                         foreach (SimpleMode mode in modes)
146                                 mode.ResolveModes (ctx);
147                 }
148                 #endregion
149         }
150
151         internal class SimpleMode : SimplifiedItem
152         {
153                 string name;
154                 SimpleRule [] rules;
155
156                 // They are available only after complete simplification.
157                 SimpleRule [] elementRules;
158                 SimpleRule [] attributeRules;
159
160                 public SimpleMode (NvdlMode mode, NvdlCompileContext ctx)
161                 {
162                         FillLocation (mode);
163
164                         if (mode.Name == null)
165                                 throw new NvdlCompileException (
166                                         "'mode' element must have a name.", mode);
167                         this.name = mode.Name;
168                         SimplifyPhase1 (mode, ctx);
169                 }
170
171                 public SimpleMode (string name, NvdlNestedMode mode,
172                         NvdlCompileContext ctx)
173                 {
174                         FillLocation (mode);
175
176                         this.name = name;
177                         SimplifyPhase1 (mode, ctx);
178                 }
179
180                 public SimpleMode (NvdlIncludedMode mode, NvdlCompileContext ctx)
181                 {
182                         FillLocation (mode);
183
184                         // name doesn't matter here.
185                         SimplifyPhase1 (mode, ctx);
186                 }
187
188                 public string Name {
189                         get { return name; }
190                 }
191
192                 public SimpleRule [] ElementRules {
193                         get { return elementRules; }
194                 }
195
196                 public SimpleRule [] AttributeRules {
197                         get { return attributeRules; }
198                 }
199
200                 private void SimplifyPhase1 (NvdlModeBase mode,
201                         NvdlCompileContext ctx)
202                 {
203                         NvdlModeCompileContext mctx =
204                                 new NvdlModeCompileContext (mode);
205                         ctx.AddModeContext (this, mctx);
206                         ArrayList al = new ArrayList ();
207                         foreach (NvdlRule r in mode.Rules) {
208                                 switch (r.Match) {
209                                 case NvdlRuleTarget.Both:
210                                         al.Add (new SimpleRule (r, true, ctx));
211                                         al.Add (new SimpleRule (r, false, ctx));
212                                         break;
213                                 case NvdlRuleTarget.None:
214                                 case NvdlRuleTarget.Elements:
215                                         al.Add (new SimpleRule (r, false, ctx));
216                                         break;
217                                 case NvdlRuleTarget.Attributes:
218                                         al.Add (new SimpleRule (r, true, ctx));
219                                         break;
220                                 }
221                         }
222                         foreach (NvdlIncludedMode inc in mode.IncludedModes)
223                                 mctx.Included.Add (new SimpleMode (inc, ctx));
224                         // The rule table is just a dummy store that might
225                         // erase because of removal of inclusion.
226                         rules = (SimpleRule []) al.ToArray (typeof (SimpleRule));
227                 }
228
229                 internal void SimplifyPhase2 (NvdlCompileContext ctx)
230                 {
231                         ArrayList al = new ArrayList ();
232                         ConsumeIncludes (al, ctx);
233                         SimpleRule anyElement = null;
234                         SimpleRule anyAttribute = null;
235                         // 6.4.12 + part of 6.4.13
236                         CheckCollision (al, ref anyElement, ref anyAttribute);
237                         // 6.4.13
238                         if (anyElement == null) {
239                                 NvdlAnyNamespace ann = new NvdlAnyNamespace ();
240                                 ann.SourceUri = this.SourceUri;
241                                 ann.LineNumber = this.LineNumber;
242                                 ann.LinePosition = this.LinePosition;
243
244                                 NvdlReject reject = new NvdlReject ();
245                                 reject.SourceUri = this.SourceUri;
246                                 reject.LineNumber = this.LineNumber;
247                                 reject.LinePosition = this.LinePosition;
248                                 ann.Actions.Add (reject);
249                                 ann.Match = NvdlRuleTarget.Elements;
250
251                                 al.Add (new SimpleRule (ann, false, ctx));
252                         }
253                         if (anyAttribute == null) {
254                                 NvdlAnyNamespace ann = new NvdlAnyNamespace ();
255                                 ann.SourceUri = this.SourceUri;
256                                 ann.LineNumber = this.LineNumber;
257                                 ann.LinePosition = this.LinePosition;
258
259                                 NvdlAttach attach = new NvdlAttach ();
260                                 attach.SourceUri = this.SourceUri;
261                                 attach.LineNumber = this.LineNumber;
262                                 attach.LinePosition = this.LinePosition;
263                                 ann.Match = NvdlRuleTarget.Attributes;
264                                 ann.Actions.Add (attach);
265
266                                 al.Add (new SimpleRule (ann, true, ctx));
267                         }
268                         rules = (SimpleRule []) al.ToArray (typeof (SimpleRule));
269                 }
270
271                 private void ConsumeIncludes (ArrayList al,
272                         NvdlCompileContext ctx)
273                 {
274                         // The reason why we limit the check to current count
275                         // is to add invalid siblings (according to 6.4.12).
276                         int checkMax = al.Count;
277                         NvdlModeCompileContext mctx = ctx.GetModeContext (this);
278                         foreach (SimpleRule rule in rules) {
279                                 if (ctx.CancelledRules [rule] != null)
280                                         continue;
281                                 bool exclude = false;
282                                 for (int i = 0; i < checkMax; i++) {
283                                         SimpleRule r = (SimpleRule) al [i];
284                                         if (rule.IsAny == r.IsAny &&
285                                                 rule.MatchAttributes == r.MatchAttributes &&
286                                                 rule.NS == r.NS &&
287                                                 rule.Wildcard == r.Wildcard) {
288                                                 exclude = true;
289                                                 break;
290                                         }
291                                 }
292                                 if (exclude)
293                                         break;
294                                 al.Add (rule);
295                         }
296                         foreach (SimpleMode mode in mctx.Included)
297                                 mode.ConsumeIncludes (al, ctx);
298                 }
299
300                 private void CheckCollision (ArrayList al, ref SimpleRule el, ref SimpleRule attr)
301                 {
302                         for (int i = 0; i < al.Count; i++) {
303                                 SimpleRule r1 = (SimpleRule) al [i];
304                                 if (r1.IsAny) {
305                                         if (r1.MatchAttributes)
306                                                 attr = r1;
307                                         else
308                                                 el = r1;
309                                 }
310                                 for (int j = i + 1; j < al.Count; j++) {
311                                         SimpleRule r2 = (SimpleRule) al [j];
312                                         if (r1.MatchAttributes != r2.MatchAttributes)
313                                                 continue;
314                                         if (r1.IsAny && r2.IsAny)
315                                                 throw new NvdlCompileException ("collision in mode was found. Two anyNamespace elements.", this);
316                                         if (r1.IsAny || r2.IsAny)
317                                                 continue;
318                                         if (Nvdl.NSMatches (r1.NS, 0, r1.Wildcard,
319                                                 r2.NS, 0, r2.Wildcard))
320                                                 throw new NvdlCompileException ("collision in mode was found.", this);
321                                 }
322                         }
323                 }
324
325                 internal void ResolveModes (NvdlCompileContext ctx)
326                 {
327                         // Resolve moces and fill element/attributeRules.
328                         ArrayList e = new ArrayList ();
329                         ArrayList a = new ArrayList ();
330                         foreach (SimpleRule rule in rules) {
331                                 rule.ResolveModes (ctx, this);
332                                 if (rule.MatchAttributes)
333                                         a.Add (rule);
334                                 else
335                                         e.Add (rule);
336                         }
337
338                         elementRules = (SimpleRule []) e.ToArray (typeof (SimpleRule));
339                         attributeRules = (SimpleRule []) a.ToArray (typeof (SimpleRule));
340                 }
341         }
342
343         internal class SimpleRule : SimplifiedItem
344         {
345                 bool matchAttributes;
346                 SimpleAction [] actions;
347
348                 readonly string ns;
349                 readonly string wildcard;
350                 bool isAny;
351
352                 public SimpleRule (NvdlRule rule, bool matchAttributes,
353                         NvdlCompileContext ctx)
354                 {
355                         FillLocation (rule);
356
357                         this.matchAttributes = matchAttributes;
358                         NvdlNamespace nss = rule as NvdlNamespace;
359                         if (nss == null)
360                                 this.isAny = true;
361                         else {
362                                 this.ns = nss.NS;
363                                 if (nss.Wildcard == null)
364                                         wildcard = "*";
365                                 else if (nss.Wildcard.Length > 1)
366                                         throw new NvdlCompileException ("'wildcard' attribute can specify at most one character string.", rule);
367                                 else
368                                         wildcard = nss.Wildcard;
369                         }
370
371                         SimplifyPhase1 (rule, ctx);
372                 }
373
374                 public bool MatchAttributes {
375                         get { return matchAttributes; }
376                 }
377
378                 public SimpleAction [] Actions {
379                         get { return actions; }
380                 }
381
382                 public string NS {
383                         get { return ns; }
384                 }
385
386                 public string Wildcard {
387                         get { return wildcard; }
388                 }
389
390                 public bool IsAny {
391                         get { return isAny; }
392                 }
393
394                 public bool MatchNS (string target)
395                 {
396                         if (isAny)
397                                 return true;
398                         return Nvdl.NSMatches (ns, 0, wildcard, target, 0, "");
399                 }
400
401                 private void SimplifyPhase1 (NvdlRule r, NvdlCompileContext ctx)
402                 {
403                         ctx.AddRuleContext (this, r);
404                         // 6.4.9
405                         ArrayList al = new ArrayList ();
406                         foreach (NvdlAction a in r.Actions) {
407                                 NvdlNoCancelAction nca =
408                                         a as NvdlNoCancelAction;
409                                 if (nca != null) {
410                                         if (nca.ModeUsage != null)
411                                                 SimplifyModeUsage (nca, ctx);
412                                         NvdlResultAction ra = nca as NvdlResultAction;
413                                         if (ra != null)
414                                                 al.Add (new SimpleResultAction (ra, ctx));
415                                         else if (nca is NvdlValidate)
416                                                 al.Add (new SimpleValidate (
417                                                         (NvdlValidate) nca, ctx));
418                                         else if (nca is NvdlAllow)
419                                                 al.Add (new SimpleValidate (
420                                                         (NvdlAllow) nca, ctx));
421                                         else
422                                                 al.Add (new SimpleValidate (
423                                                         (NvdlReject) nca, ctx));
424                                 }
425                                 else if (nca == null)
426                                         ctx.CancelledRules.Add (this, this);
427                         }
428                         actions = (SimpleAction []) al.ToArray (
429                                 typeof (SimpleAction));
430                 }
431
432                 private void SimplifyModeUsage (
433                         NvdlNoCancelAction nca, NvdlCompileContext ctx)
434                 {
435                         NvdlModeUsage usage = nca.ModeUsage;
436                         if (usage.NestedMode != null && ctx.GetCompiledMode (usage) == null) {
437                                 SimpleMode sm = new SimpleMode (String.Empty,
438                                         usage.NestedMode, ctx);
439                                 ctx.AddCompiledMode (usage, sm);
440                         }
441                         foreach (NvdlContext c in usage.Contexts) {
442                                 if (c.NestedMode != null) {
443                                         SimpleMode sm = new SimpleMode (
444                                                 String.Empty, c.NestedMode, ctx);
445                                         ctx.AddCompiledMode (c, sm);
446                                 }
447                         }
448                 }
449
450                 internal void ResolveModes (NvdlCompileContext ctx, SimpleMode current)
451                 {
452                         foreach (SimpleAction a in actions)
453                                 a.ResolveModes (ctx, current);
454                 }
455         }
456
457         internal abstract class SimpleAction : SimplifiedItem
458         {
459                 readonly ListDictionary messages;
460                 readonly SimpleModeUsage modeUsage;
461                 SimpleMode mode;
462
463                 protected SimpleAction (NvdlNoCancelAction action)
464                 {
465                         FillLocation (action);
466
467                         if (action.ModeUsage != null)
468                                 modeUsage = new SimpleModeUsage (action.ModeUsage);
469                         messages = new ListDictionary ();
470                         if (action.SimpleMessage != null)
471                                 messages.Add ("", action.SimpleMessage);
472                         foreach (NvdlMessage msg in action.Messages)
473                                 messages.Add (msg.XmlLang, msg.Text);
474                 }
475
476                 public abstract bool NoResult { get; }
477
478                 public ListDictionary Messages {
479                         get { return messages; }
480                 }
481
482                 public SimpleMode DefaultMode {
483                         get { return mode; }
484                 }
485
486                 public SimpleContext [] Contexts {
487                         get { return modeUsage.Contexts; }
488                 }
489
490                 internal void ResolveModes (NvdlCompileContext ctx, SimpleMode current)
491                 {
492                         if (modeUsage != null) {
493                                 modeUsage.ResolveModes (ctx, current);
494                                 mode = modeUsage.UseMode;
495                         }
496                         if (mode == null)
497                                 mode = current;
498                 }
499         }
500
501         internal class SimpleValidate : SimpleAction
502         {
503                 readonly NvdlValidatorGenerator generator;
504                 XmlResolver resolver;
505
506                 static NvdlValidate CreateBuiltInValidate (NvdlAction a)
507                 {
508                         bool allow = a is NvdlAllow;
509                         NvdlValidate v = new NvdlValidate ();
510                         v.SourceUri = a.SourceUri;
511                         v.LineNumber = a.LineNumber;
512                         v.LinePosition = a.LinePosition;
513                         v.ModeUsage = new NvdlModeUsage ();
514                         XmlDocument doc = new XmlDocument ();
515                         XmlElement el = doc.CreateElement (
516                                 allow ? "allow" : "reject",
517                                 Nvdl.BuiltInValidationNamespace);
518                         doc.AppendChild (doc.CreateElement ("schema",
519                                 Nvdl.Namespace));
520                         doc.DocumentElement.AppendChild (el);
521                         v.SchemaBody = doc.DocumentElement;
522                         return v;
523                 }
524
525                 // 6.4.14
526                 public SimpleValidate (NvdlAllow allow, NvdlCompileContext ctx)
527                         : this (CreateBuiltInValidate (allow), ctx)
528                 {
529                 }
530
531                 // 6.4.14
532                 public SimpleValidate (NvdlReject reject, NvdlCompileContext ctx)
533                         : this (CreateBuiltInValidate (reject), ctx)
534                 {
535                 }
536
537                 public SimpleValidate (
538                         NvdlValidate validate,
539                         NvdlCompileContext ctx)
540                         : base (validate)
541                 {
542                         // 6.4.7
543                         generator = ctx.Config.GetGenerator (validate,
544                                 ctx.Rules.SchemaType);
545                 }
546
547                 internal NvdlValidatorGenerator Generator {
548                         get { return generator; }
549                 }
550
551                 public override bool NoResult {
552                         get { return true; }
553                 }
554
555                 public XmlReader CreateValidator (XmlReader reader)
556                 {
557                         return generator.CreateValidator (reader, resolver);
558                 }
559
560                 public void ValidateAttributes (XmlReader reader, string ns)
561                 {
562                         XmlDocument doc = new XmlDocument ();
563                         XmlElement el = doc.CreateElement ("virtualElement",
564                                 Nvdl.InstanceNamespace);
565                         for (int i = 0; i < reader.AttributeCount; i++) {
566                                 reader.MoveToAttribute (i);
567                                 if (reader.NamespaceURI != ns)
568                                         continue;
569                                 el.SetAttribute (reader.LocalName,
570                                         reader.NamespaceURI, reader.Value);
571                         }
572                         reader.MoveToElement ();
573                         XmlReader r = generator.CreateAttributeValidator (
574                                 new XmlNodeReader (el), resolver);
575                         while (!r.EOF)
576                                 r.Read ();
577                 }
578         }
579
580         internal class SimpleResultAction : SimpleAction
581         {
582                 readonly NvdlResultType resultType;
583
584                 public SimpleResultAction (NvdlResultAction ra,
585                         NvdlCompileContext ctx)
586                         : base (ra)
587                 {
588                         this.resultType = ra.ResultType;
589                 }
590
591                 public override bool NoResult {
592                         get { return false; }
593                 }
594
595                 public NvdlResultType ResultType {
596                         get { return resultType; }
597                 }
598         }
599
600         internal class SimpleModeUsage : SimplifiedItem
601         {
602                 // It will never be used in validation.
603                 NvdlModeUsage source; // FIXME: put this into CompileContext
604                 readonly SimpleContext [] contexts;
605                 SimpleMode mode;
606
607                 public SimpleModeUsage (NvdlModeUsage usage)
608                 {
609                         this.source = usage;
610                         contexts = new SimpleContext [usage.Contexts.Count];
611                         for (int i = 0; i < contexts.Length; i++)
612                                 contexts [i] = new SimpleContext (
613                                         usage.Contexts [i]);
614                 }
615
616                 internal void ResolveModes (NvdlCompileContext ctx, SimpleMode current)
617                 {
618                         if (source.UseMode != null) {
619                                 mode = ctx.GetCompiledMode (source.UseMode);
620                         }
621                         else if (source.NestedMode != null)
622                                 mode = ctx.GetCompiledMode (source);
623                         else
624                                 mode = current;
625
626                         for (int i = 0; i < contexts.Length; i++)
627                                 contexts [i].ResolveModes (ctx, mode);
628
629                         // FIXME: get location by some way
630                         if (mode == null)
631                                 throw new NvdlCompileException (
632                                         "mode does not contain either referenced modeUsage or nested mode.", null);
633                 }
634
635                 public SimpleMode UseMode {
636                         get { return mode; }
637                 }
638
639                 public SimpleContext [] Contexts {
640                         get { return contexts; }
641                 }
642         }
643
644         internal class SimplePath
645         {
646                 readonly SimplePathStep [] steps;
647
648                 public SimplePath (SimplePathStep [] steps)
649                 {
650                         this.steps = steps;
651                 }
652
653                 public SimplePathStep [] Steps {
654                         get { return steps; }
655                 }
656         }
657
658         internal class SimplePathStep
659         {
660                 readonly string name;
661                 readonly bool descendants;
662
663                 public SimplePathStep (string name, bool descendants)
664                 {
665                         this.name = name;
666                         this.descendants = descendants;
667                 }
668
669                 public string Name {
670                         get { return name; }
671                 }
672
673                 public bool Descendants {
674                         get { return descendants; }
675                 }
676         }
677
678         internal class SimpleContext : SimplifiedItem
679         {
680                 readonly string useModeName; // It is never used in validation.
681                 SimpleMode useMode;
682                 SimplePath [] path;
683
684                 public SimpleContext (NvdlContext context)
685                 {
686                         FillLocation (context);
687
688                         this.useModeName = context.UseMode;
689
690                         try {
691                                 string [] spaths = context.Path.Split ('|');
692                                 ArrayList al = new ArrayList ();
693                                 foreach (string spathws in spaths) {
694                                         string spath = spathws.Trim (
695                                                 Nvdl.Whitespaces);
696                                         if (spath.Length == 0)
697                                                 continue;
698                                         ParsePath (al, spath);
699                                 }
700                                 path = (SimplePath []) al.ToArray (
701                                         typeof (SimplePath));
702                         } catch (XmlException ex) {
703                                 throw new NvdlCompileException (String.Format ("Invalid path string: {0}", path), ex, context);
704                         }
705                 }
706
707                 private void ParsePath (ArrayList al, string path)
708                 {
709                         ArrayList steps = new ArrayList ();
710                         int start = 0;
711                         do {
712                                 int idx = path.IndexOf ('/', start);
713                                 if (idx < 0) {
714                                         steps.Add (new SimplePathStep (path.Substring (start), false));
715                                         start = path.Length;
716                                 }
717                                 else if (path.Length > idx + 1 && path [idx + 1] == '/') {
718                                         steps.Add (new SimplePathStep (path.Substring (start, idx - start), true));
719                                         start = idx + 2;
720                                 } else {
721                                         steps.Add (new SimplePathStep (path.Substring (start, idx - start), false));
722                                         start = idx + 1;
723                                 }
724                                 
725                         } while (start < path.Length);
726                         al.Add (new SimplePath (steps.ToArray (typeof (SimplePathStep)) as SimplePathStep []));
727                 }
728
729                 internal SimplePath [] Path {
730                         get { return path; }
731                 }
732
733                 public SimpleMode UseMode {
734                         get { return useMode; }
735                 }
736
737                 internal void ResolveModes (NvdlCompileContext ctx, SimpleMode current)
738                 {
739                         if (useModeName != null)
740                                 useMode = ctx.GetCompiledMode (useModeName);
741                         else
742                                 useMode = current;
743
744                         if (useMode == null)
745                                 throw new NvdlCompileException (String.Format ("Specified mode '{0}' was not found.",
746                                         useModeName), this);
747                 }
748         }
749 }