コード例 #1
0
ファイル: DekiScriptLibrary.cs プロジェクト: heran/DekiWiki
        //--- 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;
        }
コード例 #2
0
 //--- Constructors ---
 public DekiScriptComparer(DekiScriptRuntime runtime, DekiScriptExpression compare) {
     if(compare == null) {
         throw new ArgumentNullException("compare");
     }
     _runtime = runtime;
     _compare = compare;
     _values = new DekiScriptMap();
     _env = runtime.CreateEnv();
     _env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, _values);
 }
コード例 #3
0
 public DekiScriptExpressionInvocationTarget(DreamAccess access, DekiScriptParameter[] parameters, DekiScriptExpression expr, DekiScriptEnv env) {
     if(parameters == null) {
         throw new ArgumentNullException("parameters");
     }
     if(expr == null) {
         throw new ArgumentNullException("expr");
     }
     this.Access = access;
     this.Parameters = parameters;
     this.Expression = expr;
     _env = env;
 }
コード例 #4
0
            private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptMap args)
            {
                // invoke script
                DekiScriptEnv env = _env.NewScope();

                env.Vars.AddRange(DreamContext.Current.GetState <DekiScriptMap>("env.implicit"));
                env.Vars.Add("args", args);
                env.Vars.Add("$", args);
                var result = runtime.Evaluate(Expression, DekiScriptEvalMode.Evaluate, env);

                try {
                    return(result.Convert(_returnType));
                } catch (DekiScriptInvalidCastException) {
                    throw new DekiScriptInvalidReturnCastException(Location.None, result.ScriptType, _returnType);
                }
            }
コード例 #5
0
        public static ArrayList ListApply(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to apply (use '$' to refer to the current item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("list.apply(expression)"), expression);
            ArrayList            result = new ArrayList();

            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));
                result.Add(runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).NativeValue);
            }
            return(result);
        }
コード例 #6
0
        private void InitScriptRuntimeAndEnv()
        {
            if (_runtime != null)
            {
                return;
            }

            // Note (arnec): have to lazily init the runtime and env, because they require instance settings and they currently have
            // a requirement of DekiContext.Current.Instance being set, i.e. a race condition in the ctor
            lock (SettingsSyncRoot) {
                if (_runtime != null)
                {
                    return;
                }
                _runtime   = new ExtensionRuntime(new DekiInstanceSettings());
                _scriptEnv = _deki.InitializeRuntimeAndEnvironment(_runtime);
            }
        }
コード例 #7
0
        public static ArrayList ListIntersect(
            [DekiScriptParam("first list")] ArrayList first,
            [DekiScriptParam("second list")] ArrayList second,
            [DekiScriptParam("expression to determine if item from the first list should be included in final list (return true to include, false to exclude; use '$left' and '$right' to refer to the current item from the first and seconds lists respectively; default: equality condition)", true)] string condition,
            DekiScriptRuntime runtime
            )
        {
            ArrayList result = new ArrayList();

            if (condition != null)
            {
                // loop over both lists and keep items from the first list based on the outcome of the condition
                DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.intersect(condition)"), condition);
                foreach (object left in first)
                {
                    foreach (object right in second)
                    {
                        DekiScriptEnv env      = runtime.CreateEnv();
                        DekiScriptMap keyvalue = new DekiScriptMap();
                        keyvalue.Add("left", DekiScriptLiteral.FromNativeValue(left));
                        keyvalue.Add("right", DekiScriptLiteral.FromNativeValue(right));
                        env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                        DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                        if (!test.IsNilFalseZero)
                        {
                            result.Add(left);
                            break;
                        }
                    }
                }
            }
            else
            {
                // using simple containment check to keep items
                foreach (object item in first)
                {
                    if (second.Contains(item))
                    {
                        result.Add(item);
                    }
                }
            }
            return(result);
        }
コード例 #8
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);
        }
コード例 #9
0
        public static Hashtable MapApply(
            [DekiScriptParam("map value")] Hashtable map,
            [DekiScriptParam("expression to apply (use '$' to refer to the item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("map.apply(expression)"), expression);
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);

            foreach (DictionaryEntry entry in map)
            {
                DekiScriptMap keyvalue = new DekiScriptMap();
                keyvalue.Add("key", DekiScriptLiteral.FromNativeValue(entry.Key));
                keyvalue.Add("value", DekiScriptLiteral.FromNativeValue(Eval(entry.Value, runtime)));
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                result.Add(entry.Key, runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env));
            }
            return(result);
        }
