private JsExpression GenerateStructEqualsMethod(ITypeDefinition type, string typeVariableName) { var o = JsExpression.Identifier("o"); var parts = new List <JsExpression>(); foreach (var f in type.Fields.Where(f => !f.IsStatic)) { var expr = GenerateFieldCompare(f, o); if (expr != null) { parts.Add(expr); } } JsExpression typeCompare = JsExpression.Invocation(JsExpression.Member(_systemScript, "isInstanceOfType"), o, JsExpression.Identifier(typeVariableName)); if (parts.Count == 0) { return(JsExpression.FunctionDefinition(new[] { "o" }, JsStatement.Return(typeCompare))); } else { return(JsExpression.FunctionDefinition(new[] { "o" }, JsStatement.Block( JsStatement.If(JsExpression.LogicalNot(typeCompare), JsStatement.Return(JsExpression.False), null ), JsStatement.Return(parts.Aggregate((old, p) => old == null ? p : JsExpression.LogicalAnd(old, p))) ))); } }
private JsExpression GenerateStructCloneMethod(ITypeDefinition type, string typevarName, bool hasCreateInstance) { var stmts = new List <JsStatement>() { JsStatement.Var("r", hasCreateInstance ? (JsExpression)JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(typevarName), "createInstance")) : JsExpression.New(JsExpression.Identifier(typevarName))) }; var o = JsExpression.Identifier("o"); var r = JsExpression.Identifier("r"); foreach (var f in type.Fields.Where(f => !f.IsStatic)) { var sem = _metadataImporter.GetFieldSemantics(f); if (sem.Type == FieldScriptSemantics.ImplType.Field) { var def = f.ReturnType.GetDefinition(); JsExpression value = JsExpression.Member(o, sem.Name); if (def != null && def.Kind == TypeKind.Struct && _metadataImporter.GetTypeSemantics(def).Type == TypeScriptSemantics.ImplType.MutableValueType) { value = _runtimeLibrary.CloneValueType(value, f.ReturnType, new DefaultRuntimeContext(type, _metadataImporter, _errorReporter, _namer)); } stmts.Add(JsExpression.Assign(JsExpression.Member(r, sem.Name), value)); } } foreach (var p in type.Properties.Where(p => !p.IsStatic)) { var sem = _metadataImporter.GetPropertySemantics(p); if ((sem.Type == PropertyScriptSemantics.ImplType.GetAndSetMethods && MetadataUtils.IsAutoProperty(p) == true) || sem.Type == PropertyScriptSemantics.ImplType.Field) { var def = p.ReturnType.GetDefinition(); var fieldName = sem.Type == PropertyScriptSemantics.ImplType.GetAndSetMethods ? _metadataImporter.GetAutoPropertyBackingFieldName(p) : sem.FieldName; JsExpression value = JsExpression.Member(o, fieldName); if (def != null && def.Kind == TypeKind.Struct && _metadataImporter.GetTypeSemantics(def).Type == TypeScriptSemantics.ImplType.MutableValueType) { value = _runtimeLibrary.CloneValueType(value, p.ReturnType, new DefaultRuntimeContext(type, _metadataImporter, _errorReporter, _namer)); } stmts.Add(JsExpression.Assign(JsExpression.Member(r, fieldName), value)); } } foreach (var e in type.Events.Where(e => !e.IsStatic && MetadataUtils.IsAutoEvent(e) == true)) { var sem = _metadataImporter.GetEventSemantics(e); if (sem.Type == EventScriptSemantics.ImplType.AddAndRemoveMethods) { var def = e.ReturnType.GetDefinition(); var fieldName = _metadataImporter.GetAutoEventBackingFieldName(e); JsExpression value = JsExpression.Member(o, fieldName); if (def != null && def.Kind == TypeKind.Struct && _metadataImporter.GetTypeSemantics(def).Type == TypeScriptSemantics.ImplType.MutableValueType) { value = _runtimeLibrary.CloneValueType(value, e.ReturnType, new DefaultRuntimeContext(type, _metadataImporter, _errorReporter, _namer)); } stmts.Add(JsExpression.Assign(JsExpression.Member(r, fieldName), value)); } } stmts.Add(JsStatement.Return(r)); return(JsExpression.FunctionDefinition(new[] { "o" }, JsStatement.Block(stmts))); }
private bool HandleAwaitStatement(JsAwaitStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock) { var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState).Item1; bool createDummyState = false; if (stateAfter.StateValue == returnState.StateValue) { stateAfter = CreateNewStateValue(currentState.FinallyStack); createDummyState = true; // We must never return to our parent state after an await because } currentBlock.Add(new JsSetNextStateStatement(stateAfter.StateValue)); currentBlock.Add(JsExpression.Invocation(JsExpression.Member(stmt.Awaiter, stmt.OnCompletedMethodName), JsExpression.Identifier(_stateMachineMethodName))); if (_needDoFinallyBlocksVariable) { currentBlock.Add(JsExpression.Assign(JsExpression.Identifier(_doFinallyBlocksVariableName), JsExpression.False)); } currentBlock.Add(JsStatement.Return()); if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1) { Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter, returnState); } if (createDummyState) { Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(JsStatement.Block(JsStatement.BlockMerged(new JsStatement[0])), 0)), breakStack, continueStack, stateAfter, returnState); } return(false); }
private JsBlockStatement ProcessAsyncMethod(JsBlockStatement statement, string stateMachineMethodName, string doFinallyBlocksVariableName, JsVariableDeclaration taskCompletionSource, Func <JsExpression, JsExpression> makeSetResult, Func <JsExpression, JsExpression> makeSetException, Func <JsExpression> getTask, Func <JsExpression, JsExpression, JsExpression> bindToContext) { _stateMachineMethodName = stateMachineMethodName; _doFinallyBlocksVariableName = doFinallyBlocksVariableName; _makeSetResult = taskCompletionSource != null ? makeSetResult : null; _needDoFinallyBlocksVariable = new HasAwaitInsideTryWithFinallyVisitor().Analyze(statement); var result = Process(statement, isIteratorBlock: false, isAsync: true); var hoistResult = VariableHoistingVisitor.Process(result); string catchVariable = _allocateTempVariable(); JsStatement body; if (taskCompletionSource != null && (statement.Statements.Count == 0 || IsNextStatementReachable(statement.Statements[statement.Statements.Count - 1]))) // If we return the task, and if we risk falling out of the original method, we need to add a setResult call. { body = JsStatement.Block(hoistResult.Item1.Statements.Concat(new JsStatement[] { makeSetResult(null) })); } else { body = hoistResult.Item1; } if (taskCompletionSource != null) { body = JsStatement.Try(body, JsStatement.Catch(catchVariable, JsStatement.Block(makeSetException(JsExpression.Identifier(catchVariable)))), null); } IEnumerable <JsVariableDeclaration> declarations = new[] { JsStatement.Declaration(_stateVariableName, JsExpression.Number(0)) }; if (taskCompletionSource != null) { declarations = declarations.Concat(new[] { taskCompletionSource }); } declarations = declarations.Concat(hoistResult.Item2.Select(v => JsStatement.Declaration(v, null))); if (_needDoFinallyBlocksVariable) { body = JsStatement.Block(new[] { JsStatement.Var(_doFinallyBlocksVariableName, JsExpression.True) }.Concat(body is JsBlockStatement ? ((JsBlockStatement)body).Statements : (IEnumerable <JsStatement>) new[] { body })); } var stateMachine = JsExpression.FunctionDefinition(new string[0], body); var boundStateMachine = UsesThisVisitor.Analyze(stateMachine.Body) ? bindToContext(stateMachine, JsExpression.This) : stateMachine; IEnumerable <JsStatement> stmts = new JsStatement[] { JsStatement.Var(declarations), JsStatement.Var(stateMachineMethodName, boundStateMachine), JsExpression.Invocation(JsExpression.Identifier(stateMachineMethodName)) }; if (taskCompletionSource != null) { stmts = stmts.Concat(new[] { JsStatement.Return(getTask()) }); } return(JsStatement.Block(stmts)); }
public override JsStatement VisitReturnStatement(JsReturnStatement statement, object data) { if (_makeSetResult != null) { return(JsStatement.BlockMerged(_makeSetResult(statement.Value), JsStatement.Return())); } else { return(statement); } }
public static IList <JsStatement> Process(IMetadataImporter metadataImporter, INamer namer, ICompilation compilation, IList <JsStatement> statements) { var usedSymbols = UsedSymbolsGatherer.Analyze(statements); var importer = new ImportVisitor(metadataImporter, namer, compilation.MainAssembly, usedSymbols); var body = statements.Select(s => importer.VisitStatement(s, null)).ToList(); var moduleDependencies = importer._moduleAliases.Concat(MetadataUtils.GetAdditionalDependencies(compilation.MainAssembly)); if (MetadataUtils.IsAsyncModule(compilation.MainAssembly)) { body.InsertRange(0, new[] { JsStatement.UseStrict, JsStatement.Var("exports", JsExpression.ObjectLiteral()) }); body.Add(JsStatement.Return(JsExpression.Identifier("exports"))); var pairs = new[] { new KeyValuePair <string, string>("mscorlib", namer.GetVariableName("_", usedSymbols)) } .Concat(moduleDependencies.OrderBy(x => x.Key)) .ToList(); body = new List <JsStatement> { JsExpression.Invocation( JsExpression.Identifier("define"), JsExpression.ArrayLiteral(pairs.Select(p => JsExpression.String(p.Key))), JsExpression.FunctionDefinition( pairs.Select(p => p.Value), JsStatement.Block(body) ) ) }; } else if (moduleDependencies.Any()) { // If we require any module, we require mscorlib. This should work even if we are a leaf module that doesn't include any other module because our parent script will do the mscorlib require for us. body.InsertRange(0, new[] { JsStatement.UseStrict, JsExpression.Invocation(JsExpression.Identifier("require"), JsExpression.String("mscorlib")) } .Concat(moduleDependencies .OrderBy(x => x.Key).OrderBy(x => x.Key) .Select(x => JsStatement.Var( x.Value, JsExpression.Invocation( JsExpression.Identifier("require"), JsExpression.String(x.Key)))) .ToList())); } else { body.Insert(0, JsStatement.UseStrict); body = new List <JsStatement> { JsExpression.Invocation(JsExpression.FunctionDefinition(new string[0], JsStatement.Block(body))) }; } return(body); }
private bool HandleYieldReturnStatement(JsYieldStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock) { var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState); currentBlock.Add(_makeSetCurrent(stmt.Value)); currentBlock.Add(new JsSetNextStateStatement(stateAfter.Item1.StateValue)); currentBlock.Add(JsStatement.Return(JsExpression.True)); if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1) { Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState); } return(false); }
public void ImportingImportedTypeFromOwnAssemblyWorks() { var asm = Common.CreateMockAssembly(); var type = Common.CreateMockTypeDefinition("MyImportedType", asm, attributes: new Expression <Func <Attribute> >[] { () => new ImportedAttribute() }); var actual = Process(new JsStatement[] { JsStatement.Return(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.Member(new JsTypeReferenceExpression(type), "x"), JsExpression.Number(1))) }, asm, metadata: new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType("$" + t.FullName) }); AssertCorrect(actual, @"(function() { 'use strict'; return $MyImportedType.x + 1; })(); "); }
public void UsingTypeWithNoScriptNameInModuleReturnsTheModuleVariable() { var asm = Common.CreateMockAssembly(attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("main-module") }); var type = Common.CreateMockTypeDefinition("GlobalType", asm, attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("some-module") }); var actual = Process(new JsStatement[] { JsStatement.Return(new JsTypeReferenceExpression(type)), }, new[] { asm }, metadata: new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType("") }); AssertCorrect(actual, @"'use strict'; require('mscorlib'); var $somemodule = require('some-module'); return $somemodule; "); }
public void ImportingTypesFromGlobalNamespaceWorks() { var otherAsm = Common.CreateMockAssembly(); var actual = Process(new JsStatement[] { new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("GlobalType", otherAsm)), JsStatement.Return(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.Member(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("Global.NestedNamespace.InnerNamespace.Type", otherAsm)), "x"), JsExpression.Number(1))) }, Common.CreateMockAssembly(), new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType(string.Join(".", t.FullName.Split('.').Select(x => "$" + x))) }); AssertCorrect(actual, @"(function() { 'use strict'; $GlobalType; return $Global.$NestedNamespace.$InnerNamespace.$Type.x + 1; })(); "); }
public void ImportingTypeFromOwnAssemblyButOtherModuleNameResultsInARequire() { var asm = Common.CreateMockAssembly(attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("main-module") }); var type = Common.CreateMockTypeDefinition("GlobalType", asm, attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("some-module") }); var actual = Process(new JsStatement[] { new JsTypeReferenceExpression(type), JsStatement.Return(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.Member(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("Global.NestedNamespace.InnerNamespace.Type", asm, attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("some-module") })), "x"), JsExpression.Number(1))) }, new[] { asm }, metadata: new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType(string.Join(".", t.FullName.Split('.').Select(x => "$" + x))) }); AssertCorrect(actual, @"'use strict'; require('mscorlib'); var $somemodule = require('some-module'); $somemodule.$GlobalType; return $somemodule.$Global.$NestedNamespace.$InnerNamespace.$Type.x + 1; "); }
public void ImportingTypeFromOwnAssemblyUsesTheTypeVariable() { var asm = Common.CreateMockAssembly(); var type = Common.CreateMockTypeDefinition("GlobalType", asm); var actual = Process(new JsStatement[] { new JsTypeReferenceExpression(type), JsStatement.Return(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.Member(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("Global.NestedNamespace.InnerNamespace.Type", asm)), "x"), JsExpression.Number(1))) }, new[] { asm }, new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType(string.Join(".", t.FullName.Split('.').Select(x => "$" + x))) }); AssertCorrect(actual, @"(function() { 'use strict'; var $asm = {}; $$GlobalType; return $$Global_$NestedNamespace_$InnerNamespace_$Type.x + 1; })(); "); }
private JsBlockStatement Process(JsBlockStatement statement, bool isIteratorBlock, bool isAsync) { _stateVariableName = _allocateStateVariable(); _nextStateIndex = 0; _isIteratorBlock = isIteratorBlock; _isAsync = isAsync; _processedStates = new HashSet <State>(); _labelStates = new Dictionary <string, State>(); _finallyHandlers = new List <Tuple <string, JsBlockStatement> >(); _allStates = new List <State>(); _remainingBlocks = new Queue <RemainingBlock>(); _exitState = null; _childStates = new Dictionary <int, List <int> >(); var body = ProcessInner(statement, ImmutableStack <Tuple <string, State> > .Empty, ImmutableStack <Tuple <string, State> > .Empty, ImmutableStack <Tuple <int, string> > .Empty, null).Item1; if (_isIteratorBlock) { body.Add(JsStatement.Return(JsExpression.False)); } var resultBody = new FinalizerRewriter(_stateVariableName, _labelStates).Process(JsStatement.Block(body)); return(resultBody); }
private JsFunctionDefinitionExpression GenerateStructGetHashCodeMethod(ITypeDefinition type) { JsExpression h = JsExpression.Identifier("h"); var stmts = new List <JsStatement>(); foreach (var f in type.Fields.Where(f => !f.IsStatic)) { var expr = GetFieldHashCode(f); if (expr != null) { if (stmts.Count == 0) { stmts.Add(JsStatement.Var("h", expr)); } else { stmts.Add(JsExpression.Assign(h, JsExpression.BitwiseXor(JsExpression.Multiply(h, JsExpression.Number(397)), expr))); } } } switch (stmts.Count) { case 0: stmts.Add(JsStatement.Return(JsExpression.Number(0))); break; case 1: stmts[0] = JsStatement.Return(JsExpression.BitwiseOr(((JsVariableDeclarationStatement)stmts[0]).Declarations[0].Initializer, JsExpression.Number(0))); break; default: stmts.Add(JsStatement.Return(h)); break; } return(JsExpression.FunctionDefinition(EmptyList <string> .Instance, JsStatement.Block(stmts))); }
public JsFunctionDefinitionExpression CompileAutoPropertyGetter(IProperty property, PropertyScriptSemantics impl, string backingFieldName) { try { CreateCompilationContext(null, null, property.DeclaringTypeDefinition, null); if (property.IsStatic) { var jsType = _runtimeLibrary.InstantiateType(Utils.SelfParameterize(property.DeclaringTypeDefinition), _statementCompiler); return(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.Member(jsType, backingFieldName)))); } else if (impl.GetMethod.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) { return(JsExpression.FunctionDefinition(new[] { _namer.ThisAlias }, JsStatement.Return(JsExpression.Member(JsExpression.Identifier(_namer.ThisAlias), backingFieldName)))); } else { return(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.Member(JsExpression.This, backingFieldName)))); } } catch (Exception ex) { _errorReporter.Region = property.Getter.Region; _errorReporter.InternalError(ex); return(JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock)); } }
private static JsExpression ConstructMemberInfo(IMember m, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType, MethodScriptSemantics semanticsIfAccessor) { if (m is IMethod && ((IMethod)m).IsConstructor) { return(ConstructConstructorInfo((IMethod)m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType)); } var properties = GetCommonMemberInfoProperties(m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType); if (m.IsStatic) { properties.Add(new JsObjectLiteralProperty("isStatic", JsExpression.True)); } if (m is IMethod) { var method = (IMethod)m; var sem = semanticsIfAccessor ?? metadataImporter.GetMethodSemantics(method); if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7201, m.FullName, "method"); return(JsExpression.Null); } if ((sem.Type == MethodScriptSemantics.ImplType.NormalMethod || sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) && sem.ExpandParams) { properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True)); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method))); if (sem.Type == MethodScriptSemantics.ImplType.InlineCode) { var usedNames = new HashSet <string>(); var parameters = new List <IVariable>(); var variables = new Dictionary <IVariable, VariableData>(); var arguments = new List <ResolveResult>(); foreach (var p in method.Parameters) { string name = namer.GetVariableName(p.Name, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); arguments.Add(new LocalResolveResult(variable)); } var tokens = InlineCodeMethodCompiler.Tokenize(method, sem.LiteralCode, _ => {}); var compileResult = Compile(CreateMethodInvocationResolveResult(method, method.IsStatic ? (ResolveResult) new TypeResolveResult(method.DeclaringType) : new ThisResolveResult(method.DeclaringType), arguments), method.DeclaringTypeDefinition, method, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, true, variables, usedNames); var definition = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), JsStatement.Block(compileResult.AdditionalStatements.Concat(new[] { JsStatement.Return(compileResult.Expression) }))); if (tokens.Any(t => t.Type == InlineCodeToken.TokenType.TypeParameter && t.OwnerType == SymbolKind.Method)) { definition = JsExpression.FunctionDefinition(method.TypeParameters.Select(namer.GetTypeParameterName), JsStatement.Return(definition)); properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count))); } properties.Add(new JsObjectLiteralProperty("def", definition)); } else { if (IsJsGeneric(method, metadataImporter)) { properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count))); } if (sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) { properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True)); } properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(method.ReturnType))); properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(method.Parameters.Select(p => instantiateType(p.Type))))); } else if (m is IField) { var field = (IField)m; var sem = metadataImporter.GetFieldSemantics(field); if (sem.Type != FieldScriptSemantics.ImplType.Field) { errorReporter.Message(Messages._7201, m.FullName, "field"); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Field))); properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(field.ReturnType))); properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } else if (m is IProperty) { var prop = (IProperty)m; var sem = metadataImporter.GetPropertySemantics(prop); properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property))); properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(prop.ReturnType))); if (prop.Parameters.Count > 0) { properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(prop.Parameters.Select(p => instantiateType(p.Type))))); } switch (sem.Type) { case PropertyScriptSemantics.ImplType.GetAndSetMethods: if (sem.GetMethod != null && sem.GetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.GetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.GetMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "property", "getter"); return(JsExpression.Null); } if (sem.SetMethod != null && sem.SetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.SetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.SetMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "property", "setter"); return(JsExpression.Null); } if (sem.GetMethod != null) { properties.Add(new JsObjectLiteralProperty("getter", ConstructMemberInfo(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.GetMethod))); } if (sem.SetMethod != null) { properties.Add(new JsObjectLiteralProperty("setter", ConstructMemberInfo(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.SetMethod))); } break; case PropertyScriptSemantics.ImplType.Field: if (prop.CanGet) { properties.Add(new JsObjectLiteralProperty("getter", ConstructFieldPropertyAccessor(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: true, includeDeclaringType: includeDeclaringType))); } if (prop.CanSet) { properties.Add(new JsObjectLiteralProperty("setter", ConstructFieldPropertyAccessor(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: false, includeDeclaringType: includeDeclaringType))); } properties.Add(new JsObjectLiteralProperty("fname", JsExpression.String(sem.FieldName))); break; default: errorReporter.Message(Messages._7201, m.FullName, "property"); return(JsExpression.Null); } } else if (m is IEvent) { var evt = (IEvent)m; var sem = metadataImporter.GetEventSemantics(evt); if (sem.Type != EventScriptSemantics.ImplType.AddAndRemoveMethods) { errorReporter.Message(Messages._7201, m.FullName, "event"); return(JsExpression.Null); } if (sem.AddMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.AddMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.AddMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "event", "add accessor"); return(JsExpression.Null); } if (sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "event", "remove accessor"); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Event))); properties.Add(new JsObjectLiteralProperty("adder", ConstructMemberInfo(evt.AddAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.AddMethod))); properties.Add(new JsObjectLiteralProperty("remover", ConstructMemberInfo(evt.RemoveAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType, sem.RemoveMethod))); } else { throw new ArgumentException("Invalid member " + m); } return(JsExpression.ObjectLiteral(properties)); }
private static JsExpression ConstructConstructorInfo(IMethod constructor, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType) { var properties = GetCommonMemberInfoProperties(constructor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType); var sem = metadataImporter.GetConstructorSemantics(constructor); if (sem.Type == ConstructorScriptSemantics.ImplType.NotUsableFromScript) { errorReporter.Message(Messages._7200, constructor.FullName); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Constructor))); properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(constructor.Parameters.Select(p => instantiateType(p.Type))))); if (sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } if (sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True)); } if ((sem.Type == ConstructorScriptSemantics.ImplType.UnnamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) && sem.ExpandParams) { properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True)); } if (sem.Type == ConstructorScriptSemantics.ImplType.Json || sem.Type == ConstructorScriptSemantics.ImplType.InlineCode) { var usedNames = new HashSet <string>(); var parameters = new List <IVariable>(); var variables = new Dictionary <IVariable, VariableData>(); IList <ResolveResult> constructorParameters = null; IList <ResolveResult> initializerStatements = null; if (sem.Type == ConstructorScriptSemantics.ImplType.Json && constructor.DeclaringType.Kind == TypeKind.Anonymous) { initializerStatements = new List <ResolveResult>(); foreach (var p in constructor.DeclaringType.GetProperties()) { string paramName = MakeCamelCase(p.Name); string name = namer.GetVariableName(paramName, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.ReturnType, paramName, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); initializerStatements.Add(new OperatorResolveResult(p.ReturnType, ExpressionType.Assign, new MemberResolveResult(new InitializedObjectResolveResult(constructor.DeclaringType), p), new LocalResolveResult(variable))); } } else { constructorParameters = new List <ResolveResult>(); foreach (var p in constructor.Parameters) { string name = namer.GetVariableName(p.Name, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); constructorParameters.Add(new LocalResolveResult(variable)); } } var compileResult = CompileConstructorInvocation(constructor, initializerStatements, constructor.DeclaringTypeDefinition, constructor, constructorParameters, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, variables, usedNames); var definition = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), JsStatement.Block(compileResult.AdditionalStatements.Concat(new[] { JsStatement.Return(compileResult.Expression) }))); properties.Add(new JsObjectLiteralProperty("def", definition)); } return(JsExpression.ObjectLiteral(properties)); }
public static JsExpression ConstructAttribute(IAttribute attr, ITypeDefinition currentType, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter) { errorReporter.Region = attr.Region; var initializerStatements = attr.NamedArguments.Select(a => new OperatorResolveResult(a.Key.ReturnType, ExpressionType.Assign, new MemberResolveResult(new InitializedObjectResolveResult(attr.AttributeType), a.Key), a.Value)).ToList <ResolveResult>(); var constructorResult = CompileConstructorInvocation(attr.Constructor, initializerStatements, currentType, null, attr.PositionalArguments, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, null, null); if (constructorResult.AdditionalStatements.Count > 0) { return(JsExpression.Invocation(JsExpression.FunctionDefinition(new string[0], JsStatement.Block(constructorResult.AdditionalStatements.Concat(new[] { JsStatement.Return(constructorResult.Expression) }))))); } else { return(constructorResult.Expression); } }
public virtual JsStatement VisitReturnStatement(JsReturnStatement statement, TData data) { var value = (statement.Value != null ? VisitExpression(statement.Value, data) : null); return(ReferenceEquals(value, statement.Value) ? statement : JsStatement.Return(value)); }
public IList <JsStatement> Process(IEnumerable <JsType> types, IMethod entryPoint) { var result = new List <JsStatement>(); var orderedTypes = OrderByNamespace(types, t => _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name).ToList(); var exportedNamespacesByRoot = new Dictionary <string, HashSet <string> >(); foreach (var t in orderedTypes) { try { string name = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name; bool isGlobal = string.IsNullOrEmpty(name); bool isMixin = MetadataUtils.IsMixin(t.CSharpTypeDefinition); bool export = t.CSharpTypeDefinition.IsExternallyVisible(); result.Add(JsStatement.Comment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName)); string typevarName = _namer.GetTypeVariableName(name); if (t is JsClass) { var c = (JsClass)t; if (isGlobal) { result.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(JsExpression.Identifier(GetRoot(t.CSharpTypeDefinition)), m.Name), m.Definition))); export = false; } else if (isMixin) { result.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition))); export = false; } else if (MetadataUtils.IsResources(c.CSharpTypeDefinition)) { result.Add(GenerateResourcesClass(c)); } else { var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock); if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) { var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList(); var stmts = new List <JsStatement> { JsStatement.Var(InstantiatedGenericTypeVariableName, unnamedCtor) }; AddClassMembers(c, InstantiatedGenericTypeVariableName, stmts); stmts.AddRange(c.StaticInitStatements); stmts.Add(JsStatement.Return(JsExpression.Identifier(InstantiatedGenericTypeVariableName))); var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName)); for (int i = 0; i < stmts.Count; i++) { stmts[i] = replacer.Process(stmts[i]); } result.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(typeParameterNames, JsStatement.Block(stmts)))); result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name))); var args = new List <JsExpression> { JsExpression.Identifier(typevarName), JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount) }; result.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? InitGenericInterface : InitGenericClass), args)); } else { result.Add(JsStatement.Var(typevarName, unnamedCtor)); result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name))); AddClassMembers(c, typevarName, result); } } } else if (t is JsEnum) { var e = (JsEnum)t; result.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock))); result.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(e.CSharpTypeDefinition).Name))); } if (export) { string root = GetRoot(t.CSharpTypeDefinition); var split = SplitIntoNamespaceAndName(name); if (!string.IsNullOrEmpty(split.Item1)) { HashSet <string> hs; if (!exportedNamespacesByRoot.TryGetValue(root, out hs)) { hs = exportedNamespacesByRoot[root] = new HashSet <string>(); } hs.Add(split.Item1); } result.Add(JsExpression.Assign(MakeNestedMemberAccess(name, JsExpression.Identifier(root)), JsExpression.Identifier(typevarName))); } } catch (Exception ex) { _errorReporter.Region = t.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName); } } result.InsertRange(0, exportedNamespacesByRoot.OrderBy(x => x.Key).SelectMany(x => CreateNamespaces(JsExpression.Identifier(x.Key), x.Value)).ToList()); var typesToRegister = TopologicalSortTypesByInheritance(orderedTypes) .Where(c => !(c is JsClass && MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) && !string.IsNullOrEmpty(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name) && !MetadataUtils.IsResources(c.CSharpTypeDefinition) && !MetadataUtils.IsMixin(c.CSharpTypeDefinition)) .ToList(); foreach (var t in typesToRegister) { try { string name = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name; string typevarName = _namer.GetTypeVariableName(name); if (t.CSharpTypeDefinition.Kind == TypeKind.Enum) { result.Add(CreateInitEnumCall((JsEnum)t, typevarName)); } else { var c = (JsClass)t; if (t.CSharpTypeDefinition.Kind == TypeKind.Interface) { result.Add(CreateInitInterfaceCall(c, typevarName, GetImplementedInterfaces(t.CSharpTypeDefinition.GetDefinition()).ToList())); } else { result.Add(CreateInitClassCall(c, typevarName, GetBaseClass(t.CSharpTypeDefinition), GetImplementedInterfaces(t.CSharpTypeDefinition).ToList())); if (c.NamedConstructors.Count > 0) { result.Add(AssignNamedConstructorPrototypes(c, JsExpression.Identifier(_namer.GetTypeVariableName(name)))); } } } } catch (Exception ex) { _errorReporter.Region = t.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName); } } foreach (var t in orderedTypes) { var metadata = GetMetadataDescriptor(t.CSharpTypeDefinition, false); if (metadata != null) { result.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, SetMetadata), JsExpression.Identifier(_namer.GetTypeVariableName(_metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name)), metadata)); } } result.AddRange(GetStaticInitializationOrder(orderedTypes.OfType <JsClass>(), 1) .Where(c => !MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter) && !MetadataUtils.IsResources(c.CSharpTypeDefinition)) .SelectMany(c => c.StaticInitStatements)); if (entryPoint != null) { if (entryPoint.Parameters.Count > 0) { _errorReporter.Region = entryPoint.Region; _errorReporter.Message(Messages._7800, entryPoint.FullName); } else { var sem = _metadataImporter.GetMethodSemantics(entryPoint); if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod) { _errorReporter.Region = entryPoint.Region; _errorReporter.Message(Messages._7801, entryPoint.FullName); } else { result.Add(JsExpression.Invocation(JsExpression.Member(new JsTypeReferenceExpression(entryPoint.DeclaringTypeDefinition), sem.Name))); } } } return(result); }
public void ObjectLiteralWithFunctionValuesAreOutputOnMultipleLines() { AssertCorrect(JsExpression.ObjectLiteral(new JsObjectLiteralProperty("x", JsExpression.Number(1)), new JsObjectLiteralProperty("y", JsExpression.FunctionDefinition(new string[0], JsStatement.Return())), new JsObjectLiteralProperty("z", JsExpression.Number(3))), @"{ x: 1, y: function() { return; }, z: 3 }"); }
public void FunctionDefinitionExpressionIsCorrectlyOutput() { AssertCorrect(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.Null)), "function() {\n\treturn null;\n}"); AssertCorrect(JsExpression.FunctionDefinition(new [] { "a", "b" }, JsStatement.Return(JsExpression.Null)), "function(a, b) {\n\treturn null;\n}"); AssertCorrect(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.Null), name: "myFunction"), "function myFunction() {\n\treturn null;\n}"); }
public void ReturnStatementWithOrWithoutExpressionIsCorrectlyOutput() { AssertCorrect(JsStatement.Return(null), "return;\n"); AssertCorrect(JsStatement.Return(JsExpression.Identifier("x")), "return x;\n"); }
public JsExpression GetExpressionForLocal(string name, JsExpression accessor, IType type, IRuntimeContext context) { var scriptType = TypeOf(type, context); JsExpression getterDefinition = JsExpression.FunctionDefinition(new string[0], JsStatement.Return(accessor)); JsExpression setterDefinition = JsExpression.FunctionDefinition(new[] { "$" }, JsExpression.Assign(accessor, JsExpression.Identifier("$"))); if (UsesThisVisitor.Analyze(accessor)) { getterDefinition = JsExpression.Invocation(JsExpression.Member(getterDefinition, "bind"), JsExpression.This); setterDefinition = JsExpression.Invocation(JsExpression.Member(setterDefinition, "bind"), JsExpression.This); } return(JsExpression.ObjectLiteral( new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.MemberAccess)), new JsObjectLiteralProperty("type", scriptType), new JsObjectLiteralProperty("expression", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.Constant)), new JsObjectLiteralProperty("type", scriptType), new JsObjectLiteralProperty("value", JsExpression.ObjectLiteral()) )), new JsObjectLiteralProperty("member", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String(name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property)), new JsObjectLiteralProperty("returnType", scriptType), new JsObjectLiteralProperty("getter", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String("get_" + name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)), new JsObjectLiteralProperty("returnType", scriptType), new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral()), new JsObjectLiteralProperty("def", getterDefinition) )), new JsObjectLiteralProperty("setter", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String("set_" + name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)), new JsObjectLiteralProperty("returnType", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Void).GetDefinition())), new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(scriptType)), new JsObjectLiteralProperty("def", setterDefinition) )) )) )); }
private JsExpression RewriteMethod(JsMethod method) { return(method.TypeParameterNames.Count == 0 ? method.Definition : JsExpression.FunctionDefinition(method.TypeParameterNames, JsStatement.Return(method.Definition))); }
private void AddClassMembers(JsClass c, string typevarName, List <JsStatement> stmts) { if (c.NamedConstructors.Count > 0) { stmts.AddRange(c.NamedConstructors.Select(m => (JsStatement)JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), m.Name), m.Definition))); } var defaultConstructor = Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition).GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic); bool hasCreateInstance = false; if (defaultConstructor != null) { var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor); if (sem.Type != ConstructorScriptSemantics.ImplType.UnnamedConstructor && sem.Type != ConstructorScriptSemantics.ImplType.NotUsableFromScript) { var createInstance = MetadataUtils.CompileConstructorInvocation(defaultConstructor, null, c.CSharpTypeDefinition, null, EmptyList <ResolveResult> .Instance, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, null, null); stmts.Add(JsExpression.Assign( JsExpression.Member(JsExpression.Identifier(typevarName), "createInstance"), JsExpression.FunctionDefinition(new string[0], JsStatement.Block(createInstance.AdditionalStatements.Concat(new[] { JsStatement.Return(createInstance.Expression) }))))); hasCreateInstance = true; } } if (c.CSharpTypeDefinition.Kind == TypeKind.Struct) { stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "getDefaultValue"), hasCreateInstance ? JsExpression.Member(JsExpression.Identifier(typevarName), "createInstance") : JsExpression.FunctionDefinition(EmptyList <string> .Instance, JsStatement.Return(JsExpression.New(JsExpression.Identifier(typevarName)))))); if (_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Type == TypeScriptSemantics.ImplType.MutableValueType) { stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "$clone"), GenerateStructCloneMethod(c.CSharpTypeDefinition, typevarName, hasCreateInstance))); } } stmts.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), m.Name), RewriteMethod(m)))); if (MetadataUtils.IsSerializable(c.CSharpTypeDefinition, _attributeStore)) { string typeCheckCode = MetadataUtils.GetSerializableTypeCheckCode(c.CSharpTypeDefinition, _attributeStore); if (!string.IsNullOrEmpty(typeCheckCode)) { var oldReg = _errorReporter.Region; _errorReporter.Region = c.CSharpTypeDefinition.Attributes.Single(a => a.AttributeType.FullName == typeof(SerializableAttribute).FullName).Region; var method = MetadataUtils.CreateTypeCheckMethod(Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition), _compilation); var errors = new List <string>(); var tokens = InlineCodeMethodCompiler.Tokenize(method, typeCheckCode, errors.Add); if (errors.Count == 0) { var context = new DefaultRuntimeContext(c.CSharpTypeDefinition, _metadataImporter, _errorReporter, _namer); var result = InlineCodeMethodCompiler.CompileExpressionInlineCodeMethodInvocation(method, tokens, JsExpression.Identifier("obj"), new JsExpression[0], n => { var type = ReflectionHelper.ParseReflectionName(n).Resolve(_compilation); if (type.Kind == TypeKind.Unknown) { errors.Add("Unknown type '" + n + "' specified in inline implementation"); return(JsExpression.Null); } return(_runtimeLibrary.InstantiateType(type, context)); }, t => _runtimeLibrary.InstantiateTypeForUseAsTypeArgumentInInlineCode(t, context), errors.Add); stmts.Add(JsExpression.Assign( JsExpression.Member(JsExpression.Identifier(typevarName), "isInstanceOfType"), JsExpression.FunctionDefinition(new[] { "obj" }, JsStatement.Return(result)))); foreach (var e in errors) { _errorReporter.Message(Messages._7157, c.CSharpTypeDefinition.FullName, e); } } _errorReporter.Region = oldReg; } else { stmts.Add(JsExpression.Assign( JsExpression.Member(JsExpression.Identifier(typevarName), "isInstanceOfType"), JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.True)))); } } if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) { var args = new List <JsExpression> { JsExpression.Identifier(typevarName), new JsTypeReferenceExpression(c.CSharpTypeDefinition), JsExpression.ArrayLiteral(c.CSharpTypeDefinition.TypeParameters.Select(tp => JsExpression.Identifier(_namer.GetTypeParameterName(tp)))), CreateInstanceMembers(c, typevarName), }; if (c.CSharpTypeDefinition.Kind != TypeKind.Interface) { args.Add(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(GetBaseClass(c.CSharpTypeDefinition) ?? JsExpression.Null))); } args.Add(JsExpression.FunctionDefinition(new string[0], JsStatement.Return(JsExpression.ArrayLiteral(GetImplementedInterfaces(c.CSharpTypeDefinition))))); stmts.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? RegisterGenericInterfaceInstance : RegisterGenericClassInstance), args)); if (c.CSharpTypeDefinition.Kind == TypeKind.Class && c.NamedConstructors.Count > 0) { stmts.Add(AssignNamedConstructorPrototypes(c, JsExpression.Identifier(typevarName))); } if (c.CSharpTypeDefinition.Kind == TypeKind.Struct) { stmts.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), "__class"), JsExpression.False)); } var metadata = GetMetadataDescriptor(c.CSharpTypeDefinition, true); if (metadata != null) { stmts.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, SetMetadata), JsExpression.Identifier(typevarName), metadata)); } } }
public JsFunctionDefinitionExpression CompileConstructor(ConstructorDeclaration ctor, IMethod constructor, List <JsStatement> instanceInitStatements, ConstructorScriptSemantics impl) { var region = _errorReporter.Region = ctor != null?ctor.GetRegion() : constructor.DeclaringTypeDefinition.Region; try { CreateCompilationContext(ctor, constructor, constructor.DeclaringTypeDefinition, (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod ? _namer.ThisAlias : null)); IList <JsStatement> body = new List <JsStatement>(); body.AddRange(PrepareParameters(constructor.Parameters, variables, expandParams: impl.ExpandParams, staticMethodWithThisAsFirstArgument: false)); if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { if (ctor != null && !ctor.Initializer.IsNull) { body.AddRange(_statementCompiler.CompileConstructorInitializer(ctor.Initializer, true)); } else { body.AddRange(_statementCompiler.CompileImplicitBaseConstructorCall(constructor.DeclaringTypeDefinition, true)); } } if (ctor == null || ctor.Initializer.IsNull || ctor.Initializer.ConstructorInitializerType != ConstructorInitializerType.This) { if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { // The compiler one step up has created the statements as "this.a = b;", but we need to replace that with "$this.a = b;" (or whatever name the this alias has). var replacer = new ThisReplacer(JsExpression.Identifier(_namer.ThisAlias)); instanceInitStatements = instanceInitStatements.Select(s => replacer.VisitStatement(s, null)).ToList(); } body.AddRange(instanceInitStatements); // Don't initialize fields when we are chaining, but do it when we 1) compile the default constructor, 2) don't have an initializer, or 3) when the initializer is not this(...). } if (impl.Type != ConstructorScriptSemantics.ImplType.StaticMethod) { if (ctor != null && !ctor.Initializer.IsNull) { body.AddRange(_statementCompiler.CompileConstructorInitializer(ctor.Initializer, false)); } else { body.AddRange(_statementCompiler.CompileImplicitBaseConstructorCall(constructor.DeclaringTypeDefinition, false)); } } if (ctor != null) { body.AddRange(_statementCompiler.Compile(ctor.Body).Statements); } if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { if (body.Count == 0 || !(body[body.Count - 1] is JsReturnStatement)) { body.Add(JsStatement.Return()); } body = StaticMethodConstructorReturnPatcher.Process(body, _namer.ThisAlias).AsReadOnly(); } var compiled = JsExpression.FunctionDefinition(constructor.Parameters.Where((p, i) => i != constructor.Parameters.Count - 1 || !impl.ExpandParams).Select(p => variables[p].Name), JsStatement.Block(body)); return(_statementCompiler.StateMachineRewriteNormalMethod(compiled)); } catch (Exception ex) { _errorReporter.Region = region; _errorReporter.InternalError(ex); return(JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock)); } }
private TypeOOPEmulationPhase CreateTypeDefinitions(JsType type) { string name = _metadataImporter.GetTypeSemantics(type.CSharpTypeDefinition).Name; bool isGlobal = string.IsNullOrEmpty(name); bool isMixin = MetadataUtils.IsMixin(type.CSharpTypeDefinition, _attributeStore); bool export = type.CSharpTypeDefinition.IsExternallyVisible(); var statements = new List <JsStatement>(); statements.Add(JsStatement.Comment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + type.CSharpTypeDefinition.FullName)); string typevarName = _namer.GetTypeVariableName(name); if (type is JsClass) { var c = (JsClass)type; if (isGlobal) { statements.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(JsExpression.Identifier(GetRoot(type.CSharpTypeDefinition)), m.Name), m.Definition))); export = false; } else if (isMixin) { statements.AddRange(c.StaticMethods.Select(m => (JsStatement)JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition))); export = false; } else if (MetadataUtils.IsResources(c.CSharpTypeDefinition, _attributeStore)) { statements.Add(GenerateResourcesClass(c)); } else { var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock); if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) { var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList(); var stmts = new List <JsStatement> { JsStatement.Var(InstantiatedGenericTypeVariableName, unnamedCtor) }; AddClassMembers(c, InstantiatedGenericTypeVariableName, stmts); stmts.AddRange(c.StaticInitStatements); stmts.Add(JsStatement.Return(JsExpression.Identifier(InstantiatedGenericTypeVariableName))); var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName)); for (int i = 0; i < stmts.Count; i++) { stmts[i] = replacer.Process(stmts[i]); } statements.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(typeParameterNames, JsStatement.Block(stmts)))); statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name))); var args = new List <JsExpression> { JsExpression.Identifier(typevarName), _linker.CurrentAssemblyExpression, JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount) }; statements.Add(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? InitGenericInterface : InitGenericClass), args)); } else { statements.Add(JsStatement.Var(typevarName, unnamedCtor)); statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name))); AddClassMembers(c, typevarName, statements); } } } else if (type is JsEnum) { var e = (JsEnum)type; statements.Add(JsStatement.Var(typevarName, JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock))); statements.Add(JsExpression.Assign(JsExpression.Member(JsExpression.Identifier(typevarName), TypeName), JsExpression.String(_metadataImporter.GetTypeSemantics(e.CSharpTypeDefinition).Name))); } if (export) { string root = GetRoot(type.CSharpTypeDefinition); statements.Add(JsExpression.Assign(MakeNestedMemberAccess(name, JsExpression.Identifier(root)), JsExpression.Identifier(typevarName))); } return(new TypeOOPEmulationPhase(null, statements)); }
public override JsStatement VisitReturnStatement(JsReturnStatement statement, object data) { return(JsStatement.Return(_identifier)); }
public static IList <JsStatement> Process(IMetadataImporter metadataImporter, INamer namer, IAttributeStore attributeStore, ICompilation compilation, IList <JsStatement> statements) { var locals = LocalVariableGatherer.Analyze(statements); var globals = ImplicitGlobalsGatherer.Analyze(statements, locals, reportGlobalsAsUsedInAllParentScopes: false); var introducedNames = IntroducedNamesGatherer.Analyze(statements, metadataImporter, attributeStore, compilation.MainAssembly); var renameMap = RenameMapBuilder.BuildMap(statements, locals, globals, introducedNames, namer); var usedSymbols = new HashSet <string>(); foreach (var sym in locals.Values.SelectMany(v => v) // Declared locals. .Concat(globals.Values.SelectMany(v => v)) // Implicitly declared globals. .Concat(renameMap.Values.SelectMany(v => v.Values)) // Locals created during preparing rename. .Concat(introducedNames.Values.SelectMany(v => v)) // All global types used. ) { usedSymbols.Add(sym); } statements = IdentifierRenamer.Process(statements, renameMap).ToList(); bool isModule = MetadataUtils.GetModuleName(compilation.MainAssembly, attributeStore) != null || MetadataUtils.IsAsyncModule(compilation.MainAssembly, attributeStore); var importer = new ImportVisitor(metadataImporter, namer, attributeStore, compilation.MainAssembly, usedSymbols, JsExpression.Identifier(isModule ? "exports" : "$asm")); var body = (!isModule ? new[] { JsStatement.Var("$asm", JsExpression.ObjectLiteral()) } : new JsStatement[0]).Concat(statements.Select(s => importer.VisitStatement(s, null))).ToList(); var moduleDependencies = importer._moduleAliases.Concat(MetadataUtils.GetAdditionalDependencies(compilation.MainAssembly, attributeStore)); if (MetadataUtils.IsAsyncModule(compilation.MainAssembly, attributeStore)) { body.InsertRange(0, new[] { JsStatement.UseStrict, JsStatement.Var("exports", JsExpression.ObjectLiteral()) }); body.Add(JsStatement.Return(JsExpression.Identifier("exports"))); var pairs = new[] { new KeyValuePair <string, string>("mscorlib", namer.GetVariableName("_", usedSymbols)) } .Concat(moduleDependencies.OrderBy(x => x.Key)) .ToList(); body = new List <JsStatement> { JsExpression.Invocation( JsExpression.Identifier("define"), JsExpression.ArrayLiteral(pairs.Select(p => JsExpression.String(p.Key))), JsExpression.FunctionDefinition( pairs.Select(p => p.Value), JsStatement.Block(body) ) ) }; } else if (moduleDependencies.Any()) { // If we require any module, we require mscorlib. This should work even if we are a leaf module that doesn't include any other module because our parent script will do the mscorlib require for us. body.InsertRange(0, new[] { JsStatement.UseStrict, JsExpression.Invocation(JsExpression.Identifier("require"), JsExpression.String("mscorlib")) } .Concat(moduleDependencies .OrderBy(x => x.Key).OrderBy(x => x.Key) .Select(x => JsStatement.Var( x.Value, JsExpression.Invocation( JsExpression.Identifier("require"), JsExpression.String(x.Key)))) .ToList())); } else { body.Insert(0, JsStatement.UseStrict); body = new List <JsStatement> { JsExpression.Invocation(JsExpression.FunctionDefinition(new string[0], JsStatement.Block(body))) }; } return(body); }