Esempio n. 1
0
 /// <summary>
 /// Creates a structurally equivalent construction from a given construction.
 /// </summary>
 /// <param name="construction">The construction to copy the structure of.</param>
 /// <returns>A structurally equivalent copy of the given construction.</returns>
 public static IStonConstruction Copy(IStonConstruction construction)
 {
     if (construction == null)
     {
         throw new ArgumentNullException("construction");
     }
     return(new StonConstruction(construction));
 }
Esempio n. 2
0
        public AComplexEntity(IStonConstruction construction = null, IStonMemberInit memberInit = null, IStonCollectionInit collectionInit = null, IStonType type = null, string globalIdentifier = null)
        {
            GlobalIdentifier = globalIdentifier;
            Type             = type;

            Construction   = construction;
            MemberInit     = memberInit;
            CollectionInit = collectionInit;
        }
 // checks that a given combination of complex value components is valid
 private void ExpectValidComplexEntity(IStonConstruction construction = null, IStonMemberInit memberInit = null, IStonCollectionInit collectionInit = null)
 {
     try
     {
         new StonComplexEntity(construction, memberInit, collectionInit);
     }
     catch (StonException ex)
     {
         Assert.Fail(ex.Message);
     }
 }
Esempio n. 4
0
        /// <summary>
        /// Creates a new complex-valued entity, with a given value and optional declared type and global identifier.
        /// </summary>
        /// <param name="construction">The construction part of the complex value.</param>
        /// <param name="memberInit">The member initialization part of the complex value.</param>
        /// <param name="collectionInit">The collection initialization part of the complex value.</param>
        /// <param name="type">The declared type of the entity.</param>
        /// <param name="globalIdentifier">The global identifier of the entity.</param>
        public StonComplexEntity(IStonConstruction construction = null, IStonMemberInit memberInit = null, IStonCollectionInit collectionInit = null, IStonType type = null, string globalIdentifier = null)
            : base(type, globalIdentifier)
        {
            Construction = construction != null?StonConstruction.Copy(construction) : null;

            MemberInit = memberInit != null?StonMemberInit.Copy(memberInit) : null;

            CollectionInit = collectionInit != null?StonCollectionInit.Copy(collectionInit) : null;

            Helpers.Validator.ValidateEntity(this);
        }
 // checks that a given combination of complex value components is invalid, and causes a specific error
 private void ExpectInvalidComplexEntity(IStonConstruction construction = null, IStonMemberInit memberInit = null, IStonCollectionInit collectionInit = null, string message = null)
 {
     try
     {
         new StonComplexEntity(construction, memberInit, collectionInit);
         Assert.Fail("The value is valid. This should *not* have happened.");
     }
     catch (StonException ex)
     {
         Assert.AreEqual(message, ex.Message);
     }
 }
Esempio n. 6
0
        // writes a construction component of a complex value
        private void WriteConstruction(StonTokenWriter writer, IStonConstruction construction)
        {
            if (construction == null)
            {
                return;
            }
            if (construction.PositionalParameters == null)
            {
                throw new StonException("A complex value construction cannot have a non-existing positional parameters collection.");
            }
            if (construction.NamedParameters == null)
            {
                throw new StonException("A complex value construction cannot have a non-existing named parameters collection.");
            }

            writer.Write('(');

            // writing positional parameters
            WriteSequence(
                writer,
                construction.PositionalParameters,
                (w, p) => { w.Write(':'); WriteEntity(w, p); }
                );

            // a comma between positional and named parameters, if both types of parameters are present
            // it is necessary, because positional parameters sequence and named parameters sequence are written separately
            if (construction.PositionalParameters.Any() && construction.NamedParameters.Any())
            {
                writer.Write(',');
            }

            // writing named parameters
            WriteSequence(
                writer,
                construction.NamedParameters,
                (w, p) => {
                WriteStringLiteral(w, p.Key);
                w.Write(':');
                WriteEntity(w, p.Value);
            }
                );

            writer.Write(')');
        }
Esempio n. 7
0
        /// <summary>
        /// Checks the validity of a given STON complex value construction.
        /// </summary>
        /// <param name="construction">The construction to check the validity of.</param>
        public static void ValidateConstruction(IStonConstruction construction)
        {
            if (construction == null)
            {
                throw new ArgumentNullException("construction");
            }
            if (construction.PositionalParameters == null)
            {
                throw new StonException("A complex value construction cannot have a non-existing positional parameters collection.");
            }
            if (construction.NamedParameters == null)
            {
                throw new StonException("A complex value construction cannot have a non-existing named parameters collection.");
            }

            foreach (var parameter in construction.PositionalParameters)
            {
                if (parameter == null)
                {
                    throw new StonException("A complex value construction cannot have a non-existing parameter value.");
                }
            }
            var names = new HashSet <string>();

            foreach (var namedParameter in construction.NamedParameters)
            {
                if (namedParameter.Key == null)
                {
                    throw new StonException("A complex value construction cannot have a non-existing parameter name.");
                }
                if (!names.Add(namedParameter.Key))
                {
                    throw new StonException($"The complex value construction has a duplicate named parameter \"{namedParameter.Key}\".");
                }
                if (namedParameter.Value == null)
                {
                    throw new StonException("A complex value construction cannot have a non-existing parameter value.");
                }
            }
        }