コード例 #10
0
        public static object ListReduce(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to compute combined value (use '$value' and '$item' to refer to the current value and item, respectively)")] string expression,
            [DekiScriptParam("starting value (default: nil)", true)] object value,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.reduce(expression)"), expression);

            foreach (object entry in list)
            {
                DekiScriptEnv env    = runtime.CreateEnv();
                DekiScriptMap values = new DekiScriptMap();
                values.Add("value", DekiScriptLiteral.FromNativeValue(value));
                values.Add("item", DekiScriptLiteral.FromNativeValue(entry));
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, values);
                value = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).NativeValue;
            }
            return(value);
        }
コード例 #11
0
        //--- Methods ---
        public Empty Visit(DekiScriptDomBlock expr, DekiScriptDomEvaluationState state)
        {
            var context = state.Context;
            var env     = state.Env;
            var parent  = state.Parent;

            try {
                DekiScriptEnv locals = env.NewLocalScope();

                // check if we need to evaluate the block 'Value'
                if (expr.IsDynamic)
                {
                    expr.Value.VisitWith(DekiScriptExpressionEvaluation.Instance, locals);
                }
                expr.Node.VisitWith(this, new DekiScriptDomEvaluationState(context, parent, locals));
            } catch (Exception e) {
                EmbedExceptionMessage(expr, env, context, e, parent);
            }
            return(Empty.Value);
        }
コード例 #12
0
        public static XDoc WebLink(
            [DekiScriptParam("link uri")] string uri,
            [DekiScriptParam("link contents; can be text, an image, or another document (default: link uri)", true)] object text,
            [DekiScriptParam("link hover title (default: none)", true)] string title,
            [DekiScriptParam("link target (default: none)", true)] string target
            )
        {
            // check __settings.nofollow if links should be followed or not
            bool         nofollow = true;
            DreamContext context  = DreamContext.CurrentOrNull;

            if (context != null)
            {
                DekiScriptEnv env = context.GetState <DekiScriptEnv>();
                if (env != null)
                {
                    // TODO (steveb): this should be stored in the runtime instead!
                    DekiScriptBool setting = env.Vars.GetAt(new[] { DekiScriptEnv.SETTINGS, "nofollow" }) as DekiScriptBool;
                    if (setting != null)
                    {
                        nofollow = setting.AsBool() ?? true;
                    }
                }
            }

            XDoc result = DekiScriptLiteral.FromNativeValue(text ?? uri).AsEmbeddableXml(true);
            XDoc body   = result["body[not(@target)]"];

            result.Start("body").Start("a");
            if (nofollow)
            {
                result.Attr("rel", "custom nofollow");
            }
            else
            {
                result.Attr("rel", "custom");
            }
            result.Attr("href", WebCheckUri(uri)).Attr("title", title).Attr("target", target).AddNodes(body).End().End();
            body.Remove();
            return(result);
        }
コード例 #13
0
        public static int ListCount(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("condition to execute for each item (use '$' to refer to the item)")] string condition,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.count(condition)"), condition);
            int count = 0;

            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));
                DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                if (!test.IsNilFalseZero)
                {
                    ++count;
                }
            }
            return(count);
        }
コード例 #14
0
        private static bool TryParseDekiScriptExpression(string ctor, DekiScriptEnv env, DekiScriptRuntime runtime, ref int i, out string value)
        {
            string source = ParseExpression(ctor, null, ParseMode.EXPRESSION, false, env, runtime, null, ref i);

            if ((i >= ctor.Length) || (ctor[i] != '}'))
            {
                value = null;
                return(false);
            }

            // try to parse and execute the dekiscript fragment
            try {
                source = source.Substring(1, source.Length - 2);
                DekiScriptExpression dekiscript = DekiScriptParser.Parse(new Location("jem"), source);
                DekiScriptLiteral    result     = runtime.Evaluate(dekiscript, DekiScriptEvalMode.EvaluateSafeMode, env);
                value = DekiScriptLibrary.JsonEmit(result.NativeValue);
            } catch (Exception e) {
                // execution failed; convert exception into a javascript comment
                value = "alert(\"ERROR in DekiScript expression:\\n---------------------------\\n\\n\" + " + e.GetCoroutineStackTrace().QuoteString() + ")";
            }
            return(true);
        }
