Пример #1
0
        protected override Expression VisitPropertyDefinitionExpression(PropertyDefinitionExpression property)
        {
            var name = property.PropertyName.Uncapitalize();

            fieldDefinitionsForProperties.Add(new FieldDefinitionExpression(name, property.PropertyType, AccessModifiers.Protected));

            var thisProperty = FickleExpression.Variable(property.PropertyType, "this." + name);

            var getterBody = FickleExpression.Block
                             (
                new Expression[] { FickleExpression.Return(thisProperty) }
                             );

            var setterParam = FickleExpression.Parameter(property.PropertyType, name);

            var setterBody = FickleExpression.Block
                             (
                new Expression[] { Expression.Assign(thisProperty, setterParam) }
                             );

            var propertyGetter = new MethodDefinitionExpression("get" + property.PropertyName, new List <Expression>(), AccessModifiers.Public, property.PropertyType, getterBody, false);
            var propertySetter = new MethodDefinitionExpression("set" + property.PropertyName, new List <Expression> {
                setterParam
            }, AccessModifiers.Public, typeof(void), setterBody, false);

            return(new Expression[] { propertyGetter, propertySetter }.ToStatementisedGroupedExpression());
        }
        private Expression CreateScalarPropertiesAsFormEncodedStringMethod(TypeDefinitionExpression expression)
        {
            var self       = Expression.Parameter(expression.Type, "self");
            var properties = ExpressionGatherer.Gather(expression, ServiceExpressionType.PropertyDefinition).Where(c => !(c.Type is FickleListType)).ToList();
            var parameters = properties.OfType <PropertyDefinitionExpression>().ToDictionary(c => c.PropertyName, c => Expression.Property(self, c.PropertyName));
            var path       = string.Join("", properties.OfType <PropertyDefinitionExpression>().Select(c => c.PropertyName + "={" + c.PropertyName + "}"));

            var formatInfo = ObjectiveStringFormatInfo.GetObjectiveStringFormatInfo
                             (
                path,
                c => parameters[c],
                (s, t) => t == typeof(string) ? s : s + "&",
                c => FickleExpression.Call(c, typeof(string), "stringByAppendingString", Expression.Constant("&"))
                             );

            var parameterInfos = new List <ParameterInfo>
            {
                new FickleParameterInfo(typeof(string), "format")
            };

            parameterInfos.AddRange(formatInfo.ParameterExpressions.Select(c => new ObjectiveParameterInfo(c.Type, c.Name, true)));

            var args = new List <Expression>
            {
                Expression.Constant(formatInfo.Format)
            };

            args.AddRange(formatInfo.ValueExpressions);

            var methodInfo = new FickleMethodInfo(typeof(string), typeof(string), "stringWithFormat", parameterInfos.ToArray(), true);
            var methodBody = Expression.Block(FickleExpression.Return(Expression.Call(null, methodInfo, args)).ToStatement());

            return(new MethodDefinitionExpression("scalarPropertiesAsFormEncodedString", new List <Expression>().ToReadOnlyCollection(), typeof(string), methodBody, false, null));
        }
Пример #3
0
        protected virtual Expression CreateToStringMethod()
        {
            var value      = Expression.Parameter(currentTypeDefinition.Type, "value");
            var methodName = currentTypeDefinition.Type.Name.Capitalize() + "ToString";

            var parameters = new Expression[]
            {
                value
            };

            var array = FickleExpression.Variable("NSMutableArray", "array");
            var temp  = FickleExpression.Variable(currentTypeDefinition.Type, "temp");

            var expressions = new List <Expression>
            {
                Expression.Assign(array, Expression.New(array.Type))
            };

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                var currentEnumValue = Expression.Constant((int)enumValue.Value);

                expressions.Add
                (
                    Expression.IfThen
                    (
                        Expression.Equal(Expression.And(currentEnumValue, Expression.Convert(value, typeof(int))), Expression.Convert(currentEnumValue, typeof(int))),
                        FickleExpression.StatementisedGroupedExpression
                        (
                            GroupedExpressionsExpressionStyle.Wide,
                            FickleExpression.Call(array, typeof(void), "addObject", Expression.Constant(enumValue.Name)),
                            Expression.Assign(temp, Expression.Convert(Expression.Or(Expression.Convert(temp, typeof(int)), currentEnumValue), currentTypeDefinition.Type))
                        ).ToBlock()
                    )
                );
            }

            expressions.Add(Expression.IfThen(Expression.NotEqual(value, temp), FickleExpression.Return(FickleExpression.Call(Expression.Convert(value, typeof(object)), typeof(string), "stringValue", null)).ToStatementBlock()));
            expressions.Add(FickleExpression.Return(FickleExpression.Call(array, "componentsJoinedByString", Expression.Constant(","))));

            var defaultBody = FickleExpression.StatementisedGroupedExpression
                              (
                GroupedExpressionsExpressionStyle.Wide,
                expressions.ToArray()
                              );

            var cases = new List <SwitchCase>();

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                cases.Add(Expression.SwitchCase(Expression.Return(Expression.Label(), Expression.Constant(enumValue.Name)).ToStatement(), Expression.Constant((int)enumValue.Value, currentTypeDefinition.Type)));
            }

            var switchStatement = Expression.Switch(value, defaultBody, cases.ToArray());

            var body = FickleExpression.Block(new [] { array, temp }, switchStatement);

            return(new MethodDefinitionExpression(methodName, parameters.ToReadOnlyCollection(), AccessModifiers.Static | AccessModifiers.ClasseslessFunction, typeof(string), body, false, "__unused", null));
        }
