public DekiScriptExpression Visit(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression prefix = expr.Prefix.VisitWith(this, state);
            DekiScriptExpression index  = expr.Index.VisitWith(this, state);
            DekiScriptAccess     access = (DekiScriptAccess)DekiScriptExpression.Access(expr.Location, prefix, index);

            if ((prefix is DekiScriptLiteral) && (index is DekiScriptLiteral))
            {
                DekiScriptLiteral result = DekiScriptExpressionEvaluation.Instance.Evaluate(access, state, false);

                // check if result is a property
                if (DekiScriptRuntime.IsProperty(result))
                {
                    // retrieve property information
                    var descriptor = state.Runtime.ResolveRegisteredFunctionUri(((DekiScriptUri)result).Value);
                    if ((descriptor != null) && descriptor.IsIdempotent)
                    {
                        // evaluate property, since it never changes
                        return(state.Runtime.EvaluateProperty(expr.Location, result, state.Env));
                    }
                    return(DekiScriptExpression.Call(expr.Location, result, new DekiScriptList()));
                }
                return(result);
            }
            return(access);
        }
Пример #2
0
        public static Hashtable ListGroupBy(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to apply for grouping (use '$' to refer to the current item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("list.groupby(expression)"), expression);

            // loop over all items in list
            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));

                // evalute grouping expression
                string key = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).AsString();
                if (key != null)
                {
                    // check if an accumulation list already exists; otherwise, create one
                    ArrayList accumulator = (ArrayList)result[key];
                    if (accumulator == null)
                    {
                        accumulator = new ArrayList();
                        result[key] = accumulator;
                    }
                    accumulator.Add(entry);
                }
            }
            return(result);
        }
        public DekiScriptExpression Visit(DekiScriptAssign expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression result = expr.Value.VisitWith(this, state);
            DekiScriptLiteral    value  = (result is DekiScriptLiteral) ? (DekiScriptLiteral)result : DekiScriptUnknown.Value;

            if (expr.Define)
            {
                state.Env.Vars.Add(expr.Variable, value);
            }
            else
            {
                state.Env.Vars[expr.Variable] = value;
            }
            if (result is DekiScriptLiteral)
            {
                // NOTE: variable was assigned a value; it will be substituted into subsequent operations

                return(DekiScriptNil.Value);
            }
            if (expr.Define)
            {
                return(DekiScriptExpression.VarStatement(expr.Location, DekiScriptExpression.Id(expr.Location, expr.Variable), result));
            }
            return(DekiScriptExpression.LetStatement(expr.Location, DekiScriptExpression.Id(expr.Location, expr.Variable), result));
        }
Пример #4
0
        private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptList args)
        {
            // convert passed in arguments
            object[] arguments = new object[Parameters.Length];
            int      i         = 0;

            try {
                for (; i < Parameters.Length; ++i)
                {
                    var value = args[i].NativeValue;

                    // check if we need to convert the value
                    if ((value != null) && (Parameters[i].NativeType != typeof(object)))
                    {
                        // check for the special case where we cast from XML to STR
                        if ((value is XDoc) && (Parameters[i].NativeType == typeof(string)))
                        {
                            XDoc xml = (XDoc)value;
                            if (xml.HasName("html"))
                            {
                                value = xml["body[not(@target)]"].Contents;
                            }
                            else
                            {
                                value = xml.ToString();
                            }
                        }
                        else
                        {
                            // rely on the default type conversion rules
                            value = SysUtil.ChangeType(value, Parameters[i].NativeType);
                        }
                    }
                    arguments[i] = value;
                }
            } catch {
                throw new ArgumentException(string.Format("could not convert parameter '{0}' (index {1}) from {2} to {3}", Parameters[i].Name, i, args[i].ScriptTypeName, DekiScriptLiteral.AsScriptTypeName(Parameters[i].ScriptType)));
            }

            // invoke method
            var result = _invoke(runtime, arguments);

            // check if result is a URI
            if (result is XUri)
            {
                // normalize URI if possible
                DreamContext context = DreamContext.CurrentOrNull;
                if (context != null)
                {
                    result = context.AsPublicUri((XUri)result);
                }
            }
            var literal = DekiScriptLiteral.FromNativeValue(result);

            try {
                return(literal.Convert(ReturnType));
            } catch (DekiScriptInvalidCastException) {
                throw new DekiScriptInvalidReturnCastException(Location.None, literal.ScriptType, ReturnType);
            }
        }
        internal void ReplaceNodeWithValue(XmlNode node, DekiScriptLiteral value)
        {
            XmlNode parent = node.ParentNode;

            InsertValueBeforeNode(parent, node, value);
            parent.RemoveChild(node);
        }
