Пример #1
0
 public UnresolvedReference(ConceptDescription dependant, ConceptMember referenceMember)
 {
     Dependant      = dependant;
     Member         = referenceMember;
     ReferencedStub = (IConceptInfo)Member.GetValue(Dependant.Concept);
     ReferencedKey  = ReferencedStub?.GetKey();
 }
Пример #2
0
        private static void AppendMember(StringBuilder text, IConceptInfo ci, ConceptMember member, bool exceptionOnNullMember)
        {
            object memberValue = member.GetValue(ci);

            if (memberValue == null)
            {
                if (exceptionOnNullMember)
                {
                    throw new DslSyntaxException(ci, string.Format(
                                                     "{0}'s property {1} is null. Info: {2}.",
                                                     ci.GetType().Name, member.Name, ci.GetErrorDescription()));
                }
                else
                {
                    text.Append("<null>");
                }
            }
            else if (member.IsConceptInfo)
            {
                IConceptInfo value = (IConceptInfo)member.GetValue(ci);
                if (member.ValueType == typeof(IConceptInfo))
                {
                    text.Append(BaseConceptInfoType(value).Name).Append(":");
                }
                AppendMembers(text, value, SerializationOptions.KeyMembers, exceptionOnNullMember);
            }
            else if (member.ValueType == typeof(string))
            {
                text.Append(SafeDelimit(member.GetValue(ci).ToString()));
            }
            else
            {
                throw new FrameworkException(string.Format(
                                                 "IConceptInfo member {0} of type {1} in {2} is not supported.",
                                                 member.Name, member.ValueType.Name, ci.GetType().Name));
            }
        }
Пример #3
0
        private bool IsConceptMemberEqual(IConceptInfo newConcept, IConceptInfo existingConcept, ConceptMember conceptMemeber)
        {
            if (conceptMemeber.IsConceptInfo)
            {
                if ((conceptMemeber.GetValue(existingConcept) as IConceptInfo).GetKey() !=
                    (conceptMemeber.GetValue(newConcept) as IConceptInfo).GetKey())
                {
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            else
            {
                var value1 = conceptMemeber.GetValue(existingConcept);
                var value2 = conceptMemeber.GetValue(newConcept);

                if (value1 == null)
                {
                    return(value2 == null);
                }
                else if (value2 == null)
                {
                    return(false);
                }
                else
                {
                    return(value1.Equals(value2));
                }
            }
        }
Пример #4
0
 private static void AppendMember(StringBuilder text, IConceptInfo ci, ConceptMember member, bool exceptionOnNullMember)
 {
     object memberValue = member.GetValue(ci);
     if (memberValue == null)
         if (exceptionOnNullMember)
             throw new DslSyntaxException(ci, string.Format(
                 "{0}'s property {1} is null. Info: {2}.",
                 ci.GetType().Name, member.Name, ci.GetErrorDescription()));
         else
             text.Append("<null>");
     else if (member.IsConceptInfo)
     {
         IConceptInfo value = (IConceptInfo)member.GetValue(ci);
         if (member.ValueType == typeof(IConceptInfo))
             text.Append(BaseConceptInfoType(value).Name).Append(":");
         AppendMembers(text, value, SerializationOptions.KeyMembers, exceptionOnNullMember);
     }
     else if (member.ValueType == typeof(string))
         text.Append(SafeDelimit(member.GetValue(ci).ToString()));
     else
         throw new FrameworkException(string.Format(
             "IConceptInfo member {0} of type {1} in {2} is not supported.",
             member.Name, member.ValueType.Name, ci.GetType().Name));
 }
Пример #5
0
        public ValueOrError<object> ReadMemberValue(ConceptMember member, ITokenReader tokenReader, IConceptInfo lastConcept,
            bool firstMember, ref bool lastPropertyWasInlineParent, ref bool lastConceptUsed, bool readingAReference)
        {
            try
            {
                if (lastPropertyWasInlineParent && member.IsKey && !member.IsConceptInfo) // TODO: Removing "IsConceptInfo" from this condition would produce a mismatch. Think of a better solution for parsing the concept key.
                {
                    if (!tokenReader.TryRead("."))
                        return ValueOrError<object>.CreateError(string.Format(
                            "Parent property and the following key value ({0}) must be separated with a dot. Expected \".\"",
                            member.Name));
                }
                lastPropertyWasInlineParent = false;

                if (member.IsStringType)
                    return tokenReader.ReadText();

                if (member.ValueType == typeof(IConceptInfo))
                    if (firstMember && lastConcept != null)
                    {
                        lastConceptUsed = true;
                        return (object)lastConcept;
                    }
                    else
                        return ValueOrError<object>.CreateError("Member of type IConceptInfo can only be used as a first member and enclosed within the referenced parent concept.");

                if (member.IsConceptInfo && lastConcept != null && member.ValueType.IsInstanceOfType(lastConcept)
                         && member.ValueType.IsAssignableFrom(ConceptInfoType)) // Recursive "parent" property
                {
                    lastConceptUsed = true;
                    return (object)lastConcept;
                }

                if (member.IsConceptInfo && lastConcept != null && member.ValueType.IsInstanceOfType(lastConcept)
                         && firstMember)
                {
                    lastConceptUsed = true;
                    return (object)lastConcept;
                }

                if (member.IsConceptInfo && firstMember)
                {
                    if (member.ValueType == ConceptInfoType)
                        return ValueOrError.CreateError(string.Format(
                            "Recursive concept {0} cannot be used as a root because its parent property ({1}) must reference another concept. Use a non-recursive concept for the root and a derivation of the root concept with additional parent property as a recursive concept.",
                            ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType), member.Name));

                    if (!readingAReference && Members.Where(m => m.IsParsable).Count() == 1)
                    {
                        // This validation is not necessary for consistent parsing. It is enforced simply to avoid ambiguity when parsing
                        // similar concepts such as "Logging { AllProperties; }", "History { AllProperties; }" and "Persisted { AllProperties; }".

                        var parentMembers = ConceptMembers.Get(member.ValueType).Where(m => m.IsParsable).ToArray();
                        if (parentMembers.Count() == 1 && parentMembers.Single().IsConceptInfo)
                            return ValueOrError.CreateError(string.Format(
                                "{0} must be enclosed within the referenced parent concept {1}. A single-reference concept that references another single-reference concept must always be used with embedded syntax to avoid ambiguity.",
                                ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType),
                                ConceptInfoHelper.GetKeywordOrTypeName(member.ValueType)));
                    }

                    GenericParser subParser = new GenericParser(member.ValueType, "");
                    lastConceptUsed = true;
                    lastPropertyWasInlineParent = true;
                    return subParser.ParseMembers(tokenReader, lastConcept, true).ChangeType<object>();
                }

                if (member.IsConceptInfo)
                {
                    GenericParser subParser = new GenericParser(member.ValueType, "");
                    return subParser.ParseMembers(tokenReader, null, true).ChangeType<object>();
                }

                return ValueOrError.CreateError(string.Format(
                    "GenericParser does not support members of type \"{0}\". Try using string or implementation of IConceptInfo.",
                    member.ValueType.Name));
            }
            catch (DslSyntaxException ex)
            {
                return ValueOrError<object>.CreateError(ex.Message);
            }
        }
