Expression FromJSValue(AstType type, Expression expression)
        {
            var      primitiveType = type as PrimitiveType;
            TypeData enumType;

            if (Types.TryGetType(type.ToString(), out enumType) && enumType.IsEnum)
            {
                primitiveType = enumType.DeclaredType.BaseType as PrimitiveType;
            }
            else
            {
                enumType = null;
            }

            string toMethod;

            switch (primitiveType?.Keyword)
            {
            case "string":
                toMethod = "ToNullableString";
                break;

            case "int":
                toMethod = "ToInt32";
                break;

            case "uint":
            case "ushort":
                toMethod = "ToUInt32";
                break;

            case "bool":
                toMethod = "ToBool";
                break;

            case "double":
                toMethod = "ToDouble";
                break;

            default:
                if (primitiveType != null)
                {
                    throw new Exception($"unsupported primitive type: {primitiveType}");
                }

                return(new IdentifierExpression("Wrap")
                {
                    TypeArguments = { type.Clone() }
                }.Invoke(expression));
            }

            expression = new InvocationExpression(new MemberReferenceExpression(expression, toMethod));
            return(enumType != null?expression.CastTo(type.Clone()) : expression);
        }