public JsStatement VisitGotoStateStatement(JsGotoStateStatement statement, object data) { var result = new List <JsStatement>(); State targetState; if (statement.TargetState == null) { if (!_labelStates.TryGetValue(statement.TargetLabel, out targetState)) { throw new InvalidOperationException("The label " + statement.TargetLabel + " does not exist."); } } else { targetState = statement.TargetState.Value; } var remaining = statement.CurrentState.FinallyStack; for (int i = 0, n = remaining.Count() - targetState.FinallyStack.Count(); i < n; i++) { var current = remaining.Peek(); remaining = remaining.Pop(); result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(_stateVariableName), JsExpression.Number(remaining.IsEmpty ? -1 : remaining.Peek().Item1)))); result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(current.Item2), "call"), JsExpression.This))); } result.Add(MakeSetNextStateStatement(targetState.StateValue)); result.Add(targetState.StateValue == -1 ? (JsStatement) new JsBreakStatement(targetState.LoopLabelName) : new JsContinueStatement(targetState.LoopLabelName)); return(new JsBlockStatement(result, mergeWithParent: true)); }
public void FunctionIsParenthesizedWhenInvokedDirectly() { AssertCorrect(JsExpression.Invocation( JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement, null) ), "(function() {\r\n})()"); }
private JsExpression GetScriptType(IType type, TypeContext context, Func <ITypeParameter, JsExpression> resolveTypeParameter) { string contextName = GetTypeContextShortName(context); if (type is ParameterizedType) { var pt = (ParameterizedType)type; return(JsExpression.Invocation(JsExpression.Identifier(contextName + "_$InstantiateGenericType"), new[] { new JsTypeReferenceExpression(Common.CreateMockTypeDefinition(type.Name, Common.CreateMockAssembly())) }.Concat(pt.TypeArguments.Select(a => GetScriptType(a, TypeContext.GenericArgument, resolveTypeParameter))))); } else if (type.TypeParameterCount > 0) { // This handles open generic types ( typeof(C<,>) ) return(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition(contextName + "_" + type.GetDefinition().Name, Common.CreateMockAssembly()))); } else if (type.Kind == TypeKind.Array) { return(JsExpression.Invocation(JsExpression.Identifier(contextName + "_$Array"), GetScriptType(((ArrayType)type).ElementType, TypeContext.GenericArgument, resolveTypeParameter))); } else if (type.Kind == TypeKind.Anonymous) { return(JsExpression.Identifier(contextName + "_$Anonymous")); } else if (type is ITypeDefinition) { return(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition(contextName + "_" + type.Name, Common.CreateMockAssembly()))); } else if (type is ITypeParameter) { return(resolveTypeParameter((ITypeParameter)type)); } else { throw new ArgumentException("Unsupported type + " + type); } }
private JsExpression CreateInitEnumCall(JsEnum type, string ctorName) { var values = new List <JsObjectLiteralProperty>(); foreach (var v in type.CSharpTypeDefinition.Fields) { if (v.ConstantValue != null) { var sem = _metadataImporter.GetFieldSemantics(v); if (sem.Type == FieldScriptSemantics.ImplType.Field) { values.Add(new JsObjectLiteralProperty(sem.Name, JsExpression.Number(Convert.ToDouble(v.ConstantValue)))); } else if (sem.Type == FieldScriptSemantics.ImplType.Constant && sem.Name != null) { values.Add(new JsObjectLiteralProperty(sem.Name, sem.Value is string?JsExpression.String((string)sem.Value) : JsExpression.Number(Convert.ToDouble(sem.Value)))); } } else { _errorReporter.Region = v.Region; _errorReporter.InternalError("Enum field " + v.FullName + " is not constant."); } } var args = new List <JsExpression> { JsExpression.Identifier(ctorName), _linker.CurrentAssemblyExpression, JsExpression.ObjectLiteral(values) }; if (MetadataUtils.IsNamedValues(type.CSharpTypeDefinition, _attributeStore)) { args.Add(JsExpression.True); } return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitEnum), args)); }
private JsExpression CreateDefaultConstructorInvocation(IMethod defaultConstructor, JsExpression typeRef) { var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor); switch (sem.Type) { case ConstructorScriptSemantics.ImplType.UnnamedConstructor: // default behavior is good enough. case ConstructorScriptSemantics.ImplType.NotUsableFromScript: // Can't be invoked so we don't need to create it. return(null); case ConstructorScriptSemantics.ImplType.NamedConstructor: return(JsExpression.New(JsExpression.Member(typeRef, sem.Name))); case ConstructorScriptSemantics.ImplType.StaticMethod: return(JsExpression.Invocation(JsExpression.Member(typeRef, sem.Name))); case ConstructorScriptSemantics.ImplType.InlineCode: var prevRegion = _errorReporter.Region; try { _errorReporter.Region = defaultConstructor.Region; return(InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(defaultConstructor, sem.LiteralCode, null, EmptyList <JsExpression> .Instance, r => r.Resolve(_compilation), _runtimeLibrary.GetScriptType, false, s => _errorReporter.Message(7525, s))); } finally { _errorReporter.Region = prevRegion; } case ConstructorScriptSemantics.ImplType.Json: return(JsExpression.ObjectLiteral()); default: throw new Exception("Invalid constructor implementation type: " + sem.Type); } }
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))); }
public JsExpression TypeIs(JsExpression expression, IType sourceType, IType targetType, IRuntimeContext context) { var importedCheck = CompileImportedTypeCheckCode(targetType, ref expression, context, true); if (importedCheck != null) { return(importedCheck); } var def = targetType.GetDefinition(); if (def != null && (!MetadataUtils.DoesTypeObeyTypeSystem(def) || (MetadataUtils.IsSerializable(def) && string.IsNullOrEmpty(MetadataUtils.GetSerializableTypeCheckCode(def))))) { _errorReporter.Message(Messages._7701, targetType.FullName); return(JsExpression.Null); } var jsTarget = GetCastTarget(sourceType, targetType, context); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(ReferenceNotEquals(expression, JsExpression.Null, context)); } return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "isInstanceOfType"), expression, jsTarget)); }
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))) ))); } }
public JsExpression Downcast(JsExpression expression, IType sourceType, IType targetType, IRuntimeContext context) { if (_omitDowncasts) { return(expression); } if (sourceType.Kind == TypeKind.Dynamic && targetType.IsKnownType(KnownTypeCode.Boolean)) { return(JsExpression.LogicalNot(JsExpression.LogicalNot(expression))); } JsExpression jsTarget = CompileImportedTypeCheckCode(targetType, ref expression, context, false); if (jsTarget == null) { jsTarget = GetCastTarget(sourceType, targetType, context); } if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(expression); } return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "cast"), expression, jsTarget)); }
public JsExpression CallBase(IMethod method, IEnumerable <JsExpression> thisAndArguments, IRuntimeContext context) { var impl = GetMethodSemantics(method); JsExpression jsMethod = JsExpression.Member(JsExpression.Member(GetScriptType(method.DeclaringType, TypeContext.GetScriptType, context), "prototype"), impl.Name); if (method is SpecializedMethod && !impl.IgnoreGenericArguments) { jsMethod = InstantiateGenericMethod(jsMethod, ((SpecializedMethod)method).TypeArguments, context); } if (impl.ExpandParams) { var args = thisAndArguments.ToList(); if (args[args.Count - 1] is JsArrayLiteralExpression) { return(JsExpression.Invocation(JsExpression.Member(jsMethod, "call"), args.Take(args.Count - 1).Concat(((JsArrayLiteralExpression)args[args.Count - 1]).Elements))); } else { return(JsExpression.Invocation(JsExpression.Member(jsMethod, "apply"), args[0], args.Count == 2 ? args[1] : JsExpression.Invocation(JsExpression.Member(JsExpression.ArrayLiteral(args.Skip(1).Take(args.Count - 2)), "concat"), args[args.Count - 1]))); } } else { return(JsExpression.Invocation(JsExpression.Member(jsMethod, "call"), thisAndArguments)); } }
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); }
protected void AssertCorrect(string orig, string expected, MethodType methodType = MethodType.Normal) { int tempIndex = 0, stateIndex = 0, loopLabelIndex = 0; var stmt = JsBlockStatement.MakeBlock(JavaScriptParser.Parser.ParseStatement(orig)); JsBlockStatement result; if (methodType == MethodType.Iterator) { int finallyHandlerIndex = 0; result = StateMachineRewriter.RewriteIteratorBlock(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)), () => string.Format("$finally" + (++finallyHandlerIndex).ToString(CultureInfo.InvariantCulture)), v => JsExpression.Invocation(JsExpression.Identifier("setCurrent"), v), sm => { var body = new List <JsStatement>(); if (sm.Variables.Count > 0) { body.Add(new JsVariableDeclarationStatement(sm.Variables)); } body.AddRange(sm.FinallyHandlers.Select(h => new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(h.Item1), h.Item2)))); if (sm.Disposer != null) { body.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("dispose"), new JsFunctionDefinitionExpression(new string[0], sm.Disposer)))); } body.Add(sm.MainBlock); return(new JsBlockStatement(body)); }); } else if (methodType == MethodType.AsyncTask || methodType == MethodType.AsyncVoid) { result = StateMachineRewriter.RewriteAsyncMethod(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)), "$sm", "$doFinally", methodType == MethodType.AsyncTask ? new JsVariableDeclaration("$tcs", JsExpression.New(JsExpression.Identifier("TaskCompletionSource"))) : null, expr => { if (methodType != MethodType.AsyncTask) { throw new InvalidOperationException("Should not set result in async void method"); } return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setResult"), expr ?? JsExpression.String("<<null>>"))); }, expr => { if (methodType != MethodType.AsyncTask) { throw new InvalidOperationException("Should not set exception in async void method"); } return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setException"), expr)); }, () => { if (methodType != MethodType.AsyncTask) { throw new InvalidOperationException("Should not get task async void method"); } return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "getTask"))); }, (sm, ctx) => JsExpression.Invocation(JsExpression.Identifier("$Bind"), sm, ctx)); } else { result = StateMachineRewriter.RewriteNormalMethod(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture))); } var actual = OutputFormatter.Format(result); Assert.That(actual.Replace("\r\n", "\n"), Is.EqualTo(expected.Replace("\r\n", "\n")), "Expected:\n" + expected + "\n\nActual:\n" + actual); }
public void IncrementIsParenthesizedWhenUsedAsInvocationMethod() { AssertCorrect(JsExpression.Invocation( JsExpression.Unary(ExpressionNodeType.PostfixMinusMinus, JsExpression.Identifier("x") ), new JsExpression[0] ), "(x--)()"); }
public JsExpression TypeIs(JsExpression expression, IType sourceType, IType targetType) { var jsTarget = GetCastTarget(sourceType, targetType); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(ReferenceNotEquals(expression, JsExpression.Null)); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Type), "isInstanceOfType"), expression, jsTarget)); }
public void IncrementIsParenthesizedWhenBeingUsedAsInvocationTarget() { AssertCorrect(JsExpression.Invocation( JsExpression.Unary(ExpressionNodeType.PostfixPlusPlus, JsExpression.Identifier("X") ), new[] { JsExpression.Number(1) } ), "(X++)(1)"); }
public JsExpression TryDowncast(JsExpression expression, IType sourceType, IType targetType) { var jsTarget = GetCastTarget(sourceType, targetType); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(expression); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Type), "safeCast"), expression, jsTarget)); }
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 void ChainedFunctionCallsAreNotParenthtesized() { AssertCorrect(JsExpression.Invocation( JsExpression.Invocation( JsExpression.Identifier("x"), new[] { JsExpression.Number(1) } ), new[] { JsExpression.Number(2) } ), "x(1)(2)"); }
public JsExpression CallBase(IType baseType, string methodName, IList <IType> typeArguments, IEnumerable <JsExpression> thisAndArguments) { JsExpression method = JsExpression.MemberAccess(JsExpression.MemberAccess(GetScriptType(baseType, TypeContext.BindBaseCall), "prototype"), methodName); if (typeArguments != null && typeArguments.Count > 0) { method = InstantiateGenericMethod(method, typeArguments); } return(JsExpression.Invocation(JsExpression.MemberAccess(method, "call"), thisAndArguments)); }
public JsExpression BindBaseCall(IType baseType, string methodName, IList <IType> typeArguments, JsExpression @this) { JsExpression method = JsExpression.MemberAccess(JsExpression.MemberAccess(GetScriptType(baseType, TypeContext.BindBaseCall), "prototype"), methodName); if (typeArguments != null && typeArguments.Count > 0) { method = InstantiateGenericMethod(method, typeArguments); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Delegate), "mkdel"), @this, method)); }
public void InvocationIsNotParenthesizedWhenUsedAsMemberAccessTarget() { AssertCorrect(JsExpression.Member( JsExpression.Invocation( JsExpression.Number(1), new[] { JsExpression.Number(2) } ), "Member" ), "1(2).Member"); }
public void MemberAccessIsNotParenthesizedWhenUsedAsInvocationTarget() { AssertCorrect(JsExpression.Invocation( JsExpression.Member( JsExpression.Identifier("x"), "Member" ), new JsExpression[0] ), "x.Member()"); }
public JsExpression CloneDelegate(JsExpression source, IType sourceType, IType targetType, IRuntimeContext context) { if (Equals(sourceType, targetType)) { // The user does something like "D d1 = F(); var d2 = new D(d1)". Assume he does this for a reason and create a clone of the delegate. return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "delegateClone"), source)); } else { return(source); // The clone is just to convert the delegate to a different type. The risk of anyone comparing the references is small, so just return the original as delegates are immutable anyway. } }
private JsExpression CreateInitInterfaceCall(JsClass type, string ctorName, IList <JsExpression> interfaces) { var args = new List <JsExpression> { JsExpression.Identifier(ctorName), _linker.CurrentAssemblyExpression, CreateInstanceMembers(type, null) }; if (interfaces.Count > 0) { args.Add(JsExpression.ArrayLiteral(interfaces)); } return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitInterface), args)); }
private JsType ConvertType(JsClass type) { if (type.InstanceMethods.Any(m => m.Name == "runTests")) { _errorReporter.Region = type.CSharpTypeDefinition.Region; _errorReporter.Message(MessageSeverity.Error, 7019, string.Format("The type {0} cannot define a method named 'runTests' because it has a [TestFixtureAttribute].", type.CSharpTypeDefinition.FullName)); return(type); } var instanceMethods = new List <JsMethod>(); var tests = new List <Tuple <string, string, bool, int?, JsFunctionDefinitionExpression> >(); foreach (var method in type.InstanceMethods) { var testAttr = _attributeStore.AttributesFor(method.CSharpMember).GetAttribute <TestAttribute>(); if (testAttr != null) { if (!method.CSharpMember.IsPublic || !method.CSharpMember.ReturnType.IsKnownType(KnownTypeCode.Void) || ((IMethod)method.CSharpMember).Parameters.Count > 0 || ((IMethod)method.CSharpMember).TypeParameters.Count > 0) { _errorReporter.Region = method.CSharpMember.Region; _errorReporter.Message(MessageSeverity.Error, 7020, string.Format("Method {0}: Methods decorated with a [TestAttribute] must be public, non-generic, parameterless instance methods that return void.", method.CSharpMember.FullName)); } tests.Add(Tuple.Create(testAttr.Description ?? method.CSharpMember.Name, testAttr.Category, testAttr.IsAsync, testAttr.ExpectedAssertionCount >= 0 ? (int?)testAttr.ExpectedAssertionCount : null, method.Definition)); } else { instanceMethods.Add(method); } } var testInvocations = new List <JsExpression>(); foreach (var category in tests.GroupBy(t => t.Item2).Select(g => new { Category = g.Key, Tests = g.Select(x => new { Description = x.Item1, IsAsync = x.Item3, ExpectedAssertionCount = x.Item4, Function = x.Item5 }) }).OrderBy(x => x.Category)) { if (category.Category != null) { testInvocations.Add(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("QUnit"), "module"), JsExpression.String(category.Category))); } testInvocations.AddRange(category.Tests.Select(t => JsExpression.Invocation(JsExpression.Identifier(t.IsAsync ? "asyncTest" : "test"), t.ExpectedAssertionCount != null ? new JsExpression[] { JsExpression.String(t.Description), JsExpression.Number(t.ExpectedAssertionCount.Value), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) } : new JsExpression[] { JsExpression.String(t.Description), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) }))); } instanceMethods.Add(new JsMethod(null, "runTests", null, JsExpression.FunctionDefinition(new string[0], JsStatement.Block(testInvocations.Select(t => (JsStatement)t))))); var result = type.Clone(); result.InstanceMethods.Clear(); foreach (var m in instanceMethods) { result.InstanceMethods.Add(m); } return(result); }
public void NewExpressionIsParenthesizedWhenBeingUsedAsInvocationTarget() { // Just to get rid of ambiguities AssertCorrect(JsExpression.Invocation( JsExpression.New( JsExpression.Identifier("X"), new JsExpression[0] ), new[] { JsExpression.Number(1) } ), "(new X())(1)"); }
public JsExpression BindBaseCall(IMethod method, JsExpression @this, IRuntimeContext context) { var impl = GetMethodSemantics(method); JsExpression jsMethod = JsExpression.Member(JsExpression.Member(GetScriptType(method.DeclaringType, TypeContext.GetScriptType, context), "prototype"), impl.Name); if (method is SpecializedMethod && !impl.IgnoreGenericArguments) { jsMethod = InstantiateGenericMethod(jsMethod, ((SpecializedMethod)method).TypeArguments, context); } return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "mkdel"), @this, jsMethod)); }
public JsExpression CreateArray(IType elementType, IEnumerable <JsExpression> size, IRuntimeContext context) { var sizeList = (size is IList <JsExpression>) ? (IList <JsExpression>)size : size.ToList(); if (sizeList.Count == 1) { return(JsExpression.New(CreateTypeReferenceExpression(KnownTypeReference.Array), sizeList)); } else { return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "multidimArray"), new[] { Default(elementType, context) }.Concat(sizeList))); } }
public JsExpression FromNullable(JsExpression expression, IRuntimeContext context) { if (_omitNullableChecks) { return(expression); } if (expression.NodeType == ExpressionNodeType.LogicalNot) { return(expression); // This is a little hacky. The problem we want to solve is that 'bool b = myDynamic' should compile to !!myDynamic, but the actual call is unbox(convert(myDynamic, bool)), where convert() will return the !!. Anyway, in JS, the !expression will never be null anyway. } return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "unbox"), expression)); }
private JsExpression CreateRegisterEnumCall(ITypeDefinition type, string name, JsExpression ctor) { var args = new List <JsExpression> { GetRoot(type), JsExpression.String(name), ctor }; var metadata = GetMetadataDescriptor(type, false); if (metadata != null) { args.Add(metadata); } return(JsExpression.Invocation(JsExpression.Member(_systemScript, RegisterEnum), args)); }