Пример #1
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));
            }
        }