Пример #6
0
        public ValueOrError <object> ReadMemberValue(ConceptMember member, ITokenReader tokenReader, IConceptInfo lastConcept,
                                                     bool firstMember, ref bool lastPropertyWasInlineParent, ref bool lastConceptUsed, bool readingAReference)
        {
            try
            {
                if (lastPropertyWasInlineParent && member.IsKey && !member.IsConceptInfo) // TODO: Removing "IsConceptInfo" from this condition would produce a mismatch. Think of a better solution for parsing the concept key.
                {
                    if (!tokenReader.TryRead("."))
                    {
                        return(ValueOrError <object> .CreateError(string.Format(
                                                                      "Parent property and the following key value ({0}) must be separated with a dot. Expected \".\"",
                                                                      member.Name)));
                    }
                }
                lastPropertyWasInlineParent = false;

                if (member.IsStringType)
                {
                    return(tokenReader.ReadText().ChangeType <object>());
                }

                if (member.ValueType == typeof(IConceptInfo))
                {
                    if (firstMember && lastConcept != null)
                    {
                        lastConceptUsed = true;
                        return((object)lastConcept);
                    }
                    else
                    {
                        return(ValueOrError <object> .CreateError("Member of type IConceptInfo can only be used as a first member and enclosed within the referenced parent concept."));
                    }
                }

                if (member.IsConceptInfo && lastConcept != null && member.ValueType.IsInstanceOfType(lastConcept) &&
                    member.ValueType.IsAssignableFrom(ConceptInfoType))         // Recursive "parent" property
                {
                    lastConceptUsed = true;
                    return((object)lastConcept);
                }

                if (member.IsConceptInfo && lastConcept != null && member.ValueType.IsInstanceOfType(lastConcept) &&
                    firstMember)
                {
                    lastConceptUsed = true;
                    return((object)lastConcept);
                }

                if (member.IsConceptInfo && firstMember)
                {
                    if (member.ValueType == ConceptInfoType)
                    {
                        return(ValueOrError.CreateError(string.Format(
                                                            "Recursive concept {0} cannot be used as a root because its parent property ({1}) must reference another concept. Use a non-recursive concept for the root and a derivation of the root concept with additional parent property as a recursive concept.",
                                                            ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType), member.Name)));
                    }

                    if (!readingAReference && Members.Where(m => m.IsParsable).Count() == 1)
                    {
                        // This validation is not necessary for consistent parsing. It is enforced simply to avoid ambiguity when parsing
                        // similar concepts such as "Logging { AllProperties; }", "History { AllProperties; }" and "Persisted { AllProperties; }".

                        var parentMembers = ConceptMembers.Get(member.ValueType).Where(m => m.IsParsable).ToArray();
                        if (parentMembers.Count() == 1 && parentMembers.Single().IsConceptInfo)
                        {
                            return(ValueOrError.CreateError(string.Format(
                                                                "{0} must be enclosed within the referenced parent concept {1}. A single-reference concept that references another single-reference concept must always be used with embedded syntax to avoid ambiguity.",
                                                                ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType),
                                                                ConceptInfoHelper.GetKeywordOrTypeName(member.ValueType))));
                        }
                    }

                    GenericParser subParser = new GenericParser(member.ValueType, "");
                    lastConceptUsed             = true;
                    lastPropertyWasInlineParent = true;
                    return(subParser.ParseMembers(tokenReader, lastConcept, true).ChangeType <object>());
                }

                if (member.IsConceptInfo)
                {
                    GenericParser subParser = new GenericParser(member.ValueType, "");
                    return(subParser.ParseMembers(tokenReader, null, true).ChangeType <object>());
                }

                return(ValueOrError.CreateError(string.Format(
                                                    "GenericParser does not support members of type \"{0}\". Try using string or implementation of IConceptInfo.",
                                                    member.ValueType.Name)));
            }
            catch (DslSyntaxException ex)
            {
                return(ValueOrError <object> .CreateError(ex.Message));
            }
        }
