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())))); }
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)); }
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 ); }
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); }
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); }
//--- 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); } }
//--- 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 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); }
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); }
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); }
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); }
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); }
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); }
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 }); }
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); }
//--- 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); }
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(); }
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); }