public TypeInfo GetTypeInformation(TypeReference type) { if (type == null) { throw new ArgumentNullException("type"); } TypeInfo result; var typedef = TypeUtil.GetTypeDefinition(type); if (typedef == null) { return(null); } var identifier = new TypeIdentifier(typedef); if (TypeInformation.TryGet(identifier, out result)) { return(result); } var fullName = type.FullName; var args = new MakeTypeInfoArgs(); EnqueueType(args.TypesToInitialize, type); // We must construct type information in two passes, so that method group construction // behaves correctly and ignores all the right methods. // The first pass walks all the way through the type graph (starting with the current type), // ensuring we have type information for all the types in the graph. We do this iteratively // to avoid overflowing the stack. // After we have type information for all the types in the graph, we then walk over all // the types again, and construct their method groups, since we have the necessary // information to determine which methods are ignored. while (args.TypesToInitialize.Count > 0) { var kvp = args.TypesToInitialize.First; args.TypesToInitialize.Remove(kvp.Key); args.Definition = kvp.Value; TypeInformation.TryCreate( kvp.Key, args, MakeTypeInfo ); } foreach (var ti in args.SecondPass.Values) { ti.Initialize(); ti.ConstructMethodGroups(); } if (!TypeInformation.TryGet(identifier, out result)) { return(null); } else { return(result); } }
protected TypeInfo ConstructTypeInformation(TypeIdentifier identifier, TypeDefinition type, Dictionary <TypeIdentifier, TypeDefinition> moreTypes) { var moduleInfo = GetModuleInformation(type.Module); TypeInfo baseType = null, declaringType = null; if (type.BaseType != null) { baseType = GetExisting(type.BaseType); if (baseType == null) { throw new InvalidOperationException(String.Format( "Missing type info for base type '{0}' of type '{1}'", type.BaseType, type )); } } if (type.DeclaringType != null) { declaringType = GetExisting(type.DeclaringType); if (declaringType == null) { throw new InvalidOperationException(String.Format( "Missing type info for declaring type '{0}' of type '{1}'", type.DeclaringType, type )); } } var result = new TypeInfo(this, moduleInfo, type, declaringType, baseType, identifier); Action <TypeReference> addType = (tr) => { if (tr == null) { return; } var td = TypeUtil.GetTypeDefinition(tr); if (td == null) { return; } var _identifier = new TypeIdentifier(td); if (_identifier.Equals(identifier)) { return; } else if (moreTypes.ContainsKey(_identifier)) { return; } moreTypes[_identifier] = td; }; foreach (var member in result.Members.Values) { addType(member.ReturnType); var method = member as Internal.MethodInfo; if (method != null) { foreach (var p in method.Member.Parameters) { addType(p.ParameterType); } } } return(result); }
public void VisitNode(JSBinaryOperatorExpression bop) { bool parens = true; bool needsTruncation = false, needsCast = false; if (ParentNode is JSIfStatement) { parens = false; } else if ((ParentNode is JSWhileLoop) && ((JSWhileLoop)ParentNode).Condition == bop) { parens = false; } else if ((ParentNode is JSDoLoop) && ((JSDoLoop)ParentNode).Condition == bop) { parens = false; } else if (ParentNode is JSForLoop) { var fl = (JSForLoop)ParentNode; if ( (fl.Condition == bop) || (fl.Increment.SelfAndChildrenRecursive.Any((n) => bop.Equals(n))) || (fl.Initializer.SelfAndChildrenRecursive.Any((n) => bop.Equals(n))) ) { parens = false; } } else if ((ParentNode is JSSwitchStatement) && ((JSSwitchStatement)ParentNode).Condition == bop) { parens = false; } else if ( (ParentNode is JSBinaryOperatorExpression) && ((JSBinaryOperatorExpression)ParentNode).Operator == bop.Operator && bop.Operator is JSLogicalOperator ) { parens = false; } else if (ParentNode is JSVariableDeclarationStatement) { parens = false; } else if (ParentNode is JSExpressionStatement) { parens = false; } var leftType = bop.Left.GetActualType(TypeSystem); var rightType = bop.Right.GetActualType(TypeSystem); var resultType = bop.GetActualType(TypeSystem); // We need to perform manual truncation to maintain the semantics of C#'s division operator if ((bop.Operator == JSOperator.Divide)) { needsTruncation = (TypeUtil.IsIntegral(leftType) || TypeUtil.IsIntegral(rightType)) && TypeUtil.IsIntegral(resultType); } // Arithmetic on enum types needs a cast at the end. if (bop.Operator is JSArithmeticOperator) { if (TypeUtil.IsEnum(TypeUtil.StripNullable(resultType))) { needsCast = true; } } if (needsTruncation) { if (bop.Operator is JSAssignmentOperator) { throw new NotImplementedException("Truncation of assignment operations not implemented"); } Output.WriteRaw("Math.floor"); } else if (needsCast) { Output.WriteRaw("JSIL.Cast"); } parens |= needsTruncation; parens |= needsCast; if (parens) { Output.LPar(); } Visit(bop.Left); Output.Space(); Output.WriteRaw(bop.Operator.Token); Output.Space(); if ( (bop.Operator is JSLogicalOperator) && (Stack.OfType <JSBinaryOperatorExpression>().Skip(1).FirstOrDefault() != null) ) { Output.NewLine(); } Visit(bop.Right); if (needsCast) { Output.Comma(); Output.Identifier(TypeUtil.StripNullable(resultType), ReferenceContext); } if (parens) { Output.RPar(); } }