public override DekiScriptLiteral ResolveMissingName(string name)
        {
            var result = base.ResolveMissingName(name);

            if (result != null)
            {
                return(result);
            }

            // check if name refers to a template name
            Title title = Title.FromUriPath(name);

            // If the page title is prefixed with :, do not assume the template namespace
            if (title.Path.StartsWith(":"))
            {
                title.Path = title.Path.Substring(1);
            }
            else if (title.IsMain)
            {
                title.Namespace = NS.TEMPLATE;
            }
            PageBE page = PageBL.GetPageByTitle(title);

            if ((page == null) || (page.ID == 0))
            {
                return(null);
            }
            return(DekiScriptExpression.Constant(DekiContext.Current.Deki.Self.At("template"), new DekiScriptList().Add(DekiScriptExpression.Constant(title.AsPrefixedDbPath()))));
        }
Example #2
0
        private DekiScriptExpression BuildChildren(XmlNode current)
        {
            List <DekiScriptExpression> result = new List <DekiScriptExpression>(current.ChildNodes.Count);

            for (XmlNode node = current.FirstChild, next; node != null; node = next)
            {
                PushNode(node);
                next = node.NextSibling;
                switch (node.NodeType)
                {
                case XmlNodeType.Comment:

                    // TODO (steveb): for now we skip comment, though we MAY want to emit them
                    break;

                case XmlNodeType.Element:
                    next = Parse((XmlElement)node, result);
                    break;

                case XmlNodeType.Text:
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    result.Add(DekiScriptExpression.Constant(node.Value));
                    break;

                case XmlNodeType.CDATA:

                    // TODO (steveb): we MAY want to treat CDATA differently than text section
                    result.Add(DekiScriptExpression.Constant(node.Value));
                    break;
                }
                PopNode();
            }
            return(DekiScriptExpression.Block(Location, result));
        }
Example #3
0
        public Hashtable PopularPages(
            [DekiExtParam("max results (default: 10)", true)] int?max,
            [DekiExtParam("poll interval (only for js format, default: 30)", true)] int?interval
            )
        {
            int               maxResults  = max ?? 10;
            int               resultCount = 0;
            DekiScriptMap     env         = DreamContext.Current.GetState <DekiScriptMap>();
            DekiScriptLiteral uriLiteral  = env.GetAt("site.uri");
            XUri              deki        = new XUri(uriLiteral.NativeValue.ToString()).At("@api", "deki");
            Hashtable         map         = new Hashtable(StringComparer.OrdinalIgnoreCase);

            map.Add("interval", _ttl.TotalSeconds);
            ArrayList pages = new ArrayList();

            map.Add("pages", pages);
            int total = 0;
            Dictionary <uint, int> rankLookup = new Dictionary <uint, int>();

            lock (_pageViews) {
                foreach (View view in _pageViews)
                {
                    if (rankLookup.ContainsKey(view.PageId))
                    {
                        rankLookup[view.PageId]++;
                    }
                    else
                    {
                        rankLookup[view.PageId] = 1;
                    }
                    total++;
                }
            }
            List <Tuplet <uint, int> > rank = new List <Tuplet <uint, int> >();

            foreach (KeyValuePair <uint, int> kvp in rankLookup)
            {
                rank.Add(new Tuplet <uint, int>(kvp.Key, kvp.Value));
            }
            rank.Sort(delegate(Tuplet <uint, int> a, Tuplet <uint, int> b) {
                return(b.Item2.CompareTo(a.Item2));
            });
            map.Add("total", total);
            foreach (Tuplet <uint, int> page in rank)
            {
                Hashtable pageMap = new Hashtable(StringComparer.OrdinalIgnoreCase);
                pages.Add(pageMap);

                // BUGBUGBUG (arnec): the AsLocalUri should not be required after bug #5964 is resolved
                pageMap.Add("page", DekiScriptExpression.Constant(deki.At("$page").AsLocalUri(), new[] { DekiScriptExpression.Constant(page.Item1), DekiScriptExpression.Constant(true) }));
                pageMap.Add("views", page.Item2);
                resultCount++;
                if (resultCount >= maxResults)
                {
                    break;
                }
            }
            return(map);
        }
        public void OutputBuffer_web_uri_followed_by_html()
        {
            var expr = DekiScriptExpression.Block(Location.None, new[] { DekiScriptExpression.Constant(new XUri("http://foo/index.html")), DekiScriptExpression.Constant(new XDoc("html").Elem("body", "test")) });

            _dekiScriptTester.Test(
                expr,
                @"<html><body><a rel=""custom nofollow"" href=""http://foo/index.html"">http://foo/index.html</a>test</body></html>",
                typeof(DekiScriptXml), false
                );
        }
        public void OutputBuffer_image_uri_followed_by_html()
        {
            var expr = DekiScriptExpression.Block(Location.None, new[] { DekiScriptExpression.Constant(new XUri("http://foo/index.png")), DekiScriptExpression.Constant(new XDoc("html").Elem("body", "test")) });

            _dekiScriptTester.Test(
                expr,
                @"<html><body><img src=""http://foo/index.png"" />test</body></html>",
                typeof(DekiScriptXml), false
                );
        }
        public void OutputBuffer_web_uri_inside_xml()
        {
            var expr = DekiScriptExpression.XmlElement(Location.None, null, DekiScriptExpression.Constant("doc"), null, DekiScriptExpression.Constant(new XUri("http://foo/index.html")));

            _dekiScriptTester.Test(
                expr,
                @"<doc><a rel=""custom nofollow"" href=""http://foo/index.html"">http://foo/index.html</a></doc>",
                typeof(DekiScriptXml), false
                );
        }