Пример #4
0
        private Expression CreateDeserialiseStreamMethod()
        {
            var inputStream = Expression.Parameter(FickleType.Define("InputStream"), "in");

            var jsonReaderType = FickleType.Define("JsonReader");
            var jsonReader     = Expression.Variable(jsonReaderType, "reader");
            var result         = Expression.Variable(currentType, "result");

            var inputStreamReaderNew = FickleExpression.New(FickleType.Define("InputStreamReader"), "InputStreamReader", inputStream);

            var jsonReaderNew        = FickleExpression.New(jsonReaderType, "JsonReader", inputStreamReaderNew);
            var jsonReaderNextString = FickleExpression.Call(jsonReader, "nextString", null);
            var resultCreate         = Expression.Assign(result, FickleExpression.StaticCall(currentType, currentType, "deserialize", jsonReaderNextString)).ToStatement();

            var jsonReaderClose = FickleExpression.Call(jsonReader, "close", null).ToStatement();

            var exception          = Expression.Variable(typeof(Exception), "exception");;
            var errorCodesVariable = Expression.Constant("DeserializationError", typeof(String));

            var returnResult = FickleExpression.Return(result);

            var createErrorArguments = new
            {
                errorCode    = errorCodesVariable,
                errorMessage = FickleExpression.Call(exception, "getMessage", null),
                stackTrace   = FickleExpression.StaticCall(FickleType.Define("Log"), typeof(String), "getStackTraceString", exception),
            };

            var resultCreateErrorResponse = Expression.Assign(result, FickleExpression.StaticCall(currentType, currentType, "createErrorResponse", createErrorArguments)).ToStatement();

            var tryCatch = Expression.TryCatchFinally(
                resultCreate,
                jsonReaderClose,
                Expression.Catch(typeof(Exception), resultCreateErrorResponse));

            var methodVariables = new List <ParameterExpression>
            {
                result,
                jsonReader
            };

            var methodStatements = new List <Expression>
            {
                Expression.Assign(jsonReader, jsonReaderNew).ToStatement(),
                tryCatch,
                returnResult
            };

            var body = FickleExpression.Block(methodVariables.ToArray(), methodStatements.ToArray());

            return(new MethodDefinitionExpression("deserialize", new List <Expression>()
            {
                inputStream
            }, AccessModifiers.Public | AccessModifiers.Static, currentType, body, false, null, null, new List <Exception>()
            {
                new Exception()
            }));
        }
