public EmulateInt64(MethodTypeFactory methodTypeFactory, TypeSystem typeSystem) { TypeSystem = typeSystem; MethodTypeFactory = methodTypeFactory; int64 = new JSType(TypeSystem.Int64); uint64 = new JSType(TypeSystem.UInt64); }
public void VisitNode (JSType type) { var ct = GetCachedType(type.Type); if (ct != null) { ParentNode.ReplaceChild(type, ct); VisitReplacement(ct); } else { VisitChildren(type); } }
public void VisitNode (JSPublicInterfaceOfExpression poe) { VisitChildren(poe); // Replace foo.__Type__.__PublicInterface__ with foo var innerTypeOf = poe.Inner as ITypeOfExpression; if (innerTypeOf != null) { var replacement = new JSType(innerTypeOf.Type); ParentNode.ReplaceChild(poe, replacement); VisitReplacement(replacement); } }
public void VisitNode(JSInvocationExpression ie) { var type = ie.JSType; var method = ie.JSMethod; var thisExpression = ie.ThisReference; if (method != null) { if ( (type != null) && (type.Type.FullName == "System.Object") ) { switch (method.Method.Member.Name) { case "GetType": JSNode replacement; var thisType = JSExpression.DeReferenceType(thisExpression.GetExpectedType(TypeSystem), false); if ((thisType is GenericInstanceType) && thisType.FullName.StartsWith("System.Nullable")) { replacement = new JSType(thisType); } else { replacement = JSIL.GetType(thisExpression); } ParentNode.ReplaceChild(ie, replacement); VisitReplacement(replacement); return; } } else if ( (type != null) && (type.Type.FullName.StartsWith("System.Nullable")) && (type.Type is GenericInstanceType) ) { var t = (type.Type as GenericInstanceType).GenericArguments[0]; var @null = JSLiteral.Null(t); var @default = new JSDefaultValueLiteral(t); switch (method.Method.Member.Name) { case ".ctor": JSExpression value; if (ie.Arguments.Count == 0) { value = @null; } else { value = ie.Arguments[0]; } var boe = new JSBinaryOperatorExpression( JSOperator.Assignment, ie.ThisReference, value, type.Type ); ParentNode.ReplaceChild(ie, boe); VisitReplacement(boe); break; case "GetValueOrDefault": var isNull = new JSBinaryOperatorExpression( JSOperator.Equal, ie.ThisReference, @null, TypeSystem.Boolean ); JSTernaryOperatorExpression ternary; if (ie.Arguments.Count == 0) { ternary = new JSTernaryOperatorExpression( isNull, @default, ie.ThisReference, type.Type ); } else { ternary = new JSTernaryOperatorExpression( isNull, ie.Arguments[0], ie.ThisReference, type.Type ); } ParentNode.ReplaceChild(ie, ternary); VisitReplacement(ternary); break; default: throw new NotImplementedException(method.Method.Member.FullName); } return; } else if ( (type != null) && ILBlockTranslator.TypesAreEqual(TypeSystem.String, type.Type) && (method.Method.Name == "Concat") ) { if (ie.Arguments.Count > 2) { if (ie.Arguments.All( (arg) => ILBlockTranslator.TypesAreEqual( TypeSystem.String, arg.GetExpectedType(TypeSystem) ) )) { var boe = JSBinaryOperatorExpression.New( JSOperator.Add, ie.Arguments, TypeSystem.String ); ParentNode.ReplaceChild( ie, boe ); VisitReplacement(boe); } } else if ( ie.Arguments.Count == 2 ) { var lhs = ie.Arguments[0]; var lhsType = ILBlockTranslator.DereferenceType(lhs.GetExpectedType(TypeSystem)); if (!( ILBlockTranslator.TypesAreEqual(TypeSystem.String, lhsType) || ILBlockTranslator.TypesAreEqual(TypeSystem.Char, lhsType) )) { lhs = JSInvocationExpression.InvokeMethod(lhsType, JS.toString, lhs, null); } var rhs = ie.Arguments[1]; var rhsType = ILBlockTranslator.DereferenceType(rhs.GetExpectedType(TypeSystem)); if (!( ILBlockTranslator.TypesAreEqual(TypeSystem.String, rhsType) || ILBlockTranslator.TypesAreEqual(TypeSystem.Char, rhsType) )) { rhs = JSInvocationExpression.InvokeMethod(rhsType, JS.toString, rhs, null); } var boe = new JSBinaryOperatorExpression( JSOperator.Add, lhs, rhs, TypeSystem.String ); ParentNode.ReplaceChild( ie, boe ); VisitReplacement(boe); } else if ( ILBlockTranslator.GetTypeDefinition(ie.Arguments[0].GetExpectedType(TypeSystem)).FullName == "System.Array" ) { } else { var firstArg = ie.Arguments.FirstOrDefault(); ParentNode.ReplaceChild( ie, firstArg ); if (firstArg != null) VisitReplacement(firstArg); } return; } else if ( ILBlockTranslator.IsDelegateType(method.Reference.DeclaringType) && (method.Method.Name == "Invoke") ) { var newIe = new JSDelegateInvocationExpression( thisExpression, ie.GetExpectedType(TypeSystem), ie.Arguments.ToArray() ); ParentNode.ReplaceChild(ie, newIe); VisitReplacement(newIe); return; } else if ( (method.Reference.DeclaringType.FullName == "System.Type") && (method.Method.Name == "GetTypeFromHandle") ) { var typeObj = ie.Arguments.FirstOrDefault(); ParentNode.ReplaceChild(ie, typeObj); VisitReplacement(typeObj); return; } else if ( (method.Reference.DeclaringType.Name == "RuntimeHelpers") && (method.Method.Name == "InitializeArray") ) { var array = ie.Arguments[0]; var arrayType = array.GetExpectedType(TypeSystem); var field = ie.Arguments[1].SelfAndChildrenRecursive.OfType<JSField>().First(); var initializer = JSArrayExpression.UnpackArrayInitializer(arrayType, field.Field.Member.InitialValue); var copy = JSIL.ShallowCopy(array, initializer, arrayType); ParentNode.ReplaceChild(ie, copy); VisitReplacement(copy); return; } else if ( method.Method.DeclaringType.Definition.FullName == "System.Array" && (ie.Arguments.Count == 1) ) { switch (method.Method.Name) { case "GetLength": case "GetUpperBound": { var index = ie.Arguments[0] as JSLiteral; if (index != null) { var newDot = JSDotExpression.New(thisExpression, new JSStringIdentifier( String.Format("length{0}", Convert.ToInt32(index.Literal)), TypeSystem.Int32 )); if (method.Method.Name == "GetUpperBound") { var newExpr = new JSBinaryOperatorExpression( JSOperator.Subtract, newDot, JSLiteral.New(1), TypeSystem.Int32 ); ParentNode.ReplaceChild(ie, newExpr); } else { ParentNode.ReplaceChild(ie, newDot); } } break; } case "GetLowerBound": ParentNode.ReplaceChild(ie, JSLiteral.New(0)); break; } } } VisitChildren(ie); }
protected JSExpression Translate_PropertyCall(JSExpression thisExpression, JSMethod method, JSExpression[] arguments, bool @virtual, bool @static) { var propertyInfo = method.Method.DeclaringProperty; if (propertyInfo == null) return null; if (propertyInfo.IsIgnored) return new JSIgnoredMemberReference(true, propertyInfo, arguments); // JS provides no way to override [], so keep it as a regular method call if (propertyInfo.Member.IsIndexer()) return null; var parms = method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement") ?? propertyInfo.Metadata.GetAttributeParameters("JSIL.Meta.JSReplacement"); if (parms != null) { var argsDict = new Dictionary<string, JSExpression>(); argsDict["this"] = thisExpression; argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem)); foreach (var kvp in method.Method.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) { argsDict.Add(kvp.Name, kvp.Value); } return new JSVerbatimLiteral(method, (string)parms[0].Value, argsDict, propertyInfo.ReturnType); } var thisType = GetTypeDefinition(thisExpression.GetExpectedType(TypeSystem)); Func<JSExpression> generate = () => { var actualThis = @static ? new JSType(method.Method.DeclaringType.Definition) : thisExpression; if ((method.Reference.DeclaringType is GenericInstanceType) && !method.Reference.HasThis) { actualThis = new JSType(method.Reference.DeclaringType); } if ((propertyInfo.Member.GetMethod != null) && (method.Method.Member.Name == propertyInfo.Member.GetMethod.Name)) { return new JSPropertyAccess( actualThis, new JSProperty(method.Reference, propertyInfo) ); } else { if (arguments.Length == 0) throw new InvalidOperationException("Attempting to invoke a property setter with no arguments"); return new JSBinaryOperatorExpression( JSOperator.Assignment, new JSPropertyAccess( actualThis, new JSProperty(method.Reference, propertyInfo) ), arguments[0], propertyInfo.ReturnType ); } }; // Accesses to a base property should go through a regular method invocation, since // javascript properties do not have a mechanism for base access if (method.Method.Member.HasThis) { if (!TypesAreEqual(method.Method.DeclaringType.Definition, thisType) && !@virtual) { return null; } else { return generate(); } } return generate(); }
protected JSExpression Translate_MethodReplacement( JSMethod method, JSExpression thisExpression, JSExpression[] arguments, bool @virtual, bool @static, bool explicitThis ) { var methodInfo = method.Method; var metadata = methodInfo.Metadata; if (metadata != null) { var parms = metadata.GetAttributeParameters("JSIL.Meta.JSReplacement"); if (parms != null) { var argsDict = new Dictionary<string, JSExpression>(); argsDict["this"] = thisExpression; argsDict["typeof(this)"] = new JSType(thisExpression.GetExpectedType(TypeSystem)); foreach (var kvp in methodInfo.Parameters.Zip(arguments, (p, v) => new { p.Name, Value = v })) { argsDict.Add(kvp.Name, kvp.Value); } return new JSVerbatimLiteral( method, (string)parms[0].Value, argsDict, method.Method.ReturnType ); } } if (methodInfo.IsIgnored) return new JSIgnoredMemberReference(true, methodInfo, new[] { thisExpression }.Concat(arguments).ToArray()); switch (method.Method.Member.FullName) { case "System.Object JSIL.Builtins::Eval(System.String)": return JSInvocationExpression.InvokeStatic( JS.eval, arguments ); case "System.Object JSIL.Verbatim::Expression(System.String)": { var expression = arguments[0] as JSStringLiteral; if (expression == null) throw new InvalidOperationException("JSIL.Verbatim.Expression must recieve a string literal as an argument"); return new JSVerbatimLiteral( method, expression.Value, null, null ); } case "System.Object JSIL.JSGlobal::get_Item(System.String)": { var expression = arguments[0] as JSStringLiteral; if (expression != null) return new JSDotExpression( JSIL.GlobalNamespace, new JSStringIdentifier(expression.Value, TypeSystem.Object) ); else return new JSIndexerExpression( JSIL.GlobalNamespace, arguments[0], TypeSystem.Object ); } case "System.Object JSIL.JSLocal::get_Item(System.String)": { var expression = arguments[0] as JSStringLiteral; if (expression == null) throw new InvalidOperationException("JSLocal must recieve a string literal as an index"); return new JSStringIdentifier(expression.Value, TypeSystem.Object); } case "System.Object JSIL.Builtins::get_This()": return new JSIndirectVariable(Variables, "this", ThisMethodReference); } JSExpression result = Translate_PropertyCall(thisExpression, method, arguments, @virtual, @static); if (result == null) { if (@static) result = JSInvocationExpression.InvokeStatic(method.Reference.DeclaringType, method, arguments); else if (explicitThis) result = JSInvocationExpression.InvokeBaseMethod(method.Reference.DeclaringType, method, thisExpression, arguments); else result = JSInvocationExpression.InvokeMethod(method.Reference.DeclaringType, method, thisExpression, arguments); } return result; }