Example #7
0
 private static object Eval(object value, DekiScriptRuntime runtime)
 {
     if (value is XUri)
     {
         DekiScriptLiteral uri = DekiScriptExpression.Constant((XUri)value);
         if (DekiScriptRuntime.IsProperty(uri))
         {
             value = runtime.EvaluateProperty(Location.None, uri, runtime.CreateEnv()).NativeValue;
         }
     }
     return(value);
 }
Example #8
0
        public void Call_func_with_arg_list()
        {
            string         path = LoadExtension();
            DekiScriptList args = new DekiScriptList()
                                  .Add(DekiScriptExpression.Constant("1"))
                                  .Add(DekiScriptExpression.Constant("2"));
            DreamMessage result = Plug.New(_host.LocalMachineUri).At(path, "Addition").Post(args.ToXml());

            Assert.IsTrue(result.IsSuccessful);
            XDoc resultDoc = result.ToDocument();

            Assert.AreEqual("value", resultDoc.Name);
            Assert.AreEqual(3, resultDoc.Elements.First.AsInt);
        }
Example #9
0
        //--- Constructors ---
        public DekiScriptLiteral Process(DekiScriptOutputBuffer buffer, int marker, bool safe)
        {
            ParseBuffer(buffer, marker, null, safe);

            // update buffer
            buffer.Reset(marker);

            // return computed value as literal
            DekiScriptLiteral result;

            switch (_state)
            {
            case State.EMPTY:
                result = DekiScriptNil.Value;
                break;

            case State.VALUE:
                result = (DekiScriptLiteral)_value;
                break;

            case State.COMPOSITE:
                result = DekiScriptExpression.Constant(((StringBuilder)_value).ToString());
                break;

            case State.XML:
                result = new DekiScriptXml(new XDoc(_document));
                break;

            case State.HTML:
                foreach (var body in from body in _bodies orderby body.Key select body)
                {
                    _html.InsertBefore(body.Value, _tail);
                }
                if (_head != null)
                {
                    RemoveDuplicateElements(_head);
                }
                if (_tail != null)
                {
                    RemoveDuplicateElements(_tail);
                }
                goto case State.XML;

            default:
                throw new ShouldNeverHappenException();
            }
            Clear();
            return(result);
        }
        public Empty Visit(DekiScriptGeneratorForeachKeyValue expr, DekiScriptGeneratorEvaluationState state)
        {
            DekiScriptLiteral collection = Eval(expr.Collection, state);

            // retrieve collection
            Dictionary <string, DekiScriptLiteral> map;

            if (collection is DekiScriptMap)
            {
                // loop over map key-value pairs
                map = ((DekiScriptMap)collection).Value;
            }
            else if (collection is DekiScriptNil)
            {
                // nothing to do
                map = new Dictionary <string, DekiScriptLiteral>();
            }
            else
            {
                throw new DekiScriptBadTypeException(expr.Location, collection.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.NIL });
            }

            // store state of variables
            var previousKey   = state.State.Env.Vars[expr.Key];
            var previousValue = state.State.Env.Vars[expr.Value];
            var previousIndex = state.State.Env.Vars[DekiScriptRuntime.INDEX_ID];

            try {
                // loop over collection
                int index = 0;
                foreach (KeyValuePair <string, DekiScriptLiteral> entry in map)
                {
                    // set the environment variable
                    state.State.Env.Vars.Add(expr.Key, DekiScriptExpression.Constant(entry.Key));
                    state.State.Env.Vars.Add(expr.Value, entry.Value);
                    state.State.Env.Vars.Add(DekiScriptRuntime.INDEX_ID, DekiScriptExpression.Constant(index));

                    // iterate over block statements
                    EvalNext(expr, state);
                    ++index;
                }
            } finally {
                state.State.Env.Vars.Add(expr.Key, previousKey);
                state.State.Env.Vars.Add(expr.Value, previousValue);
                state.State.Env.Vars.Add(DekiScriptRuntime.INDEX_ID, previousIndex);
            }
            return(Empty.Value);
        }
        private static DekiScriptLiteral ToDekiScriptRecurse(XDoc doc)
        {
            XDoc xdoc = doc.Elements;

            switch (xdoc.Name)
            {
            case "nil":
                return(DekiScriptNil.Value);

            case "boolean":
                if (xdoc.Contents.GetType().Equals(typeof(String)))
                {
                    return(DekiScriptExpression.Constant((xdoc.Contents.Contains("1") || xdoc.Contents.Contains("true")) ? true : false));
                }
                return(DekiScriptExpression.Constant(xdoc.AsBool ?? false));

            case "double":
                return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0));

            case "int":
            case "i4":
                return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0));

            case "string":
                return(DekiScriptExpression.Constant(xdoc.AsText ?? string.Empty));

            case "struct": {
                DekiScriptMap result = new DekiScriptMap();
                foreach (XDoc value in xdoc["member"])
                {
                    result.Add(value["name"].Contents, ToDekiScriptRecurse(value["value"]));
                }
                return(result);
            }

            case "array": {
                DekiScriptList result = new DekiScriptList();
                foreach (XDoc value in xdoc["data/value"])
                {
                    result.Add(ToDekiScriptRecurse(value));
                }
                return(result);
            }

            default:
                throw new ArgumentException("this type does not exist in the XML-RPC standard");
            }
        }
        //--- Class Methods ---
        public static void Generate(DekiScriptGenerator expr, DekiScriptEval callback, DekiScriptExpressionEvaluationState state)
        {
            // set counter variable
            int counter         = 0;
            var previousCounter = state.Env.Vars[DekiScriptRuntime.COUNT_ID];

            try {
                state.Env.Vars.Add(DekiScriptRuntime.COUNT_ID, DekiScriptExpression.Constant(counter));
                expr.VisitWith(Instance, new DekiScriptGeneratorEvaluationState(innerEnv => {
                    callback(innerEnv);
                    state.Env.Vars.Add(DekiScriptRuntime.COUNT_ID, DekiScriptExpression.Constant(++counter));
                }, state));
            } finally {
                state.Env.Vars.Add(DekiScriptRuntime.COUNT_ID, previousCounter);
            }
        }