Пример #5
0
        private Expression CreateDeserializeMethod()
        {
            var inputString = Expression.Parameter(typeof(String), "value");

            var methodVariables = new List <ParameterExpression>();

            var methodStatements = new List <Expression>();

            if (codeGenerationContext.Options.SerializeEnumsAsStrings)
            {
                var returnResult = FickleExpression.Return(FickleExpression.StaticCall(currentType, "valueOf", inputString));

                methodStatements.Add(returnResult);
            }
            else
            {
                var intValue = Expression.Variable(typeof(int), "intValue");

                methodVariables.Add(intValue);

                var convertInt = Expression.Assign(intValue, FickleExpression.StaticCall("ConvertUtils", typeof(int), "toint", inputString));

                methodStatements.Add(convertInt);

                Expression ifThenElseExpression = FickleExpression.Block(FickleExpression.Return(Expression.Constant(null)));

                foreach (var enumMemberExpression in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
                {
                    var enumMemberName  = enumMemberExpression.Name;
                    var enumMemberValue = Expression.Variable(typeof(int), enumMemberName + ".value");

                    var enumMemberNameExpression = Expression.Variable(typeof(int), enumMemberName);

                    var condition = Expression.Equal(intValue, enumMemberValue);
                    var action    = FickleExpression.Block(FickleExpression.Return(enumMemberNameExpression));

                    var currentExpression = Expression.IfThenElse(condition, action, ifThenElseExpression);

                    ifThenElseExpression = currentExpression;
                }

                methodStatements.Add(ifThenElseExpression);
            }

            var body = FickleExpression.Block(methodVariables.ToArray(), methodStatements.ToArray());

            return(new MethodDefinitionExpression("deserialize", new List <Expression>()
            {
                inputString
            }, AccessModifiers.Public | AccessModifiers.Static, currentType, body, false, null, null, new List <Exception>()
            {
                new Exception()
            }));
        }
        protected virtual MethodDefinitionExpression CreateParseResultMethod()
        {
            var client      = Expression.Parameter(FickleType.Define("PKWebServiceClient"), "client");
            var data        = Expression.Parameter(FickleType.Define("NSData"), "parseResult");
            var contentType = Expression.Parameter(typeof(string), "withContentType");
            var statusCode  = Expression.Parameter(typeof(int), "andStatusCode");
            var response    = FickleExpression.Variable("id", "response");
            var options     = FickleExpression.Property(client, "NSDictionary", "options");

            var parameters = new Expression[]
            {
                client,
                data,
                contentType,
                statusCode
            };

            var bodyExpressions = new List <Expression>();
            var delegateType    = new FickleDelegateType(FickleType.Define("id"), new FickleParameterInfo(client.Type, "client"), new FickleParameterInfo(FickleType.Define("NSData"), "data"));
            var block           = Expression.Variable(delegateType, "block");

            bodyExpressions.Add(Expression.Assign(block, FickleExpression.Call(options, FickleType.Define("id"), "objectForKey", Expression.Constant("$ParseResultBlock"))));
            bodyExpressions.Add(Expression.Assign(response, FickleExpression.Call(block, "id", "Invoke", new { client, data })).ToStatement());

            var setResponseStatus = Expression.IfThen
                                    (
                Expression.Equal(FickleExpression.Call(response, "id", "responseStatus", null), Expression.Constant(null, FickleType.Define("id"))),
                FickleExpression.Call(response, "setResponseStatus", FickleExpression.New("ResponseStatus", "init", null)).ToStatementBlock()
                                    );

            var populateResponseStatus = FickleExpression.Call(FickleExpression.Call(response, "id", "responseStatus", null), "setHttpStatus", statusCode);

            bodyExpressions.Add(setResponseStatus);
            bodyExpressions.Add(populateResponseStatus);
            bodyExpressions.Add(FickleExpression.Return(response));

            var body = FickleExpression.Block
                       (
                new[] { response, block },
                bodyExpressions.ToArray()
                       );

            return(new MethodDefinitionExpression
                   (
                       "webServiceClient",
                       parameters.ToReadOnlyCollection(),
                       FickleType.Define("id"),
                       body,
                       false,
                       null
                   ));
        }
Пример #7
0
        protected virtual Expression CreateTryParseMethod()
        {
            var value      = Expression.Parameter(typeof(string), "value");
            var methodName = currentTypeDefinition.Type.Name.Capitalize() + "TryParse";
            var result     = Expression.Parameter(currentTypeDefinition.Type.MakeByRefType(), "result");
            var retval     = Expression.Variable(currentTypeDefinition.Type, "retval");

            var parameters = new Expression[]
            {
                value,
                result
            };

            var parts     = Expression.Variable(FickleType.Define("NSArray"), "parts");
            var splitCall = FickleExpression.Call(value, FickleType.Define("NSArray"), "componentsSeparatedByString", new { value = Expression.Constant(",") });
            var part      = Expression.Variable(typeof(string), "part");
            var flagCases = new List <SwitchCase>();
            var number    = Expression.Variable(FickleType.Define("NSNumber"), "number");

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                flagCases.Add(Expression.SwitchCase(Expression.Assign(retval, Expression.Convert(Expression.Or(Expression.Convert(retval, typeof(int)), Expression.Constant((int)enumValue.Value)), currentTypeDefinition.Type)).ToStatement(), Expression.Constant(enumValue.Name)));
            }

            var foreachBody = FickleExpression.StatementisedGroupedExpression
                              (
                Expression.Switch(part, FickleExpression.Return(Expression.Constant(false)).ToStatement(), flagCases.ToArray())
                              ).ToBlock();

            var defaultBody = FickleExpression.StatementisedGroupedExpression
                              (
                GroupedExpressionsExpressionStyle.Wide,
                Expression.Assign(number, FickleExpression.Call(Expression.New(FickleType.Define("NSNumberFormatter")), number.Type, "numberFromString", value)),
                Expression.IfThen
                (
                    Expression.NotEqual(number, Expression.Constant(null, number.Type)),
                    FickleExpression.StatementisedGroupedExpression
                    (
                        GroupedExpressionsExpressionStyle.Wide,
                        Expression.Assign(result, Expression.Convert(FickleExpression.Call(number, typeof(int), "intValue", null), currentTypeDefinition.Type)),
                        Expression.Return(Expression.Label(), Expression.Constant(true))
                    ).ToBlock()
                ),
                Expression.Assign(parts, splitCall),
                Expression.Assign(retval, Expression.Convert(Expression.Constant(0), currentTypeDefinition.Type)),
                FickleExpression.ForEach(part, parts, foreachBody),
                Expression.Assign(result, retval),
                Expression.Return(Expression.Label(), Expression.Constant(true))
                              );

            var cases = new List <SwitchCase>();

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                cases.Add(Expression.SwitchCase(Expression.Assign(result, Expression.Convert(Expression.Constant((int)enumValue.Value), currentTypeDefinition.Type)).ToStatement(), Expression.Constant(enumValue.Name)));
            }

            var switchStatement = Expression.Switch(value, defaultBody, cases.ToArray());

            var body = FickleExpression.Block(new[] { parts, number, retval }, switchStatement, Expression.Return(Expression.Label(), Expression.Constant(true)));

            return(new MethodDefinitionExpression(methodName, parameters.ToReadOnlyCollection(), AccessModifiers.Static | AccessModifiers.ClasseslessFunction, typeof(bool), body, false, "__unused", null));
        }
