/// <summary> /// Will walk the path by using the path seperator "." and evaluate the object at the end /// </summary> /// <param name="path"></param> /// <returns></returns> internal async Task <ContextObject> GetContextForPath(string path, Parser.ScopeData scopeData) { var elements = new Queue <string>(); foreach (var m in PathFinder.Matches(path).OfType <Match>()) { elements.Enqueue(m.Value); } return(await GetContextForPath(elements, scopeData)); }
private async Task <ContextObject> GetContextForPath(Queue <string> elements, Parser.ScopeData scopeData) { var retval = this; if (elements.Any()) { var path = elements.Dequeue(); var preHandeld = HandlePathContext(elements, path); if (preHandeld != null) { return(preHandeld); } if (path.StartsWith("~")) //go the root object { var parent = Parent; var lastParent = parent; while (parent != null) { parent = parent.Parent; if (parent != null) { lastParent = parent; } } if (lastParent != null) { retval = await lastParent.GetContextForPath(elements, scopeData); } } else if (path.Equals("$recursion")) //go the root object { retval = new ContextObject(Options, path) { Parent = this, Value = scopeData.PartialDepth.Count }; } else if (path.StartsWith("..")) //go one level up { if (Parent != null) { var parentsRetVal = (await Parent.GetContextForPath(elements, scopeData)); if (parentsRetVal != null) { retval = parentsRetVal; } else { retval = await GetContextForPath(elements, scopeData); } } else { retval = await GetContextForPath(elements, scopeData); } } else if (path.StartsWith("?")) //enumerate ether an IDictionary, an cs object or an IEnumerable to a KeyValuePair array { //ALWAYS return the context, even if the value is null. var innerContext = new ContextObject(Options, path) { Parent = this }; await EnsureValue(); switch (Value) { case IDictionary <string, object> dictList: innerContext.Value = dictList.Select(e => e); break; //This is a draft that i have discarded as its more likely to enumerate a single IEnumerable with #each alone //case IEnumerable ctx: // innerContext.Value = ctx.OfType<object>().Select((item, index) => new KeyValuePair<string, object>(index.ToString(), item)); // break; default: { if (Value != null) { innerContext.Value = Value .GetType() .GetTypeInfo() .GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(e => !e.IsSpecialName && !e.GetIndexParameters().Any()) .Select(e => new KeyValuePair <string, object>(e.Name, e.GetValue(Value))); } break; } } retval = await innerContext.GetContextForPath(elements, scopeData); } //TODO: handle array accessors and maybe "special" keys. else { //ALWAYS return the context, even if the value is null. var innerContext = new ContextObject(Options, path) { Parent = this }; await EnsureValue(); if (Value is IDictionary <string, object> ctx) { ctx.TryGetValue(path, out var o); innerContext.Value = o; } else if (Value != null) { var propertyInfo = Value.GetType().GetTypeInfo().GetProperty(path); if (propertyInfo != null) { innerContext.Value = propertyInfo.GetValue(Value); } } retval = await innerContext.GetContextForPath(elements, scopeData); } } return(retval); }