コード例 #15
0
        protected override Yield Stop(Result result)
        {
            _publicDigitalSignature = null;
            _manifestPath           = null;
            _resourcesPath          = null;
            _manifestUri            = null;
            _resourcesUri           = null;
            _manifest    = null;
            _debug       = false;
            _runtime     = null;
            _commonEnv   = null;
            _copyright   = null;
            _description = null;
            _functions   = null;
            _help        = null;
            _label       = null;
            _logo        = null;
            _namespace   = null;
            _title       = null;
            yield return(Coroutine.Invoke(base.Stop, new Result()));

            result.Return();
        }
コード例 #16
0
        //--- Class Methods ---
        public static string Parse(string code, string id, DekiScriptEnv env, DekiScriptRuntime runtime)
        {
            StringBuilder result = new StringBuilder();

            // check if code is attached to an id'ed element
            if (!string.IsNullOrEmpty(id))
            {
                result.AppendLine("$(\"#" + id + "\").each(function() {");
                result.AppendLine("var $this = $(this);");
            }

            // convert JEM code into regular javascript
            int i = 0;

            result.Append(ParseExpression(code, id, ParseMode.ALL, false, env, runtime, new Dictionary <string, string>(), ref i));

            // check if code is attached to an id'ed element
            if (!string.IsNullOrEmpty(id))
            {
                result.AppendLine("});");
            }
            return(result.ToString());
        }