Пример #6
0
        public static Hashtable MapFilter(
            [DekiScriptParam("map value")] Hashtable map,
            [DekiScriptParam("condition to execute for each item (use '$' to refer to the key-value pair)")] string condition,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("map.select(condition)"), condition);
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);

            foreach (DictionaryEntry entry in map)
            {
                DekiScriptMap keyvalue = new DekiScriptMap();
                object        value    = Eval(entry.Value, runtime);
                keyvalue.Add("key", DekiScriptLiteral.FromNativeValue(entry.Key));
                keyvalue.Add("value", DekiScriptLiteral.FromNativeValue(value));
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                if (!test.IsNilFalseZero)
                {
                    result.Add(entry.Key, value);
                }
            }
            return(result);
        }
Пример #7
0
        public Hashtable PopularPages(
            [DekiExtParam("max results (default: 10)", true)] int?max,
            [DekiExtParam("poll interval (only for js format, default: 30)", true)] int?interval
            )
        {
            int               maxResults  = max ?? 10;
            int               resultCount = 0;
            DekiScriptMap     env         = DreamContext.Current.GetState <DekiScriptMap>();
            DekiScriptLiteral uriLiteral  = env.GetAt("site.uri");
            XUri              deki        = new XUri(uriLiteral.NativeValue.ToString()).At("@api", "deki");
            Hashtable         map         = new Hashtable(StringComparer.OrdinalIgnoreCase);

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

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

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

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

                // BUGBUGBUG (arnec): the AsLocalUri should not be required after bug #5964 is resolved
                pageMap.Add("page", DekiScriptExpression.Constant(deki.At("$page").AsLocalUri(), new[] { DekiScriptExpression.Constant(page.Item1), DekiScriptExpression.Constant(true) }));
                pageMap.Add("views", page.Item2);
                resultCount++;
                if (resultCount >= maxResults)
                {
                    break;
                }
            }
            return(map);
        }
Пример #8
0
 //--- Class Methods ---
 public static bool IsProperty(DekiScriptLiteral value)
 {
     if (value.ScriptType == DekiScriptType.URI)
     {
         return((((DekiScriptUri)value).Value.LastSegment ?? string.Empty).StartsWithInvariant("$"));
     }
     return(false);
 }
 //--- Constructors ---
 public DekiScriptReturnException(Location location, DekiScriptLiteral value) : base(location, "Unhandled 'return' statement")
 {
     if (value == null)
     {
         throw new ArgumentNullException("value");
     }
     this.Value = value;
 }
Пример #10
0
 //--- Methods ---
 public DekiScriptLiteral Convert(DekiScriptLiteral value)
 {
     try {
         return(value.Convert(ScriptType));
     } catch (DekiScriptInvalidCastException) {
         throw new DekiScriptInvalidParameterCastException(Location.None, this, value.ScriptType);
     }
 }
