Exemplo n.º 1
0
        // 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);
        }