Пример #1
0
        /// <summary>
        /// If a call/newobj requires translating to an Expr that is not a call/newobj, then it is done here.
        /// </summary>
        /// <param name="call"></param>
        /// <returns></returns>
        public static Expr ResolveCallSite(ICall call)
        {
            var ctx      = call.Ctx;
            var mRef     = call.CallMethod;
            var tRefDecl = mRef.DeclaringType;
            var mDef     = mRef.Resolve();
            // A call to a method in a "JsClass" class - all external methods/properties require translating to JS
            var tDefDecl    = mDef.DeclaringType;
            var jsClassAttr = tDefDecl.GetCustomAttribute <JsClassAttribute>() ?? tDefDecl.GetCustomAttribute <JsAbstractClassAttribute>();

            if (jsClassAttr != null)
            {
                if (mDef.IsExternal())
                {
                    var jsDetail               = mDef.GetCustomAttribute <JsDetailAttribute>(true);
                    var jsDetailName           = jsDetail.NullThru(x => (string)x.Properties.FirstOrDefault(y => y.Name == "Name").Argument.Value);
                    var jsDetailIsDomEventProp = jsDetail.NullThru(x => ((bool?)x.Properties.FirstOrDefault(y => y.Name == "IsDomEvent").Argument.Value) ?? false);
                    if (mDef.IsGetter || mDef.IsSetter)
                    {
                        // Property access
                        if (jsDetailIsDomEventProp)
                        {
                            // Special handling of DOM events
                            if (!mDef.IsSetter)
                            {
                                throw new InvalidOperationException("Only setters supported on DOM events");
                            }
                            if (!mDef.Name.StartsWith("set_On"))
                            {
                                throw new InvalidOperationException("DOM event name must start with 'On'");
                            }
                            if (call.Args.Count() != 1)
                            {
                                throw new InvalidOperationException("DOM event setter must have exactly one argument");
                            }
                            var eventName        = jsDetailName ?? mDef.Name.Substring(6).ToLowerInvariant();
                            var eventNameExpr    = ctx.Literal(eventName);
                            var safeCallFunction = (Action <object, string, Delegate>)InternalFunctions.SafeAddEventListener;
                            var safeCall         = new ExprCall(ctx, safeCallFunction, null, call.Obj, eventNameExpr, call.Args.First());
                            return(safeCall);
                        }
                        else
                        {
                            var propertyName = jsDetailName ?? JsCase(mDef.Name.Substring(4));
                            if (mDef.Name.Substring(4) == "Item")
                            {
                                propertyName = null;
                            }
                            else if (mDef.IsStatic)
                            {
                                propertyName = JsCase(mDef.DeclaringType.Name) + "." + propertyName;
                            }
                            var jsProperty = new ExprJsResolvedProperty(ctx, call, propertyName);
                            return(jsProperty);
                        }
                    }
                    else if (mDef.IsConstructor && !mDef.IsStatic)
                    {
                        // Constructor new object call
                        var typeName = jsDetailName ?? (string)jsClassAttr.ConstructorArguments[0].Value;
                        var expr     = new ExprJsResolvedCtor(ctx, typeName, tRefDecl, call.Args);
                        return(expr);
                    }
                    else
                    {
                        // Normal method call
                        var methodName = jsDetailName ?? JsCase(mDef.Name);
                        if (mDef.IsStatic)
                        {
                            methodName = JsCase(mDef.DeclaringType.Name) + "." + methodName;
                        }
                        var expr = new ExprJsResolvedMethod(ctx, call.Type, call.Obj, methodName, call.Args);
                        return(expr);
                    }
                }
                else
                {
                    return(null);
                }
            }
            var jsRedirectAttr = mDef.GetCustomAttribute <JsRedirectAttribute>(true);

            if (jsRedirectAttr != null)
            {
                if (jsRedirectAttr.ConstructorArguments[0].Value == null)
                {
                    return(FindExprReturn(call, call.CallMethod.DeclaringType));
                }
                var redirectToTRef = ((TypeReference)jsRedirectAttr.ConstructorArguments[0].Value).FullResolve(mRef);
                var redirectToMRef = redirectToTRef.EnumResolvedMethods(mRef).First(x => x.MatchMethodOnly(mRef));
                switch (call.ExprType)
                {
                case Expr.NodeType.NewObj:
                    return(new ExprNewObj(ctx, redirectToMRef, call.Args));

                case Expr.NodeType.Call:
                    return(new ExprCall(ctx, redirectToMRef, call.Obj, call.Args, call.IsVirtualCall, null, call.Type));

                default:
                    throw new NotImplementedException("Cannot handle: " + call.ExprType);
                }
            }
            var exprRet = FindExprReturn(call);

            if (exprRet != null)
            {
                return(exprRet);
            }
            return(null);
        }
Пример #2
0
 protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e)
 {
     this.code.Append(e.PropertyName);
     return(e);
 }