コード例 #17
0
        //--- Class Constructor ---
        static DekiScriptRuntime()
        {
            // register built-in functions
            _commonFunctions = new Dictionary <XUri, DekiScriptInvocationTargetDescriptor>();
            foreach (MethodInfo method in typeof(DekiScriptLibrary).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
            {
                // check if it has the DekiScriptFunction attribute
                DekiScriptFunctionAttribute functionAttribute = (DekiScriptFunctionAttribute)Attribute.GetCustomAttribute(method, typeof(DekiScriptFunctionAttribute));
                if (functionAttribute != null)
                {
                    var parameters = from param in method.GetParameters()
                                     let attr = (DekiScriptParamAttribute[])param.GetCustomAttributes(typeof(DekiScriptParamAttribute), false)
                                                select((attr != null) && (attr.Length > 0)) ? new DekiScriptNativeInvocationTarget.Parameter(attr[0].Hint, attr[0].Optional) : null;
                    var target   = new DekiScriptNativeInvocationTarget(null, method, parameters.ToArray());
                    var function = new DekiScriptInvocationTargetDescriptor(target.Access, functionAttribute.IsProperty, functionAttribute.IsIdempotent, functionAttribute.Name ?? method.Name, target.Parameters, target.ReturnType, functionAttribute.Description, functionAttribute.Transform, target);
                    _commonFunctions[new XUri("native:///").At(function.SystemName)] = function;
                }
            }

            // build common env
            DekiScriptMap common = new DekiScriptMap();

            // add global constants
            common.AddNativeValueAt("num.e", Math.E);
            common.AddNativeValueAt("num.pi", Math.PI);
            common.AddNativeValueAt("num.epsilon", double.Epsilon);
            common.AddNativeValueAt("num.positiveinfinity", double.PositiveInfinity);
            common.AddNativeValueAt("num.negativeinfinity", double.NegativeInfinity);
            common.AddNativeValueAt("num.nan", double.NaN);

            // add global functions & properties
            foreach (var function in _commonFunctions)
            {
                common.AddNativeValueAt(function.Value.Name, function.Key);
            }
            _commonEnv = new DekiScriptEnv(common);
        }
コード例 #18
0
 //--- Constructors ---
 public DekiScriptGeneratorEvaluationState(DekiScriptEval callback, DekiScriptEnv env)
 {
     this.Callback = callback;
     this.Env      = env;
 }
コード例 #19
0
        private static string ParseExpression(string code, string id, ParseMode mode, bool whenCondition, DekiScriptEnv env, DekiScriptRuntime runtime, Dictionary <string, string> channels, ref int i)
        {
            StringBuilder result  = new StringBuilder();
            int           nesting = 0;

            for (; i < code.Length; ++i)
            {
                int start;
                switch (code[i])
                {
                case '"':
                case '\'':

                    // process strings
                    start = i;
                    ScanString(code, code[i], ref i);
                    result.Append(code, start, i - start);
                    --i;
                    break;

                case '/':

                    // check if / denotes the beginning of a comment, if so process it
                    start = i;
                    if (TryScanComment(code, ref i))
                    {
                        // NOTE: remove comments in when-condition

                        if (!whenCondition)
                        {
                            result.Append(code, start, i - start);
                            result.Append("\n");
                        }
                        --i;
                    }
                    else
                    {
                        result.Append(code[i]);
                    }
                    break;

                case '\\':

                    // backslash (\) always appends the next character
                    result.Append(code[i++]);
                    if (i < code.Length)
                    {
                        result.Append(code[i]);
                    }
                    break;

                case '(':

                    // increase nesting level
                    result.Append(code[i]);
                    ++nesting;
                    break;

                case '{':

                    // check if this is the beginning of a dekiscript block {{ }}
                    if (((i + 1) < code.Length) && (code[i + 1] == '{'))
                    {
                        ++i;
                        string value;
                        start = i;
                        if (TryParseDekiScriptExpression(code, env, runtime, ref i, out value))
                        {
                            result.Append(value);
                        }
                        else
                        {
                            ++nesting;
                            result.Append('{');
                            result.Append(code, start, i - start);
                            --i;
                        }
                    }
                    else
                    {
                        ++nesting;
                        result.Append(code[i]);
                    }
                    break;

                case ')':
                case '}':

                    // decrease nesting level and check if this is the end of the sougth expression
                    result.Append(code[i]);
                    --nesting;

                    // NOTE: only exit if
                    // 1) we don't have to read all of the code
                    // 2) there are no open parentheses or cruly braces
                    // 3) we don't on a complete statement or the current characteris a closing curly brace

                    if ((mode != ParseMode.ALL) && (nesting <= 0) && ((mode != ParseMode.STATEMENT) || (code[i] == '}')))
                    {
                        // found the end of the expression
                        ++i;
                        return(result.ToString());
                    }
                    break;

                case ';':

                    // check if the statement is the end of the sougth expression
                    result.Append(code[i]);

                    // NOTE: only exit if
                    // 1) we don't have to read all of the code
                    // 2) there are no open parentheses or cruly braces
                    // 3) we stop on a complete statement

                    if ((nesting <= 0) && (mode == ParseMode.STATEMENT))
                    {
                        // found the end of the expression
                        ++i;
                        return(result.ToString());
                    }
                    break;

                case '@':

                    // channel name
                    if (channels != null)
                    {
                        ++i;
                        start = i;
                        string channel;
                        string name;
                        if ((i < code.Length) && ((code[i] == '"') || (code[i] == '\'')))
                        {
                            // process: @"channel_name" or @'channel_name'
                            ScanString(code, code[i], ref i);
                            channel = code.Substring(start, i - start);
                            name    = channel.Substring(1, channel.Length - 2).UnescapeString();
                        }
                        else
                        {
                            // process: @channel_magic_id
                            ScanId(code, ref i);
                            name = code.Substring(start, i - start);
                            if (!channels.TryGetValue(name, out channel))
                            {
                                channel = env.GetMagicId(name).ToString();
                            }
                        }
                        start = i;
                        ScanWhitespace(code, ref i);
                        if ((i < code.Length) && (code[i] == '('))
                        {
                            // process: @channel ( ... )
                            string message = ParseExpression(code, id, ParseMode.EXPRESSION, false, env, runtime, channels, ref i);
                            message = message.Substring(1, message.Length - 2).Trim();
                            if (message.Length == 0)
                            {
                                result.AppendFormat("Deki.publish({0})", channel);
                            }
                            else
                            {
                                result.AppendFormat("Deki.publish({0}, {1})", channel, message);
                            }
                        }
                        else
                        {
                            // channel is used for reading; add it to the channel set to read on activation
                            channels[name] = channel;

                            // convert channel name and add whitespace
                            result.AppendFormat("$channels[{0}]", name.QuoteString());
                            result.Append(code, start, i - start);
                        }
                        --i;
                    }
                    else
                    {
                        result.Append(code[i]);
                    }
                    break;

                case '#':

                    // NOTE: don't process #id in the when-condition

                    // element name
                    if (!whenCondition && (channels != null))
                    {
                        ++i;
                        start = i;

                        // process: #id
                        ScanId(code, ref i);
                        string name = code.Substring(start, i - start);
                        result.Append("$(\"#" + name + "\")");
                        --i;
                    }
                    else
                    {
                        result.Append(code[i]);
                    }
                    break;

                default:

                    // NOTE: don't process when() in the when-condition

                    // check if this is the beginning of an identifier
                    if (!whenCondition && IsAlpha(code[i]))
                    {
                        start = i;
                        ScanId(code, ref i);
                        int j = i;
                        ScanWhitespace(code, ref j);

                        // check if scanned identifier is the keyword 'when'
                        if (((i - start) == WHEN.Length) && (string.Compare(code, start, WHEN, 0, WHEN.Length, StringComparison.Ordinal) == 0) && (j < code.Length) && (code[j] == '('))
                        {
                            i = j;
                            Dictionary <string, string> subChannels = new Dictionary <string, string>();

                            // parse the condition of the 'when()' statement
                            string condition = ParseExpression(code, id, ParseMode.EXPRESSION, true, env, runtime, subChannels, ref i);

                            // parse the body of the 'when()' expression
                            string body = ParseExpression(code, id, ParseMode.STATEMENT, false, env, runtime, subChannels, ref i);
                            BuildWhenStatement(condition.Trim(), id, body.Trim(), result, env, subChannels);
                        }
                        else
                        {
                            result.Append(code, start, i - start);
                        }
                        --i;
                    }
                    else
                    {
                        result.Append(code[i]);
                    }
                    break;
                }
            }
            return(result.ToString());
        }
コード例 #20
0
 //--- Constructor ---
 public DekiScriptDomEvaluationState(DekiScriptEvalContext context, XmlNode parent, DekiScriptEnv env)
 {
     this.Context = context;
     this.Env     = env;
     this.Parent  = parent;
 }
コード例 #21
0
 private void EvaluateNamespaceDefinitionAttribute(DekiScriptDomElement.Attribute expr, DekiScriptEvalContext context, DekiScriptEnv env)
 {
     if (expr.IsNamespaceDefinition)
     {
         DekiScriptLiteral name  = expr.Name.VisitWith(DekiScriptExpressionEvaluation.Instance, env);
         DekiScriptLiteral value = expr.Value.VisitWith(DekiScriptExpressionEvaluation.Instance, env);
         if (!value.IsNil)
         {
             if (string.IsNullOrEmpty(expr.Prefix))
             {
                 context.Namespaces.AddNamespace(string.Empty, value.AsString());
             }
             else
             {
                 context.Namespaces.AddNamespace(XmlConvert.EncodeLocalName(name.AsString() ?? string.Empty), value.AsString());
             }
         }
     }
 }
コード例 #22
0
 private void EvaluateAttribute(DekiScriptDomElement.Attribute expr, DekiScriptEvalContext context, XmlElement element, DekiScriptEnv env)
 {
     if (!expr.IsNamespaceDefinition)
     {
         try {
             string name = expr.Name.VisitWith(DekiScriptExpressionEvaluation.Instance, env).AsString();
             if (name != null)
             {
                 name = XmlConvert.EncodeLocalName(name);
                 string value = expr.Value.VisitWith(DekiScriptExpressionEvaluation.Instance, env).AsString();
                 if (value != null)
                 {
                     element.SetAttribute(name, context.Namespaces.LookupNamespace(expr.Prefix), value);
                 }
             }
         } catch (Exception e) {
             context.InsertExceptionMessageBeforeNode(env, element, null, expr.Location, e);
         }
     }
 }
コード例 #23
0
        public XDoc Evaluate(DekiScriptDom expr, DekiScriptEvalMode mode, bool fallthrough, DekiScriptEnv env)
        {
            DekiScriptEvalContext context = new DekiScriptEvalContext(mode, fallthrough);

            try {
                expr.VisitWith(this, new DekiScriptDomEvaluationState(context, context.Document, env));
            } catch (DekiScriptDocumentTooLargeException) {
                // this exception is thrown to unwind the DOM stack; we can safely ignore it
            }
            context.MergeContextIntoDocument(context.Document);
            return(new XDoc(context.Document));
        }
コード例 #24
0
        public virtual DekiScriptLiteral Evaluate(DekiScriptExpression expr, DekiScriptEvalMode mode, DekiScriptEnv env)
        {
            DekiScriptExpressionEvaluationState state = new DekiScriptExpressionEvaluationState(mode, env, this, EvaluationTimeout, GetMaxOutputSize(mode));

            try {
                return(state.Pop(expr.VisitWith(DekiScriptExpressionEvaluation.Instance, state)));
            } catch (DekiScriptReturnException e) {
                state.Push(e.Value);
                return(state.PopAll());
            }
        }
コード例 #25
0
 public DekiScriptExpressionInvocationTarget(DreamAccess access, DekiScriptParameter[] parameters, DekiScriptExpression expr, DekiScriptEnv env)
 {
     if (parameters == null)
     {
         throw new ArgumentNullException("parameters");
     }
     if (expr == null)
     {
         throw new ArgumentNullException("expr");
     }
     this.Access     = access;
     this.Parameters = parameters;
     this.Expression = expr;
     _env            = env;
 }
コード例 #26
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);
        }