Пример #11
0
            //--- Methods ---
            public int Compare(object left, object right)
            {
                _values.Add("left", DekiScriptLiteral.FromNativeValue(left));
                _values.Add("right", DekiScriptLiteral.FromNativeValue(right));
                _env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, _values);
                DekiScriptLiteral test = _runtime.Evaluate(_compare, DekiScriptEvalMode.EvaluateSafeMode, _env);

                return((int)(test.AsNumber() ?? 0.0));
            }
Пример #12
0
        public static ArrayList ListOrderBy(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("key name or list of key names; sort direction is controlled by appendending \" ascending\" or \" descending\" to the key(s); when omitted, the direction is asending by default")] object keys,
            DekiScriptRuntime runtime
            )
        {
            // check for trivial sort case
            if (keys is string)
            {
                string key = ((string)keys).Trim();

                // the key cannot contain access operators
                if (key.IndexOfAny(new[] { '.', '[', ']' }) < 0)
                {
                    return(ListOrderBy_IsReversed(ref key) ? ListSort(list, key, true, null, runtime) : ListSort(list, key, false, null, runtime));
                }

                // let's change 'keys' into an array list for processing convenience
                ArrayList temp = new ArrayList {
                    keys
                };
                keys = temp;
            }

            // check that 'keys' has a valid type
            if (!(keys is ArrayList))
            {
                throw new DekiScriptBadTypeException(Location.None, DekiScriptLiteral.AsScriptType(keys.GetType()), new[] { DekiScriptType.STR, DekiScriptType.LIST });
            }

            // build comparison expression
            StringBuilder compare = new StringBuilder();

            foreach (string key in (ArrayList)keys)
            {
                if (compare.Length > 0)
                {
                    compare.Append(" || ");
                }

                // process sort field
                string field = key;
                if (ListOrderBy_IsReversed(ref field))
                {
                    compare.AppendFormat("(if($left.{0} < $right.{0}) 1; else if($left.{0} > $right.{0}) -1; else 0;)", field);
                }
                else
                {
                    compare.AppendFormat("(if($left.{0} < $right.{0}) -1; else if($left.{0} > $right.{0}) 1; else 0;)", field);
                }
            }

            // sort list
            list.Sort(new DekiScriptComparer(runtime, DekiScriptParser.Parse(new Location("list.orderby(compare)"), compare.ToString())));
            return(list);
        }
        public Empty Visit(DekiScriptGeneratorIf expr, DekiScriptGeneratorEvaluationState state)
        {
            DekiScriptLiteral condition = expr.Condition.VisitWith(DekiScriptExpressionEvaluation.Instance, state.Env);

            if (!condition.IsNilFalseZero)
            {
                Generate(expr, state);
            }
            return(Empty.Value);
        }
        public Empty Visit(DekiScriptGeneratorForeachValue expr, DekiScriptGeneratorEvaluationState state)
        {
            DekiScriptLiteral collection = expr.Collection.VisitWith(DekiScriptExpressionEvaluation.Instance, state.Env);

            // 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.Line, expr.Column, collection.ScriptType, new DekiScriptType[] { DekiScriptType.LIST, DekiScriptType.MAP, DekiScriptType.XML, DekiScriptType.NIL });
            }

            // loop over collection
            int index = 0;

            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.Env.Locals.Add(expr.Vars[j], list[i + j]);
                }
                state.Env.Locals.Add(DekiScriptRuntime.INDEX_ID, DekiScriptNumber.New(index));

                // iterate over block statements
                Generate(expr, state);
                index += expr.Vars.Length;
            }
            return(Empty.Value);
        }
Пример #15
0
 private static object Eval(object value, DekiScriptRuntime runtime)
 {
     if (value is XUri)
     {
         DekiScriptLiteral uri = DekiScriptExpression.Constant((XUri)value);
         if (DekiScriptRuntime.IsProperty(uri))
         {
             value = runtime.EvaluateProperty(Location.None, uri, runtime.CreateEnv()).NativeValue;
         }
     }
     return(value);
 }
