//--- 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; }
//--- 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); }
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; }
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); } }
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); }
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); } }
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); }
//--- 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); }
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); }
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); }
//--- 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); }
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); }
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); }
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); }
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(); }
//--- 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()); }
//--- 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); }
//--- Constructors --- public DekiScriptGeneratorEvaluationState(DekiScriptEval callback, DekiScriptEnv env) { this.Callback = callback; this.Env = env; }
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()); }
//--- Constructor --- public DekiScriptDomEvaluationState(DekiScriptEvalContext context, XmlNode parent, DekiScriptEnv env) { this.Context = context; this.Env = env; this.Parent = parent; }
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()); } } } }
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); } } }
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)); }
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()); } }
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; }
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); }
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; }
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); }
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 + ");"); } }
//--- Constructors --- public DekiScriptOptimizerState(DekiScriptEvalMode mode, DekiScriptEnv env) { this.Mode = mode; this.Env = env; }
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); }
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); } }
//--- Methods --- public void Generate(DekiScriptGenerator expr, DekiScriptEval callback, DekiScriptEnv env) { expr.VisitWith(this, new DekiScriptGeneratorEvaluationState(callback, env)); }