Example #13
0
        //--- Class Methods ---
        public static DekiScriptMap MakeErrorObject(Exception e, DekiScriptEnv env)
        {
            DekiScriptMap exception = new DekiScriptMap();

            // add call stack if one is available
            DekiScriptList callstack = null;

            if (env != null)
            {
                DekiScriptLiteral callstackVar;
                if (env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar))
                {
                    callstack = callstackVar as DekiScriptList;
                }
            }
            while (e is DekiScriptInvokeException)
            {
                var ex = (DekiScriptInvokeException)e;
                if (callstack == null)
                {
                    callstack = new DekiScriptList();
                }
                callstack.AddNativeValue(ex.FunctionName);
                e = ex.InnerException;
            }
            if (callstack != null)
            {
                exception.Add("callstack", callstack);
            }

            // add exception text
            exception.Add("message", DekiScriptExpression.Constant(e.Message));
            exception.Add("stacktrace", DekiScriptExpression.Constant(e.GetCoroutineStackTrace()));
            if (e.InnerException != null)
            {
                exception.Add("inner", MakeErrorObject(e.InnerException, null));
            }
            if (e is DekiScriptException)
            {
                exception.Add("source", DekiScriptExpression.Constant(((DekiScriptException)e).Location.Origin));
            }
            return(exception);
        }
Example #14
0
        public DekiScriptLiteral GetMagicId(string id)
        {
            DekiScriptLiteral result = DekiScriptNil.Value;

            // check if magic IDs map already exists; if not, create one
            if (_magicIds == null)
            {
                _magicIds = new DekiScriptMap();
            }
            else
            {
                result = _magicIds[id];
            }

            // check if a magic ID was found; if not, create one
            if (result.IsNil)
            {
                result = DekiScriptExpression.Constant(id + "_" + StringUtil.CreateAlphaNumericKey(8));
                _magicIds.Add(id, result);
            }
            return(result);
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptUnary expr, DekiScriptExpressionEvaluationState state)
        {
            switch (expr.OpCode)
            {
            case DekiScriptUnary.Op.Negate:
                return(state.Push(DekiScriptExpression.Constant(-state.Pop(expr.Value.VisitWith(this, state)).AsNumber())));

            case DekiScriptUnary.Op.LogicalNot:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(expr.Value.VisitWith(this, state)).IsNilFalseZero)));

            case DekiScriptUnary.Op.TypeOf:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(expr.Value.VisitWith(this, state)).ScriptTypeName)));

            case DekiScriptUnary.Op.Length: {
                DekiScriptLiteral value = state.Pop(expr.Value.VisitWith(this, state));
                switch (value.ScriptType)
                {
                case DekiScriptType.NIL:
                    return(state.Push(DekiScriptExpression.Constant(0)));

                case DekiScriptType.LIST:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptList)value).Value.Count)));

                case DekiScriptType.STR:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptString)value).Value.Length)));

                case DekiScriptType.MAP:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptMap)value).Value.Count)));

                case DekiScriptType.XML:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptXml)value).Value.ListLength)));

                default:
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }
        public void Test(DekiScriptExpression expr, string resultValue, Type expectedType, bool safe)
        {
            var env = Runtime.CreateEnv();

            env.Vars.Add(DekiScriptEnv.SAFEMODE, DekiScriptExpression.Constant(safe));
            DekiScriptExpression result = Runtime.Evaluate(expr, safe ? DekiScriptEvalMode.EvaluateSafeMode : DekiScriptEvalMode.Evaluate, env);

            Assert.IsAssignableFrom(expectedType, result);
            string value;

            if (result is DekiScriptString)
            {
                value = ((DekiScriptString)result).Value;
            }
            else if (result is DekiScriptXml)
            {
                value = ((DekiScriptXml)result).Value.ToString();
            }
            else
            {
                value = result.ToString();
            }
            Assert.AreEqual(resultValue, value);
        }
