public Empty Visit(DekiScriptGeneratorIf expr, DekiScriptGeneratorEvaluationState state)
        {
            DekiScriptLiteral condition = expr.Condition.VisitWith(DekiScriptExpressionEvaluation.Instance, state.Env);

            if (!condition.IsNilFalseZero)
            {
                Generate(expr, state);
            }
            return(Empty.Value);
        }
        //--- Methods ---
        public Empty Visit(DekiScriptGeneratorIf expr, DekiScriptGeneratorEvaluationState state)
        {
            // evaluate the generator condition
            DekiScriptLiteral condition = Eval(expr.Condition, state);

            // check if condition is met
            if (!condition.IsNilFalseZero)
            {
                EvalNext(expr, state);
            }
            return(Empty.Value);
        }
        //--- Methods ---
        private XmlNode Parse(XmlElement current, List<DekiScriptExpression> list) {
            XmlNode next = current.NextSibling;
            string value;

            // check if element needs to be evaluated
            try {
                if(current.NamespaceURI.EqualsInvariant(XDekiScript.ScriptNS)) {

                    // element has "eval:" prefix
                    switch(current.LocalName) {
                    #region <if test="bool-expr">...</if>{<elseif test="bool-expr">...</elseif>}[<else>...</else>]
                    case "if": {
                        List<Tuplet<DekiScriptExpression, DekiScriptExpression>> conditionals = new List<Tuplet<DekiScriptExpression, DekiScriptExpression>>();

                        // initial "if" statement
                        DekiScriptExpression condition = Parse(SubLocation("/@test"), current.GetAttribute("test"));
                        conditionals.Add(new Tuplet<DekiScriptExpression, DekiScriptExpression>(condition, BuildChildren(current)));

                        // check for subsequent "elseif" and "else" statements
                        while(true) {

                            // move to next node
                            XmlNode originalNext = next;

                            // skip empty text nodes
                            while((next != null) && ((next.NodeType == XmlNodeType.Whitespace) || (next.NodeType == XmlNodeType.SignificantWhitespace) || ((next.NodeType == XmlNodeType.Text) && (next.Value.Trim().Length == 0)))) {
                                next = next.NextSibling;
                            }

                            // check if next node is an alternate branch
                            if((next != null) && next.NamespaceURI.EqualsInvariant(XDekiScript.ScriptNS) && (next.LocalName.EqualsInvariant("elseif") || next.LocalName.EqualsInvariant("else"))) {
                                current = (XmlElement) next;
                                PopNode();
                                PushNode(current);
                                next = current.NextSibling;
                                if(current.LocalName.EqualsInvariant("elseif")) {

                                    // process "elseif" branch
                                    condition = Parse(SubLocation("/@test"), current.GetAttribute("test"));
                                    conditionals.Add(new Tuplet<DekiScriptExpression, DekiScriptExpression>(condition, BuildChildren(current)));
                                } else {

                                    // process "else" branch
                                    conditionals.Add(new Tuplet<DekiScriptExpression, DekiScriptExpression>(null, BuildChildren(current)));
                                    break;
                                }
                            } else {

                                // couln't find an alternatte branch, restore the original next node
                                next = originalNext;
                                break;
                            }
                        }
                        list.Add(DekiScriptExpression.IfElseStatements(Location, conditionals));
                    }
                        break;
                    #endregion

                    #region <foreach [var="id"] in="list-or-map-or-xml-expr" [where|test="bool-expr"]>...</foreach>
                    case "foreach": {
                        string variable = current.HasAttribute("var") ? current.GetAttribute("var").Trim() : DekiScriptRuntime.DEFAULT_ID;
                        string where = current.GetAttribute("where");
                        if(string.IsNullOrEmpty(where)) {
                            where = current.GetAttribute("test");
                        }
                        DekiScriptGenerator generator = null;
                        if(!string.IsNullOrEmpty(where)) {
                            var location = SubLocation("/@where");
                            generator = new DekiScriptGeneratorIf(location, Parse(location, where), null);
                        }
                        generator = new DekiScriptGeneratorForeachValue(Location, new[] { variable }, Parse(Location, current.GetAttribute("in")), generator);
                        list.Add(DekiScriptExpression.ForeachStatement(Location, generator, BuildChildren(current)));
                    }
                        break;
                    #endregion

                    #region <expr value="expr" /> -OR- <expr>expr</expr>
                    case "expr": {
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        DekiScriptExpression expr = Parse(Location, code);
                        list.Add(expr);
                    }
                        break;
                    #endregion

                    #region <js value="expr" /> -OR- <js>expr</js>
                    case "js": {
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        DekiScriptExpression expr = Parse(Location, code);
                        list.Add(DekiScriptExpression.Call(Location, DekiScriptExpression.Access(Location, DekiScriptExpression.Id(Location, "json"), DekiScriptExpression.Constant("emit")), new DekiScriptListConstructor(null, expr)));
                    }
                        break;
                    #endregion

                    #region <block value="expr">...</block>
                    case "block": {

                        // TODO (steveb): it seems odd we use InnerText here instead of value; what is the motivation?
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        list.Add(DekiScriptExpression.BlockWithDeclaration(Location, Parse(Location, code), BuildChildren(current)));
                    }
                        break;
                    #endregion

                    default:
                        throw new DekiScriptParserException(string.Format("{0}, unknown elementn <eval:{1}>", Location, current.LocalName), Location.None);
                    }
                } else {
                    List<DekiScriptExpression> nodes = new List<DekiScriptExpression>();

                    // process "function" attribute
                    if(!string.IsNullOrEmpty(value = current.GetAttribute("function"))) {

                        // NOTE (steveb): process content transform

                        // check if function contains '$' sign, which is a place holder for the main argument
                        DekiScriptExpression evaluation = Parse(SubLocation("/@function"), (value.IndexOf('$') < 0) ? value + "($)" : value);

                        // determine if main argument is a string or an xml document
                        DekiScriptExpression arg;
                        if(current.LocalName.EqualsInvariant("pre")) {
                            ConvertBrToNewline(current);

                            // pass argument in as a string
                            arg = DekiScriptExpression.Constant(StripCode(current.InnerText));
                        } else {

                            // pass argument in as a HTML document
                            List<DekiScriptExpression> inner = new List<DekiScriptExpression>();
                            BuildElement(current, inner);

                            DekiScriptExpression body = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant("body"), null, DekiScriptExpression.Block(Location, inner));
                            DekiScriptExpression html = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant("html"), null, body);
                            arg = html;
                        }

                        // create DOM expression
                        DekiScriptExpression assign = DekiScriptExpression.VarStatement(Location, DekiScriptExpression.Id(Location, DekiScriptRuntime.DEFAULT_ID), arg);
                        DekiScriptExpression statements = DekiScriptExpression.BlockWithDeclaration(Location, assign, evaluation);
                        nodes.Add(TryCatch(statements, true));
                    } else if(current.LocalName.EqualsInvariant("span") && current.GetAttribute("class").EqualsInvariant("script")) {
                        ConvertBrToNewline(current);

                        // convert <span class="script">...</span> to <eval:expr>...</eval:expr>
                        nodes.Add(TryCatch(Parse(Location, new XmlNodePlainTextReadonlyByteStream(current)), true));
                    } else if(current.LocalName.EqualsInvariant("pre")) {
                        string cls = current.GetAttribute("class");
                        if(cls.EqualsInvariant("script")) {
                            ConvertBrToNewline(current);

                            DekiScriptExpression expr = TryCatch(Parse(Location, new XmlNodePlainTextReadonlyByteStream(current)), true);
                            nodes.Add(expr);
                        } else if(cls.EqualsInvariant("script-jem")) {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-jem">...</pre> to <html><body><script type="text/jem">...</script></body></html>
                            DekiScriptExpression html = Html("body", "script", "text/javascript", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        } else if(cls.EqualsInvariant("script-js")) {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-js">...</pre> to <html><body><script type="text/js">...</script></body></html>
                            DekiScriptExpression html = Html("body", "script", "text/javascript", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        } else if(cls.EqualsInvariant("script-css")) {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-css">...</pre> to <html><head><style type="text/css">...</style></head></html>
                            DekiScriptExpression html = Html("head", "style", "text/css", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        } else {
                            BuildElement(current, nodes);
                        }
                    } else {
                        BuildElement(current, nodes);
                    }

                    // process "block" attribute
                    bool scripted = false;
                    if(!string.IsNullOrEmpty(value = current.GetAttribute("block"))) {
                        scripted = true;

                        // attribute "block" is present
                        var location = SubLocation("/@block");
                        DekiScriptExpression blockExpr = Parse(location, value);
                        blockExpr = DekiScriptExpression.BlockWithDeclaration(Location, blockExpr, nodes);
                        nodes.Clear();
                        nodes.Add(blockExpr);
                    }

                    // process "foreach" attribute
                    if(!string.IsNullOrEmpty(value = current.GetAttribute("foreach"))) {
                        scripted = true;

                        // attribute "foreach" is present
                        StringBuilder expression = new StringBuilder();
                        expression.Append(value);
                        string where = current.GetAttribute("where");
                        if(!string.IsNullOrEmpty(where)) {
                            expression.Append(", if ").Append(where);
                        }
                        var location = SubLocation("/@foreach");
                        DekiScriptForeach foreachExpr = (DekiScriptForeach)Parse(location, "foreach(" + expression + "){}");
                        DekiScriptExpression foreachExpr2 = DekiScriptExpression.ForeachStatement(location, foreachExpr.Generator, nodes);
                        nodes.Clear();
                        nodes.Add(foreachExpr2);
                    }

                    // process "if" attribute
                    if(!string.IsNullOrEmpty(value = current.GetAttribute("if"))) {
                        scripted = true;

                        // attribute "if" is present
                        var location = SubLocation("/@if");
                        DekiScriptExpression condition = Parse(location, value);
                        condition = DekiScriptExpression.IfElseStatements(location, new[] { new Tuplet<DekiScriptExpression, DekiScriptExpression>(condition, DekiScriptExpression.Block(Location, nodes)) });
                        nodes.Clear();
                        nodes.Add(condition);
                    }

                    // process "init" attribute
                    if(!string.IsNullOrEmpty(value = current.GetAttribute("init"))) {
                        scripted = true;

                        // attribute "init" is present
                        DekiScriptExpression init = Parse(Location, value);
                        DekiScriptExpression dom = DekiScriptExpression.BlockWithDeclaration(SubLocation("/@init"), init, nodes);
                        nodes.Clear();
                        nodes.Add(dom);
                    }

                    // append inner nodes
                    switch(nodes.Count) {
                    case 0:

                        // nothing to do
                        break;
                    case 1:
                        list.Add(TryCatch(nodes[0], scripted));
                        break;
                    default:
                        list.AddRange(nodes);
                        break;
                    }
                }
            } catch(Exception e) {
                XDoc warning = new XDoc("html").Start("body").Add(DekiScriptRuntime.CreateWarningFromException(null, Location, e)).End();
                list.Add(new DekiScriptXml(warning));
            }
            return next;
        }
Example #4
0
        //--- Methods ---
        private XmlNode Parse(XmlElement current, List <DekiScriptExpression> list)
        {
            XmlNode next = current.NextSibling;
            string  value;

            // check if element needs to be evaluated
            try {
                if (current.NamespaceURI.EqualsInvariant(XDekiScript.ScriptNS))
                {
                    // element has "eval:" prefix
                    switch (current.LocalName)
                    {
                        #region <if test="bool-expr">...</if>{<elseif test="bool-expr">...</elseif>}[<else>...</else>]
                    case "if": {
                        List <Tuplet <DekiScriptExpression, DekiScriptExpression> > conditionals = new List <Tuplet <DekiScriptExpression, DekiScriptExpression> >();

                        // initial "if" statement
                        DekiScriptExpression condition = Parse(SubLocation("/@test"), current.GetAttribute("test"));
                        conditionals.Add(new Tuplet <DekiScriptExpression, DekiScriptExpression>(condition, BuildChildren(current)));

                        // check for subsequent "elseif" and "else" statements
                        while (true)
                        {
                            // move to next node
                            XmlNode originalNext = next;

                            // skip empty text nodes
                            while ((next != null) && ((next.NodeType == XmlNodeType.Whitespace) || (next.NodeType == XmlNodeType.SignificantWhitespace) || ((next.NodeType == XmlNodeType.Text) && (next.Value.Trim().Length == 0))))
                            {
                                next = next.NextSibling;
                            }

                            // check if next node is an alternate branch
                            if ((next != null) && next.NamespaceURI.EqualsInvariant(XDekiScript.ScriptNS) && (next.LocalName.EqualsInvariant("elseif") || next.LocalName.EqualsInvariant("else")))
                            {
                                current = (XmlElement)next;
                                PopNode();
                                PushNode(current);
                                next = current.NextSibling;
                                if (current.LocalName.EqualsInvariant("elseif"))
                                {
                                    // process "elseif" branch
                                    condition = Parse(SubLocation("/@test"), current.GetAttribute("test"));
                                    conditionals.Add(new Tuplet <DekiScriptExpression, DekiScriptExpression>(condition, BuildChildren(current)));
                                }
                                else
                                {
                                    // process "else" branch
                                    conditionals.Add(new Tuplet <DekiScriptExpression, DekiScriptExpression>(null, BuildChildren(current)));
                                    break;
                                }
                            }
                            else
                            {
                                // couln't find an alternatte branch, restore the original next node
                                next = originalNext;
                                break;
                            }
                        }
                        list.Add(DekiScriptExpression.IfElseStatements(Location, conditionals));
                    }
                    break;
                        #endregion

                        #region <foreach [var="id"] in="list-or-map-or-xml-expr" [where|test="bool-expr"]>...</foreach>
                    case "foreach": {
                        string variable = current.HasAttribute("var") ? current.GetAttribute("var").Trim() : DekiScriptRuntime.DEFAULT_ID;
                        string where = current.GetAttribute("where");
                        if (string.IsNullOrEmpty(where))
                        {
                            where = current.GetAttribute("test");
                        }
                        DekiScriptGenerator generator = null;
                        if (!string.IsNullOrEmpty(where))
                        {
                            var location = SubLocation("/@where");
                            generator = new DekiScriptGeneratorIf(location, Parse(location, where), null);
                        }
                        generator = new DekiScriptGeneratorForeachValue(Location, new[] { variable }, Parse(Location, current.GetAttribute("in")), generator);
                        list.Add(DekiScriptExpression.ForeachStatement(Location, generator, BuildChildren(current)));
                    }
                    break;
                        #endregion

                        #region <expr value="expr" /> -OR- <expr>expr</expr>
                    case "expr": {
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        DekiScriptExpression expr = Parse(Location, code);
                        list.Add(expr);
                    }
                    break;
                        #endregion

                        #region <js value="expr" /> -OR- <js>expr</js>
                    case "js": {
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        DekiScriptExpression expr = Parse(Location, code);
                        list.Add(DekiScriptExpression.Call(Location, DekiScriptExpression.Access(Location, DekiScriptExpression.Id(Location, "json"), DekiScriptExpression.Constant("emit")), new DekiScriptListConstructor(null, expr)));
                    }
                    break;
                        #endregion

                        #region <block value="expr">...</block>
                    case "block": {
                        // TODO (steveb): it seems odd we use InnerText here instead of value; what is the motivation?
                        string code = current.HasAttribute("value") ? current.GetAttribute("value") : current.InnerText;
                        list.Add(DekiScriptExpression.BlockWithDeclaration(Location, Parse(Location, code), BuildChildren(current)));
                    }
                    break;
                        #endregion

                    default:
                        throw new DekiScriptParserException(string.Format("{0}, unknown elementn <eval:{1}>", Location, current.LocalName), Location.None);
                    }
                }
                else
                {
                    List <DekiScriptExpression> nodes = new List <DekiScriptExpression>();

                    // process "function" attribute
                    if (!string.IsNullOrEmpty(value = current.GetAttribute("function")))
                    {
                        // NOTE (steveb): process content transform

                        // check if function contains '$' sign, which is a place holder for the main argument
                        DekiScriptExpression evaluation = Parse(SubLocation("/@function"), (value.IndexOf('$') < 0) ? value + "($)" : value);

                        // determine if main argument is a string or an xml document
                        DekiScriptExpression arg;
                        if (current.LocalName.EqualsInvariant("pre"))
                        {
                            ConvertBrToNewline(current);

                            // pass argument in as a string
                            arg = DekiScriptExpression.Constant(StripCode(current.InnerText));
                        }
                        else
                        {
                            // pass argument in as a HTML document
                            List <DekiScriptExpression> inner = new List <DekiScriptExpression>();
                            BuildElement(current, inner);

                            DekiScriptExpression body = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant("body"), null, DekiScriptExpression.Block(Location, inner));
                            DekiScriptExpression html = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant("html"), null, body);
                            arg = html;
                        }

                        // create DOM expression
                        DekiScriptExpression assign     = DekiScriptExpression.VarStatement(Location, DekiScriptExpression.Id(Location, DekiScriptRuntime.DEFAULT_ID), arg);
                        DekiScriptExpression statements = DekiScriptExpression.BlockWithDeclaration(Location, assign, evaluation);
                        nodes.Add(TryCatch(statements, true));
                    }
                    else if (current.LocalName.EqualsInvariant("span") && current.GetAttribute("class").EqualsInvariant("script"))
                    {
                        ConvertBrToNewline(current);

                        // convert <span class="script">...</span> to <eval:expr>...</eval:expr>
                        nodes.Add(TryCatch(Parse(Location, new XmlNodePlainTextReadonlyByteStream(current)), true));
                    }
                    else if (current.LocalName.EqualsInvariant("pre"))
                    {
                        string cls = current.GetAttribute("class");
                        if (cls.EqualsInvariant("script"))
                        {
                            ConvertBrToNewline(current);

                            DekiScriptExpression expr = TryCatch(Parse(Location, new XmlNodePlainTextReadonlyByteStream(current)), true);
                            nodes.Add(expr);
                        }
                        else if (cls.EqualsInvariant("script-jem"))
                        {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-jem">...</pre> to <html><body><script type="text/jem">...</script></body></html>
                            DekiScriptExpression html = Html("body", "script", "text/jem", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        }
                        else if (cls.EqualsInvariant("script-js"))
                        {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-js">...</pre> to <html><body><script type="text/js">...</script></body></html>
                            DekiScriptExpression html = Html("body", "script", "text/javascript", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        }
                        else if (cls.EqualsInvariant("script-css"))
                        {
                            ConvertBrToNewline(current);

                            // convert <pre class="script-css">...</pre> to <html><head><style type="text/css">...</style></head></html>
                            DekiScriptExpression html = Html("head", "style", "text/css", DekiScriptExpression.Constant(current.InnerText.ReplaceAll("\u00A0", " ", "\00AD", "")));
                            nodes.Add(html);
                        }
                        else
                        {
                            BuildElement(current, nodes);
                        }
                    }
                    else
                    {
                        BuildElement(current, nodes);
                    }

                    // process "block" attribute
                    bool scripted = false;
                    if (!string.IsNullOrEmpty(value = current.GetAttribute("block")))
                    {
                        scripted = true;

                        // attribute "block" is present
                        var location = SubLocation("/@block");
                        DekiScriptExpression blockExpr = Parse(location, value);
                        blockExpr = DekiScriptExpression.BlockWithDeclaration(Location, blockExpr, nodes);
                        nodes.Clear();
                        nodes.Add(blockExpr);
                    }

                    // process "foreach" attribute
                    if (!string.IsNullOrEmpty(value = current.GetAttribute("foreach")))
                    {
                        scripted = true;

                        // attribute "foreach" is present
                        StringBuilder expression = new StringBuilder();
                        expression.Append(value);
                        string where = current.GetAttribute("where");
                        if (!string.IsNullOrEmpty(where))
                        {
                            expression.Append(", if ").Append(where);
                        }
                        var location = SubLocation("/@foreach");
                        DekiScriptForeach    foreachExpr  = (DekiScriptForeach)Parse(location, "foreach(" + expression + "){}");
                        DekiScriptExpression foreachExpr2 = DekiScriptExpression.ForeachStatement(location, foreachExpr.Generator, nodes);
                        nodes.Clear();
                        nodes.Add(foreachExpr2);
                    }

                    // process "if" attribute
                    if (!string.IsNullOrEmpty(value = current.GetAttribute("if")))
                    {
                        scripted = true;

                        // attribute "if" is present
                        var location = SubLocation("/@if");
                        DekiScriptExpression condition = Parse(location, value);
                        condition = DekiScriptExpression.IfElseStatements(location, new[] { new Tuplet <DekiScriptExpression, DekiScriptExpression>(condition, DekiScriptExpression.Block(Location, nodes)) });
                        nodes.Clear();
                        nodes.Add(condition);
                    }

                    // process "init" attribute
                    if (!string.IsNullOrEmpty(value = current.GetAttribute("init")))
                    {
                        scripted = true;

                        // attribute "init" is present
                        DekiScriptExpression init = Parse(Location, value);
                        DekiScriptExpression dom  = DekiScriptExpression.BlockWithDeclaration(SubLocation("/@init"), init, nodes);
                        nodes.Clear();
                        nodes.Add(dom);
                    }

                    // append inner nodes
                    switch (nodes.Count)
                    {
                    case 0:

                        // nothing to do
                        break;

                    case 1:
                        list.Add(TryCatch(nodes[0], scripted));
                        break;

                    default:
                        list.AddRange(nodes);
                        break;
                    }
                }
            } catch (Exception e) {
                XDoc warning = new XDoc("html").Start("body").Add(DekiScriptRuntime.CreateWarningFromException(null, Location, e)).End();
                list.Add(new DekiScriptXml(warning));
            }
            return(next);
        }
Example #5
0
	void GeneratorHead(out DekiScriptGenerator gen) {
		Location location = Location.None;
		Location wherelocation = Location.None;
		DekiScriptExpression where = null; 
		List<string> names = new List<string>(); 
		DekiScriptExpression expr = null; 
		string value = null;
		gen = null;
		
		Expect(19);
		location = t.Location; 
		Expect(1);
		names.Add(t.val); 
		if (la.kind == 31) {
			Get();
			Expect(1);
			value = t.val; 
			Expect(52);
			Expression(out expr);
			if (la.kind == 70) {
				Get();
				wherelocation = t.Location; 
				Expression(out where);
			}
		} else if (la.kind == 20 || la.kind == 52) {
			while (la.kind == 20) {
				Get();
				Expect(1);
				names.Add(t.val); 
			}
			Expect(52);
			Expression(out expr);
			if (la.kind == 70) {
				Get();
				wherelocation = t.Location; 
				Expression(out where);
			}
		} else SynErr(80);
		if (la.kind == 20) {
			Get();
			GeneratorNext(out gen);
		}
		if(where != null) gen = new DekiScriptGeneratorIf(wherelocation, where, gen);
		if(value == null) gen = new DekiScriptGeneratorForeachValue(location, names.ToArray(), expr, gen);
		else gen = new DekiScriptGeneratorForeachKeyValue(location, names[0], value, expr, gen);
		
	}