Esempio n. 8
0
 /// <summary>
 /// Creates a new complex-valued entity, with a given value and optional declared type and global identifier.
 /// </summary>
 /// <param name="construction">The construction part of the complex value.</param>
 /// <param name="memberInit">The member initialization part of the complex value.</param>
 /// <param name="collectionInit">The collection initialization part of the complex value.</param>
 /// <param name="type">The declared type of the entity.</param>
 /// <param name="globalIdentifier">The global identifier of the entity.</param>
 /// <returns>The new STON entity.</returns>
 public IStonComplexEntity CreateComplexEntity(IStonConstruction construction = null, IStonMemberInit memberInit = null, IStonCollectionInit collectionInit = null, IStonType type = null, string globalIdentifier = null)
 => new StonComplexEntity(construction, memberInit, collectionInit, type, globalIdentifier);
Esempio n. 9
0
        // reads a STON entity, complete or address
        private IStonEntity _ReadEntity(StonTokenReader reader, bool isAddress)
        {
            // stores a CANUN identifier or path for later use until its purpose is known
            string storedWord = null;

            // determining the global identifier, if any
            string globalIdentifier = null;

            // the identifier is explicitly prepended with a global identifier sigil
            if (reader.Peek().HasChartype(StonChartype.IdentifierSigil))
            {
                if (isAddress)
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.None);                   // identifiers are not allowed for index parameter entities
                }
                reader.ReadAndSkip();
                globalIdentifier = reader.ReadCanun();
                reader.ExpectAndSkip(StonChartype.IdentifierAssign);
            }
            // the entity begins with a CANUN name that might or might not be a global identifier
            else if (reader.Peek().HasChartype(StonChartype.CanunBegin))
            {
                storedWord = reader.ReadCanun();
                // if and only if the CANUN name is followed by a global identifier assignment token
                // the name is to be used as a global identifier
                if (reader.Peek().HasChartype(StonChartype.IdentifierAssign))
                {
                    if (isAddress)
                    {
                        throw reader.MakeUnexpectedCharacterException(StonChartype.None);               // once again, identifiers are not allowed for index parameter entities
                    }
                    reader.ReadAndSkip();
                    globalIdentifier = storedWord;
                    storedWord       = null;
                }
            }

            // finding the address, if any
            if (reader.Peek().HasChartype(StonChartype.AddressBegin))
            {
                // the reference entity cannot have a type declaration
                if (storedWord != null)
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.None);
                }

                return(ElementFactory.CreateReferenceEntity(ReadAddress(reader), globalIdentifier));
            }

            // determining the type, if any
            IStonType type              = null;
            bool      isTypeFromWord    = false;
            bool      collectionStarted = false; // a variable indicating whether during reading type a collection initialization has been started or not

            // when bare type definitions are involved, a collection initialization might appear like a collection type suffix
            // so it's impossible to tell the two apart before reading the initial sign

            // no word is stored; either there was no word in the first place, or there was a global identifier before
            if (storedWord == null)
            {
                // storing a CANUN path, which might be a type or a named value
                if (reader.Peek().HasChartype(StonChartype.CanunBegin))
                {
                    storedWord = ReadCanunPath(reader);
                }
                // reading a type if the following token is characteristic for types
                else if (reader.Peek().HasChartype(StonChartype.Extension | StonChartype.TypeOpen))
                {
                    type = ReadBareUnion(reader, null, ref collectionStarted);
                }
            }
            else
            {
                // if a CANUN name is stored, it might be a part of a longer CANUN path
                // which itself might be a type or a named value
                if (reader.Peek().HasChartype(StonChartype.NameSeparator))
                {
                    storedWord = storedWord + (char)reader.ReadAndSkip() + ReadCanunPath(reader);
                }
            }

            // if a CANUN path is followed by a type opening, collection suffix or a union type separator
            // it means that path must be a type name
            if (storedWord != null && reader.Peek().HasChartype(StonChartype.TypeOpen | StonChartype.CollectionSuffixBegin | StonChartype.UnionTypeSeparator))
            {
                type       = ReadBareUnion(reader, storedWord, ref collectionStarted);
                storedWord = null;
            }
            if (storedWord != null)
            {
                type           = ElementFactory.CreateNamedType(storedWord);
                isTypeFromWord = true;
            }


            // finding the complex value, if any

            // when the collection initialization has been entered when reading a type definition
            // the rest of the collection initialization is read
            if (collectionStarted)
            {
                // a complex value is not allowed in an address index parameter
                if (isAddress)
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.CollectionSuffixContinue);
                }

                // reading the rest of the collection initialization
                // and subsequent member initialization, if available
                IStonCollectionInit collectionInit = ReadCollectionInit(reader, true);
                IStonMemberInit     memberInit     = null;
                if (reader.Peek().HasChartype(StonChartype.MemberInitOpen))
                {
                    memberInit = ReadMemberInit(reader);
                }

                return(ElementFactory.CreateComplexEntity(null, memberInit, collectionInit, type, globalIdentifier));
            }

            // reading any valid combination of complex value components (construction, member initialization, collection initialization)
            if (reader.Peek().HasChartype(StonChartype.ConstructionOpen | StonChartype.MemberInitOpen | StonChartype.CollectionInitOpen))
            {
                // a complex value is not allowed in an address index parameter
                if (isAddress)
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.None);
                }

                IStonConstruction   constructor    = null;
                IStonMemberInit     memberInit     = null;
                IStonCollectionInit collectionInit = null;

                if (reader.Peek().HasChartype(StonChartype.ConstructionOpen))
                {
                    constructor = ReadConstruction(reader);
                }
                if (reader.Peek().HasChartype(StonChartype.MemberInitOpen))
                {
                    memberInit = ReadMemberInit(reader);
                }
                if (reader.Peek().HasChartype(StonChartype.CollectionInitOpen))
                {
                    collectionInit = ReadCollectionInit(reader);
                    if (memberInit == null && reader.Peek().HasChartype(StonChartype.MemberInitOpen))
                    {
                        memberInit = ReadMemberInit(reader);
                    }
                }

                return(ElementFactory.CreateComplexEntity(constructor, memberInit, collectionInit, type, globalIdentifier));
            }

            // finding the string, binary or number simple value, if complex value is not present

            // reading a string literal or string literals chain
            if (reader.TryAndSkip(StonChartype.StringChainOpen))
            {
                if (!reader.Peek().HasChartype(StonChartype.TextDelimiter | StonChartype.CodeDelimiter))
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.TextDelimiter | StonChartype.CodeDelimiter);
                }
            }
            if (reader.Peek().HasChartype(StonChartype.TextDelimiter | StonChartype.CodeDelimiter))
            {
                bool isCode = reader.Peek().HasChartype(StonChartype.CodeDelimiter);        // whether the value is a text or a code

                var builder = new StringBuilder();
                reader.ReadString(builder, isCode);
                while (reader.Peek().HasChartype(StonChartype.StringChainContinue))
                {
                    if (reader.ReadAndSkip().HasChartype(StonChartype.StringChainOpen))
                    {
                        builder.Append('\n');
                    }
                    reader.ReadString(builder, isCode);
                }

                return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(isCode ? StonDataType.Code : StonDataType.Text, builder.ToString()), type, globalIdentifier));
            }

            // reading a number of binary value
            bool minus = false;

            // reading the initial sign, if any
            if (reader.Peek().HasChartype(StonChartype.Sign))
            {
                if (reader.ReadAndSkip() == '-')
                {
                    minus = true;
                }
                // a digit must follow the sign
                if (!reader.Peek().HasChartype(StonChartype.Digit))
                {
                    throw reader.MakeUnexpectedCharacterException(StonChartype.Digit);
                }
            }
            // both number and binary literals might begin with a zero (excluding initial sign)
            // whichever it is, is decided by whether the zero is followed by a base identifier or not
            if (reader.TryAndSkip(StonChartype.ZeroDigit))
            {
                if (reader.Peek().HasChartype(StonChartype.BaseIdentifier))
                {
                    return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Binary, reader.ReadBinaryContent(minus)), type, globalIdentifier));
                }
                else
                {
                    return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Number, reader.ReadNumberContent(minus)), type, globalIdentifier));
                }
            }
            // only number literals might begin with a non-zero digit (aside from initial sign)
            else if (reader.Peek().HasChartype(StonChartype.NonZeroDigit))
            {
                return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Number, reader.ReadNumberContent(minus)), type, globalIdentifier));
            }

            // finding the named or null value, if everything else fails

            string value;

            if (reader.Peek().HasChartype(StonChartype.CanunBegin))
            {
                value = ReadCanunPath(reader);
            }
            else if (isTypeFromWord)
            {
                value = (type as IStonNamedType).Name;
                type  = null;
            }
            else
            {
                throw reader.MakeUnexpectedCharacterException(StonChartype.None);       // there is no named value, and thus there's all the reason to panic
            }
            if (value == "null")
            {
                return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Null, null), type, globalIdentifier));
            }
            else
            {
                return(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Named, value), type, globalIdentifier));
            }
        }
Esempio n. 10
0
 /// <summary>
 /// Creates a structurally equivalent construction from a given construction.
 /// </summary>
 /// <param name="construction">The construction to copy the structure of.</param>
 public StonConstruction(IStonConstruction construction)
     : this(construction.PositionalParameters, construction.NamedParameters)
 {
 }