public JSTryCatchBlock TranslateNode(ILTryCatchBlock tcb) { var body = TranslateNode(tcb.TryBlock); JSVariable catchVariable = null; JSBlockStatement catchBlock = null; JSBlockStatement finallyBlock = null; if (tcb.CatchBlocks.Count > 0) { var pairs = new List<KeyValuePair<JSExpression, JSStatement>>(); catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference)); bool foundUniversalCatch = false; foreach (var cb in tcb.CatchBlocks) { JSExpression pairCondition = null; if ( (cb.ExceptionType.FullName == "System.Exception") || (cb.ExceptionType.FullName == "System.Object") ) { // Bad IL sometimes contains entirely meaningless catch clauses. It's best to just ignore them. if ( (cb.Body.Count == 1) && (cb.Body[0] is ILExpression) && (((ILExpression)cb.Body[0]).Code == ILCode.Rethrow) ) { continue; } if (foundUniversalCatch) { Translator.WarningFormat("Found multiple catch-all catch clauses. Any after the first will be ignored."); continue; } foundUniversalCatch = true; } else { if (foundUniversalCatch) throw new NotImplementedException("Catch-all clause must be last"); pairCondition = new JSIsExpression(catchVariable, cb.ExceptionType); } var pairBody = TranslateBlock(cb.Body); if (cb.ExceptionVariable != null) { var excVariable = DeclareVariable(cb.ExceptionVariable, ThisMethodReference); pairBody.Statements.Insert( 0, new JSVariableDeclarationStatement(new JSBinaryOperatorExpression( JSOperator.Assignment, excVariable, catchVariable, cb.ExceptionVariable.Type )) ); } pairs.Add(new KeyValuePair<JSExpression, JSStatement>( pairCondition, pairBody )); } if (!foundUniversalCatch) pairs.Add(new KeyValuePair<JSExpression,JSStatement>( null, new JSExpressionStatement(new JSThrowExpression(catchVariable)) )); if ((pairs.Count == 1) && (pairs[0].Key == null)) catchBlock = new JSBlockStatement( pairs[0].Value ); else catchBlock = new JSBlockStatement( JSIfStatement.New(pairs.ToArray()) ); } if (tcb.FinallyBlock != null) finallyBlock = TranslateNode(tcb.FinallyBlock); if (tcb.FaultBlock != null) { if (catchBlock != null) throw new Exception("A try block cannot have both a catch block and a fault block"); catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference)); catchBlock = new JSBlockStatement(TranslateBlock(tcb.FaultBlock.Body)); catchBlock.Statements.Add(new JSExpressionStatement(new JSThrowExpression(catchVariable))); } return new JSTryCatchBlock( body, catchVariable, catchBlock, finallyBlock ); }
protected JSExpression Translate_ComparisonOperator(ILExpression node, JSBinaryOperator op) { if ( (node.Arguments[0].ExpectedType.FullName == "System.Boolean") && (node.Arguments[1].ExpectedType.FullName == "System.Boolean") && (node.Arguments[1].Code.ToString().Contains("Ldc_")) ) { // Comparison against boolean constant bool comparand = Convert.ToInt64(node.Arguments[1].Operand) != 0; bool checkEquality = (op == JSOperator.Equal); if (comparand != checkEquality) return new JSUnaryOperatorExpression( JSOperator.LogicalNot, TranslateNode(node.Arguments[0]), TypeSystem.Boolean ); else return TranslateNode(node.Arguments[0]); } else if ( (!node.Arguments[0].ExpectedType.IsValueType) && (!node.Arguments[1].ExpectedType.IsValueType) && (node.Arguments[0].ExpectedType == node.Arguments[1].ExpectedType) && (node.Arguments[0].Code == ILCode.Isinst) ) { // The C# expression 'x is y' translates into roughly '(x is y) > null' in IL, // because there's no IL opcode for != and the IL isinst opcode returns object, not bool var value = TranslateNode(node.Arguments[0].Arguments[0]); var arg1 = TranslateNode(node.Arguments[1]); var nullLiteral = arg1 as JSNullLiteral; var targetType = (TypeReference)node.Arguments[0].Operand; var targetInfo = TypeInfo.Get(targetType); JSExpression checkTypeResult; if ((targetInfo != null) && targetInfo.IsIgnored) checkTypeResult = JSLiteral.New(false); else checkTypeResult = new JSIsExpression( value, targetType ); if (nullLiteral != null) { if ( (op == JSOperator.Equal) || (op == JSOperator.LessThanOrEqual) || (op == JSOperator.LessThan) ) { return new JSUnaryOperatorExpression( JSOperator.LogicalNot, checkTypeResult, TypeSystem.Boolean ); } else if ( (op == JSOperator.GreaterThan) ) { return checkTypeResult; } else { return new JSUntranslatableExpression(node); } } } return Translate_BinaryOp(node, op); }
public void VisitNode(JSIsExpression @is) { var ct = GetCachedType(@is.Type); if (ct != null) @is.CachedTypeIndex = ct.Index; VisitChildren(@is); }