Пример #8
0
        public CURR Return(string variableName, Type type)
        {
            this.expressions.Add(FickleExpression.Return(Expression.Variable(type, variableName)));

            return((CURR)this);
        }
Пример #9
0
        public CURR Return(Action <ExpressionScope <CURR> > func)
        {
            var block = new ExpressionScope <CURR>((CURR)this, c => this.expressions.Add(FickleExpression.Return(c)));

            func(block);

            block.End();

            return((CURR)this);
        }
Пример #10
0
        public CURR Return(Expression expression)
        {
            this.expressions.Add(FickleExpression.Return(expression));

            return((CURR)this);
        }
        protected Expression CreateGatewayCallMethod(MethodDefinitionExpression method, out ParameterExpression optionsParameter)
        {
            var methodName = method.Name.ToCamelCase();

            methodCount++;

            var self               = Expression.Variable(currentType, "self");
            var hostname           = Expression.Variable(typeof(string), "hostname");
            var port               = Expression.Variable(typeof(string), "port");
            var protocol           = Expression.Variable(typeof(string), "protocol");
            var optionsParam       = FickleExpression.Parameter("NSDictionary", "options");
            var localOptions       = FickleExpression.Variable("NSMutableDictionary", "localOptions");
            var requestObject      = FickleExpression.Variable("NSObject", "requestObject");
            var requestObjectValue = (Expression)Expression.Constant(null, typeof(object));
            var url                 = Expression.Variable(typeof(string), "url");
            var responseType        = ObjectiveBinderHelpers.GetWrappedResponseType(this.CodeGenerationContext, method.ReturnType);
            var variables           = new [] { url, localOptions, protocol, hostname, requestObject, port };
            var declaredHostname    = currentTypeDefinitionExpression.Attributes["Hostname"];
            var declaredPath        = method.Attributes["Path"];
            var path                = StringUriUtils.Combine("%@://%@%@", declaredPath);
            var httpMethod          = method.Attributes["Method"];
            var declaredProtocol    = Convert.ToBoolean(method.Attributes["Secure"]) ? "https" : "http";
            var retryBlockVariable  = Expression.Variable(new FickleDelegateType(typeof(void), new FickleParameterInfo(FickleType.Define("id"), "block")), "retryBlock");
            var retryBlockParameter = Expression.Variable(FickleType.Define("id"), "block");

            var parametersByName = method.Parameters.ToDictionary(c => ((ParameterExpression)c).Name, c => (ParameterExpression)c, StringComparer.InvariantCultureIgnoreCase);

            var formatInfo = ObjectiveStringFormatInfo.GetObjectiveStringFormatInfo(path, c => parametersByName[c]);

            var args       = formatInfo.ValueExpressions;
            var parameters = formatInfo.ParameterExpressions;

            var parameterInfos = new List <FickleParameterInfo>
            {
                new ObjectiveParameterInfo(typeof(string), "s"),
                new ObjectiveParameterInfo(typeof(string), "protocol", true),
                new ObjectiveParameterInfo(typeof(string), "hostname", true),
                new ObjectiveParameterInfo(typeof(string), "port", true),
            };

            parameterInfos.AddRange(parameters.Select(c => new ObjectiveParameterInfo(c.Type, c.Name, true)));

            var methodInfo = new FickleMethodInfo(typeof(string), typeof(string), "stringWithFormat", parameterInfos.ToArray(), true);

            args.InsertRange(0, new Expression[] { Expression.Constant(formatInfo.Format), protocol, hostname, port });

            var newParameters = new List <Expression>(method.Parameters)
            {
                optionsParam
            };
            var callback = Expression.Parameter(new FickleDelegateType(typeof(void), new FickleParameterInfo(responseType, "response")), "callback");

            newParameters.Add(callback);

            Expression blockArg = Expression.Parameter(FickleType.Define("id"), "arg1");

            var returnType = method.ReturnType;

            if (ObjectiveBinderHelpers.NeedsValueResponseWrapper(method.ReturnType))
            {
                returnType = FickleType.Define(ObjectiveBinderHelpers.GetValueResponseWrapperTypeName(method.ReturnType));
            }

            var responseFilter = FickleExpression.Property(self, "FKGatewayResponseFilter", "responseFilter");
            var conversion     = Expression.Convert(blockArg, returnType);

            var innerRetryBlockBody = FickleExpression.Block
                                      (
                FickleExpression.Call(Expression.Convert(retryBlockParameter, retryBlockVariable.Type), typeof(void), "Invoke", new { block = retryBlockParameter }).ToStatement()
                                      );

            var innerRetryBlock = (Expression)FickleExpression.SimpleLambda
                                  (
                typeof(void), innerRetryBlockBody, new Expression[0]
                                  );

            var body = FickleExpression.GroupedWide
                       (
                Expression.IfThen(Expression.NotEqual(responseFilter, Expression.Constant(null, responseFilter.Type)), Expression.Assign(blockArg, FickleExpression.Call(responseFilter, typeof(object), "gateway", new { value = self, receivedResponse = blockArg, fromRequestURL = url, withRequestObject = requestObject, retryBlock = innerRetryBlock, andOptions = localOptions })).ToStatementBlock()),
                Expression.IfThen
                (
                    Expression.AndAlso(Expression.NotEqual(blockArg, Expression.Constant(null, blockArg.Type)), Expression.NotEqual(callback, Expression.Constant(null, callback.Type))),
                    FickleExpression.Call(callback, "Invoke", conversion).ToStatementBlock()
                )
                       );

            var conversionBlock = FickleExpression.SimpleLambda(null, body, new Expression[0], blockArg);

            var error = FickleExpression.Variable("NSError", "error");

            Expression parseResultBlock;

            var nsdataParam = Expression.Parameter(FickleType.Define("NSData"), "data");
            var clientParam = Expression.Parameter(FickleType.Define("PKWebServiceClient"), "client");
            var jsonObjectWithDataParameters = new[] { new FickleParameterInfo(FickleType.Define("NSDictionary"), "obj"), new FickleParameterInfo(typeof(int), "options"), new FickleParameterInfo(FickleType.Define("NSError", true), "error", true) };
            var objectWithDataMethodInfo     = new FickleMethodInfo(FickleType.Define("NSJSONSerialization"), FickleType.Define("NSData"), "JSONObjectWithData", jsonObjectWithDataParameters, true);
            var deserializedValue            = Expression.Parameter(FickleType.Define("id"), "deserializedValue");

            var parseErrorResult = FickleExpression.Call(self, "webServiceClient", new
            {
                clientParam,
                createErrorResponseWithErrorCode = "JsonDeserializationError",
                andMessage = FickleExpression.Call(error, "localizedDescription", null)
            });

            if (method.ReturnType == typeof(void))
            {
                var responseObject = FickleExpression.Variable(responseType, "responseObject");

                parseResultBlock = FickleExpression.SimpleLambda
                                   (
                    FickleType.Define("id"),
                    FickleExpression.GroupedWide
                    (
                        Expression.Assign(responseObject, FickleExpression.New(responseType, "init", null)).ToStatement(),
                        Expression.Assign(deserializedValue, Expression.Call(objectWithDataMethodInfo, nsdataParam, FickleExpression.Variable(typeof(int), "NSJSONReadingAllowFragments"), error)).ToStatement(),
                        Expression.IfThen(Expression.Equal(deserializedValue, Expression.Constant(null)), FickleExpression.Return(parseErrorResult).ToStatementBlock()),
                        FickleExpression.Return(responseObject).ToStatement()
                    ),
                    new Expression[] { deserializedValue, responseObject, error },
                    clientParam, nsdataParam
                                   );
            }
            else if (TypeSystem.IsPrimitiveType(method.ReturnType) || method.ReturnType is FickleListType)
            {
                var responseObject = FickleExpression.Variable(responseType, "responseObject");
                var needToBoxValue = ObjectiveBinderHelpers.ValueResponseValueNeedsBoxing(method.ReturnType);

                parseResultBlock = FickleExpression.SimpleLambda
                                   (
                    FickleType.Define("id"),
                    FickleExpression.GroupedWide
                    (
                        Expression.Assign(responseObject, FickleExpression.New(responseType, "init", null)).ToStatement(),
                        Expression.Assign(deserializedValue, Expression.Call(objectWithDataMethodInfo, nsdataParam, FickleExpression.Variable(typeof(int), "NSJSONReadingAllowFragments"), error)).ToStatement(),
                        Expression.IfThen(Expression.Equal(deserializedValue, Expression.Constant(null)), FickleExpression.Return(parseErrorResult).ToStatementBlock()),
                        PropertiesFromDictionaryExpressonBinder.GetDeserializeExpressionProcessValueDeserializer(method.ReturnType, deserializedValue, c => FickleExpression.Call(responseObject, typeof(void), "setValue", needToBoxValue  ? Expression.Convert(c, typeof(object)) : c).ToStatement()),
                        FickleExpression.Return(responseObject).ToStatement()
                    ),
                    new Expression[] { deserializedValue, responseObject, error },
                    clientParam, nsdataParam
                                   );
            }
            else
            {
                parseResultBlock = FickleExpression.SimpleLambda
                                   (
                    FickleType.Define("id"),
                    FickleExpression.GroupedWide
                    (
                        Expression.Assign(deserializedValue, Expression.Call(objectWithDataMethodInfo, nsdataParam, FickleExpression.Variable(typeof(int), "NSJSONReadingAllowFragments"), error)).ToStatement(),
                        PropertiesFromDictionaryExpressonBinder.GetDeserializeExpressionProcessValueDeserializer(method.ReturnType, deserializedValue, c => FickleExpression.Return(c).ToStatement()),
                        FickleExpression.Return(parseErrorResult).ToStatement()
                    ),
                    new Expression[] { deserializedValue, error },
                    clientParam, nsdataParam
                                   );
            }

            var uniqueNameMaker = new UniqueNameMaker(c => newParameters.Cast <ParameterExpression>().Any(d => d.Name.EqualsIgnoreCaseInvariant(c)));

            var key = FickleExpression.Variable(typeof(string), uniqueNameMaker.Make("key"));

            var integrateOptions = FickleExpression.ForEach
                                   (
                key,
                optionsParam,
                FickleExpression.Call(localOptions, typeof(void), "setObject", new { value = FickleExpression.Call(optionsParam, typeof(object), "objectForKey", key), forKey = key }).ToStatementBlock()
                                   );

            parseResultBlock = FickleExpression.Call(parseResultBlock, parseResultBlock.Type, "copy", null);

            var client = Expression.Variable(FickleType.Define(this.CodeGenerationContext.Options.ServiceClientTypeName ?? "PKWebServiceClient"), "client");

            Expression clientCallExpression;

            if (httpMethod.Equals("get", StringComparison.InvariantCultureIgnoreCase))
            {
                clientCallExpression = FickleExpression.Call(client, "getWithCallback", conversionBlock);
            }
            else
            {
                var contentParameterName = method.Attributes["Content"];
                var contentFormat        = method.Attributes["ContentFormat"];

                if (string.IsNullOrEmpty(contentParameterName))
                {
                    clientCallExpression = FickleExpression.Call(client, "postWithRequestObject", new
                    {
                        requestObject,
                        andCallback = conversionBlock
                    });
                }
                else
                {
                    var content = parametersByName[contentParameterName];

                    requestObjectValue = content.Type == typeof(byte[]) ? (Expression)content : FickleExpression.Call(self, typeof(object), this.GetNormalizeRequestMethodName(content.Type, contentFormat), new { serializeRequest = Expression.Convert(content, typeof(object)), paramName = Expression.Constant(contentParameterName) });

                    clientCallExpression = FickleExpression.Call(client, "postWithRequestObject", new
                    {
                        requestObject,
                        andCallback = conversionBlock
                    });
                }
            }

            var retryBlock = (Expression)FickleExpression.SimpleLambda
                             (
                typeof(void),
                FickleExpression.StatementisedGroupedExpression
                (
                    Expression.Assign(client, FickleExpression.Call(Expression.Variable(currentType, "self"), "PKWebServiceClient", "createClientWithURL", new
            {
                url,
                options = localOptions
            })),
                    Expression.Assign(FickleExpression.Property(client, currentType, "delegate"), self),
                    clientCallExpression
                ),
                new Expression[] { client },
                retryBlockParameter
                             );

            retryBlock = FickleExpression.Call(retryBlock, retryBlock.Type, "copy", null);

            var block = FickleExpression.Block
                        (
                variables.Concat(retryBlockVariable).ToArray(),
                Expression.Assign(requestObject, requestObjectValue),
                Expression.Assign(callback, FickleExpression.Call(callback, callback.Type, "copy", null)),
                Expression.Assign(localOptions, FickleExpression.Call(FickleExpression.Property(self, FickleType.Define("NSDictionary"), "options"), "NSMutableDictionary", "mutableCopyWithZone", new
            {
                zone = Expression.Constant(null, FickleType.Define("NSZone"))
            })),
                Expression.IfThen(Expression.NotEqual(requestObject, Expression.Constant(null)), FickleExpression.Call(localOptions, typeof(void), "setObject", new { value = requestObject, forKey = "$RequestObject" }).ToStatementBlock()),
                FickleExpression.Call(localOptions, typeof(void), "setObject", new { value = FickleExpression.StaticCall(responseType, "class", null), forKey = "$ResponseClass" }).ToStatement(),
                Expression.Assign(hostname, FickleExpression.Call(localOptions, typeof(string), "objectForKey", Expression.Constant("hostname"))),
                Expression.IfThen(Expression.Equal(hostname, Expression.Constant(null)), Expression.Assign(hostname, Expression.Constant(declaredHostname)).ToStatementBlock()),
                Expression.Assign(protocol, FickleExpression.Call(localOptions, typeof(string), "objectForKey", Expression.Constant("protocol"))),
                Expression.IfThen(Expression.Equal(protocol, Expression.Constant(null)), Expression.Assign(protocol, Expression.Constant(declaredProtocol)).ToStatementBlock()),
                Expression.Assign(port, FickleExpression.Call(FickleExpression.Call(localOptions, FickleType.Define("NSNumber"), "objectForKey", Expression.Constant("port")), typeof(string), "stringValue", null)),
                Expression.IfThenElse(Expression.Equal(port, Expression.Constant(null)), Expression.Assign(port, Expression.Constant("")).ToStatementBlock(), Expression.Assign(port, FickleExpression.Call(Expression.Constant(":"), typeof(string), "stringByAppendingString", port)).ToStatementBlock()),
                FickleExpression.Grouped
                (
                    FickleExpression.Call(localOptions, "setObject", new
            {
                obj    = parseResultBlock,
                forKey = "$ParseResultBlock"
            }).ToStatement(),
                    method.ReturnType.GetUnwrappedNullableType() == typeof(bool) ?
                    FickleExpression.Call(localOptions, "setObject", new
            {
                obj = Expression.Convert(Expression.Constant(1), typeof(object))
            }).ToStatement() : null
                ),
                Expression.Assign(url, Expression.Call(null, methodInfo, args)),
                FickleExpression.Call(localOptions, typeof(void), "setObject", new { value = url, forKey = "$RequestURL" }).ToStatement(),
                integrateOptions,
                Expression.Assign(retryBlockVariable, retryBlock),
                FickleExpression.Call(retryBlockVariable, typeof(void), "Invoke", retryBlockVariable).ToStatement()
                        );

            optionsParameter = optionsParam;

            return(new MethodDefinitionExpression(methodName, newParameters.ToReadOnlyCollection(), typeof(void), block, false, null));
        }
        protected virtual MethodDefinitionExpression CreateNormalizeRequestObjectMethod(Type forType, string format)
        {
            var requestObject = Expression.Parameter(FickleType.Define("id"), "serializeRequest");
            var paramName     = Expression.Parameter(typeof(string), "paramName");
            var newArray      = FickleExpression.Variable("NSMutableArray", "newArray");
            var name          = this.GetNormalizeRequestMethodName(forType, format);
            var value         = FickleExpression.Variable("id", "value");
            var item          = Expression.Variable(FickleType.Define("id"), "item");
            var formatIsForm  = format == "form";

            var complexType = ((forType as FickleType)?.ServiceClass != null);

            Expression processing;

            if (forType == typeof(TimeSpan))
            {
                processing = FickleExpression.Call(Expression.Convert(item, typeof(TimeSpan)), typeof(string), "ToString", null);
            }
            else if (forType == typeof(Guid))
            {
                processing = FickleExpression.Call(Expression.Convert(item, typeof(Guid)), typeof(string), "ToString", null);
            }
            else if (forType.IsEnum)
            {
                processing = Expression.Convert(FickleExpression.Call(item, typeof(int), "intValue", null), forType);

                if (this.CodeGenerationContext.Options.SerializeEnumsAsStrings)
                {
                    processing = FickleExpression.StaticCall((Type)null, typeof(string), forType.Name + "ToString", processing);
                }
                else
                {
                    processing = Expression.Convert(processing, typeof(object));
                }
            }
            else if (forType == typeof(bool))
            {
                processing = Expression.Condition
                             (
                    Expression.Equal(FickleExpression.Call(item, typeof(bool), "boolValue", null), Expression.Constant(true)),
                    Expression.Constant("true"),
                    Expression.Constant("false")
                             );
            }
            else if (forType.IsNumericType())
            {
                processing = Expression.Convert(item, FickleType.Define("NSNumber"));

                if (formatIsForm)
                {
                    processing = FickleExpression.Call(processing, "stringValue", null);
                }
            }
            else
            {
                if (formatIsForm)
                {
                    processing = FickleExpression.Call(item, "NSDictionary", "scalarPropertiesAsFormEncodedString", null);
                }
                else
                {
                    processing = FickleExpression.Call(item, "NSString", "allPropertiesAsDictionary", null);
                }
            }

            var isArray         = Expression.Variable(typeof(bool), "isArray");
            var array           = Expression.Variable(FickleType.Define("NSArray"), "array");
            var urlEncodedValue = ObjectiveExpression.ToUrlEncodedExpression(processing);
            var joined          = FickleExpression.Call(newArray, typeof(string), "componentsJoinedByString", Expression.Constant("&"));

            if (formatIsForm && !complexType)
            {
                processing = FickleExpression.Call(FickleExpression.Call(paramName, "stringByAppendingString", Expression.Constant("=")), typeof(string), "stringByAppendingString", urlEncodedValue);
            }

            var arrayProcessing = processing;

            if (formatIsForm)
            {
                arrayProcessing = FickleExpression.Call(FickleExpression.Call(paramName, "stringByAppendingString", Expression.Constant("=")), typeof(string), "stringByAppendingString", urlEncodedValue);
            }

            processing = Expression.IfThenElse
                         (
                isArray,
                FickleExpression.Block
                (
                    new [] { newArray },
                    Expression.Assign(array, requestObject),
                    Expression.Assign(newArray, FickleExpression.New("NSMutableArray", "initWithCapacity", FickleExpression.Call(array, typeof(int), "count", null))),
                    FickleExpression.ForEach
                    (
                        item,
                        array,
                        FickleExpression.Call(newArray, typeof(void), "addObject", arrayProcessing).ToStatementBlock()
                    ),
                    Expression.Assign(value, formatIsForm ? joined : (Expression)newArray),
                    FickleExpression.Return(value)
                ),
                FickleExpression.Block
                (
                    new [] { item },
                    Expression.Assign(item, requestObject),
                    Expression.Assign(value, processing),
                    FickleExpression.Return(value)
                )
                         );

            var body = FickleExpression.Block
                       (
                new[] { array, isArray, value },
                Expression.Assign(isArray, Expression.TypeIs(requestObject, typeof(Array))),
                processing
                       );

            return(new MethodDefinitionExpression
                   (
                       name,
                       new[] { requestObject, paramName }.ToReadOnlyCollection(),
                       FickleType.Define("id"),
                       body,
                       false,
                       null
                   ));
        }
        protected override Expression VisitMethodDefinitionExpression(MethodDefinitionExpression method)
        {
            var client = Expression.Variable(this.fickleApiClientType, FickleApiClientFieldName);

            var apiCallGenericTypes = new List <Type>();

            var returnTaskType = FickleType.Define("Task");

            if (method.ReturnType != typeof(void))
            {
                returnTaskType.MakeGenericType(method.ReturnType);
            }

            var methodParameters = new List <Expression>(method.Parameters);
            var methodVariables  = new List <ParameterExpression>();
            var methodStatements = new List <Expression>();

            var requestUrl = Expression.Variable(typeof(InterpolatedString), "fickleRequestUrl");

            methodVariables.Add(requestUrl);
            methodStatements.Add(Expression.Assign(requestUrl, Expression.Constant(new InterpolatedString(method.Attributes["Path"]))));

            var httpMethod      = Expression.Constant(method.Attributes["Method"]);
            var isSecure        = Expression.Constant(method.Attributes["Secure"] == "True");
            var isAuthenticated = Expression.Constant(method.Attributes["Authenticated"] == "True");
            var returnFormat    = Expression.Constant(method.Attributes["ReturnFormat"]);



            if (method.ReturnType != typeof(void))
            {
                apiCallGenericTypes.Add(method.ReturnType);
            }

            object apiArgs;

            var contentParameterName = method.Attributes["Content"];

            if (!string.IsNullOrEmpty(contentParameterName))
            {
                var contentParam = method.Parameters.FirstOrDefault(x => ((ParameterExpression)x).Name.Equals(contentParameterName, StringComparison.InvariantCultureIgnoreCase));

                if (contentParam == null)
                {
                    throw new Exception("Content paramter not found");
                }

                apiCallGenericTypes.Add(contentParam.Type);

                apiArgs = new
                {
                    requestUrl,
                    httpMethod,
                    isSecure,
                    isAuthenticated,
                    returnFormat,
                    contentParam
                };
            }
            else
            {
                apiArgs = new
                {
                    requestUrl,
                    httpMethod,
                    isSecure,
                    isAuthenticated,
                    returnFormat
                };
            }

            var clientCall = FickleExpression.Call(client, returnTaskType, "ExecuteAsync", apiArgs);

            if (apiCallGenericTypes.Count > 0)
            {
                clientCall.Method.MakeGenericMethod(apiCallGenericTypes.ToArray());
            }

            var result = Expression.Variable(returnTaskType, "fickleResult");

            methodVariables.Add(result);

            methodStatements.Add(Expression.Assign(result, clientCall));
            methodStatements.Add(FickleExpression.Return(result));

            var methodBody = FickleExpression.Block
                             (
                methodVariables.ToArray(),
                methodStatements.ToArray()
                             );

            return(new MethodDefinitionExpression(method.Name, methodParameters.ToReadOnlyCollection(), AccessModifiers.Public, returnTaskType, methodBody, false, null));
        }