Example #17
0
        public static void InitializeCustomDekiScriptHeaders(PageBE page)
        {
            var           current = DreamContext.Current;
            DekiScriptMap env     = current.GetState <DekiScriptMap>("pageimplicitenv-" + page.ID);

            // check if we already have an initialized environment
            if (env == null)
            {
                DekiContext  deki     = DekiContext.Current;
                DekiInstance instance = deki.Instance;
                env = new DekiScriptMap();

                // add site fields
                DekiScriptMap siteFields = new DekiScriptMap();
                siteFields.Add("name", DekiScriptExpression.Constant(instance.SiteName));
                siteFields.Add("host", DekiScriptExpression.Constant(deki.UiUri.Uri.Host));
                siteFields.Add("language", DekiScriptExpression.Constant(instance.SiteLanguage));
                siteFields.Add("uri", DekiScriptExpression.Constant(deki.UiUri.Uri.ToString()));
                siteFields.Add("id", DekiScriptExpression.Constant(instance.Id));
                env.Add("site", siteFields);

                // add page fields
                DekiScriptMap pageFields = new DekiScriptMap();
                pageFields.Add("title", DekiScriptExpression.Constant(page.Title.AsUserFriendlyName()));
                pageFields.Add("path", DekiScriptExpression.Constant(page.Title.AsPrefixedDbPath()));
                pageFields.Add("namespace", DekiScriptExpression.Constant(Title.NSToString(page.Title.Namespace)));
                pageFields.Add("id", DekiScriptExpression.Constant(page.ID.ToString()));
                pageFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(page.Title)));
                pageFields.Add("date", DekiScriptExpression.Constant(page.TimeStamp.ToString("R")));
                pageFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(page.Language) ? null : page.Language));
                env.Add("page", pageFields);

                // add user fields
                DekiScriptMap userFields = new DekiScriptMap();
                if (deki.User != null)
                {
                    UserBE user = deki.User;
                    userFields.Add("id", DekiScriptExpression.Constant(user.ID.ToString()));
                    userFields.Add("name", DekiScriptExpression.Constant(user.Name));
                    userFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(Title.FromDbPath(NS.USER, user.Name, null))));
                    userFields.Add("emailhash", DekiScriptExpression.Constant(StringUtil.ComputeHashString((user.Email ?? string.Empty).Trim().ToLowerInvariant(), Encoding.UTF8)));
                    userFields.Add("anonymous", DekiScriptExpression.Constant(UserBL.IsAnonymous(user).ToString().ToLowerInvariant()));
                    userFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(user.Language) ? null : user.Language));
                }
                else
                {
                    userFields.Add("id", DekiScriptExpression.Constant("0"));
                    userFields.Add("name", DekiScriptExpression.Constant(string.Empty));
                    userFields.Add("uri", DekiScriptExpression.Constant(string.Empty));
                    userFields.Add("emailhash", DekiScriptExpression.Constant(string.Empty));
                    userFields.Add("anonymous", DekiScriptExpression.Constant("true"));
                    userFields.Add("language", DekiScriptNil.Value);
                }
                env.Add("user", userFields);

                // store env for later
                current.SetState("pageimplicitenv-" + page.ID, env);
            }

            // set implicit environment
            DreamContext.Current.SetState(env);
        }
Example #18
0
        public static DekiScriptEnv CreateEnvironment(PageBE page)
        {
            DekiScriptEnv commonEnv = DekiContext.Current.Instance.CreateEnvironment();

            // need to strip the config value back out for Deki
            commonEnv.Vars["config"] = new DekiScriptMap();

            // initialize environment
            DekiScriptEnv env      = commonEnv;
            DekiContext   deki     = DekiContext.Current;
            DekiInstance  instance = deki.Instance;

            // add site variables
            env.Vars.AddNativeValueAt("site.name", instance.SiteName);
            env.Vars.AddNativeValueAt("site.hostname", deki.UiUri.Uri.HostPort);
            env.Vars.AddNativeValueAt("site.api", deki.ApiUri.SchemeHostPortPath);
            env.Vars.AddNativeValueAt("site.language", instance.SiteLanguage);
            env.Vars.AddNativeValueAt("site.uri", deki.UiUri.Uri.ToString());
            env.Vars.AddNativeValueAt("site.pagecount", deki.Deki.PropertyAt("$sitepagecount"));
            env.Vars.AddNativeValueAt("site.usercount", deki.Deki.PropertyAt("$siteusercount"));
            env.Vars.AddNativeValueAt("site.homepage", deki.Deki.PropertyAt("$page", DekiContext.Current.Instance.HomePageId, true));
            env.Vars.AddNativeValueAt("site.feed", deki.ApiUri.At("site", "feed").ToString());
            env.Vars.AddNativeValueAt("site.tags", deki.Deki.PropertyAt("$sitetags"));
            env.Vars.AddNativeValueAt("site.users", deki.Deki.PropertyAt("$siteusers"));
            env.Vars.AddNativeValueAt("site.id", DekiScriptExpression.Constant(instance.Id));
            env.Vars.AddNativeValueAt("site.timezone", DekiScriptExpression.Constant(instance.SiteTimezone));

            // add page variables
            env.Vars.Add("page", deki.Deki.PropertyAt("$page", page.ID, true));

            // add user variables
            env.Vars.Add("user", deki.Deki.PropertyAt("$user", (deki.User != null) ? deki.User.ID : 0));

            // add instance functions & properties
            bool hasUnsafeContentPermission = DekiXmlParser.PageAuthorCanExecute();

            foreach (var service in instance.RunningServices.ExtensionServices)
            {
                if (service != null)
                {
                    var extension = service.Extension;
                    if (extension != null)
                    {
                        if (hasUnsafeContentPermission || !extension.IsProtected)
                        {
                            var functions = extension.Functions;
                            if (functions != null)
                            {
                                foreach (var function in functions)
                                {
                                    env.Vars.AddNativeValueAt(function.Name.ToLowerInvariant(), function.Uri);
                                }
                            }
                            else
                            {
                                _log.WarnFormat("CreateEnvironment - null functions (id: {0})", service.ServiceId);
                            }
                        }
                    }
                    else
                    {
                        _log.WarnFormat("CreateEnvironment - null extension (id: {0})", service.ServiceId);
                    }
                }
                else
                {
                    _log.Warn("CreateEnvironment - null service");
                }
            }
            return(env);
        }
        public Empty Visit(DekiScriptGeneratorForeachValue expr, DekiScriptGeneratorEvaluationState state)
        {
            DekiScriptLiteral collection = Eval(expr.Collection, state);

            // retrieve collection
            List <DekiScriptLiteral> list;

            if (collection is DekiScriptList)
            {
                // loop over list values
                list = ((DekiScriptList)collection).Value;
            }
            else if (collection is DekiScriptMap)
            {
                // loop over map key-value pairs
                list = new List <DekiScriptLiteral>(((DekiScriptMap)collection).Value.Values);
            }
            else if (collection is DekiScriptXml)
            {
                // loop over xml selection
                List <XDoc> selection = ((DekiScriptXml)collection).Value.ToList();
                list = new List <DekiScriptLiteral>(selection.Count);
                foreach (XDoc doc in selection)
                {
                    list.Add(new DekiScriptXml(doc));
                }
            }
            else if (collection is DekiScriptNil)
            {
                // nothing to do
                list = new List <DekiScriptLiteral>();
            }
            else
            {
                throw new DekiScriptBadTypeException(expr.Location, collection.ScriptType, new[] { DekiScriptType.LIST, DekiScriptType.MAP, DekiScriptType.XML, DekiScriptType.NIL });
            }

            // store state of variables
            int index        = 0;
            var previousVars = new DekiScriptLiteral[expr.Vars.Length];

            for (int j = 0; j < expr.Vars.Length; ++j)
            {
                previousVars[j] = state.State.Env.Vars[expr.Vars[j]];
            }
            var previousIndex = state.State.Env.Vars[DekiScriptRuntime.INDEX_ID];

            try {
                // loop over collection
                for (int i = 0; i <= (list.Count - expr.Vars.Length); i += expr.Vars.Length)
                {
                    // set the environment variable
                    for (int j = 0; j < expr.Vars.Length; ++j)
                    {
                        state.State.Env.Vars.Add(expr.Vars[j], list[i + j]);
                    }
                    state.State.Env.Vars.Add(DekiScriptRuntime.INDEX_ID, DekiScriptExpression.Constant(index));

                    // iterate over block statements
                    EvalNext(expr, state);
                    index += expr.Vars.Length;
                }
            } finally {
                // restore state of variables
                for (int j = 0; j < expr.Vars.Length; ++j)
                {
                    state.State.Env.Vars.Add(expr.Vars[j], previousVars[j]);
                }
                state.State.Env.Vars.Add(DekiScriptRuntime.INDEX_ID, previousIndex);
            }
            return(Empty.Value);
        }
