예제 #1
0
        private Modifier(JObject spec, OpMode opMode, IReadOnlyDictionary <string, IFunction> functionsMap)
        {
            if (spec == null)
            {
                throw new SpecException(opMode.GetName() + " expected a spec of Map type, got 'null'.");
            }

            if (functionsMap == null || functionsMap.Count == 0)
            {
                throw new SpecException(opMode.GetName() + " expected a populated functions' map type, got " + (functionsMap == null ? "null" : "empty"));
            }

            TemplatrSpecBuilder templatrSpecBuilder = new TemplatrSpecBuilder(opMode, functionsMap);

            _rootSpec = new ModifierCompositeSpec(ROOT_KEY, spec, opMode, templatrSpecBuilder);
        }
        public ModifierCompositeSpec(string key, JObject spec, OpMode opMode, TemplatrSpecBuilder specBuilder) :
            base(key, opMode)
        {
            var literals = new Dictionary <string, IBaseSpec>();
            var computed = new List <ModifierSpec>();

            List <ModifierSpec> children = specBuilder.CreateSpec(spec);

            // remember max explicit index from spec to expand input array at runtime
            // need to validate spec such that it does not specify both array and literal path element
            int maxExplicitIndexFromSpec = -1, confirmedMapAtIndex = -1, confirmedArrayAtIndex = -1;

            for (int i = 0; i < children.Count; i++)
            {
                var childSpec        = children[i];
                var childPathElement = childSpec.GetPathElement();

                // for every child,
                //  a) mark current index as either must be map or must be array
                //  b) mark it as literal or computed
                //  c) if arrayPathElement,
                //      - make sure its an explicit index type
                //      - save the max explicit index in spec
                if (childPathElement is LiteralPathElement)
                {
                    confirmedMapAtIndex = i;
                    literals[childPathElement.RawKey] = childSpec;
                }
                else if (childPathElement is ArrayPathElement childArrayPathElement)
                {
                    confirmedArrayAtIndex = i;

                    if (!childArrayPathElement.IsExplicitArrayIndex())
                    {
                        throw new SpecException(opMode.GetName() + " RHS only supports explicit Array path element");
                    }
                    int?explicitIndex = childArrayPathElement.GetExplicitArrayIndex();
                    // if explicit index from spec also enforces "[...]?" don't bother using that as max index
                    if (!childSpec.GetCheckValue())
                    {
                        maxExplicitIndexFromSpec = Math.Max(maxExplicitIndexFromSpec, explicitIndex ?? 0);
                    }

                    literals[explicitIndex.ToString()] = childSpec;
                }
                else
                {
                    // StarPathElements evaluates to string keys in a Map, EXCEPT StarAllPathElement
                    // which can be both all keys in a map or all indexes in a list
                    if (!(childPathElement is StarAllPathElement))
                    {
                        confirmedMapAtIndex = i;
                    }
                    computed.Add(childSpec);
                }

                // Bail as soon as both confirmedMapAtIndex & confirmedArrayAtIndex is set
                if (confirmedMapAtIndex > -1 && confirmedArrayAtIndex > -1)
                {
                    throw new SpecException(opMode.GetName() + " RHS cannot mix int array index and string map key, defined spec for " + key + " contains: " +
                                            children[confirmedMapAtIndex].GetPathElement().GetCanonicalForm() + " conflicting " +
                                            children[confirmedArrayAtIndex].GetPathElement().GetCanonicalForm());
                }
            }

            // set the dataType from calculated indexes
            _specDataType = DataType.DetermineDataType(confirmedArrayAtIndex, confirmedMapAtIndex, maxExplicitIndexFromSpec);

            // Only the computed children need to be sorted
            computed.Sort(_computedKeysComparator);
            computed.TrimExcess();

            _literalChildren  = literals;
            _computedChildren = computed.AsReadOnly();

            // extract generic execution strategy
            _executionStrategy = DetermineExecutionStrategy();
        }