Пример #7
0
        private ValueOrError <object> ReadMemberValue(ConceptMember member, ITokenReader tokenReader, IConceptInfo useLastConcept,
                                                      bool firstMember, ref bool parsedFirstReferenceElement, bool readingAReference)
        {
            try
            {
                if (member.IsStringType)
                {
                    if (useLastConcept != null)
                    {
                        return(ValueOrError <object> .CreateError($"This concept cannot be nested within {useLastConcept.GetType().Name}. Trying to read {ConceptInfoType.Name}."));
                    }

                    if (readingAReference && parsedFirstReferenceElement)
                    {
                        if (!tokenReader.TryRead("."))
                        {
                            return(ValueOrError <object> .CreateError(string.Format(
                                                                          "Parent property and the following key value ({0}) must be separated with a dot. Expected \".\"",
                                                                          member.Name)));
                        }
                    }

                    parsedFirstReferenceElement = true;

                    // Legacy syntax:
                    if (!readingAReference && member.IsKey && member.IsStringType && !firstMember)
                    {
                        if (tokenReader.TryRead("."))
                        {
                            AddWarning($"Obsolete syntax: Remove '.' from {Keyword} statement. {((TokenReader)tokenReader).ReportPosition()}.");
                        }
                    }

                    return(tokenReader.ReadText().ChangeType <object>());
                }

                if (member.ValueType == typeof(IConceptInfo))
                {
                    if (useLastConcept != null)
                    {
                        return((object)useLastConcept);
                    }
                    else
                    {
                        return(ValueOrError <object> .CreateError($"Member of type IConceptInfo can only be nested within" +
                                                                  $" the referenced parent concept. It must be a first member or marked with {nameof(ConceptParentAttribute)}."));
                    }
                }

                if (useLastConcept != null && member.ValueType.IsInstanceOfType(useLastConcept))
                {
                    return((object)useLastConcept);
                }

                if (member.IsConceptInfo && firstMember && !readingAReference && Members.Count(m => m.IsParsable) == 1)
                {
                    // This validation is not necessary for consistent parsing. It is enforced simply to avoid ambiguity for future concept overloads
                    // when parsing similar concepts such as "Logging { AllProperties; }", "History { AllProperties; }" and "Persisted { AllProperties; }".
                    var parentMembers = ConceptMembers.Get(member.ValueType).Where(m => m.IsParsable).ToArray();
                    if (parentMembers.Count() == 1 && parentMembers.Single().IsConceptInfo)
                    {
                        return(ValueOrError.CreateError($"{ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType)} must be nested" +
                                                        $" within the referenced parent concept {ConceptInfoHelper.GetKeywordOrTypeName(member.ValueType)}." +
                                                        $" A single-reference concept that references another single-reference concept must always be used with nested syntax to avoid ambiguity."));
                    }
                }

                if (member.IsConceptInfo)
                {
                    if (firstMember && member.ValueType == ConceptInfoType)
                    {
                        return(ValueOrError.CreateError(string.Format(
                                                            "Recursive concept {0} cannot be used as a root because its parent property ({1}) must reference another concept. Use a non-recursive concept for the root and a derivation of the root concept with additional parent property as a recursive concept.",
                                                            ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType), member.Name)));
                    }

                    GenericParser subParser = new GenericParser(member.ValueType, "");
                    return(subParser.ParseMembers(tokenReader, useLastConcept, true, ref parsedFirstReferenceElement).ChangeType <object>());
                }

                return(ValueOrError.CreateError(string.Format(
                                                    "GenericParser does not support members of type \"{0}\". Try using string or implementation of IConceptInfo.",
                                                    member.ValueType.Name)));
            }
            catch (DslSyntaxException ex)
            {
                return(ValueOrError <object> .CreateError(ex.Message));
            }
        }