Example #20
0
        private void LoadScript()
        {
            _manifestPath  = null;
            _resourcesPath = null;
            _manifestUri   = null;
            _resourcesUri  = null;
            _manifest      = null;

            // read manifest
            _manifestPath = Config["manifest"].AsText;
            if (string.IsNullOrEmpty(_manifestPath))
            {
                throw new ArgumentNullException("manifest");
            }
            _manifestUri = XUri.TryParse(_manifestPath);
            if (_manifestUri != null)
            {
                _manifestPath = null;
                _manifest     = Plug.New(_manifestUri).Get().ToDocument();
                _resourcesUri = Config["resources"].AsUri ?? _manifestUri.WithoutLastSegment();
            }
            else
            {
                _manifest      = XDocFactory.LoadFrom(_manifestPath, MimeType.XML);
                _resourcesPath = Config["resources"].AsText ?? Path.GetDirectoryName(_manifestPath);
            }
            if (!_manifest.HasName("extension"))
            {
                throw new ArgumentException("invalid extension manifest");
            }

            // initilize runtime
            _runtime = new DekiScriptRuntime();

            // read manifest settings
            _title       = _manifest["title"].AsText;
            _label       = _manifest["label"].AsText;
            _copyright   = _manifest["copyright"].AsText;
            _description = _manifest["description"].AsText;
            _help        = _manifest["uri.help"].AsText;
            _logo        = _manifest["uri.logo"].AsText;
            _namespace   = _manifest["namespace"].AsText;

            // initialize evaluation environment
            _commonEnv = _runtime.CreateEnv();

            // read functions
            _functions = new Dictionary <XUri, DekiScriptInvocationTargetDescriptor>();
            foreach (var function in _manifest["function"])
            {
                var descriptor = ConvertFunction(function);
                if (descriptor != null)
                {
                    var uri = Self.At(descriptor.SystemName);
                    DekiScriptInvocationTargetDescriptor old;
                    if (_functions.TryGetValue(uri, out old))
                    {
                        _log.WarnFormat("duplicate function name {0} in script {1}", descriptor.Name, _manifestUri);
                    }
                    _functions[uri] = descriptor;
                }
            }
            _runtime.RegisterExtensionFunctions(_functions);

            // add extension functions to env
            foreach (var function in _functions)
            {
                _commonEnv.Vars.AddNativeValueAt(function.Value.Name.ToLowerInvariant(), function.Key);
            }

            // add configuration settings
            DreamContext  context      = DreamContext.Current;
            DekiScriptMap scriptConfig = new DekiScriptMap();

            foreach (KeyValuePair <string, string> entry in Config.ToKeyValuePairs())
            {
                XUri local;
                if (XUri.TryParse(entry.Value, out local))
                {
                    local = context.AsPublicUri(local);
                    scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(local.ToString()));
                }
                else
                {
                    scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(entry.Value));
                }
            }
            _commonEnv.Vars.Add("config", scriptConfig);
        }
Example #21
0
        private DekiScriptExpression Html(string container, string tag, string type, DekiScriptExpression expr)
        {
            DekiScriptExpression style = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant(tag), new[] { new DekiScriptXmlElement.Attribute(Location, null, DekiScriptExpression.Constant("type"), DekiScriptExpression.Constant(type)) }, expr);
            DekiScriptExpression head  = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant(container), null, style);
            DekiScriptExpression html  = DekiScriptExpression.XmlElement(Location, null, DekiScriptExpression.Constant("html"), null, head);

            return(html);
        }
