// 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) && ExpressionFunctions.TryParseList(curScope, out var li)) { curPath += $"[{parts[i]}]"; (curScope, error) = ExpressionFunctions.AccessIndex(li, index); } else { curPath += $".{parts[i]}"; if (ExpressionFunctions.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 (ExpressionFunctions.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) = ExpressionFunctions.SetProperty(curScope, parts.Last(), value); if (error != null) { return; } } // Update the version once memory has been updated version++; }