private void HandleMappingWithAllLooseProperties( DefinitionInfo mappingDefinition, DefinitionInfo keyDefinition, DefinitionInfo valueDefinition, MappingToken mapping) { TemplateToken nextValue; var keys = new HashSet <String>(StringComparer.OrdinalIgnoreCase); while (m_objectReader.AllowLiteral(out LiteralToken rawLiteral)) { var nextKeyScalar = ParseScalar(rawLiteral, mappingDefinition.AllowedContext); // Expression if (nextKeyScalar is ExpressionToken) { // Legal if (mappingDefinition.AllowedContext.Length > 0) { m_memory.AddBytes(nextKeyScalar); nextValue = ReadValue(valueDefinition); mapping.Add(nextKeyScalar, nextValue); } // Illegal else { m_context.Error(nextKeyScalar, TemplateStrings.ExpressionNotAllowed()); SkipValue(); } continue; } // Not a string, convert if (!(nextKeyScalar is StringToken nextKey)) { nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString()); } // Duplicate if (!keys.Add(nextKey.Value)) { m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value)); SkipValue(); continue; } // Validate Validate(nextKey, keyDefinition); m_memory.AddBytes(nextKey); // Add the pair nextValue = ReadValue(valueDefinition); mapping.Add(nextKey, nextValue); } ExpectMappingEnd(); }
private void Validate( ref ScalarToken scalar, DefinitionInfo definition) { switch (scalar.Type) { case TokenType.Null: case TokenType.Boolean: case TokenType.Number: case TokenType.String: var literal = scalar as LiteralToken; // Legal if (definition.Get <ScalarDefinition>().Any(x => x.IsMatch(literal))) { return; } // Not a string, convert if (literal.Type != TokenType.String) { literal = new StringToken(literal.FileId, literal.Line, literal.Column, literal.ToString()); // Legal if (definition.Get <StringDefinition>().Any(x => x.IsMatch(literal))) { scalar = literal; return; } } // Illegal m_context.Error(literal, TemplateStrings.UnexpectedValue(literal)); break; case TokenType.BasicExpression: // Illegal if (definition.AllowedContext.Length == 0) { m_context.Error(scalar, TemplateStrings.ExpressionNotAllowed()); } break; default: m_context.Error(scalar, TemplateStrings.UnexpectedValue(scalar)); break; } }
private void HandleMappingWithWellKnownProperties( DefinitionInfo definition, List <MappingDefinition> mappingDefinitions, MappingToken mapping) { // Check if loose properties are allowed String looseKeyType = null; String looseValueType = null; DefinitionInfo?looseKeyDefinition = null; DefinitionInfo?looseValueDefinition = null; if (!String.IsNullOrEmpty(mappingDefinitions[0].LooseKeyType)) { looseKeyType = mappingDefinitions[0].LooseKeyType; looseValueType = mappingDefinitions[0].LooseValueType; } var keys = new HashSet <String>(StringComparer.OrdinalIgnoreCase); var hasExpressionKey = false; while (m_objectReader.AllowLiteral(out LiteralToken rawLiteral)) { var nextKeyScalar = ParseScalar(rawLiteral, definition.AllowedContext); // Expression if (nextKeyScalar is ExpressionToken) { hasExpressionKey = true; // Legal if (definition.AllowedContext.Length > 0) { m_memory.AddBytes(nextKeyScalar); var anyDefinition = new DefinitionInfo(definition, TemplateConstants.Any); mapping.Add(nextKeyScalar, ReadValue(anyDefinition)); } // Illegal else { m_context.Error(nextKeyScalar, TemplateStrings.ExpressionNotAllowed()); SkipValue(); } continue; } // Not a string, convert if (!(nextKeyScalar is StringToken nextKey)) { nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString()); } // Duplicate if (!keys.Add(nextKey.Value)) { m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value)); SkipValue(); continue; } // Well known if (m_schema.TryMatchKey(mappingDefinitions, nextKey.Value, out String nextValueType)) { m_memory.AddBytes(nextKey); var nextValueDefinition = new DefinitionInfo(definition, nextValueType); var nextValue = ReadValue(nextValueDefinition); mapping.Add(nextKey, nextValue); continue; } // Loose if (looseKeyType != null) { if (looseKeyDefinition == null) { looseKeyDefinition = new DefinitionInfo(definition, looseKeyType); looseValueDefinition = new DefinitionInfo(definition, looseValueType); } Validate(nextKey, looseKeyDefinition.Value); m_memory.AddBytes(nextKey); var nextValue = ReadValue(looseValueDefinition.Value); mapping.Add(nextKey, nextValue); continue; } // Error m_context.Error(nextKey, TemplateStrings.UnexpectedValue(nextKey.Value)); SkipValue(); } // Only one if (mappingDefinitions.Count > 1) { var hitCount = new Dictionary <String, Int32>(); foreach (MappingDefinition mapdef in mappingDefinitions) { foreach (String key in mapdef.Properties.Keys) { if (!hitCount.TryGetValue(key, out Int32 value)) { hitCount.Add(key, 1); } else { hitCount[key] = value + 1; } } } List <String> nonDuplicates = new List <String>(); foreach (String key in hitCount.Keys) { if (hitCount[key] == 1) { nonDuplicates.Add(key); } } nonDuplicates.Sort(); String listToDeDuplicate = String.Join(", ", nonDuplicates); m_context.Error(mapping, TemplateStrings.UnableToDetermineOneOf(listToDeDuplicate)); } else if (mappingDefinitions.Count == 1 && !hasExpressionKey) { foreach (var property in mappingDefinitions[0].Properties) { if (property.Value.Required) { if (!keys.Contains(property.Key)) { m_context.Error(mapping, $"Required property is missing: {property.Key}"); } } } } ExpectMappingEnd(); }