Example #22
0
        private List <DekiScriptXmlElement.Attribute> BuildAttributes(XmlNode current)
        {
            List <DekiScriptXmlElement.Attribute> result = new List <DekiScriptXmlElement.Attribute>(current.Attributes.Count);

            for (int i = 0; i < current.Attributes.Count; ++i)
            {
                XmlAttribute attribute = current.Attributes[i];
                PushNode(attribute);

                // check if attribute needs to be evaluated
                if (attribute.NamespaceURI == XDekiScript.ScriptNS)
                {
                    // NOTE (steveb): eval:key="value"
                    DekiScriptXmlElement.Attribute attr = new DekiScriptXmlElement.Attribute(Location, null, DekiScriptExpression.Constant(attribute.LocalName), Parse(Location, attribute.Value));
                    result.Add(attr);
                }
                else if (attribute.Value.StartsWithInvariant("{{") && attribute.Value.EndsWithInvariant("}}"))
                {
                    // NOTE (steveb): key="{{value}}"
                    DekiScriptExpression           expr = Parse(Location, StripCode(attribute.Value.Substring(2, attribute.Value.Length - 4)));
                    DekiScriptXmlElement.Attribute attr = new DekiScriptXmlElement.Attribute(Location, attribute.Prefix, DekiScriptExpression.Constant(attribute.LocalName), expr);
                    result.Add(attr);
                }
                else if (!attribute.NamespaceURI.EqualsInvariant("http://www.w3.org/2000/xmlns/") || !attribute.Value.EqualsInvariant("http://mindtouch.com/2007/dekiscript"))
                {
                    // skip "init", "if", "foreach", "block", "where", "function" since they have already been processed
                    if (!attribute.NamespaceURI.EqualsInvariant(string.Empty) || !(
                            attribute.LocalName.EqualsInvariant("init") ||
                            attribute.LocalName.EqualsInvariant("if") ||
                            attribute.LocalName.EqualsInvariant("foreach") ||
                            attribute.LocalName.EqualsInvariant("where") ||
                            attribute.LocalName.EqualsInvariant("block") ||
                            attribute.LocalName.EqualsInvariant("function")
                            ))
                    {
                        // add static attribute
                        DekiScriptXmlElement.Attribute attr = new DekiScriptXmlElement.Attribute(Location, attribute.Prefix, DekiScriptExpression.Constant(attribute.LocalName), DekiScriptExpression.Constant(attribute.Value));
                        result.Add(attr);
                    }
                }
                PopNode();
            }
            return(result);
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptBinary expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression Left  = expr.Left;
            DekiScriptExpression Right = expr.Right;

            switch (expr.OpCode)
            {
            case DekiScriptBinary.Op.LeftValue:
                return(Left.VisitWith(this, state));

            case DekiScriptBinary.Op.IdentityEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityEqual(left, right)));
            }

            case DekiScriptBinary.Op.IdentityNotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityNotEqual(left, right)));
            }

            case DekiScriptBinary.Op.IsType: {
                DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state));
                string            type = ((DekiScriptString)Right).Value;
                return(state.Push(DekiScriptExpression.Constant(type.EqualsInvariantIgnoreCase("any") || left.ScriptTypeName.EqualsInvariantIgnoreCase(type))));
            }

            case DekiScriptBinary.Op.Equal: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.Equal(left, right)));
            }

            case DekiScriptBinary.Op.NotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.NotEqual(left, right)));
            }

            case DekiScriptBinary.Op.GreaterOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() >= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) >= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.GreaterThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() > right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) > 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() <= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) <= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() < right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) < 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LogicalAnd: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (!result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.LogicalOr: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Addition:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() + state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Division:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() / state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Modulo: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if ((left is DekiScriptString) && ((right is DekiScriptMap) || (right is DekiScriptList)))
                {
                    // NOTE (steveb): string.format shorthand notation: "abc = $abc" % { abc: 123 } -OR- "0 = $0" % [ 123 ]
                    return(state.Push(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue))));
                }
                else
                {
                    return(state.Push(DekiScriptExpression.Constant(left.AsNumber() % right.AsNumber())));
                }
            }

            case DekiScriptBinary.Op.Multiplication:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() * state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Subtraction:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() - state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.NullCoalesce: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNil)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Concat: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (left is DekiScriptNil)
                {
                    return(state.Push(right));
                }
                else if (right is DekiScriptNil)
                {
                    return(state.Push(left));
                }
                else if ((left is DekiScriptMap) && (right is DekiScriptMap))
                {
                    // left and right expressions are maps, merge them
                    DekiScriptMap result = new DekiScriptMap();
                    result.AddRange((DekiScriptMap)left);
                    result.AddRange((DekiScriptMap)right);
                    return(state.Push(result));
                }
                else if ((left is DekiScriptList) && (right is DekiScriptList))
                {
                    // left and right expressions are lists, concatenate them
                    DekiScriptList result = new DekiScriptList();
                    result.AddRange((DekiScriptList)left);
                    result.AddRange((DekiScriptList)right);
                    return(state.Push(result));
                }
                else
                {
                    // treat left and right expressions as strings
                    string leftText  = left.AsString();
                    string rightText = right.AsString();
                    if ((leftText != null) && (rightText != null))
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText + rightText)));
                    }
                    else if (leftText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText)));
                    }
                    else if (rightText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(rightText)));
                    }
                    else
                    {
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
            }

            case DekiScriptBinary.Op.UriAppend: {
                // TODO (steveb): we should throw an exception when the LHS is not a valid string or uri

                XUri   left   = XUri.TryParse(state.Pop(Left.VisitWith(this, state)).AsString());
                string result = null;
                if (left != null)
                {
                    DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                    if (right is DekiScriptString)
                    {
                        result = DekiScriptLibrary.UriBuild(left, right.AsString(), null);
                    }
                    else if (right is DekiScriptMap)
                    {
                        result = DekiScriptLibrary.UriBuild(left, null, (Hashtable)right.NativeValue);
                    }
                    else
                    {
                        result = left.ToString();
                    }
                }
                return(state.Push(DekiScriptLiteral.FromNativeValue(result)));
            }

            case DekiScriptBinary.Op.InCollection: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (right is DekiScriptList)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else if (right is DekiScriptMap)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else
                {
                    return(state.Push(DekiScriptBool.False));
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }
Example #24
0
        public void Execute(ExecutionPlan plan)
        {
            var service = DreamTestHelper.CreateService(
                _hostinfo,
                "sid://mindtouch.com/2007/12/dekiscript",
                "dekiscript",
                new XDoc("config").Elem("manifest", _manifestUri)
                );

            foreach (var functionName in _manifest["function/name"])
            {
                var name = functionName.AsText;
                _tester.Runtime.RegisterFunction(name, service.AtLocalHost.At(name));
            }
            try {
                var expr = _tester.Parse(plan.Expr);
                var env  = _tester.Runtime.CreateEnv();
                env.Vars.Add(DekiScriptEnv.SAFEMODE, DekiScriptExpression.Constant(plan.Safe));
                DekiScriptExpression result = _tester.Runtime.Evaluate(expr, plan.Safe ? DekiScriptEvalMode.EvaluateSafeMode : DekiScriptEvalMode.Evaluate, env);
                if (plan.TypedVerification != null)
                {
                    Assert.AreEqual(plan.ExpectedType, result.GetType());
                    plan.TypedVerification(result);
                }
                else if (plan.DocVerification != null)
                {
                    if (!(result is DekiScriptXml))
                    {
                        Assert.Fail(string.Format("return type was '{0}' not DekiScriptXml", result.GetType()));
                    }
                    var doc = ((DekiScriptXml)result).Value;
                    plan.DocVerification(doc);
                }
                else if (plan.StringVerification != null)
                {
                    string value;
                    if (result is DekiScriptString)
                    {
                        value = ((DekiScriptString)result).Value;
                    }
                    else if (result is DekiScriptXml)
                    {
                        value = ((DekiScriptXml)result).Value.ToString();
                    }
                    else
                    {
                        value = result.ToString();
                    }
                    plan.StringVerification(value, result.GetType());
                }
                else
                {
                    Assert.Fail("Execution completed without exception");
                }
            } catch (Exception e) {
                if (plan.ExceptionVerification != null)
                {
                    plan.ExceptionVerification(e);
                }
                else
                {
                    throw;
                }
            } finally {
                service.WithPrivateKey().AtLocalHost.Delete();
            }
        }
        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 DekiScriptLiteral Evaluate(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state, bool evaluateProperties)
        {
            DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state));
            DekiScriptLiteral index  = state.Pop(expr.Index.VisitWith(this, state));

            switch (prefix.ScriptType)
            {
            case DekiScriptType.MAP: {
                DekiScriptLiteral result = ((DekiScriptMap)prefix)[index];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.LIST: {
                DekiScriptLiteral value  = DekiScriptExpression.Constant(index.AsNumber());
                DekiScriptLiteral result = ((DekiScriptList)prefix)[value];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.URI: {
                DekiScriptUri uri = (DekiScriptUri)prefix;

                // coerce the index type to STR
                index = DekiScriptExpression.Constant(index.AsString());
                if (index.ScriptType != DekiScriptType.STR)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }

                // curry the argument
                DekiScriptList args;
                if (!uri.Arguments.IsNil)
                {
                    // the uri already has curried parameters, make sure they are in LIST format; otherwise fail
                    if (uri.Arguments.ScriptType != DekiScriptType.LIST)
                    {
                        throw new DekiScriptBadTypeException(expr.Location, uri.Arguments.ScriptType, new[] { DekiScriptType.NIL, DekiScriptType.LIST });
                    }
                    args = new DekiScriptList((DekiScriptList)uri.Arguments);
                }
                else
                {
                    args = new DekiScriptList();
                }
                args.Add(index);
                return(new DekiScriptUri(uri.Value, args));
            }

            case DekiScriptType.STR: {
                DekiScriptString text = (DekiScriptString)prefix;

                // coerce the index type to NUM
                double?value = index.AsNumber();
                if (value == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.NUM });
                }

                // retrieve character at given index position
                int position = (int)value;
                if ((position < 0) || (position >= text.Value.Length))
                {
                    // index is out of bounds, return nil
                    return(DekiScriptNil.Value);
                }
                return(DekiScriptExpression.Constant(text.Value[position].ToString()));
            }

            case DekiScriptType.XML: {
                string path = index.AsString();
                if (path == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }
                XDoc doc = ((DekiScriptXml)prefix).Value[path];
                if (doc.HasName("html"))
                {
                    doc = DekiScriptLibrary.CleanseHtmlDocument(doc);
                }
                return(new DekiScriptXml(doc));
            }

            case DekiScriptType.NIL:
                return(DekiScriptNil.Value);
            }
            throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST, DekiScriptType.XML, DekiScriptType.STR, DekiScriptType.URI });
        }
