private void AddChildren(Tag parent) { List<Token> toks; while((toks=GetLineTokens())!=null) { int size = toks.Count; if(toks[0].type==Type.END_BLOCK) { return; } else if(toks[size-1].type==Type.START_BLOCK) { Tag tag = ConstructTag(toks.GetRange(0, size-1)); AddChildren(tag); parent.AddChild(tag); } else { parent.AddChild(ConstructTag(toks)); } } // we have to use -2 for position rather than -1 for unknown because // the parseException method adds 1 to line and position ParseException("No close block (}).", lineNumber, -2); }
/// <summary> /// Add the attributes /// </summary> /// <param name="tag">The tag to populate</param> /// <param name="toks">The token list to use</param> /// <param name="tpos">Where to start</param> private void AddTagAttributes(Tag tag, List<Token> toks, int tpos) { int i=tpos, size=toks.Count; while(i<size) { Token t = toks[i]; if(t.type!=Type.IDENTIFIER) ExpectingButGot("IDENTIFIER", t.type, t.line, t.position); string nameOrNamespace = t.text; if(i==size-1) ExpectingButGot("\":\" or \"=\" \"LITERAL\"", "END OF LINE.", t.line, t.position); t = toks[++i]; if(t.type==Type.COLON) { if(i==size-1) ExpectingButGot("IDENTIFIER", "END OF LINE", t.line, t.position); t = toks[++i]; if(t.type!=Type.IDENTIFIER) ExpectingButGot("IDENTIFIER", t.type, t.line, t.position); string name = t.text; if(i==size-1) ExpectingButGot("\"=\"", "END OF LINE", t.line, t.position); t = toks[++i]; if(t.type!=Type.EQUALS) ExpectingButGot("\"=\"", t.type, t.line, t.position); if(i==size-1) ExpectingButGot("LITERAL", "END OF LINE", t.line, t.position); t = toks[++i]; if(!t.literal) ExpectingButGot("LITERAL", t.type, t.line, t.position); if(t.type==Type.DATE && (i+1)<size && toks[i+1].type==Type.TIME) { SDLDateTime dt = (SDLDateTime)t.GetObjectForLiteral(); TimeSpanWithZone tswz = (TimeSpanWithZone) toks[i+1].GetObjectForLiteral(); if(tswz.Days!=0) ExpectingButGot("TIME (component of date/time) " + "in attribute value", "TIME SPAN", t.line, t.position); tag[nameOrNamespace, name]=Combine(dt,tswz); i++; } else { object v = t.GetObjectForLiteral(); if(v is TimeSpanWithZone) { TimeSpanWithZone tswz = (TimeSpanWithZone)v; if(tswz.TimeZone!=null) ExpectingButGot("TIME SPAN", "TIME (component of date/time)", t.line, t.position); TimeSpan ts = new TimeSpan( tswz.Days, tswz.Hours, tswz.Minutes, tswz.Seconds, tswz.Milliseconds); tag[nameOrNamespace, name]=ts; } else { tag[nameOrNamespace, name]=v; } } } else if(t.type==Type.EQUALS){ if(i==size-1) ExpectingButGot("LITERAL", "END OF LINE", t.line, t.position); t = toks[++i]; if(!t.literal) ExpectingButGot("LITERAL", t.type, t.line, t.position); if(t.type==Type.DATE && (i+1)<size && toks[i+1].type==Type.TIME) { SDLDateTime dc = (SDLDateTime)t.GetObjectForLiteral(); TimeSpanWithZone tswz = (TimeSpanWithZone) toks[i+1].GetObjectForLiteral(); if(tswz.Days!=0) ExpectingButGot("TIME (component of date/time) " + "in attribute value", "TIME SPAN", t.line, t.position); tag[nameOrNamespace]=Combine(dc,tswz); i++; } else { object v = t.GetObjectForLiteral(); if(v is TimeSpanWithZone) { TimeSpanWithZone tswz = (TimeSpanWithZone)v; if(tswz.TimeZone!=null) ExpectingButGot("TIME SPAN", "TIME (component of date/time)", t.line, t.position); TimeSpan ts = new TimeSpan( tswz.Days, tswz.Hours, tswz.Minutes, tswz.Seconds, tswz.Milliseconds); tag[nameOrNamespace]=ts; } else { tag[nameOrNamespace]=v; } } } else { ExpectingButGot("\":\" or \"=\"", t.type, t.line, t.position); } i++; } }
/// <summary> /// Add the values /// </summary> /// <param name="tag">The tag to populate</param> /// <param name="toks">The token list to use</param> /// <param name="tpos">Where to start</param> /// <returns>The position at the end of the value list</returns> private int AddTagValues(Tag tag, List<Token> toks, int tpos) { int size=toks.Count, i=tpos; for(;i<size;i++) { Token t = toks[i]; if(t.literal) { // if a DATE token is followed by a TIME token combine them if(t.type==Type.DATE && (i+1)<size && toks[i+1].type==Type.TIME) { SDLDateTime dt = (SDLDateTime)t.GetObjectForLiteral(); TimeSpanWithZone tswz = (TimeSpanWithZone) toks[i+1].GetObjectForLiteral(); if(tswz.Days!=0) { tag.AddValue(dt); tag.AddValue(new TimeSpan(tswz.Days, tswz.Hours, tswz.Minutes, tswz.Seconds, tswz.Milliseconds)); if(tswz.TimeZone!=null) ParseException("TimeSpan cannot have a " + "timezone", t.line, t.position); } else { tag.AddValue(Combine(dt,tswz)); } i++; } else { object v = t.GetObjectForLiteral(); if(v is TimeSpanWithZone) { TimeSpanWithZone tswz = (TimeSpanWithZone)v; if(tswz.TimeZone!=null) ExpectingButGot("TIME SPAN", "TIME (component of date/time)", t.line, t.position); tag.AddValue(new TimeSpan( tswz.Days, tswz.Hours, tswz.Minutes, tswz.Seconds, tswz.Milliseconds )); } else { tag.AddValue(v); } } } else if(t.type==Type.IDENTIFIER) { break; } else { ExpectingButGot("LITERAL or IDENTIFIER", t.type, t.line, t.position); } } return i; }
/// <summary> /// Construct a tag (but not its children) from a string of tokens /// </summary> /// <param name="toks"></param> /// <returns>A tag with no children</returns> /// <exception cref="SDLParseException">If the tokens do not represent /// valid SDL</exception> Tag ConstructTag(List<Token> toks) { if(toks.Count==0) // we have to use -2 for position rather than -1 for unknown because // the parseException method adds 1 to line and position ParseException("Internal Error: Empty token list", lineNumber, -2); Token t0 = toks[0]; if(t0.literal) { toks.Insert(0, t0=new Token(this, "content", -1, -1)); } else if(t0.type!=Type.IDENTIFIER) { ExpectingButGot("IDENTIFIER", "" + t0.type + " (" + t0.text + ")", t0.line, t0.position); } int size = toks.Count; Tag tag = null; if(size==1) { tag = new Tag(t0.text); } else { int valuesStartIndex = 1; Token t1 = toks[1]; if(t1.type==Type.COLON) { if(size==2 || toks[2].type!=Type.IDENTIFIER) ParseException("Colon (:) encountered in unexpected " + "location.", t1.line, t1.position); Token t2 = toks[2]; tag = new Tag(t0.text,t2.text); valuesStartIndex = 3; } else { tag = new Tag(t0.text); } // read values int i =AddTagValues(tag, toks, valuesStartIndex); // read attributes if(i<size) AddTagAttributes(tag, toks, i); } return tag; }
/// <summary> /// Remove a child from this tag /// </summary> /// <param name="child">The child to remove</param> /// <returns>true if the child is removed</returns> public bool RemoveChild(Tag child) { childrenDirty = true; return children.Remove(child); }
//////////////////////////////////////////////////////////////////////// /// <summary> /// Add a child to this tag /// </summary> /// <param name="child">The child to add</param> public void AddChild(Tag child) { childrenDirty = true; children.Add(child); }