public static void CommaSeparatedList <T> (this JavascriptFormatter formatter, IEnumerable <T> list, Action <T> process) { bool first = true; foreach (var item in list) { if (first) { first = false; } else { formatter.Comma(); } process(item); } }
protected void TranslateMethodGroup(DecompilerContext context, JavascriptFormatter output, MethodGroupInfo methodGroup) { var methods = (from m in methodGroup.Methods where !m.IsIgnored select m).ToArray(); if (methods.Length < 1) return; foreach (var method in methods) { foreach (var p in method.Member.Parameters) { var resolved = p.ParameterType.Resolve(); if ((resolved != null) && !DeclaredTypes.Contains(resolved.FullName) && (resolved.Module.Assembly == methodGroup.DeclaringType.Definition.Module.Assembly) ) { ForwardDeclareType(context, output, resolved); } } } output.Identifier( (methods.First().IsGeneric) ? "JSIL.OverloadedGenericMethod" : "JSIL.OverloadedMethod", null ); output.LPar(); output.Identifier(methodGroup.DeclaringType.Definition); if (!methodGroup.IsStatic) { output.Dot(); output.Keyword("prototype"); } output.Comma(); output.Value(Util.EscapeIdentifier(methodGroup.Name)); output.Comma(); output.OpenBracket(true); bool isFirst = true; foreach (var method in methods) { if (!isFirst) { output.Comma(); output.NewLine(); } output.OpenBracket(); output.Value(Util.EscapeIdentifier(method.GetName(true))); output.Comma(); output.OpenBracket(); output.CommaSeparatedList( from p in method.Member.Parameters select p.ParameterType, ListValueType.TypeIdentifier ); output.CloseBracket(); output.CloseBracket(); isFirst = false; } output.CloseBracket(true, () => { output.RPar(); output.Semicolon(); }); }
protected void TranslateMethod( DecompilerContext context, JavascriptFormatter output, MethodReference methodRef, MethodDefinition method, bool stubbed, HashSet<string> externalMemberNames, HashSet<string> staticExternalMemberNames, Action<JSFunctionExpression> bodyTransformer = null ) { var methodInfo = TypeInfoProvider.GetMemberInformation<Internal.MethodInfo>(method); if (methodInfo == null) return; bool isReplaced = methodInfo.Metadata.HasAttribute("JSIL.Meta.JSReplacement"); bool methodIsProxied = (methodInfo.IsFromProxy && methodInfo.Member.HasBody) && !methodInfo.IsExternal && !isReplaced; if (methodInfo.IsExternal || (stubbed && !methodIsProxied)) { if (isReplaced) return; if (externalMemberNames == null) throw new ArgumentNullException("externalMemberNames"); if (staticExternalMemberNames == null) throw new ArgumentNullException("staticExternalMemberNames"); var isProperty = methodInfo.DeclaringProperty != null; if (!isProperty || !methodInfo.Member.IsCompilerGenerated()) { (method.IsStatic ? staticExternalMemberNames : externalMemberNames) .Add(Util.EscapeIdentifier(methodInfo.GetName(true))); return; } } if (methodInfo.IsIgnored) return; if (!method.HasBody) return; if (methodIsProxied) { output.Comment("Implementation from {0}", methodInfo.Member.DeclaringType.FullName); output.NewLine(); } output.Identifier(method.DeclaringType); if (!method.IsStatic) { output.Dot(); output.Keyword("prototype"); } output.Dot(); output.Identifier(methodInfo.GetName(true)); output.Token(" = "); if (method.HasGenericParameters) { output.Identifier("JSIL.GenericMethod", null); output.LPar(); output.NewLine(); output.OpenBracket(); output.CommaSeparatedList((from p in method.GenericParameters select p.Name), ListValueType.Primitive); output.CloseBracket(); output.Comma(); output.NewLine(); } JSFunctionExpression function; function = FunctionCache.GetExpression(new QualifiedMemberIdentifier( methodInfo.DeclaringType.Identifier, methodInfo.Identifier )); if (bodyTransformer != null) bodyTransformer(function); if (function != null) { AstEmitter.Visit(function); } else { output.Identifier("JSIL.UntranslatableFunction", null); output.LPar(); output.Value(method.FullName); output.RPar(); } if (method.HasGenericParameters) { output.NewLine(); output.RPar(); } output.Semicolon(); }
protected void TranslateInterface(DecompilerContext context, JavascriptFormatter output, TypeDefinition iface) { output.Identifier("JSIL.MakeInterface", null); output.LPar(); output.NewLine(); output.Value(Util.EscapeIdentifier(iface.FullName, EscapingMode.String)); output.Comma(); output.OpenBracket(); output.CommaSeparatedList( (from p in iface.GenericParameters select p.Name), ListValueType.Primitive ); output.CloseBracket(); output.Comma(); output.OpenBrace(); bool isFirst = true; foreach (var m in iface.Methods) { var methodInfo = TypeInfoProvider.GetMethod(m); if ((methodInfo != null) && methodInfo.IsIgnored) continue; if (!isFirst) { output.Comma(); output.NewLine(); } output.Value(Util.EscapeIdentifier(m.Name)); output.Token(": "); output.Identifier("Function"); isFirst = false; } foreach (var p in iface.Properties) { var propertyInfo = TypeInfoProvider.GetProperty(p); if ((propertyInfo != null) && propertyInfo.IsIgnored) continue; if (!isFirst) { output.Comma(); output.NewLine(); } output.Value(Util.EscapeIdentifier(p.Name)); output.Token(": "); output.Identifier("Property"); isFirst = false; } output.NewLine(); output.CloseBrace(false); output.RPar(); output.Semicolon(); output.NewLine(); }
protected void TranslateEnum(DecompilerContext context, JavascriptFormatter output, TypeDefinition enm) { output.Identifier("JSIL.MakeEnum", null); output.LPar(); output.NewLine(); output.Value(Util.EscapeIdentifier(enm.FullName, EscapingMode.String)); output.Comma(); output.OpenBrace(); var typeInformation = TypeInfoProvider.GetTypeInformation(enm); if (typeInformation == null) throw new InvalidOperationException(); bool isFirst = true; foreach (var em in typeInformation.EnumMembers.Values) { if (!isFirst) { output.Comma(); output.NewLine(); } output.Identifier(em.Name); output.Token(": "); output.Value(em.Value); isFirst = false; } output.NewLine(); output.CloseBrace(false); output.Comma(); output.Value(typeInformation.IsFlagsEnum); output.NewLine(); output.RPar(); output.Semicolon(); output.NewLine(); }
protected void Translate(DecompilerContext context, AssemblyDefinition assembly, Stream outputStream) { bool stubbed = IsStubbed(assembly); var initializer = new List<Action>(); var tw = new StreamWriter(outputStream, Encoding.ASCII); var formatter = new JavascriptFormatter(tw, this.TypeInfoProvider, assembly); var version = Assembly.GetExecutingAssembly().GetName().Version; formatter.Comment( "Generated by JSIL v{0}.{1}.{2} build {3}. See http://jsil.org/ for more information.", version.Major, version.Minor, version.Build, version.Revision ); formatter.NewLine(); if (stubbed) { formatter.Comment("Generating type stubs only"); formatter.NewLine(); } formatter.DeclareAssembly(); var sealedTypes = new HashSet<TypeDefinition>(); // Important to clear this because types with the exact same full names can be defined in multiple assemblies DeclaredTypes.Clear(); foreach (var module in assembly.Modules) TranslateModule(context, formatter, module, initializer, sealedTypes, stubbed); if (sealedTypes.Count > 0) { var groups = (from st in sealedTypes let parent = JavascriptFormatter.GetParent(st, null) group st by parent); initializer.Add(() => { foreach (var g in groups) { formatter.Identifier("JSIL.SealTypes", null); formatter.LPar(); formatter.Identifier(formatter.PrivateToken); formatter.Comma(); formatter.Value(g.Key); formatter.Comma(); formatter.NewLine(); formatter.CommaSeparatedList( (from typedef in g select typedef.Name), ListValueType.Primitive ); formatter.NewLine(); formatter.RPar(); formatter.Semicolon(); } }); } foreach (var init in initializer) { formatter.Identifier("JSIL.QueueInitializer", null); formatter.LPar(); formatter.OpenFunction(null, null); init(); formatter.CloseBrace(false); formatter.RPar(); formatter.Semicolon(); } tw.Flush(); }
protected void ForwardDeclareType(DecompilerContext context, JavascriptFormatter output, TypeDefinition typedef) { var typeInfo = TypeInfoProvider.GetTypeInformation(typedef); if ((typeInfo == null) || typeInfo.IsIgnored || typeInfo.IsProxy) return; if (DeclaredTypes.Contains(typedef.FullName)) { Debug.WriteLine("Cycle in type references detected: {0}", typedef); return; } context.CurrentType = typedef; output.DeclareNamespace(typedef.Namespace); DeclaredTypes.Add(typedef.FullName); if (typedef.IsInterface) { TranslateInterface(context, output, typedef); return; } else if (typedef.IsEnum) { TranslateEnum(context, output, typedef); return; } else if (typeInfo.IsDelegate) { TranslateDelegate(context, output, typedef, typeInfo); return; } var declaringType = typedef.DeclaringType; if (declaringType != null) { if (!DeclaredTypes.Contains(declaringType.FullName)) ForwardDeclareType(context, output, declaringType); } var baseClass = typedef.Module.TypeSystem.Object; if (typedef.BaseType != null) { baseClass = typedef.BaseType; var resolved = baseClass.Resolve(); if ( (resolved != null) && !DeclaredTypes.Contains(resolved.FullName) && (resolved.Module.Assembly == typedef.Module.Assembly) ) { ForwardDeclareType(context, output, resolved); } } bool isStatic = typedef.IsAbstract && typedef.IsSealed; if (isStatic) { output.Identifier("JSIL.MakeStaticClass", null); output.LPar(); output.Value(Util.EscapeIdentifier(typedef.FullName, EscapingMode.String)); output.Comma(); output.Value(typedef.IsPublic); if (typedef.HasGenericParameters) { output.Comma(); output.OpenBracket(); output.CommaSeparatedList( (from p in typedef.GenericParameters select p.Name), ListValueType.Primitive ); output.CloseBracket(); } output.RPar(); output.Semicolon(); } else { if (typedef.IsValueType) output.Identifier("JSIL.MakeStruct", null); else output.Identifier("JSIL.MakeClass", null); output.LPar(); if (!typedef.IsValueType) { output.TypeReference(baseClass); output.Comma(); } output.Value(Util.EscapeIdentifier(typedef.FullName, EscapingMode.String)); output.Comma(); output.Value(typedef.IsPublic); if (typedef.HasGenericParameters) { output.Comma(); output.OpenBracket(); output.CommaSeparatedList( (from p in typedef.GenericParameters select p.Name), ListValueType.Primitive ); output.CloseBracket(); } output.RPar(); output.Semicolon(); } foreach (var nestedTypeDef in typedef.NestedTypes) { if (!DeclaredTypes.Contains(nestedTypeDef.FullName)) ForwardDeclareType(context, output, nestedTypeDef); } output.NewLine(); }
protected void TranslateTypeDefinition(DecompilerContext context, JavascriptFormatter output, TypeDefinition typedef, List<Action> initializer, bool stubbed) { var typeInfo = TypeInfoProvider.GetTypeInformation(typedef); if (!ShouldTranslateMethods(typedef)) return; context.CurrentType = typedef; var externalMemberNames = new HashSet<string>(); var staticExternalMemberNames = new HashSet<string>(); foreach (var method in typedef.Methods) { // We translate the static constructor explicitly later, and inject field initialization if (method.Name == ".cctor") continue; TranslateMethod( context, output, method, method, stubbed, externalMemberNames, staticExternalMemberNames ); } Action initializeOverloadsAndProperties = () => { foreach (var methodGroup in typeInfo.MethodGroups) TranslateMethodGroup(context, output, methodGroup); foreach (var property in typedef.Properties) TranslateProperty(context, output, property); }; if (!stubbed) initializeOverloadsAndProperties(); Func<TypeReference, bool> isInterfaceIgnored = (i) => { var interfaceInfo = TypeInfoProvider.GetTypeInformation(i); if (interfaceInfo != null) return interfaceInfo.IsIgnored; else return true; }; var interfaces = (from i in typeInfo.Interfaces where !i.IsIgnored select i).ToArray(); if (interfaces.Length > 0) { initializer.Add(() => { output.Identifier("JSIL.ImplementInterfaces", null); output.LPar(); output.Identifier(typedef); output.Comma(); output.OpenBracket(true); output.CommaSeparatedList(interfaces, ListValueType.TypeReference); output.CloseBracket(true, () => { output.RPar(); output.Semicolon(); }); }); } Func<FieldDefinition, bool> isFieldIgnored = (f) => { IMemberInfo memberInfo; if (typeInfo.Members.TryGetValue(MemberIdentifier.New(f), out memberInfo)) return memberInfo.IsIgnored; else return true; }; var structFields = (from field in typedef.Fields where !isFieldIgnored(field) && !field.HasConstant && EmulateStructAssignment.IsStruct(field.FieldType) && !field.IsStatic select field).ToArray(); if (structFields.Length > 0) { initializer.Add(() => { output.Identifier(typedef); output.Dot(); output.Identifier("prototype"); output.Dot(); output.Identifier("__StructFields__"); output.Token(" = "); output.OpenBracket(true); bool isFirst = true; foreach (var sf in structFields) { if (!isFirst) { output.Comma(); output.NewLine(); } output.OpenBracket(); output.Value(sf.Name); output.Comma(); output.Identifier(sf.FieldType); output.CloseBracket(); isFirst = false; } output.CloseBracket(true, output.Semicolon); }); } TranslateTypeStaticConstructor(context, output, typedef, typeInfo.StaticConstructor, stubbed); if (externalMemberNames.Count + staticExternalMemberNames.Count > 0) { initializer.Add(() => { if (externalMemberNames.Count > 0) { output.Identifier("JSIL.ExternalMembers", null); output.LPar(); output.Identifier(typedef); output.Dot(); output.Keyword("prototype"); output.Comma(); output.NewLine(); output.CommaSeparatedList(externalMemberNames, ListValueType.Primitive); output.NewLine(); output.RPar(); output.Semicolon(); } if (staticExternalMemberNames.Count > 0) { output.Identifier("JSIL.ExternalMembers", null); output.LPar(); output.Identifier(typedef); output.Comma(); output.NewLine(); output.CommaSeparatedList(staticExternalMemberNames, ListValueType.Primitive); output.NewLine(); output.RPar(); output.Semicolon(); } }); } if (stubbed && (typeInfo.MethodGroups.Count + typedef.Properties.Count) > 0 ) { initializer.Add(initializeOverloadsAndProperties); } output.NewLine(); foreach (var nestedTypedef in typedef.NestedTypes) TranslateTypeDefinition(context, output, nestedTypedef, initializer, stubbed); }
protected void TranslateProperty(DecompilerContext context, JavascriptFormatter output, PropertyDefinition property) { var propertyInfo = TypeInfoProvider.GetMemberInformation<Internal.PropertyInfo>(property); if ((propertyInfo == null) || propertyInfo.IsIgnored) return; var isStatic = (property.SetMethod ?? property.GetMethod).IsStatic; if (property.DeclaringType.HasGenericParameters && isStatic) output.Identifier("JSIL.MakeGenericProperty", null); else output.Identifier("JSIL.MakeProperty", null); output.LPar(); output.Identifier(property.DeclaringType); if (!isStatic) { output.Dot(); output.Keyword("prototype"); } output.Comma(); output.Value(Util.EscapeIdentifier(propertyInfo.Name)); output.Comma(); output.NewLine(); if (property.GetMethod != null) { output.Identifier(property.DeclaringType); if (!isStatic) { output.Dot(); output.Keyword("prototype"); } output.Dot(); output.Identifier(property.GetMethod, false); } else { output.Keyword("null"); } output.Comma(); if (property.SetMethod != null) { output.Identifier(property.DeclaringType); if (!isStatic) { output.Dot(); output.Keyword("prototype"); } output.Dot(); output.Identifier(property.SetMethod, false); } else { output.Keyword("null"); } output.RPar(); output.Semicolon(); }
public static bool WriteTypeReference(this JavascriptFormatter formatter, TypeReference typeReference, TypeDefinition context, ReplaceMode replaceMode, bool useStandartSubstitution = true) { if (typeReference is ArrayType) { var arrayType = (ArrayType)typeReference; formatter.WriteRaw("$asmJsilCore.System."); formatter.Identifier(arrayType.IsVector ? "Vector" : "Array"); formatter.TRSuffix(replaceMode); formatter.WriteRaw("<"); formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.Instance); formatter.Comma(); formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.In); formatter.Comma(); formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.Out); if (!arrayType.IsVector) { formatter.Comma(); formatter.WriteRaw("\""); formatter.Value(arrayType.Dimensions.Count.ToString(CultureInfo.InvariantCulture)); formatter.WriteRaw("\""); } formatter.WriteRaw(">"); } else if (typeReference is ByReferenceType) { var byRefType = (ByReferenceType)typeReference; formatter.WriteRaw("$asmJsilCore.JSIL.Reference"); formatter.TRSuffix(replaceMode); formatter.WriteRaw("<"); formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.Instance); formatter.Comma(); formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.In); formatter.Comma(); formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.Out); formatter.WriteRaw(">"); } else if (typeReference is GenericParameter) { var gp = (GenericParameter)typeReference; DefinitelyTypedUtilities.GenericParemetersKeyedCollection map; if (gp.Owner is TypeDefinition) { map = DefinitelyTypedUtilities.BuildGenericParemetersMap(((TypeDefinition)gp.Owner).GenericParameters, null); } else if (gp.Owner is MethodDefinition) { map = DefinitelyTypedUtilities.BuildGenericParemetersMap(((MethodDefinition)gp.Owner).GenericParameters, ((MethodDefinition)gp.Owner).DeclaringType.GenericParameters); } else { throw new Exception("Unexpected generic parameter owner"); } var name = map[gp].Value; switch (replaceMode) { case ReplaceMode.Instance: formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(name)); break; case ReplaceMode.Out: formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterOutParameterName(name)); break; case ReplaceMode.In: formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInParameterName(name)); break; default: throw new ArgumentOutOfRangeException("replaceMode", replaceMode, null); } } else if (typeReference is GenericInstanceType) { var genericType = (GenericInstanceType)typeReference; if (formatter.WriteTypeReference(genericType.ElementType, context, replaceMode)) /*TODO*/ { formatter.WriteRaw("<"); formatter.CommaSeparatedList(genericType.GenericArguments, genericArgument => { formatter.WriteTypeReference(genericArgument, context, ReplaceMode.Instance); formatter.Comma(); formatter.WriteTypeReference(genericArgument, context, ReplaceMode.In); formatter.Comma(); formatter.WriteTypeReference(genericArgument, context, ReplaceMode.Out); }); formatter.WriteRaw(">"); } } else if (typeReference is PointerType || typeReference is OptionalModifierType || typeReference is RequiredModifierType || typeReference is PinnedType || typeReference is SentinelType || typeReference is FunctionPointerType || (!_coreTypes.Contains(typeReference.FullName) && formatter.TypeInfo.Get(typeReference).IsSuppressDeclaration)) { formatter.WriteRaw("Object"); // TODO! return(false); } else { string rawType; if (useStandartSubstitution && _rawTypes.TryGetValue(typeReference.FullName, out rawType)) { formatter.WriteRaw(rawType); } else { var definition = typeReference.Resolve(); var targetAssembly = JavascriptFormatter.GetContainingAssemblyName(typeReference); string assemblyRef; if (_coreTypes.Contains(definition.FullName)) { assemblyRef = "$asmJsilCore"; } else if (targetAssembly == formatter.Assembly.FullName) { assemblyRef = string.Empty; } else { assemblyRef = formatter.Manifest.Entries.FirstOrDefault(item => item.Value == targetAssembly).Key; } if (definition != null && assemblyRef != null) { if (assemblyRef != string.Empty) { formatter.Identifier(assemblyRef); formatter.Dot(); } else { formatter.Identifier("$private"); formatter.Dot(); } foreach (var part in DefinitelyTypedUtilities.GetFullNamespace(definition)) { formatter.Identifier(part); formatter.Dot(); } formatter.Identifier(DefinitelyTypedUtilities.GetClassName(definition)); /* Hack to solve ciruclar refrence in generics. * It could be improved, by we really need generic variance support or support of: * type T = something & I<T> (see Microsoft/TypeScript#6230) */ var fixedMode = (replaceMode != ReplaceMode.Instance && context == definition) ? ReplaceMode.Instance : replaceMode; formatter.TRSuffix(fixedMode); } else { //TODO: We was unable to resolve assembly. Think about JSIL Proxies formatter.WriteRaw("Object"); return(false); } } } return(true); }
public void EmitAssemblyEntryPoint(AssemblyDefinition assembly, MethodDefinition entryMethod, MethodSignature signature) { Formatter.WriteRaw("JSIL.SetEntryPoint"); Formatter.LPar(); Formatter.AssemblyReference(assembly); Formatter.Comma(); var context = new TypeReferenceContext(); Formatter.TypeReference(entryMethod.DeclaringType, context); Formatter.Comma(); Formatter.Value(entryMethod.Name); Formatter.Comma(); Formatter.MethodSignature( entryMethod, signature, context ); Formatter.RPar(); Formatter.Semicolon(true); Formatter.NewLine(); }
protected void CommaSeparatedList(IEnumerable <JSExpression> values, bool withNewlines = false) { bool isFirst = true; foreach (var value in values) { if (!isFirst) { Output.Comma(); if (withNewlines) { Output.NewLine(); } } Visit(value); isFirst = false; } }