//--- Extension Methods --- public static StringBuilder AppendLiteral(this StringBuilder builder, DekiScriptLiteral literal) { if (literal is DekiScriptString) { builder.Append(((DekiScriptString)literal).Value); } else { builder.Append(literal.ToString()); } return(builder); }
public void AppendXml(XDoc doc) { doc.Start("param").Attr("name", Name).Attr("type", DekiScriptLiteral.AsScriptTypeName(ScriptType)); if (Default.IsNil) { doc.Attr("optional", Optional ? "true" : null); } else { doc.Attr("default", Default.ToString()); } doc.Value(Hint); doc.End(); }
public Yield Execute(DreamContext context, DreamMessage request, Result <DreamMessage> response) { string expression = context.GetParam("expression"); DekiScriptExpression expr = DekiScriptParser.Parse(new Location("POST:execute"), expression); DekiScriptLiteral result = _runtime.Evaluate(expr, DekiScriptEvalMode.Evaluate, _env); if (result.ScriptType == DekiScriptType.XML) { response.Return(DreamMessage.Ok(MimeType.XML, (XDoc)result.NativeValue)); } else { response.Return(DreamMessage.Ok(MimeType.TEXT, result.ToString())); } yield break; }
private void AddText(XmlNode context, DekiScriptLiteral literal) { if (context == null) { ConvertStateToHtml(null); } // TODO (steveb): this is just plain retarded; why do we need to distinguish between string and non-string?!? if (literal is DekiScriptString) { (context ?? _body).AppendChild(_document.CreateTextNode(((DekiScriptString)literal).Value)); } else { (context ?? _body).AppendChild(_document.CreateTextNode(literal.ToString())); } }
//--- Methods --- public DekiScriptEvaluationAccumulator Add(DekiScriptLiteral literal, bool safe) { if(literal == null) { throw new ArgumentNullException("literal"); } if(literal is DekiScriptNil) { // nothing to do return this; } // check if any value was accumulated if(_value == null) { if(literal is DekiScriptXml) { _value = ((DekiScriptXml)literal).Value.Clone(); } else { _value = literal; } return this; } // check if we can append a string value if(literal is DekiScriptString) { AddString(((DekiScriptString)literal).Value, safe); return this; } if(!(literal is DekiScriptUri) && !(literal is DekiScriptXml)) { AddString(literal.ToString(), safe); return this; } // check if we need to append an XML document XDoc doc = literal.AsEmbeddableXml(safe); if(doc.IsEmpty) { return this; } XDoc accumulator = ConvertToXml(safe); // build lookup for existing bodies in accumulator Dictionary<string, XDoc> bodies = new Dictionary<string, XDoc>(); foreach(XmlNode node in accumulator.AsXmlNode.ChildNodes) { if(node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if(StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); bodies[target] = accumulator[node]; } } } // loop over all root children in new document foreach(XmlNode node in doc.AsXmlNode.ChildNodes) { if(node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if(StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); XDoc body; if(bodies.TryGetValue(target, out body)) { // body already exists, check how it should be handled string conflict = element.GetAttribute("conflict"); if(string.IsNullOrEmpty(conflict)) { // default conflict resolution depends on target: no target (i.e. main body) is append, otherwise it is ignore conflict = string.IsNullOrEmpty(target) ? "append" : "ignore"; } switch(conflict) { case "replace": // replace existing body with new one body.RemoveNodes(); body.AddNodes(doc[node]); break; case "append": // append nodes to existing body body.AddNodes(doc[node]); break; case "ignore": // ignore new body break; } } else { // target body does not exist, append it accumulator.Start("body"); if(!string.IsNullOrEmpty(target)) { accumulator.Attr("target", target); } accumulator.AddNodes(doc[node]); accumulator.End(); } } else if(StringUtil.EqualsInvariant(node.LocalName, "head")) { XDoc head = accumulator["head"]; foreach(XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } else if(StringUtil.EqualsInvariant(node.LocalName, "tail")) { XDoc head = accumulator["tail"]; foreach(XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } } } return this; }
public DekiScriptOutputBuffer.Range Visit(DekiScriptXmlElement expr, DekiScriptExpressionEvaluationState state) { // check if any namespaces are being defined state.Namespaces.PushScope(); int marker = state.Buffer.Marker; try { Dictionary <string, string> namespaces = null; List <Tuplet <string, string, string> > attributes = null; string ctor = null; string id = null; string type = null; // TODO (steveb): validate that all prefixes are defined! // evaluate element name string name = XmlConvert.EncodeLocalName(state.Pop(expr.Name.VisitWith(this, state)).AsString()); // loop over all attributes foreach (var attribute in expr.Attributes) { string attrPrefix = attribute.Prefix; string attrName = state.Pop(attribute.Name.VisitWith(this, state)).AsString(); if (string.IsNullOrEmpty(attrName)) { continue; } string attrValue = state.Pop(attribute.Value.VisitWith(this, state)).AsString(); if (attrValue == null) { continue; } bool isNamespaceDeclaration = string.IsNullOrEmpty(attrPrefix) ? attrName.EqualsInvariant(XMLNS) : attrPrefix.EqualsInvariant(XMLNS); // check if attribute is a namespace declaration if (isNamespaceDeclaration) { // add attribute to namespace declarations namespaces = namespaces ?? new Dictionary <string, string>(); // check if the default namespace is being defined if (string.IsNullOrEmpty(attrPrefix)) { namespaces.Add(string.Empty, attrValue); } else { namespaces.Add(attrName, attrValue); } } else { // add attribute to list of attributes attributes = attributes ?? new List <Tuplet <string, string, string> >(); attributes.Add(new Tuplet <string, string, string>(attrPrefix, attrName, attrValue)); if (string.IsNullOrEmpty(attrPrefix)) { switch (attrName) { case "ctor": ctor = attrValue; break; case "id": id = attrValue; break; case "type": type = attrValue; break; } } } } // check if current node needs to be replaced entirely string jem = null; if (string.IsNullOrEmpty(expr.Prefix) && !string.IsNullOrEmpty(type) && name.EqualsInvariant("script") && type.EqualsInvariant("text/jem")) { // NOTE: process <script type="text/jem"> // evaluate nested expressions DekiScriptLiteral contents = state.Pop(expr.Node.VisitWith(this, state)); if (contents is DekiScriptString) { jem = ((DekiScriptString)contents).Value; } else { jem = contents.ToString(); } jem = DekiJemProcessor.Parse(jem, null, state.Env, state.Runtime); } else { // check if @ctor is defined without an @id if (!string.IsNullOrEmpty(ctor) && (id == null)) { id = StringUtil.CreateAlphaNumericKey(8); attributes.Add(new Tuplet <string, string, string>(null, "id", id)); } // append start xml element to buffer state.Buffer.PushXmlStart(expr.Prefix, name, namespaces, attributes); // evaluate nested expressions expr.Node.VisitWith(this, state); // append end xml element to buffer state.Buffer.PushXmlEnd(); // check if the element has a JEM @ctor attribute if (!string.IsNullOrEmpty(ctor)) { // generate JEM code jem = DekiJemProcessor.Parse(ctor, id, state.Env, state.Runtime); } } // check if JEM code was generated if (jem != null) { // create <script> element var scriptAttributes = new List <Tuplet <string, string, string> > { new Tuplet <string, string, string>(null, "type", "text/javascript") }; state.Buffer.PushXmlStart(null, "script", null, scriptAttributes); state.Push(DekiScriptExpression.Constant(jem)); state.Buffer.PushXmlEnd(); } } catch { state.Buffer.Reset(marker); throw; } finally { // restore previous xml namespace definitions state.Namespaces.PopScope(); } return(state.Buffer.Since(marker)); }
internal void InsertValueBeforeNode(XmlNode parent, XmlNode reference, DekiScriptLiteral value) { if ((value is DekiScriptXml) || (value is DekiScriptUri)) { XDoc xml = value.AsEmbeddableXml(Mode == DekiScriptEvalMode.EvaluateSafeMode); if (xml.HasName("html")) { // TODO (steveb): merge XML namespaces // merge <head> and <tail> sections AddHeadElements(xml); AddTailElements(xml); // loop over body elements in response foreach (XDoc body in xml["body"]) { string target = body["@target"].AsText; string conflict = body["@conflict"].AsText ?? "ignore"; // check if the main body is targeted or something else if (string.IsNullOrEmpty(target)) { // append body nodes foreach (XmlNode node in body.AsXmlNode.ChildNodes) { parent.InsertBefore(parent.OwnerDocument.ImportNode(node, true), reference); } } else { // check if the targeted body already exists if (Bodies.ContainsKey(target) && !StringUtil.EqualsInvariant(conflict, "replace")) { if (StringUtil.EqualsInvariant(conflict, "append")) { // append nodes to existing body Bodies[target].Add(body.AsXmlNode); } } else { // create a new body element List <XmlNode> list = new List <XmlNode>(); list.Add(body.AsXmlNode); Bodies[target] = list; } } } } else if (!xml.IsEmpty) { // replace the current node with the entire document parent.InsertBefore(parent.OwnerDocument.ImportNode(xml.AsXmlNode, true), reference); } } else if (value is DekiScriptComplexLiteral) { // append text respresentation of value parent.InsertBefore(CreateTextNode(value.ToString()), reference); } else { // append value cast to text string text = value.AsString(); if (!string.IsNullOrEmpty(text)) { parent.InsertBefore(CreateTextNode(text), reference); } } }
//--- Methods --- public DekiScriptEvaluationAccumulator Add(DekiScriptLiteral literal, bool safe) { if (literal == null) { throw new ArgumentNullException("literal"); } if (literal is DekiScriptNil) { // nothing to do return(this); } // check if any value was accumulated if (_value == null) { if (literal is DekiScriptXml) { _value = ((DekiScriptXml)literal).Value.Clone(); } else { _value = literal; } return(this); } // check if we can append a string value if (literal is DekiScriptString) { AddString(((DekiScriptString)literal).Value, safe); return(this); } if (!(literal is DekiScriptUri) && !(literal is DekiScriptXml)) { AddString(literal.ToString(), safe); return(this); } // check if we need to append an XML document XDoc doc = literal.AsEmbeddableXml(safe); if (doc.IsEmpty) { return(this); } XDoc accumulator = ConvertToXml(safe); // build lookup for existing bodies in accumulator Dictionary <string, XDoc> bodies = new Dictionary <string, XDoc>(); foreach (XmlNode node in accumulator.AsXmlNode.ChildNodes) { if (node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if (StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); bodies[target] = accumulator[node]; } } } // loop over all root children in new document foreach (XmlNode node in doc.AsXmlNode.ChildNodes) { if (node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if (StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); XDoc body; if (bodies.TryGetValue(target, out body)) { // body already exists, check how it should be handled string conflict = element.GetAttribute("conflict"); if (string.IsNullOrEmpty(conflict)) { // default conflict resolution depends on target: no target (i.e. main body) is append, otherwise it is ignore conflict = string.IsNullOrEmpty(target) ? "append" : "ignore"; } switch (conflict) { case "replace": // replace existing body with new one body.RemoveNodes(); body.AddNodes(doc[node]); break; case "append": // append nodes to existing body body.AddNodes(doc[node]); break; case "ignore": // ignore new body break; } } else { // target body does not exist, append it accumulator.Start("body"); if (!string.IsNullOrEmpty(target)) { accumulator.Attr("target", target); } accumulator.AddNodes(doc[node]); accumulator.End(); } } else if (StringUtil.EqualsInvariant(node.LocalName, "head")) { XDoc head = accumulator["head"]; foreach (XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } else if (StringUtil.EqualsInvariant(node.LocalName, "tail")) { XDoc head = accumulator["tail"]; foreach (XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } } } return(this); }