Example #27
0
        private void AddXDoc(XmlNode contextualbody, XDoc doc)
        {
            // check if this is a no-op
            if (doc.IsEmpty)
            {
                return;
            }

            // create a sub-buffer for processing
            DekiScriptOutputBuffer buffer = new DekiScriptOutputBuffer(int.MaxValue);

            // push all nodes from the XML document into the buffer
            Stack <XmlNode> stack = new Stack <XmlNode>();

            // check if we're dealing with a simple <html><body> ... </body></html> document
            bool addSiblings = false;

            if ((doc.AsXmlNode.NodeType == XmlNodeType.Element) && doc.HasName("html") && doc["head/*"].IsEmpty && doc["tail/*"].IsEmpty && doc["body[@target]"].IsEmpty)
            {
                var body = doc["body"];
                if (body.IsEmpty || (body.AsXmlNode.ChildNodes.Count == 0))
                {
                    // nothing to do
                    return;
                }
                doc         = doc[body.AsXmlNode.FirstChild];
                addSiblings = true;
            }

            // loop over nodes
            XmlNode current = doc.AsXmlNode;

            do
            {
                XmlElement element;
                switch (current.NodeType)
                {
                case XmlNodeType.Element:
                    element = (XmlElement)current;
                    AppendXmlStart(buffer, element);
                    if (element.HasChildNodes)
                    {
                        stack.Push(addSiblings || (stack.Count > 0) ? current.NextSibling : null);
                        current = element.FirstChild;
                        continue;
                    }
                    buffer.PushXmlEnd();
                    break;

                case XmlNodeType.Attribute:
                    buffer.Push(DekiScriptExpression.Constant((string.IsNullOrEmpty(current.Prefix) ? current.Name : current.Prefix + ":" + current.Name) + "=" + current.Value.QuoteString()));
                    break;

                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.Text:
                case XmlNodeType.Whitespace:
                    buffer.Push(DekiScriptExpression.Constant(current.Value));
                    break;

                default:

                    // ignore this node
                    break;
                }

                // move onto next item or resume previous one
                current = addSiblings || (stack.Count > 0) ? current.NextSibling : null;
                while ((current == null) && (stack.Count > 0))
                {
                    buffer.PushXmlEnd();
                    current = stack.Pop();
                }
            } while(current != null);

            // parse the sub-buffer
            ParseBuffer(buffer, 0, contextualbody, false);
        }
