protected TALCommand Compile_METAL_FILL_PARAM(string argument) { // Compile a fill-param command, resulting argument is: // Argument: [(paramName, paramPath),...] // Break up the list of defines first List<DefineInfo> commandArgs = new List<DefineInfo>(); // We only want to match semi-colons that are not escaped foreach (string defStmt in Constants.METAL_FILL_PARAM_REGEX.Split(argument)) { // remove any leading space and un-escape any semi-colons string defineStmt = defStmt.TrimStart().Replace(";;", ";"); // Break each defineStmt into pieces "[local|global] varName expression" List<string> stmtBits = new List<string>(defineStmt.Split(new char[] { ' ' })); string varName; string expression; if (stmtBits.Count < 2) { // Error, badly formed fill-param command string msg = string.Format("Badly formed fill-param command '{0}'. Fill-param commands must be of the form: 'varName expression[;varName expression]'", argument); throw new TemplateParseException(this.currentStartTag, msg); } varName = stmtBits[0]; expression = string.Join(" ", stmtBits.GetRange(1, stmtBits.Count - 1).ToArray()); DefineInfo di = new DefineInfo(); di.defAction = DefineAction.Local; di.varName = varName; di.varPath = expression; commandArgs.Add(di); } // Determine what use-macro statement this belongs to by working through the list backwards int? ourMacroLocation = null; int location = this.tagStack.Count - 1; while (ourMacroLocation == null) { int macroLocation = this.tagStack[location].UseMacroLocation; if (macroLocation != -1) { ourMacroLocation = macroLocation; } else { location -= 1; if (location < 0) { string msg = string.Format("metal:fill-param must be used inside a metal:use-macro call"); throw new TemplateParseException(this.currentStartTag, msg); } } } // Get the use-macro command we are going to adjust TALCommand cmnd = this.commandList[(int)ourMacroLocation]; string macroName = (string)cmnd.Attributes[0]; Dictionary<string, TALSubProgram> slotMap = (Dictionary<string, TALSubProgram>)cmnd.Attributes[1]; List<DefineInfo> paramMap = (List<DefineInfo>)cmnd.Attributes[2]; int endSymbol = (int)cmnd.Attributes[3]; // Append param definitions to list paramMap.AddRange(commandArgs); // Update the command TALCommand ci = new TALCommand(); ci.Tag = cmnd.Tag; ci.ID = cmnd.ID; ci.Attributes = new List<object>(); ci.Attributes.Add(macroName); ci.Attributes.Add(slotMap); ci.Attributes.Add(paramMap); ci.Attributes.Add(endSymbol); this.commandList[(int)ourMacroLocation] = ci; return null; }
protected TALCommand Compile_METAL_FILL_SLOT(string argument) { if (argument.Length == 0) { // No argument passed string msg = "No argument passed! fill-slot commands must be of the form: 'fill-slot: name'"; throw new TemplateParseException(this.currentStartTag, msg); } // Check that the name of the slot is valid if (Constants.METAL_NAME_REGEX.Match(argument).Length != argument.Length) { string msg = string.Format("Slot name {0} is invalid.", argument); throw new TemplateParseException(this.currentStartTag, msg); } // Determine what use-macro statement this belongs to by working through the list backwards int? ourMacroLocation = null; int location = this.tagStack.Count - 1; while (ourMacroLocation == null) { int macroLocation = this.tagStack[location].UseMacroLocation; if (macroLocation != -1) { ourMacroLocation = macroLocation; } else { location -= 1; if (location < 0) { string msg = string.Format("metal:fill-slot must be used inside a metal:use-macro call"); throw new TemplateParseException(this.currentStartTag, msg); } } } // Get the use-macro command we are going to adjust TALCommand cmnd = this.commandList[(int)ourMacroLocation]; string macroName = (string)cmnd.Attributes[0]; Dictionary<string, TALSubProgram> slotMap = (Dictionary<string, TALSubProgram>)cmnd.Attributes[1]; List<DefineInfo> paramMap = (List<DefineInfo>)cmnd.Attributes[2]; int endSymbol = (int)cmnd.Attributes[3]; if (slotMap.ContainsKey(argument)) { string msg = string.Format("Slot {0} has already been filled!", argument); throw new TemplateParseException(this.currentStartTag, msg); } // The slot starts at the next command. TALSubProgram slot = new TALSubProgram(this.commandList.Count, this.endTagSymbol); slotMap.Add(argument, slot); // Update the command TALCommand ci = new TALCommand(); ci.Tag = cmnd.Tag; ci.ID = cmnd.ID; ci.Attributes = new List<object>(); ci.Attributes.Add(macroName); ci.Attributes.Add(slotMap); ci.Attributes.Add(paramMap); ci.Attributes.Add(endSymbol); this.commandList[(int)ourMacroLocation] = ci; return null; }
protected TALCommand Compile_METAL_DEFINE_PARAM(string argument) { // Compile a define-param command, resulting argument is: // Argument: [(paramType, paramName, paramPath),...] // Break up the list of defines first List<DefineInfo> commandArgs = new List<DefineInfo>(); // We only want to match semi-colons that are not escaped foreach (string defStmt in Constants.METAL_DEFINE_PARAM_REGEX.Split(argument)) { // remove any leading space and un-escape any semi-colons string defineStmt = defStmt.TrimStart().Replace(";;", ";"); // Break each defineStmt into pieces "[local|global] varName expression" List<string> stmtBits = new List<string>(defineStmt.Split(new char[] { ' ' })); string varType; string varName; string expression; if (stmtBits.Count < 3) { // Error, badly formed define-param command string msg = string.Format("Badly formed define-param command '{0}'. Define commands must be of the form: 'varType varName expression[;varType varName expression]'", argument); throw new TemplateParseException(this.currentStartTag, msg); } varType = stmtBits[0]; varName = stmtBits[1]; expression = string.Join(" ", stmtBits.GetRange(2, stmtBits.Count - 2).ToArray()); DefineInfo di = new DefineInfo(); di.defAction = DefineAction.Local; di.varType = varType; di.varName = varName; di.varPath = expression; commandArgs.Add(di); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.METAL_DEFINE_PARAM; ci.Attributes = new List<object>(); ci.Attributes.Add(commandArgs); return ci; }
protected TALCommand Compile_METAL_DEFINE_SLOT(string argument) { // Compile a define-slot command, resulting argument is: // Argument: macroName, endTagSymbol if (argument.Length == 0) { // No argument passed string msg = "No argument passed! define-slot commands must be of the form: 'name'"; throw new TemplateParseException(this.currentStartTag, msg); } // Check that the name of the slot is valid if (Constants.METAL_NAME_REGEX.Match(argument).Length != argument.Length) { string msg = string.Format("Slot name {0} is invalid.", argument); throw new TemplateParseException(this.currentStartTag, msg); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.METAL_DEFINE_SLOT; ci.Attributes = new List<object>(); ci.Attributes.Add(argument); ci.Attributes.Add(this.endTagSymbol); return ci; }
protected void AddCommand(TALCommand command) { // <DEBUG> //this.LogCommand(command); // </DEBUG> // // Only following commands can be used inside Tags without scope: // TAL_DEFINE, TAL_OUTPUT // Following commands are ignored by the "SourceGenerator" class: // TAL_START_SCOPE, TAL_STARTTAG, TAL_ENDTAG_ENDSCOPE, TAL_OMITTAG // if (command.Tag != null && command.Tag.OmitTagScope == true && command.ID != Constants.TAL_DEFINE && command.ID != Constants.TAL_OUTPUT && command.ID != Constants.TAL_START_SCOPE && command.ID != Constants.TAL_STARTTAG && command.ID != Constants.TAL_ENDTAG_ENDSCOPE && command.ID != Constants.TAL_OMITTAG) { // This command can not be used inside tag without his own scope string msg = string.Format(@"Command ""{0}"" can not be used inside tag <tal:omit-scope>'.", Constants.GetCommandName(command.ID)); throw new TemplateParseException(this.currentStartTag, msg); } if (command.ID == Constants.TAL_OUTPUT && this.commandList.Count > 0 && this.commandList[this.commandList.Count - 1].ID == Constants.TAL_OUTPUT) { // We can combine output commands TALCommand cmd = this.commandList[this.commandList.Count - 1]; foreach (object att in command.Attributes) cmd.Attributes.Add(att); } else { this.commandList.Add(command); } }
protected void addTag(Tag tag, Dictionary<string, string> cleanAttributes, Dictionary<string, object> tagProperties) { // Used to add a tag to the stack. Various properties can be passed in the dictionary // as being information required by the tag. // Currently supported properties are: // 'command' - The (command,args) tuple associated with this command // 'originalAtts' - The original attributes that include any metal/tal attributes // 'endTagSymbol' - The symbol associated with the end tag for this element // 'popFunctionList' - A list of functions to execute when this tag is popped // 'singletonTag' - A boolean to indicate that this is a singleton flag tag.Attributes = cleanAttributes; // Add the tag to the tagStack (list of tuples (tag, properties, useMacroLocation)) TALCommand command = (TALCommand)(tagProperties.ContainsKey("command") ? tagProperties["command"] : null); Dictionary<string, string> originalAtts = (Dictionary<string, string>)(tagProperties.ContainsKey("originalAtts") ? tagProperties["originalAtts"] : null); int singletonTag = (int)(tagProperties.ContainsKey("singletonTag") ? tagProperties["singletonTag"] : 0); TagInfo ti = new TagInfo(); if (command != null) { if (command.ID == Constants.METAL_USE_MACRO) { ti.Tag = tag; ti.Properties = tagProperties; ti.UseMacroLocation = this.commandList.Count + 1; } else { ti.Tag = tag; ti.Properties = tagProperties; ti.UseMacroLocation = -1; } } else { ti.Tag = tag; ti.Properties = tagProperties; ti.UseMacroLocation = -1; } this.tagStack.Add(ti); if (command != null) { // All tags that have a TAL attribute on them start with a 'start scope' TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_START_SCOPE; cmd.Attributes = new List<object>(); cmd.Attributes.Add(originalAtts); cmd.Attributes.Add(cleanAttributes); this.AddCommand(cmd); // Now we add the TAL command this.AddCommand(command); } else { // It's just a straight output, so create an output command and append it TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_OUTPUT; cmd.Attributes = new List<object>(); cmd.Attributes.Add(this.tagAsText(tag, singletonTag)); this.AddCommand(cmd); } }
protected void parseStartTag(Tag tag, Dictionary<string, string> attributes, int singletonElement) { // Note down the tag we are handling, it will be used for error handling during // compilation this.currentStartTag = new Tag(); this.currentStartTag.Name = tag.Name; this.currentStartTag.Attributes = attributes; this.currentStartTag.SourcePath = tag.SourcePath; this.currentStartTag.LineNumber = tag.LineNumber; this.currentStartTag.LinePosition = tag.LinePosition; // Look for tal/metal attributes List<int> foundTALAtts = new List<int>(); List<int> foundMETALAtts = new List<int>(); Dictionary<int, string> foundCommandsArgs = new Dictionary<int, string>(); Dictionary<string, string> cleanAttributes = new Dictionary<string, string>(); Dictionary<string, string> originalAttributes = new Dictionary<string, string>(); Dictionary<string, object> tagProperties = new Dictionary<string, object>(); List<VoidFuncDelegate> popTagFuncList = new List<VoidFuncDelegate>(); bool isTALElementNameSpace = false; string prefixToAdd = ""; tagProperties.Add("singletonTag", singletonElement); // Determine whether this element is in either the METAL or TAL namespace if (tag.Name.IndexOf(':') > 0) { // We have a namespace involved, so let's look to see if its one of ours string _namespace = tag.Name.Substring(0, tag.Name.IndexOf(':')); if (_namespace == this.metal_namespace_prefix) { isTALElementNameSpace = true; prefixToAdd = this.metal_namespace_prefix + ":"; } else if (_namespace == this.tal_namespace_prefix) { // This tag has not his own scope if (tag.Name == tal_namespace_omitscope) { tag.OmitTagScope = true; this.currentStartTag.OmitTagScope = true; } isTALElementNameSpace = true; prefixToAdd = this.tal_namespace_prefix + ":"; } if (isTALElementNameSpace) { // We should treat this an implicit omit-tag foundTALAtts.Add(Constants.TAL_OMITTAG); // Will go to default, i.e. yes foundCommandsArgs[Constants.TAL_OMITTAG] = ""; } } foreach (KeyValuePair<string, string> attr in attributes) { string att = attr.Key; string value = attr.Value; string commandAttName = ""; originalAttributes.Add(att, value); if (isTALElementNameSpace && !(att.IndexOf(':') > 0)) { // This means that the attribute name does not have a namespace, so use the prefix for this tag. commandAttName = prefixToAdd + att; } else { commandAttName = att; } if (att.Length > 4 && att.Substring(0, 5) == "xmlns") { // We have a namespace declaration. string prefix = att.Length > 5 ? att.Substring(6) : ""; if (value == Constants.METAL_NAME_URI) { // It's a METAL namespace declaration if (prefix.Length > 0) { this.metal_namespace_prefix_stack.Add(this.metal_namespace_prefix); this.setMETALPrefix(prefix); // We want this function called when the scope ends popTagFuncList.Add(this.popMETALNamespace); } else { // We don't allow METAL/TAL to be declared as a default string msg = "Can not use METAL name space by default, a prefix must be provided."; throw new TemplateParseException(this.currentStartTag, msg); } } else if (value == Constants.TAL_NAME_URI) { // TAL this time if (prefix.Length > 0) { this.tal_namespace_prefix_stack.Add(this.tal_namespace_prefix); this.setTALPrefix(prefix); // We want this function called when the scope ends popTagFuncList.Add(this.popTALNamespace); } else { // We don't allow METAL/TAL to be declared as a default string msg = "Can not use TAL name space by default, a prefix must be provided."; throw new TemplateParseException(this.currentStartTag, msg); } } else { // It's nothing special, just an ordinary namespace declaration cleanAttributes.Add(att, value); } } else if (this.tal_attribute_map.ContainsKey(commandAttName)) { // It's a TAL attribute int cmnd = this.tal_attribute_map[commandAttName]; if (cmnd == Constants.TAL_OMITTAG && isTALElementNameSpace) { //this.log.warn("Supressing omit-tag command present on TAL or METAL element"); } else { foundCommandsArgs.Add(cmnd, value); foundTALAtts.Add(cmnd); } } else if (this.metal_attribute_map.ContainsKey(commandAttName)) { // It's a METAL attribute int cmnd = this.metal_attribute_map[commandAttName]; foundCommandsArgs.Add(cmnd, value); foundMETALAtts.Add(cmnd); } else { cleanAttributes.Add(att, value); } } tagProperties.Add("popFunctionList", popTagFuncList); // This might be just content if ((foundTALAtts.Count + foundMETALAtts.Count) == 0) { // Just content, add it to the various stacks this.addTag(tag, cleanAttributes, tagProperties); return; } // Create a symbol for the end of the tag - we don't know what the offset is yet this.endTagSymbol += 1; tagProperties.Add("endTagSymbol", this.endTagSymbol); // Sort the METAL commands by priority. Priority is defined by opcode number, see Constants.METAL_* opcodes. foundMETALAtts.Sort(); // Sort the TAL commands by priority. Priority is defined by opcode number, see Constants.TAL_* opcodes. foundTALAtts.Sort(); // We handle the METAL before the TAL List<int> allCommands = new List<int>(); allCommands.AddRange(foundMETALAtts); allCommands.AddRange(foundTALAtts); int firstTag = 1; foreach (int talAtt in allCommands) { // Parse and create a command for each TALCommand cmnd = this.commandHandler[talAtt](foundCommandsArgs[talAtt]); if (cmnd != null) { if (firstTag == 1) { // The first one needs to add the tag firstTag = 0; tagProperties["originalAtts"] = originalAttributes; tagProperties["command"] = cmnd; this.addTag(tag, cleanAttributes, tagProperties); } else { // All others just append this.AddCommand(cmnd); } } } TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_STARTTAG; cmd.Attributes = new List<object>(); cmd.Attributes.Add(tag); cmd.Attributes.Add(singletonElement); if (firstTag == 1) { tagProperties["originalAtts"] = originalAttributes; tagProperties["command"] = cmd; this.addTag(tag, cleanAttributes, tagProperties); } else { // Add the start tag command in as a child of the last TAL command this.AddCommand(cmd); } }
protected TALCommand Compile_TAL_CONTENT(string argument, int replaceFlag) { // Compile a content command, resulting argument is // (replaceFlag, structureFlag, expression, endTagSymbol) // Sanity check if (argument.Length == 0) { // No argument passed string msg = "No argument passed! content/replace commands must be of the form: 'path'"; throw new TemplateParseException(this.currentStartTag, msg); } int structureFlag = 0; string[] attProps = argument.Split(new char[] { ' ' }); string express = ""; if (attProps.Length > 1) { if (attProps[0] == "structure") { structureFlag = 1; express = string.Join(" ", attProps, 1, attProps.Length - 1); } else if (attProps[1] == "text") { structureFlag = 0; express = string.Join(" ", attProps, 1, attProps.Length - 1); } else { // It's not a type selection after all - assume it's part of the path express = argument; } } else express = argument; TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_CONTENT; ci.Attributes = new List<object>(); ci.Attributes.Add(replaceFlag); ci.Attributes.Add(structureFlag); ci.Attributes.Add(express); ci.Attributes.Add(this.endTagSymbol); return ci; }
protected void LogCommand(TALCommand cmd) { List<string> attributes = new List<string>(); if (cmd.Attributes != null) { foreach (object attr in cmd.Attributes) { attributes.Add(string.Format(@"{0} {1}", Environment.NewLine, attr)); } } Console.WriteLine("{0}Command: {1}{2}", Environment.NewLine, Constants.GetCommandName(cmd.ID), string.Join("", attributes.ToArray())); }
protected void parseData(string data) { // Just add it as an output TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_OUTPUT; cmd.Attributes = new List<object>(); cmd.Attributes.Add(data); this.AddCommand(cmd); }
protected TALCommand Compile_TAL_REPEAT(string argument) { // Compile a repeat command, resulting argument is: // (varname, expression, endTagSymbol) List<string> attProps = new List<string>(argument.Split(new char[] { ' ' })); if (attProps.Count < 2) { // Error, badly formed repeat command string msg = string.Format("Badly formed repeat command '{0}'. Repeat commands must be of the form: 'localVariable path'", argument); throw new TemplateParseException(this.currentStartTag, msg); } string varName = attProps[0]; string expression = string.Join(" ", attProps.GetRange(1, attProps.Count - 1).ToArray()); TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_REPEAT; ci.Attributes = new List<object>(); ci.Attributes.Add(varName); ci.Attributes.Add(expression); ci.Attributes.Add(this.endTagSymbol); return ci; }
protected TALCommand Compile_TAL_OMITTAG(string argument) { // Compile a condition command, resulting argument is: // path // If no argument is given then set the path to default string expression = ""; if (argument.Length == 0) expression = Constants.DEFAULT_VALUE_EXPRESSION; else expression = argument; TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_OMITTAG; ci.Attributes = new List<object>(); ci.Attributes.Add(expression); return ci; }
protected TALCommand Compile_TAL_DEFINE(string argument) { // Compile a define command, resulting argument is: // [(DefineAction (global, local, set), variableName, variablePath),...] // Break up the list of defines first List<DefineInfo> commandArgs = new List<DefineInfo>(); // We only want to match semi-colons that are not escaped foreach (string defStmt in Constants.TAL_DEFINE_REGEX.Split(argument)) { // remove any leading space and un-escape any semi-colons string defineStmt = defStmt.TrimStart().Replace(";;", ";"); // Break each defineStmt into pieces "[local|global] varName expression" List<string> stmtBits = new List<string>(defineStmt.Split(new char[] { ' ' })); DefineAction defAction = DefineAction.Local; string varName; string expression; if (stmtBits.Count < 2) { // Error, badly formed define command string msg = string.Format("Badly formed define command '{0}'. Define commands must be of the form: '[local|global] varName expression[;[local|global] varName expression]'", argument); throw new TemplateParseException(this.currentStartTag, msg); } // Assume to start with that >2 elements means a local|global flag if (stmtBits.Count > 2) { if (stmtBits[0] == "global") { defAction = DefineAction.Global; varName = stmtBits[1]; expression = string.Join(" ", stmtBits.GetRange(2, stmtBits.Count - 2).ToArray()); } else if (stmtBits[0] == "local") { varName = stmtBits[1]; expression = string.Join(" ", stmtBits.GetRange(2, stmtBits.Count - 2).ToArray()); } else if (stmtBits[0] == "set") { defAction = DefineAction.SetLocal; varName = stmtBits[1]; expression = string.Join(" ", stmtBits.GetRange(2, stmtBits.Count - 2).ToArray()); } else { // Must be a space in the expression that caused the >3 thing varName = stmtBits[0]; expression = string.Join(" ", stmtBits.GetRange(1, stmtBits.Count - 1).ToArray()); } } else { // Only two bits varName = stmtBits[0]; expression = string.Join(" ", stmtBits.GetRange(1, stmtBits.Count - 1).ToArray()); } DefineInfo di = new DefineInfo(); di.defAction = defAction; di.varName = varName; di.varPath = expression; commandArgs.Add(di); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_DEFINE; ci.Attributes = new List<object>(); ci.Attributes.Add(commandArgs); return ci; }
protected TALCommand Compile_METAL_USE_MACRO(string argument) { // Sanity check if (argument.Length == 0) { // No argument passed string msg = "No argument passed! use-macro commands must be of the form: 'use-macro: path'"; throw new TemplateParseException(this.currentStartTag, msg); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.METAL_USE_MACRO; ci.Attributes = new List<object>(); ci.Attributes.Add(argument); ci.Attributes.Add(new Dictionary<string, TALSubProgram>()); ci.Attributes.Add(new List<DefineInfo>()); ci.Attributes.Add(this.endTagSymbol); return ci; }
protected void popTag(Tag tag, int omitTagFlag) { // omitTagFlag is used to control whether the end tag should be included in the // output or not. In HTML 4.01 there are several tags which should never have // end tags, this flag allows the template compiler to specify that these // should not be output. while (this.tagStack.Count > 0) { TagInfo ti = this.tagStack[this.tagStack.Count - 1]; this.tagStack.RemoveAt(this.tagStack.Count - 1); Tag oldTag = ti.Tag; Dictionary<string, object> tagProperties = ti.Properties; int? endTagSymbol = (int?)(tagProperties.ContainsKey("endTagSymbol") ? tagProperties["endTagSymbol"] : null); List<VoidFuncDelegate> popCommandList = (List<VoidFuncDelegate>)(tagProperties.ContainsKey("popCommandList") ? tagProperties["popCommandList"] : null); int singletonTag = (int)(tagProperties.ContainsKey("singletonTag") ? tagProperties["singletonTag"] : 0); if (popCommandList != null) { foreach (VoidFuncDelegate func in popCommandList) { func(); } } if (oldTag.Name == tag.Name) { // We've found the right tag, now check to see if we have any TAL commands on it if (endTagSymbol != null) { // We have a command (it's a TAL tag) // Note where the end tag symbol should point (i.e. the next command) this.symbolLocationTable[(int)endTagSymbol] = this.commandList.Count; // We need a "close scope and tag" command TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_ENDTAG_ENDSCOPE; cmd.Attributes = new List<object>(); cmd.Attributes.Add(tag.Name); cmd.Attributes.Add(omitTagFlag); cmd.Attributes.Add(singletonTag); this.AddCommand(cmd); return; } else if (omitTagFlag == 0 && singletonTag == 0) { // We are popping off an un-interesting tag, just add the close as text // We need a "close scope and tag" command TALCommand cmd = new TALCommand(); cmd.Tag = this.currentStartTag; cmd.ID = Constants.TAL_OUTPUT; cmd.Attributes = new List<object>(); cmd.Attributes.Add("</" + tag.Name + ">"); this.AddCommand(cmd); return; } else { // We are suppressing the output of this tag, so just return return; } } else { // We have a different tag, which means something like <br> which never closes is in // between us and the real tag. // If the tag that we did pop off has a command though it means un-balanced TAL tags! if (endTagSymbol != null) { // ERROR string msg = string.Format("TAL/METAL Elements must be balanced - found close tag {0} expecting {1}", tag.Name, oldTag.Name); throw new TemplateParseException(oldTag, msg); } } } throw new TemplateParseException(null, string.Format("</{0}> {1}", tag.Name, "Close tag encountered with no corresponding open tag.")); }
protected TALCommand Compile_TAL_ATTRIBUTES(string argument) { // Compile tal:attributes into attribute command // Argument: [(attributeName, expression)] // Break up the list of attribute settings first Dictionary<string, string> commandArgs = new Dictionary<string, string>(); // We only want to match semi-colons that are not escaped foreach (string attStmt in Constants.TAL_ATTRIBUTES_REGEX.Split(argument)) { // remove any leading space and un-escape any semi-colons string attributeStmt = attStmt.TrimStart().Replace(";;", ";"); // Break each attributeStmt into name and expression List<string> stmtBits = new List<string>(attributeStmt.Split(new char[] { ' ' })); if (stmtBits.Count < 2) { // Error, badly formed attributes command string msg = string.Format("Badly formed attributes command '{0}'. Attributes commands must be of the form: 'name expression[;name expression]'", argument); throw new TemplateParseException(this.currentStartTag, msg); } string attName = stmtBits[0]; string attExpr = string.Join(" ", stmtBits.GetRange(1, stmtBits.Count - 1).ToArray()); commandArgs.Add(attName, attExpr); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_ATTRIBUTES; ci.Attributes = new List<object>(); ci.Attributes.Add(commandArgs); return ci; }
protected TALCommand Compile_TAL_CONDITION(string argument) { // Compile a condition command, resulting argument is: // path, endTagSymbol // Sanity check if (argument.Length == 0) { // No argument passed string msg = "No argument passed! condition commands must be of the form: 'path'"; throw new TemplateParseException(this.currentStartTag, msg); } TALCommand ci = new TALCommand(); ci.Tag = this.currentStartTag; ci.ID = Constants.TAL_CONDITION; ci.Attributes = new List<object>(); ci.Attributes.Add(argument); ci.Attributes.Add(this.endTagSymbol); return ci; }