コード例 #27
0
        public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            var  name = context.GetParam("function");
            XUri uri  = Self.At(name);

            // check if deki server is permitted to invoke this function
            if (this is IDreamServiceLicense)
            {
                string deki;
                if (context.ServiceLicense.TryGetValue("deki", out deki) && !deki.EqualsInvariant(request.Headers[DEKI_HEADER] ?? string.Empty))
                {
                    throw new DreamAbortException(DreamMessage.Forbidden("deki server is not licensed for this service"));
                }
            }

            // check if any functions were found
            DekiScriptInvocationTargetDescriptor descriptor;

            if (!_functions.TryGetValue(uri, out descriptor))
            {
                response.Return(DreamMessage.NotFound(string.Format("function {0} not found", context.GetParam("function"))));
                yield break;
            }

            // check if invoker has access to function
            if ((descriptor.Access != DreamAccess.Public) && (descriptor.Access > DetermineAccess(context, request)))
            {
                response.Return(DreamMessage.Forbidden("insufficient access privileges"));
                yield break;
            }

            // check if request has a requested culture
            context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture);

            // check for implicit arguments
            context.SetState(GetImplicitEnvironment(request, _publicDigitalSignature));

            // create custom environment
            DekiScriptEnv env = CreateEnvironment();

            // create custom target for custom environment
            var target = descriptor.Target as DekiScriptExpressionInvocationTarget;

            if (target != null)
            {
                // TODO (steveb): re-initializing the invocation target works for the first call, but not if the function calls another function in the same extension!

                target = new DekiScriptExpressionInvocationTarget(target.Access, target.Parameters, target.Expression, env);
            }

            // invoke target
            DekiScriptLiteral eval;

            if (target != null)
            {
                eval = target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument()));
            }
            else
            {
                eval = descriptor.Target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument()));
            }

            // invoke function
            response.Return(DreamMessage.Ok(new DekiScriptList().Add(eval).ToXml()));
            yield break;
        }