Example #28
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 #29
0
        protected override Yield Start(XDoc config, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            // loop over all resources
            Type   type     = GetType();
            string assembly = type.Assembly.FullName.Split(new char[] { ',' }, 2)[0];

            foreach (DekiExtLibraryFilesAttribute files in Attribute.GetCustomAttributes(type, typeof(DekiExtLibraryFilesAttribute)))
            {
                string prefix = files.Prefix ?? type.Namespace;
                foreach (string filename in files.Filenames)
                {
                    MimeType mime = MimeType.FromFileExtension(filename);
                    _files[filename] = Plug.New(string.Format("resource://{0}/{1}.{2}", assembly, prefix, filename)).With("dream.out.type", mime.FullType);
                }
            }

            // check if a public digital signature key was provided
            string dsaKey = config["deki-signature"].AsText ?? config["dekiwiki-signature"].AsText;

            if (dsaKey != null)
            {
                try {
                    DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
                    dsa.ImportCspBlob(Convert.FromBase64String(dsaKey));
                    _publicDigitalSignature = dsa;
                } catch {
                    throw new ArgumentException("invalid digital signature provided", "deki-signature");
                }
            }

            // loop over all instance methods
            foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                // check if it has the DekiExtFunction attriute
                DekiExtFunctionAttribute ext = (DekiExtFunctionAttribute)Attribute.GetCustomAttribute(method, typeof(DekiExtFunctionAttribute));
                if (ext != null)
                {
                    // check if function has an associated script
                    XDekiScript script = null;
                    DekiExtFunctionScriptAttribute scriptAttr = (DekiExtFunctionScriptAttribute)Attribute.GetCustomAttribute(method, typeof(DekiExtFunctionScriptAttribute));
                    if (scriptAttr != null)
                    {
                        DreamMessage scriptresource = Plug.New(string.Format("resource://{0}/{1}.{2}", assembly, scriptAttr.Prefix ?? type.Namespace, scriptAttr.Scriptname)).With("dream.out.type", MimeType.XML.FullType).GetAsync().Wait();
                        if (scriptresource.IsSuccessful)
                        {
                            script = new XDekiScript(scriptresource.ToDocument());
                        }
                        if (script == null)
                        {
                            throw new InvalidOperationException(string.Format("method '{0}' is declard as script, but script could not be loaded", method.Name));
                        }
                    }

                    // add function
                    Add(ext, method, script);
                }
            }

            // add configuration settings
            var context = DreamContext.Current;

            _scriptConfig = new DekiScriptMap();
            foreach (KeyValuePair <string, string> entry in Config.ToKeyValuePairs())
            {
                XUri local;
                if (XUri.TryParse(entry.Value, out local))
                {
                    local = context.AsPublicUri(local);
                    _scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(local.ToString()));
                }
                else
                {
                    _scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(entry.Value));
                }
            }
            result.Return();
        }
Example #30
0
        private void BuildElement(XmlNode current, ICollection <DekiScriptExpression> list)
        {
            // create new element
            var attributes = BuildAttributes(current);
            var elem       = DekiScriptExpression.XmlElement(Location, current.Prefix, DekiScriptExpression.Constant(current.LocalName), attributes.ToArray(), BuildChildren(current));

            list.Add(elem);
        }