// Parses a type specification, returns true and sets 'type' on success. public static bool TryParse(DTypeSpecLexer lexer, out DType type) { Contracts.AssertValue(lexer); Contracts.Assert(_typeEncodings.Length == _types.Length); Contracts.Assert(_typeEncodings.ToCharArray().Zip(_types, (c, t) => DType.MapKindToStr(t.Kind) == c.ToString()).All(x => x)); string token; if (!lexer.TryNextToken(out token) || token.Length != 1) { type = DType.Invalid; return(false); } // Older documents may use an "a" type, which for legacy reasons is a duplicate of "o" type. if (token == DType.MapKindToStr(DKind.LegacyBlob)) { token = DType.MapKindToStr(DKind.Blob); } // Note that control types "v" or "E" are parsed to Error, since the type spec language is not a mechanism for serializing/deserializing controls. if (token == DType.MapKindToStr(DKind.Control) || token == DType.MapKindToStr(DKind.DataEntity)) { type = DType.Error; return(true); } int typeIdx = _typeEncodings.IndexOf(token); if (typeIdx < 0) { type = DType.Invalid; return(false); } Contracts.AssertIndex(typeIdx, _types.Length); DType result = _types[typeIdx]; if (result == DType.ObjNull) { // For null value type = result; return(true); } if (!result.IsAggregate) { if (result.IsEnum) { DType enumSupertype; ValueTree valueMap; if (!TryParse(lexer, out enumSupertype) || (!enumSupertype.IsPrimitive && !enumSupertype.IsUnknown) || !TryParseValueMap(lexer, out valueMap)) { type = DType.Invalid; return(false); } // For enums type = new DType(enumSupertype.Kind, valueMap); return(true); } // For non-enums, non-aggregates type = result; return(true); } Contracts.Assert(result.IsRecord || result.IsTable); TypeTree typeMap; if (!TryParseTypeMap(lexer, out typeMap)) { type = DType.Invalid; return(false); } type = new DType(result.Kind, typeMap); return(true); }