コード例 #28
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);
        }
コード例 #29
0
        private static void BuildWhenStatement(string expr, string id, string body, StringBuilder head, DekiScriptEnv env, Dictionary <string, string> channels)
        {
            // remove the optional outer () and {}; the expression is already scoped, so we don't need them anymore
            if (expr.StartsWith("(") && expr.EndsWith(")"))
            {
                expr = expr.Substring(1, expr.Length - 2).Trim();
            }

            // gather all events from 'when()' condition expression into a map { sink1: [ event1, event2, ... ], sink2: [ event1, event2, ... ], ... }
            Dictionary <string, Dictionary <string, string> > sinks = new Dictionary <string, Dictionary <string, string> >();
            string condition = EVENT_PATTERN.Replace(expr, delegate(Match match) {
                // check if a tail element was matched, which disqualifies this match
                Group tail = match.Groups["tail"];
                if (!tail.Success)
                {
                    // check for event match
                    Group group = match.Groups["event"];
                    if (group.Success)
                    {
                        string sink = match.Groups["sink"].Value;
                        Dictionary <string, string> events;
                        if (!sinks.TryGetValue(sink, out events))
                        {
                            events      = new Dictionary <string, string>();
                            sinks[sink] = events;
                        }
                        events[group.Value] = group.Value;

                        // TODO (steveb): we should also check that the event source is what we expect it to be

                        return(string.Format("($event.type == {0})", StringUtil.QuoteString(group.Value)));
                    }
                }
                else
                {
                    string sink = match.Groups["sink"].Value;
                    if (sink.StartsWith("#"))
                    {
                        return(string.Format("$(\"{0}\").{1}{2}", sink, match.Groups["event"].Value, tail.Value));
                    }
                }
                return(match.Value);
            });

            // create stub function; $event is only set when invoked for events, not for messages
            string function = "_" + StringUtil.CreateAlphaNumericKey(8);

            if (sinks.Count > 0)
            {
                head.Append("var " + function + " = function($event) { $event = $event||{}; ");
            }
            else
            {
                head.Append("var " + function + " = function() { ");
            }

            // read channel state for all channels that a read from; including 'when()' condition and body
            if (channels.Count > 0)
            {
                bool first = true;
                head.Append("var $channels = {");
                foreach (KeyValuePair <string, string> channel in channels)
                {
                    if (!first)
                    {
                        head.Append(", ");
                    }
                    first = false;
                    head.AppendFormat("{0}: Deki.query({1})||{{}}", channel.Key.QuoteString(), channel.Value);
                }
                head.Append(" }; ");
            }

            // add optional condition
            if (!string.IsNullOrEmpty(condition))
            {
                head.Append("if(" + condition + ") ");
            }

            // append body of 'when()' statement and close the function
            if (string.IsNullOrEmpty(body))
            {
                head.Append(";");
            }
            else
            {
                head.Append(body);
            }
            head.AppendLine(" };");

            // register function for event handlers
            if (sinks.Count > 0)
            {
                foreach (KeyValuePair <string, Dictionary <string, string> > events in sinks)
                {
                    string bind = string.Join(" ", new List <string>(events.Value.Values).ToArray()).QuoteString();
                    if (events.Key.EqualsInvariant("$this"))
                    {
                        head.AppendLine("$this.bind(" + bind + ", " + function + ");");
                    }
                    else
                    {
                        head.AppendLine("$(" + events.Key.QuoteString() + ").bind(" + bind + ", " + function + ");");
                    }
                }
            }

            // register function for message handlers
            foreach (KeyValuePair <string, string> channel in channels)
            {
                head.AppendLine("Deki.subscribe(" + channel.Value + ", " + (string.IsNullOrEmpty(id) ? "null" : "this") + ", " + function + ");");
            }
        }