Пример #16
0
 //--- Extension Methods ---
 public static StringBuilder AppendLiteral(this StringBuilder builder, DekiScriptLiteral literal)
 {
     if (literal is DekiScriptString)
     {
         builder.Append(((DekiScriptString)literal).Value);
     }
     else
     {
         builder.Append(literal.ToString());
     }
     return(builder);
 }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptSwitch expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptLiteral value = state.Pop(expr.Value.VisitWith(this, state));

            DekiScriptSwitch.CaseBlock caseBlock = null;

            // have to use for instead of foreach, since a fallthrough default case needs to be able to look ahead
            for (int i = 0; i < expr.Cases.Length; i++)
            {
                DekiScriptSwitch.CaseBlock current = expr.Cases[i];

                // check for default case
                foreach (DekiScriptExpression condition in current.Conditions)
                {
                    if (condition == null)
                    {
                        // check if this is the first default we've found
                        if (caseBlock == null)
                        {
                            caseBlock = current;
                        }

                        // continue in case loop, since default only gets executed if there is no match
                        continue;
                    }

                    // evaluate test
                    DekiScriptExpression test      = DekiScriptExpression.BinaryOp(current.Location, DekiScriptBinary.Op.Equal, value, condition);
                    DekiScriptLiteral    caseMatch = state.Pop(test.VisitWith(this, state));

                    // evaluate body on success
                    if (!caseMatch.IsNilFalseZero)
                    {
                        // found a matching cast statement
                        caseBlock = current;
                        break;
                    }
                }
            }

            // haven't found a match yet, so if we have a default, return it
            if (caseBlock != null)
            {
                int marker = state.Buffer.Marker;
                try {
                    return(caseBlock.Body.VisitWith(this, state));
                } catch (DekiScriptBreakException) {
                    // nothing to do
                }
                return(state.Buffer.Since(marker));
            }
            return(DekiScriptOutputBuffer.Range.Empty);
        }
        //--- Methods ---
        public Empty Visit(DekiScriptGeneratorIf expr, DekiScriptGeneratorEvaluationState state)
        {
            // evaluate the generator condition
            DekiScriptLiteral condition = Eval(expr.Condition, state);

            // check if condition is met
            if (!condition.IsNilFalseZero)
            {
                EvalNext(expr, state);
            }
            return(Empty.Value);
        }
Пример #19
0
        public object Fetch(
            [DekiExtParam("document id")] string id
            )
        {
            // fetch response from cache
            CacheEntry result;

            lock (_cacheLookup) {
                _cacheLookup.TryGetValue(id, out result);
            }

            // check if we have a cached entry
            XDoc document = null;

            if (result != null)
            {
                _log.DebugFormat("cache hit for '{0}'", result.Id);
                result.ResetMemoryExpiration();
                if (result.Cache != null)
                {
                    _log.DebugFormat("cache data in memory '{0}'", result.Id);
                    document = XDocFactory.From(result.Cache, MimeType.XML);
                }
                else
                {
                    // we have the result on disk, so let's fetch it
                    DreamMessage msg = Storage.At(CACHE_DATA, result.Guid + ".bin").GetAsync().Wait();
                    if (msg.IsSuccessful)
                    {
                        _log.DebugFormat("cache data pulled from disk");
                        result.Cache = Encoding.UTF8.GetString(msg.AsBytes());
                        document     = XDocFactory.From(result.Cache, MimeType.XML);
                    }
                    else
                    {
                        _log.DebugFormat("unable to fetch cache data from disk: {0}", msg.Status);
                    }
                }
            }

            // check if we have a document to convert
            if (document != null)
            {
                try {
                    DekiScriptList list = (DekiScriptList)DekiScriptLiteral.FromXml(document);
                    return(list[0]);
                } catch {
                    // the cached entry is corrupted, remove it
                    Clear(id);
                }
            }
            return(null);
        }
