// reads a construction component of a complex value private IStonConstruction ReadConstruction(StonTokenReader reader) { reader.ExpectAndSkip(StonChartype.ConstructionOpen); var positionalParameters = new List <IStonEntity>(); var namedParameters = new List <KeyValuePair <string, IStonEntity> >(); while (!reader.TryAndSkip(StonChartype.ConstructionClose)) { // trying to read a positional parameter, or the first named parameter if (namedParameters.Count == 0) { // value prompt right at the beginning clearly indicates a positional parameter if (reader.TryAndSkip(StonChartype.ValuePrompt)) { positionalParameters.Add(ReadEntity(reader)); } // string literal might be an entity or a named parameter name else if (reader.Peek().HasChartype(StonChartype.TextDelimiter)) { var builder = new StringBuilder(); reader.ReadString(builder, false); // if it's a single string literal followed by a value prompt, it means it is the first named parameter if (reader.TryAndSkip(StonChartype.ValuePrompt)) { namedParameters.Add(new KeyValuePair <string, IStonEntity>(builder.ToString(), ReadEntity(reader))); } // if no value prompt follows, it is assumed to be a string-valued entity else { while (reader.Peek().HasChartype(StonChartype.StringChainContinue)) { if (reader.ReadAndSkip().HasChartype(StonChartype.StringChainOpen)) { builder.Append('\n'); } reader.ReadString(builder, false); } positionalParameters.Add(ElementFactory.CreateSimpleEntity(ElementFactory.CreateSimpleValue(StonDataType.Text, builder.ToString()))); } } else { var entity = ReadEntity(reader); if (reader.Peek().HasChartype(StonChartype.ValuePrompt)) { // if value prompt follows after the read entity, it means the read entity must be a typeless, non-identified CANUN named value // serving as the parameter name if (!(entity is IStonSimpleEntity)) { throw reader.MakeUnexpectedCharacterException(StonChartype.SequenceSeparator | StonChartype.ConstructionClose); } var simpleEntity = entity as IStonSimpleEntity; if (simpleEntity.GlobalIdentifier != null || simpleEntity.Type != null || simpleEntity.Value.DataType != StonDataType.Named || simpleEntity.Value.Content.Contains('.')) { throw reader.MakeUnexpectedCharacterException(StonChartype.SequenceSeparator | StonChartype.ConstructionClose); } reader.ReadAndSkip(); namedParameters.Add(new KeyValuePair <string, IStonEntity>(simpleEntity.Value.Content, ReadEntity(reader))); } else { positionalParameters.Add(entity); } } } // reading remaining named parameters else { string name; if (reader.Peek().HasChartype(StonChartype.TextDelimiter)) { name = reader.ReadString(); } else if (reader.Peek().HasChartype(StonChartype.CanunBegin)) { name = reader.ReadCanun(); } else { throw reader.MakeUnexpectedCharacterException(StonChartype.TextDelimiter | StonChartype.CanunBegin); } reader.ExpectAndSkip(StonChartype.ValuePrompt); IStonEntity value = ReadEntity(reader); namedParameters.Add(new KeyValuePair <string, IStonEntity>(name, value)); } if (reader.TryAndSkip(StonChartype.SequenceSeparator)) { continue; } else if (!reader.Peek().HasChartype(StonChartype.ConstructionClose)) { throw reader.MakeUnexpectedCharacterException(StonChartype.SequenceSeparator | StonChartype.ConstructionClose); } } return(ElementFactory.CreateConstruction(positionalParameters, namedParameters)); }