// 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)); } }