Пример #20
0
 //--- Contructors ---
 public DekiScriptParameter(string name, DekiScriptType type, bool optional, string hint)
 {
     if (string.IsNullOrEmpty(name))
     {
         throw new NullReferenceException("name");
     }
     this.Name       = name;
     this.ScriptType = type;
     this.Optional   = optional;
     this.Hint       = hint;
     this.NativeType = typeof(object);
     this.Default    = DekiScriptNil.Value;
 }
        public Empty Visit(DekiScriptDomExpr expr, DekiScriptDomEvaluationState state)
        {
            var context = state.Context;
            var env     = state.Env;
            var parent  = state.Parent;

            try {
                DekiScriptLiteral value = expr.Value.VisitWith(DekiScriptExpressionEvaluation.Instance, env.NewLocalScope());
                context.InsertValueBeforeNode(parent, null, value);
            } catch (Exception e) {
                EmbedExceptionMessage(expr, env, context, e, parent);
            }
            return(Empty.Value);
        }
Пример #22
0
        public Range Push(DekiScriptLiteral literal)
        {
            if (literal.IsNil)
            {
                return(Range.Empty);
            }

            // append element
            int start = _buffer.Count;

            CheckBufferLimits();
            _buffer.Add(literal);
            return(new Range(start, _buffer.Count));
        }
Пример #23
0
 public void AppendXml(XDoc doc)
 {
     doc.Start("param").Attr("name", Name).Attr("type", DekiScriptLiteral.AsScriptTypeName(ScriptType));
     if (Default.IsNil)
     {
         doc.Attr("optional", Optional ? "true" : null);
     }
     else
     {
         doc.Attr("default", Default.ToString());
     }
     doc.Value(Hint);
     doc.End();
 }
        public Empty Visit(DekiScriptDomJson expr, DekiScriptDomEvaluationState state)
        {
            var context = state.Context;
            var env     = state.Env;
            var parent  = state.Parent;

            try {
                DekiScriptLiteral value  = expr.Value.VisitWith(DekiScriptExpressionEvaluation.Instance, env);
                XmlText           result = context.CreateTextNode(DekiScriptLibrary.JsonEmit(value.NativeValue));
                parent.AppendChild(result);
            } catch (Exception e) {
                EmbedExceptionMessage(expr, env, context, e, parent);
            }
            return(Empty.Value);
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptTernary expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptLiteral test = state.Pop(expr.Test.VisitWith(this, state));
            DekiScriptLiteral result;

            // check which branch should be executed
            if (!test.IsNilFalseZero)
            {
                return(expr.Left.VisitWith(this, state));
            }
            else
            {
                return(expr.Right.VisitWith(this, state));
            }
        }
 //--- Methods ---
 public virtual DekiScriptLiteral Invoke(DekiScriptRuntime runtime, DekiScriptLiteral args)
 {
     if (args is DekiScriptList)
     {
         return(InvokeList(runtime, (DekiScriptList)args));
     }
     else if (args is DekiScriptMap)
     {
         return(InvokeMap(runtime, (DekiScriptMap)args));
     }
     else
     {
         throw new DekiScriptBadTypeException(Location.None, args.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST });
     }
 }
        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);
        }
Пример #28
0
        public T EnvAt <T>(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            DekiScriptMap env = DreamContext.Current.GetState <DekiScriptMap>();

            if (env == null)
            {
                return(default(T));
            }
            DekiScriptLiteral value = env.GetAt(path);

            return(SysUtil.ChangeType <T>(value.NativeValue));
        }
Пример #29
0
        public Yield Execute(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            string expression           = context.GetParam("expression");
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("POST:execute"), expression);
            DekiScriptLiteral    result = _runtime.Evaluate(expr, DekiScriptEvalMode.Evaluate, _env);

            if (result.ScriptType == DekiScriptType.XML)
            {
                response.Return(DreamMessage.Ok(MimeType.XML, (XDoc)result.NativeValue));
            }
            else
            {
                response.Return(DreamMessage.Ok(MimeType.TEXT, result.ToString()));
            }
            yield break;
        }
