/// <summary>
        /// Try get value from a given path.
        /// </summary>
        /// <param name="path">Given path.</param>
        /// <param name="value">Resolved value.</param>
        /// <returns>True if the memory contains an element with the specified key; otherwise, false.</returns>
        public bool TryGetValue(string path, out object value)
        {
            value = null;
            if (memory == null || path.Length == 0)
            {
                return(false);
            }

            var parts = path.Split(".[]".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
                        .Select(x => x.Trim('\'', '"'))
                        .ToArray();

            var curScope = memory;

            foreach (var part in parts)
            {
                string error = null;
                if (int.TryParse(part, out var idx) && FunctionUtils.TryParseList(curScope, out var li))
                {
                    (value, error) = FunctionUtils.AccessIndex(li, idx);
                    if (error != null)
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!FunctionUtils.TryAccessProperty(curScope, part, out value))
                    {
                        return(false);
                    }
                }

                curScope = value;
            }

            if (value is IExpressionProperty ep)
            {
                value = ep.GetObject(memory);
            }

            return(true);
        }
Exemplo n.º 2
0
        private static (object value, string error) Evaluator(Expression expression, IMemory state, Options options)
        {
            object value = null;
            string error;
            var    instance = expression.Children[0];
            var    index    = expression.Children[1];
            object inst;

            (inst, error) = instance.TryEvaluate(state, options);
            if (error == null)
            {
                object idxValue;
                (idxValue, error) = index.TryEvaluate(state, new Options(options)
                {
                    NullSubstitution = null
                });
                if (error == null)
                {
                    if (idxValue.IsInteger())
                    {
                        var idx = 0;
                        (idx, error) = FunctionUtils.ParseInt32(idxValue);
                        if (error == null)
                        {
                            (value, error) = FunctionUtils.AccessIndex(inst, idx);
                        }
                    }
                    else if (idxValue is string idxStr)
                    {
                        FunctionUtils.TryAccessProperty(inst, idxStr, out value);
                    }
                    else
                    {
                        error = $"Could not coerce {index}<{idxValue?.GetType()}> to an int or string";
                    }
                }
            }

            return(value, error);
        }
Exemplo n.º 3
0
        private static (object value, string error) Evaluator(Expression expression, IMemory state, Options options)
        {
            object result = null;
            string error;

            object instance;

            (instance, error) = expression.Children[0].TryEvaluate(state, options);
            if (error == null)
            {
                var   isInstanceList = false;
                IList list           = null;
                if (FunctionUtils.TryParseList(instance, out IList ilist))
                {
                    isInstanceList = true;
                    list           = ilist;
                }
                else if (instance is JObject jobj)
                {
                    list = FunctionUtils.Object2KVPairList(jobj);
                }
                else if (FunctionUtils.ConvertToJToken(instance) is JObject jobject)
                {
                    list = FunctionUtils.Object2KVPairList(jobject);
                }
                else
                {
                    error = $"{expression.Children[0]} is not a collection or structure object to run foreach";
                }

                if (error == null)
                {
                    var iteratorName  = (string)(expression.Children[1].Children[0] as Constant).Value;
                    var stackedMemory = StackedMemory.Wrap(state);
                    result = new List <object>();
                    for (var idx = 0; idx < list.Count; idx++)
                    {
                        var local = new Dictionary <string, object>
                        {
                            { iteratorName, FunctionUtils.AccessIndex(list, idx).value },
                        };

                        // the local iterator is pushed as one memory layer in the memory stack
                        stackedMemory.Push(new SimpleObjectMemory(local));
                        var(r, e) = expression.Children[2].TryEvaluate(stackedMemory, new Options(options)
                        {
                            NullSubstitution = null
                        });
                        stackedMemory.Pop();

                        if (FunctionUtils.IsLogicTrue(r) && e == null)
                        {
                            // add if only if it evaluates to true
                            ((List <object>)result).Add(local[iteratorName]);
                        }
                    }

                    if (!isInstanceList)
                    {
                        // re-construct object
                        var jobjResult = new JObject();
                        foreach (var item in (List <object>)result)
                        {
                            FunctionUtils.TryAccessProperty(item, "key", out var keyVal);
                            FunctionUtils.TryAccessProperty(item, "value", out var val);
                            jobjResult.Add(keyVal as string, FunctionUtils.ConvertToJToken(val));
                        }

                        result = jobjResult;
                    }
                }
            }

            return(result, error);
        }
        // In this simple object scope, we don't allow you to set a path in which some parts in middle don't exist
        // for example
        // if you set dialog.a.b = x, but dialog.a don't exist, this will result in an error
        // because we can't and shouldn't smart create structure in the middle
        // you can implement a customized Scope that support such behavior

        /// <summary>
        /// Set value to a given path.
        /// </summary>
        /// <param name="path">Memory path.</param>
        /// <param name="value">Value to set.</param>
        public void SetValue(string path, object value)
        {
            if (memory == null)
            {
                return;
            }

            var parts = path.Split(".[]".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
                        .Select(x => x.Trim('\'', '"'))
                        .ToArray();

            var    curScope = memory;
            var    curPath  = string.Empty; // valid path so far
            string error    = null;

            // find the 2nd last value, the container
            for (var i = 0; i < parts.Length - 1; i++)
            {
                if (int.TryParse(parts[i], out var index) && FunctionUtils.TryParseList(curScope, out var li))
                {
                    curPath          += $"[{parts[i]}]";
                    (curScope, error) = FunctionUtils.AccessIndex(li, index);
                }
                else
                {
                    curPath += $".{parts[i]}";
                    if (FunctionUtils.TryAccessProperty(curScope, parts[i], out var newScope))
                    {
                        curScope = newScope;
                    }
                    else
                    {
                        return;
                    }
                }

                if (error != null || curScope == null)
                {
                    return;
                }
            }

            // set the last value
            if (int.TryParse(parts.Last(), out var idx))
            {
                if (FunctionUtils.TryParseList(curScope, out var li))
                {
                    if (li is JArray)
                    {
                        value = JToken.FromObject(value);
                    }

                    if (idx > li.Count)
                    {
                        error = $"{idx} index out of range";
                    }
                    else if (idx == li.Count)
                    {
                        // expand for one
                        li.Add(value);
                    }
                    else
                    {
                        li[idx] = value;
                    }
                }
                else
                {
                    error = $"set value for an index to a non-list object";
                }

                if (error != null)
                {
                    return;
                }
            }
            else
            {
                (_, error) = SetProperty(curScope, parts.Last(), value);
                if (error != null)
                {
                    return;
                }
            }
        }