Пример #1
0
 //--- 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);
 }
Пример #2
0
 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();
 }
Пример #3
0
        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;
        }
Пример #4
0
        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);
        }