Пример #30
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);
 }
 public DekiScriptFlowControlException(DekiScriptFlowControl flowControl, DekiScriptLiteral accumulatedState) : base(0, 0, string.Format("Unhandled flow control statement '{0}'", flowControl.ToString().ToLower())) {
     FlowControl = flowControl;
     AccumulatedState = accumulatedState;
 }
        //--- Methods ---
        public DekiScriptEvaluationAccumulator Add(DekiScriptLiteral literal, bool safe) {
            if(literal == null) {
                throw new ArgumentNullException("literal");
            }
            if(literal is DekiScriptNil) {

                // nothing to do
                return this;
            }

            // check if any value was accumulated
            if(_value == null) {
                if(literal is DekiScriptXml) {
                    _value = ((DekiScriptXml)literal).Value.Clone();
                } else {
                    _value = literal;
                }
                return this;
            }

            // check if we can append a string value
            if(literal is DekiScriptString) {
                AddString(((DekiScriptString)literal).Value, safe);
                return this;
            }
            if(!(literal is DekiScriptUri) && !(literal is DekiScriptXml)) {
                AddString(literal.ToString(), safe);
                return this;
            }

            // check if we need to append an XML document
            XDoc doc = literal.AsEmbeddableXml(safe);
            if(doc.IsEmpty) {
                return this;
            }
            XDoc accumulator = ConvertToXml(safe);

            // build lookup for existing bodies in accumulator
            Dictionary<string, XDoc> bodies = new Dictionary<string, XDoc>();
            foreach(XmlNode node in accumulator.AsXmlNode.ChildNodes) {
                if(node.NodeType == XmlNodeType.Element) {
                    XmlElement element = (XmlElement)node;
                    if(StringUtil.EqualsInvariant(node.LocalName, "body")) {
                        string target = element.GetAttribute("target");
                        bodies[target] = accumulator[node];
                    }
                }
            }

            // loop over all root children in new document
            foreach(XmlNode node in doc.AsXmlNode.ChildNodes) {
                if(node.NodeType == XmlNodeType.Element) {
                    XmlElement element = (XmlElement)node;
                    if(StringUtil.EqualsInvariant(node.LocalName, "body")) {

                        string target = element.GetAttribute("target");
                        XDoc body;
                        if(bodies.TryGetValue(target, out body)) {

                            // body already exists, check how it should be handled
                            string conflict = element.GetAttribute("conflict");
                            if(string.IsNullOrEmpty(conflict)) {

                                // default conflict resolution depends on target: no target (i.e. main body) is append, otherwise it is ignore
                                conflict = string.IsNullOrEmpty(target) ? "append" : "ignore";
                            }
                            switch(conflict) {
                            case "replace":

                                // replace existing body with new one
                                body.RemoveNodes();
                                body.AddNodes(doc[node]);
                                break;
                            case "append":

                                // append nodes to existing body
                                body.AddNodes(doc[node]);
                                break;
                            case "ignore":

                                // ignore new body
                                break;
                            }
                        } else {

                            // target body does not exist, append it
                            accumulator.Start("body");
                            if(!string.IsNullOrEmpty(target)) {
                                accumulator.Attr("target", target);
                            }
                            accumulator.AddNodes(doc[node]);
                            accumulator.End();
                        }
                    } else if(StringUtil.EqualsInvariant(node.LocalName, "head")) {
                        XDoc head = accumulator["head"];
                        foreach(XmlNode child in node.ChildNodes) {
                            head.Add(doc[child]);
                        }
                    } else if(StringUtil.EqualsInvariant(node.LocalName, "tail")) {
                        XDoc head = accumulator["tail"];
                        foreach(XmlNode child in node.ChildNodes) {
                            head.Add(doc[child]);
                        }
                    }
                }
            }
            return this;
        }