コード例 #30
0
 //--- Constructors ---
 public DekiScriptOptimizerState(DekiScriptEvalMode mode, DekiScriptEnv env)
 {
     this.Mode = mode;
     this.Env  = env;
 }
コード例 #31
0
 public virtual DekiScriptLiteral EvaluateProperty(Location location, DekiScriptLiteral value, DekiScriptEnv env)
 {
     if (IsProperty(value))
     {
         DekiScriptUri uri = (DekiScriptUri)value;
         try {
             value = Invoke(location, uri.Value, uri.Arguments.IsNil ? _emptyList : uri.Arguments, env);
         } catch (DekiScriptFatalException) {
             throw;
         } catch (Exception e) {
             var descriptor = ResolveRegisteredFunctionUri(uri.Value);
             throw new DekiScriptInvokeException(location, uri.Value, (descriptor != null) ? descriptor.Name : uri.Value.ToString(), e);
         }
     }
     return(value);
 }
コード例 #32
0
        public virtual DekiScriptLiteral Invoke(Location location, XUri uri, DekiScriptLiteral args, DekiScriptEnv env)
        {
            var sw = Stopwatch.StartNew();
            DekiScriptInvocationTargetDescriptor descriptor;
            var target = _functions.TryGetValue(uri, out descriptor) ? descriptor.Target : FindTarget(uri);

            try {
                // invoke function directly
                return(target.Invoke(this, args));
            } catch (Exception e) {
                throw UnwrapAsyncException(uri, e).Rethrow();
            } finally {
                sw.Stop();
                bool property = (uri.LastSegment ?? string.Empty).StartsWithInvariant("$");
                env.AddFunctionProfile(location, (descriptor != null) ? (property ? "$" : "") + descriptor.Name : uri.ToString(), sw.Elapsed);
            }
        }
コード例 #33
0
 //--- Methods ---
 public void Generate(DekiScriptGenerator expr, DekiScriptEval callback, DekiScriptEnv env)
 {
     expr.VisitWith(this, new DekiScriptGeneratorEvaluationState(callback, env));
 }