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