public JsBlockStatement CreateTypeFunction(INamedTypeSymbol classType, out JsBlockStatement typeInitializer, out JsBlockStatement staticInitializer) { var isBuiltIn = classType.IsBuiltIn(); var extraBuiltInExports = classType.GetExtraBuiltInExports(); var explicitBaseType = classType.GetAttributeValue<ITypeSymbol>(Context.Instance.JsAttributeType, "BaseType"); var baseType = explicitBaseType != null ? Type(explicitBaseType) : Equals(classType, Context.Instance.ObjectType) ? Js.Reference("Object") : classType.BaseType == null ? Type(Context.Instance.ObjectType) : Js.Reference(classType.BaseType.GetTypeName()); // classType.BaseType.HasGenericParameters() ? Js.Reference(classType.BaseType.GetTypeName()) : // Type(classType.BaseType); var block = new JsBlockStatement(); JsExpression outerClassType = Js.Reference(classType.GetTypeName()); // Generate type initializer typeInitializer = new JsBlockStatement(); // typeInitializer.Add(StoreInType(SpecialNames.GetAssembly, Js.Reference(classType.ContainingAssembly.GetAssemblyMethodName()))); // typeInitializer.Add(StoreInPrototype(SpecialNames.TypeField, Js.Reference(SpecialNames.TypeInitializerTypeFunction))); // typeInitializer.Add(StoreInType(SpecialNames.BaseType, baseType)); if (classType.IsExported() && !classType.IsBuiltIn()) { // typeInitializer.Add(StoreInPrototype(SpecialNames.TypeName, Js.Reference(SpecialNames.TypeInitializerTypeFunction).Member(SpecialNames.TypeName))); } else { typeInitializer.Add(StoreInPrototype(SpecialNames.TypeName, Js.Primitive(classType.GetFullName()))); typeInitializer.Add(StoreInType(SpecialNames.TypeName, GetFromPrototype(SpecialNames.TypeName))); } if (classType.IsBuiltIn()) typeInitializer.Add(StoreClassGetType()); typeInitializer.Add(StoreClassCreateType(classType)); var containingType = classType.ContainingType; var typeInitializerFunction = Js.Function(new[] { Js.Parameter(SpecialNames.TypeInitializerTypeFunction), Js.Parameter(SpecialNames.TypeInitializerPrototype) }.Concat(classType.TypeParameters.Select(x => Js.Parameter(x.Name))).Concat(classType.GetAnonymousTypeParameters().Select(x => Js.Parameter(x.Item2))).ToArray()).Body(typeInitializer); if (!isBuiltIn) { var displayName = classType.GetFullName(); var args = new[] { Js.Reference(SpecialNames.Assembly), containingType == null ? (JsExpression)Js.Null() : Js.Reference(SpecialNames.TypeInitializerTypeFunction), Js.Primitive(displayName), Js.Primitive(classType.HasOrIsEnclosedInGenericParameters()), Js.Array( classType.TypeParameters.Select(x => (JsExpression)Js.Reference(SpecialNames.DefineTypeParameter).Invoke( Js.Reference(SpecialNames.Assembly), Js.Primitive(x.Name), Type(x.BaseType ?? Context.Instance.ObjectType, true) ) ) .Concat(classType.GetAnonymousTypeParameters().Select(x => Js.Reference(SpecialNames.DefineTypeParameter).Invoke( Js.Reference(SpecialNames.Assembly), Js.Primitive(x.Item2), Type(x.Item1 ?? Context.Instance.ObjectType, true) ) )) .ToArray() ), baseType, typeInitializerFunction }; if (classType.ContainingType == null && !classType.IsAnonymousType) { block.Assign(Js.Reference(classType.ContainingNamespace.GetFullName()).Member(classType.GetShortTypeName()), Js.Reference(SpecialNames.Define).Invoke(args)); } else if (classType.ContainingType != null) { outerClassType = Js.Reference(SpecialNames.TypeInitializerTypeFunction).Member(classType.GetShortTypeName()); block.Assign(outerClassType, Js.Reference(SpecialNames.Define).Invoke(args)); } else { block.Assign(Js.Reference(classType.GetTypeName()), Js.Reference(SpecialNames.Define).Invoke(args)); } } if (classType.IsBuiltIn()) block.Assign(outerClassType.Member(SpecialNames.TypeInitializer), Js.Reference(SpecialNames.DefineTypeFunction).Invoke(outerClassType, typeInitializerFunction)); Func<JsExpression, JsExpression> primaryTypeInitializerCall = expression => expression .Member("call") .Invoke( new[] { containingType == null ? (JsExpression)Js.Null() : Js.Reference(SpecialNames.TypeInitializerTypeFunction), outerClassType, outerClassType.Member("prototype") } .Concat( classType.TypeParameters.Select(x => Js.Reference(SpecialNames.DefineTypeParameter).Invoke( Js.Reference(SpecialNames.Assembly), Js.Primitive(x.Name), Type(x.BaseType ?? Context.Instance.ObjectType, true) ) ) ) .Concat( classType.GetAnonymousTypeParameters().Select(x => Js.Reference(SpecialNames.DefineTypeParameter).Invoke( Js.Reference(SpecialNames.Assembly), Js.Primitive(x.Item2), Type(x.Item1 ?? Context.Instance.ObjectType, true) ) ) ) .ToArray() ); if (extraBuiltInExports == null) { if (!classType.IsBuiltIn()) block.Express(outerClassType.Member(SpecialNames.CallTypeInitializer).Invoke()); else block.Express(primaryTypeInitializerCall(outerClassType.Member(SpecialNames.TypeInitializer))); } else { block.Express(primaryTypeInitializerCall(outerClassType.Member(SpecialNames.TypeInitializer))); foreach (var extra in extraBuiltInExports) { block.Express(outerClassType.Member(SpecialNames.TypeInitializer).Member("call") .Invoke( new[] { (JsExpression)Js.Null(), Js.Reference(extra), Js.Reference(extra).Member("prototype") } .ToArray())); } } if (classType.IsBuiltIn()) { block.Express(Js.Reference(classType.ContainingAssembly.GetAssemblyTypesArray()).Member("push").Invoke(outerClassType)); } staticInitializer = new JsBlockStatement(); // staticInitializer.If(GetFromType(SpecialNames.IsStaticInitialized), Js.Return()); // staticInitializer.Add(StoreInType(SpecialNames.IsStaticInitialized, Js.Primitive(true))); if (classType.BaseType != null) { staticInitializer.Express(Type(classType.BaseType).Member(SpecialNames.StaticInitializer).Invoke()); } var staticInitializerFunction = Js.Function().Body(staticInitializer); typeInitializer.Add(StoreInType(SpecialNames.StaticInitializer, Js.Reference(SpecialNames.DefineStaticConstructor).Invoke(Js.Reference(SpecialNames.TypeInitializerTypeFunction), staticInitializerFunction))); if (classType.HasOrIsEnclosedInGenericParameters()) { var makeGenericType = new JsBlockStatement(); var name = containingType == null ? (JsExpression)Js.Null() : Js.Reference(SpecialNames.TypeInitializerTypeFunction); // makeGenericType.Return( // Js.Reference(SpecialNames.MakeGenericTypeConstructor) // .Member("call") // .Invoke(name, SpecialTypeOnlyForEnclosingTypes(classType), Js.Reference("arguments")) // .Invoke() // ); // typeInitializer.Add(StoreInType("$", Js.Function().Body(makeGenericType))); typeInitializer.Add(StoreInType(SpecialNames.TypeArgs, Js.Array(classType.TypeArguments.Select(x => Type(x)).ToArray()))); if (!classType.IsAnonymousType) { JsExpression target; if (containingType != null) { target = Js.This().Member(classType.GetShortTypeName() + SpecialNames.MakeGenericType); } else { target = Js.Reference("window." + classType.GetTypeName() + SpecialNames.MakeGenericType); } typeInitializer.Assign(target, GetFromType("$")); } if (explicitBaseType == null && classType.BaseType != null) { typeInitializer.Add(StoreInType(SpecialNames.BaseTypeArgs, Js.Array(classType.BaseType.TypeArguments.Select(x => x == classType ? Js.Reference(SpecialNames.TypeInitializerTypeFunction) : Type(x)).ToArray()))); } } return block; }
private JsBlockStatement InitializeConstructor(INamedTypeSymbol type, string constructorName, Tuple<string, IParameterSymbol>[] parameters) { var block = new JsBlockStatement(); block.Assign(GetFromPrototype(constructorName).Member(SpecialNames.TypeField), Js.Reference(SpecialNames.TypeInitializerTypeFunction)); var parameterNames = parameters.Select(x => x.Item1); JsExpression[] arguments; if (!type.IsBuiltIn()) { block.Assign(GetFromPrototype(constructorName).Member(SpecialNames.New), Js.Function().Body(Js.New(Js.Reference(SpecialNames.TypeInitializerTypeFunction), Js.This(), Js.Reference("arguments")).Return())); } else { arguments = parameters.Where(x => x.Item2 != null && x.Item2.IsBuiltIn()).Select(x => Js.Reference(x.Item1)).ToArray(); block.Assign(GetFromPrototype(constructorName).Member(SpecialNames.New), Js.Function(parameterNames.Select(x => Js.Parameter(x)).ToArray()) .Body(Js.New(GetFromPrototype(constructorName).Member(SpecialNames.TypeField), Js.Array(arguments)).Return())); } return block; }