protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { if (e.Call.CallMethod != null) { var ctx = e.Ctx; var mDef = e.Call.CallMethod.Resolve(); if (mDef.IsSetter) { var tRef = e.Call.CallMethod.Parameters.Last().ParameterType; var tDef = tRef.Resolve(); var attr = tDef.GetCustomAttribute<JsStringEnumAttribute>(); if (attr != null) { var prop = new ExprJsResolvedProperty(ctx, new FakeCall(e.Call), e.PropertyName).Named("prop"); var type = new ExprJsTypeVarName(ctx, tRef).Named("type"); var enumStringMap = new ExprJsTypeData(ctx, TypeData.EnumStringMap).Named("enumStringMap"); var value = e.Call.Args.Last().Named("value"); var js = "prop = type.enumStringMap[value]"; var expr = new ExprJsExplicit(ctx, js, e.Type, type, enumStringMap, value, prop); return expr; } } else { var tDef = e.Type.Resolve(); var attr = tDef.GetCustomAttribute<JsStringEnumAttribute>(); if (attr != null) { var prop = new ExprJsResolvedProperty(ctx, new FakeCall(e.Call), e.PropertyName).Named("prop"); var type = new ExprJsTypeVarName(ctx, e.Type).Named("type"); var enumStringMap = new ExprJsTypeData(ctx, TypeData.EnumStringMap).Named("enumStringMap"); var js = "type.enumStringMap[prop]"; var expr = new ExprJsExplicit(ctx, js, e.Type, prop, type, enumStringMap); return expr; } } } return base.VisitJsResolvedProperty(e); }
protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { if (e.PropertyName == null) { // Indexer this.Visit(e.Call.Obj); this.js.Append("["); this.Visit(e.Call.Args.First()); this.js.Append("]"); } else { // Normal attribute/property if (e.Call.Obj != null) { this.Visit(e.Call.Obj); this.js.Append("."); } this.js.Append(e.PropertyName); } if (e.Call.CallMethod != null && e.Call.CallMethod.Resolve().IsSetter) { this.js.Append(" = "); this.Visit(e.Call.Args.Last()); } return(e); }
protected virtual ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { this.ThrowOnNoOverride(); var call = this.HandleCall(e.Call, (obj, args) => new DupCall { ExprType = e.Call.ExprType, CallMethod = e.Call.CallMethod, IsVirtualCall = e.Call.IsVirtualCall, Obj = obj, Args = args, Type = e.Call.Type, Ctx = e.Call.Ctx, }); if (call != e.Call) { return(new ExprJsResolvedProperty(e.Ctx, call, e.PropertyName)); } else { return(e); } }
protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { if (e.Call.CallMethod != null) { var ctx = e.Ctx; var mDef = e.Call.CallMethod.Resolve(); if (mDef.IsSetter) { var tRef = e.Call.CallMethod.Parameters.Last().ParameterType; var tDef = tRef.Resolve(); var attr = tDef.GetCustomAttribute <JsStringEnumAttribute>(); if (attr != null) { var prop = new ExprJsResolvedProperty(ctx, new FakeCall(e.Call), e.PropertyName).Named("prop"); var type = new ExprJsTypeVarName(ctx, tRef).Named("type"); var enumStringMap = new ExprJsTypeData(ctx, TypeData.EnumStringMap).Named("enumStringMap"); var value = e.Call.Args.Last().Named("value"); var js = "prop = type.enumStringMap[value]"; var expr = new ExprJsExplicit(ctx, js, e.Type, type, enumStringMap, value, prop); return(expr); } } else { var tDef = e.Type.Resolve(); var attr = tDef.GetCustomAttribute <JsStringEnumAttribute>(); if (attr != null) { var prop = new ExprJsResolvedProperty(ctx, new FakeCall(e.Call), e.PropertyName).Named("prop"); var type = new ExprJsTypeVarName(ctx, e.Type).Named("type"); var enumStringMap = new ExprJsTypeData(ctx, TypeData.EnumStringMap).Named("enumStringMap"); var js = "type.enumStringMap[prop]"; var expr = new ExprJsExplicit(ctx, js, e.Type, prop, type, enumStringMap); return(expr); } } } return(base.VisitJsResolvedProperty(e)); }
protected virtual ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { this.ThrowOnNoOverride(); var call = this.HandleCall(e.Call, (obj, args) => new DupCall { ExprType = e.Call.ExprType, CallMethod = e.Call.CallMethod, IsVirtualCall = e.Call.IsVirtualCall, Obj = obj, Args = args, Type = e.Call.Type, Ctx = e.Call.Ctx, }); if (call != e.Call) { return new ExprJsResolvedProperty(e.Ctx, call, e.PropertyName); } else { return e; } }
protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { if (e.PropertyName == null) { // Indexer this.Visit(e.Call.Obj); this.js.Append("["); this.Visit(e.Call.Args.First()); this.js.Append("]"); } else { // Normal attribute/property if (e.Call.Obj != null) { this.Visit(e.Call.Obj); this.js.Append("."); } this.js.Append(e.PropertyName); } if (e.Call.CallMethod != null && e.Call.CallMethod.Resolve().IsSetter) { this.js.Append(" = "); this.Visit(e.Call.Args.Last()); } return e; }
/// <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; }
protected override ICode VisitJsResolvedProperty(ExprJsResolvedProperty e) { this.code.Append(e.PropertyName); return e; }