コード例 #1
0
        /// <see cref="IJsonPlusNode.Clone(IJsonPlusNode)"/>
        public IJsonPlusNode Clone(IJsonPlusNode newParent)
        {
            JsonPlusObjectMember newField = new JsonPlusObjectMember(Path, (JsonPlusObject)newParent);

            newField._internalValues.AddRange(_internalValues);
            return(newField);
        }
コード例 #2
0
        private JsonPlusValue ResolveSubstitution(JsonPlusSubstitution sub)
        {
            JsonPlusObjectMember subField = sub.ParentMember;

            // first case, this substitution is a direct self-reference
            if (sub.Path == sub.GetMemberPath())
            {
                IJsonPlusNode parent = sub.Parent;
                while (parent is JsonPlusValue)
                {
                    parent = parent.Parent;
                }

                // Fail case
                if (parent is JsonPlusArray)
                {
                    throw new JsonPlusException(RS.SelfRefSubstitutionInArray);
                }

                // try to resolve substitution by looking backward in the field assignment stack
                return(subField.OlderValueThan(sub));
            }

            // need to recursively get full path
            JsonPlusPath fieldPath = subField.GetMemberPath();

            // second case, the substitution references a field child in the past
            if (sub.Path.IsChildPathOf(fieldPath))
            {
                JsonPlusValue olderValue = subField.OlderValueThan(sub);
                if ((olderValue != null) &&
                    (olderValue.Type == JsonPlusType.Object))
                {
                    int          difLength = sub.Path.Count - fieldPath.Count;
                    JsonPlusPath deltaPath = sub.Path.SubPath(sub.Path.Count - difLength, difLength);

                    JsonPlusObject olderObject = olderValue.GetObject();
                    if (olderObject.TryGetValue(deltaPath, out JsonPlusValue innerValue))
                    {
                        return(innerValue.Type == JsonPlusType.Object ? innerValue : null);
                    }
                }
            }

            // Detect invalid parent-referencing substitution
            if (fieldPath.IsChildPathOf(sub.Path))
            {
                throw new JsonPlusException(RS.SubstitutionRefDirectParentError);
            }

            // Detect invalid cyclic reference loop
            if (IsValueCyclic(subField, sub))
            {
                throw new JsonPlusException(RS.CyclicSubstitutionLoop);
            }

            // third case, regular substitution
            _root.GetObject().TryGetValue(sub.Path, out JsonPlusValue field);
            return(field);
        }
コード例 #3
0
        private JsonPlusObjectMember ParseObjectMember(JsonPlusObject owner)
        {
            // sanity check
            if (_tokens.Current.Type != TokenType.LiteralValue)
            {
                throw JsonPlusParserException.Create(_tokens.Current, Path, string.Format(RS.UnexpectedTokenInMember, TokenType.LiteralValue, _tokens.Current.Type));
            }

            JsonPlusPath pathDelta = ParseKey();

            if (_tokens.Current.IsNonSignificant())
            {
                ConsumeWhitelines();
            }

            // sanity check
            if (_tokens.Current.Type != TokenType.Assignment &&
                _tokens.Current.Type != TokenType.StartOfObject &&
                _tokens.Current.Type != TokenType.SelfAssignment)
            {
                throw JsonPlusParserException.Create(_tokens.Current, Path,
                                                     string.Format(RS.UnexpectedTokenWith3AltInMember,
                                                                   TokenType.Assignment, TokenType.StartOfObject, TokenType.SelfAssignment,
                                                                   _tokens.Current.Type));
            }

            // sanity check
            if (pathDelta == null || pathDelta.Count == 0)
            {
                throw JsonPlusParserException.Create(_tokens.Current, Path, RS.ObjectMemberPathUnspecified);
            }

            List <JsonPlusObjectMember> childInPath = owner.TraversePath(pathDelta);

            Path.AddRange(pathDelta);
            JsonPlusObjectMember currentField = childInPath[childInPath.Count - 1];

            JsonPlusValue parsedValue = ParseValue(currentField);

            foreach (JsonPlusSubstitution removedSub in currentField.SetValue(parsedValue))
            {
                _substitutions.Remove(removedSub);
            }

            Path.RemoveRange(Path.Count - pathDelta.Count, pathDelta.Count);
            return(childInPath[0]);
        }
コード例 #4
0
        private JsonPlusPath GetMemberPath(JsonPlusObjectMember member, JsonPlusPath subPath)
        {
            if (member.ParentMember == null && subPath == null)
            {
                return(new JsonPlusPath(new string[] { member.Key }));
            }

            if (subPath == null)
            {
                return(GetMemberPath(member.ParentMember, new JsonPlusPath(new string[] { member.Key })));
            }

            subPath.Add(member.Key);

            if (member.ParentMember == null)
            {
                return(subPath);
            }

            return(GetMemberPath(member.ParentMember, subPath));
        }
コード例 #5
0
        private bool IsValueCyclic(JsonPlusObjectMember field, JsonPlusSubstitution sub)
        {
            Stack <JsonPlusValue>       pendingValues = new Stack <JsonPlusValue>();
            List <JsonPlusObjectMember> visitedFields = new List <JsonPlusObjectMember> {
                field
            };
            Stack <JsonPlusSubstitution> pendingSubs = new Stack <JsonPlusSubstitution>();

            pendingSubs.Push(sub);

            while (pendingSubs.Count > 0)
            {
                JsonPlusSubstitution currentSub = pendingSubs.Pop();
                if (!_root.GetObject().TryGetMember(currentSub.Path, out var currentField))
                {
                    continue;
                }

                if (visitedFields.Contains(currentField))
                {
                    return(true);
                }

                visitedFields.Add(currentField);
                pendingValues.Push(currentField.Value);
                while (pendingValues.Count > 0)
                {
                    JsonPlusValue currentValue = pendingValues.Pop();

                    foreach (IJsonPlusNode value in currentValue)
                    {
                        switch (value)
                        {
                        case JsonPlusLiteralValue _:
                            break;

                        case JsonPlusObject o:
                            foreach (JsonPlusObjectMember f in o.Values)
                            {
                                if (visitedFields.Contains(f))
                                {
                                    return(true);
                                }

                                visitedFields.Add(f);
                                pendingValues.Push(f.Value);
                            }
                            break;

                        case JsonPlusArray a:
                            foreach (JsonPlusValue item in a.GetArray())
                            {
                                pendingValues.Push(item);
                            }
                            break;

                        case JsonPlusSubstitution s:
                            pendingSubs.Push(s);
                            break;
                        }
                    }
                }
            }
            return(false);
        }