public bool TryUnwrapJsniExpression(IMethodSymbol method, ExpressionSyntax originalTarget, ExpressionSyntax[] originalArguments, JsExpression target, JsExpression[] arguments, out JsExpression result) { // Special compiler handler of Jsni -- these are special methods that translate into otherwise inexpressible javascript if (Equals(method.ContainingType, Context.Instance.JsniType)) { if (method.ReducedFrom != null && !Equals(method.ReducedFrom, method)) { method = method.ReducedFrom; arguments = new[] { target }.Concat(arguments).ToArray(); originalArguments = new[] { originalTarget }.Concat(originalArguments).ToArray(); } switch (method.Name) { case "apply": { if (method.TypeArguments.Any()) { // First argument is an Action -- we want to deconstruct it to extract the target and method name. var body = originalArguments[0].GetBody(); var lambdaInvocation = (InvocationExpressionSyntax)body; var lambdaMethod = (IMethodSymbol)ModelExtensions.GetSymbolInfo(transformer.model, lambdaInvocation).Symbol; result = Type(lambdaMethod.ContainingType).Member("prototype").Member(lambdaMethod.GetMemberName()).Member("apply").Invoke(arguments[1], arguments[2]); return true; } else { result = arguments[0].Member("apply").Invoke(arguments[1], arguments[2]); return true; } } case "call": { if (method.TypeArguments.Any()) { // First argument is an Action -- we want to deconstruct it to extract the target and method name. var body = originalArguments[0].GetBody(); var lambdaInvocation = (InvocationExpressionSyntax)body; var lambdaMethod = (IMethodSymbol)ModelExtensions.GetSymbolInfo(transformer.model, lambdaInvocation).Symbol; result = Type(lambdaMethod.ContainingType).Member("prototype").Member(lambdaMethod.GetMemberName()).Member("call").Invoke(arguments.Skip(1).ToArray()); return true; } else { // First argument is an Action -- we want to deconstruct it to extract the target and method name. result = arguments[0].Member("call").Invoke(arguments.Skip(1).ToArray()); return true; } } case "type": result = method.TypeArguments.Any() ? Type(method.TypeArguments.Single()) : ((JsMemberReferenceExpression)((JsInvocationExpression)arguments[0]).Target).Target; return true; case "new": case "@new": result = Js.New(arguments[0].Parenthetical(), arguments.Skip(1).ToArray()); return true; case "array": result = Js.Array(arguments); return true; case "invoke": result = arguments[0].Invoke(arguments.Skip(1).ToArray()); return true; case "memberset": { var memberName = GetConstantString(originalArguments[1]); result = arguments[0].Member(memberName).Assign(arguments[2]); return true; } case "member": { var memberName = GetConstantString(originalArguments[1]); result = arguments[0].Member(memberName); return true; } case "function": case "procedure": var nameArguments = originalArguments.Skip(1).ToArray(); var nameOverrides = nameArguments.Select(x => GetConstantString(x)).ToArray(); var lambda = originalArguments[0]; var lambdaSymbol = (IMethodSymbol)transformer.model.GetSymbolInfo(lambda).Symbol; var lambdaParameters = lambda.GetParameters(); var jsParameters = lambdaParameters.Select(x => Js.Parameter(x.Identifier.ToString())).Cast<IJsDeclaration>().ToArray(); for (var i = 0; i < nameOverrides.Length; i++) { jsParameters[i] = new WrappedParent(jsParameters[i]) { Name = nameOverrides[i] }; } for (var i = 0; i < jsParameters.Length; i++) { var parameter = jsParameters[i]; var symbol = lambdaSymbol.Parameters[i]; transformer.DeclareInCurrentScope(symbol, parameter); } var jsBody = new JsBlockStatement(); transformer.PushOutput(jsBody); var lambdaBody = lambda.GetBody(); var lambdaNode = lambdaBody.Accept(transformer); JsStatement lambdaStatement; if (lambdaNode is JsExpression) { switch (method.Name) { case "function": lambdaStatement = ((JsExpression)lambdaNode).Return(); break; default: lambdaStatement = ((JsExpression)lambdaNode).Express(); break; } } else { lambdaStatement = (JsStatement)lambdaNode; } result = Js.Function(jsParameters).Body(lambdaStatement); transformer.PopOutput(); return true; case "arguments": result = Js.Reference("arguments"); return true; case "this": case "@this": result = Js.This(); return true; case "delete": var deleteTarget = arguments[0]; result = deleteTarget.Delete(); return true; case "_typeof": var typeofTarget = arguments[0]; result = Js.TypeOf(typeofTarget); return true; case "reference": result = Js.Reference(GetConstantString(originalArguments[0])); return true; case "parseInt": result = Js.Reference("parseInt").Invoke(arguments); return true; case "parseFloat": result = Js.Reference("parseFloat").Invoke(arguments); return true; case "encodeURIComponent": result = Js.Reference("encodeURIComponent").Invoke(arguments); return true; case "decodeURIComponent": result = Js.Reference("decodeURIComponent").Invoke(arguments); return true; case "getComputedStyle": result = Js.Reference("getComputedStyle").Invoke(arguments); return true; case "isNaN": result = Js.Reference("isNaN").Invoke(arguments); return true; case "instanceof": result = Js.InstanceOf(arguments[0], arguments[1]).Parenthetical(); return true; case "object": // Deconstruct the object passed in into a JS object var obj = (AnonymousObjectCreationExpressionSyntax)originalArguments[0]; result = Js.Object( obj.Initializers.Select(x => Js.Item( x.NameEquals.Name.ToString(), (JsExpression)x.Expression.Accept(transformer) )).ToArray() ); if (arguments.Length > 1 && originalArguments[1].IsTrue()) { result = result.Compact(); } return true; case "regex": result = new JsRegexExpression(GetConstantString(originalArguments[0])); if (originalArguments.Length > 1) ((JsRegexExpression)result).Suffix = GetConstantString(originalArguments[1]); return true; case "in": result = arguments[0].In(arguments[1]); return true; case "setTimeout": result = Js.Reference("setTimeout").Invoke(arguments[0], arguments[1]); return true; case "setInterval": result = Js.Reference("setInterval").Invoke(arguments[0], arguments[1]); return true; case "clearTimeout": result = Js.Reference("clearTimeout").Invoke(arguments[0]); return true; case "clearInterval": result = Js.Reference("clearInterval").Invoke(arguments[0]); return true; case "code": result = new JsNativeExpression(GetConstantString(originalArguments[0])); return true; } } result = null; return false; }