Index: src/Boo.Lang.Parser/wsaboo.g =================================================================== --- src/Boo.Lang.Parser/wsaboo.g (revision 2738) +++ src/Boo.Lang.Parser/wsaboo.g (working copy) @@ -68,6 +68,7 @@ ENUM="enum"; EVENT="event"; EXCEPT="except"; + FAILURE="failure"; FINAL="final"; FROM="from"; FOR="for"; @@ -1323,10 +1324,16 @@ }: t:TRY { s = new TryStatement(SourceLocationFactory.ToLexicalInfo(t)); } begin {s.ProtectedBlock = new Block();} block[s.ProtectedBlock.Statements] { lastBlock = s.ProtectedBlock; } + (EXCEPT|FAILURE|ENSURE)=> ( lastBlock = exception_handler[s] )* ( + ftoken:FAILURE { eblock = new Block(SourceLocationFactory.ToLexicalInfo(ftoken)); } begin + block[eblock.Statements] + { s.FailureBlock = lastBlock = eblock; } + )? + ( etoken:ENSURE { eblock = new Block(SourceLocationFactory.ToLexicalInfo(etoken)); } begin block[eblock.Statements] { s.EnsureBlock = lastBlock = eblock; } @@ -1339,18 +1346,50 @@ { ExceptionHandler eh = null; TypeReference tr = null; + Expression e = null; lastBlock = null; }: - c:EXCEPT (x:ID (AS tr=type_reference)?)? begin + c:EXCEPT (x:ID)? (AS tr=type_reference)? ((IF|u:UNLESS) e=expression)? begin { eh = new ExceptionHandler(SourceLocationFactory.ToLexicalInfo(c)); + eh.Declaration = new Declaration(); + eh.Declaration.Type = tr; + if (x != null) { - eh.Declaration = new Declaration(SourceLocationFactory.ToLexicalInfo(x)); + eh.Declaration.LexicalInfo = SourceLocationFactory.ToLexicalInfo(x); eh.Declaration.Name = x.getText(); - eh.Declaration.Type = tr; } + else + { + eh.Declaration.Name = null; + eh.Flags |= ExceptionHandlerFlags.Anonymous; + } + if (tr != null) + { + eh.Declaration.LexicalInfo = tr.LexicalInfo; + } + else if (x != null) + { + eh.Declaration.LexicalInfo = eh.LexicalInfo; + } + if(tr == null) + { + eh.Flags |= ExceptionHandlerFlags.Untyped; + } + if (e != null) + { + if(u != null) + { + UnaryExpression not = new UnaryExpression(SourceLocationFactory.ToLexicalInfo(u)); + not.Operator = UnaryOperatorType.LogicalNot; + not.Operand = e; + e = not; + } + eh.FilterCondition = e; + eh.Flags |= ExceptionHandlerFlags.Filter; + } eh.Block = new Block(SourceLocationFactory.ToLexicalInfo(c)); } block[eh.Block.Statements] Index: src/Boo.Lang.Parser/boo.g =================================================================== --- src/Boo.Lang.Parser/boo.g (revision 2738) +++ src/Boo.Lang.Parser/boo.g (working copy) @@ -74,6 +74,7 @@ ENUM="enum"; EVENT="event"; EXCEPT="except"; + FAILURE="failure"; FINAL="final"; FROM="from"; FOR="for"; @@ -1443,10 +1444,16 @@ }: t:TRY { s = new TryStatement(SourceLocationFactory.ToLexicalInfo(t)); } compound_stmt[s.ProtectedBlock] + (EXCEPT|FAILURE|ENSURE)=> ( exception_handler[s] )* ( + ftoken:FAILURE { eblock = new Block(SourceLocationFactory.ToLexicalInfo(ftoken)); } + compound_stmt[eblock] + { s.FailureBlock = eblock; } + )? + ( etoken:ENSURE { eblock = new Block(SourceLocationFactory.ToLexicalInfo(etoken)); } compound_stmt[eblock] { s.EnsureBlock = eblock; } @@ -1458,17 +1465,49 @@ { ExceptionHandler eh = null; TypeReference tr = null; + Expression e = null; }: - c:EXCEPT (x:ID (AS tr=type_reference)?)? + c:EXCEPT (x:ID)? (AS tr=type_reference)? ((IF|u:UNLESS) e=boolean_expression)? { eh = new ExceptionHandler(SourceLocationFactory.ToLexicalInfo(c)); + eh.Declaration = new Declaration(); + eh.Declaration.Type = tr; + if (x != null) { - eh.Declaration = new Declaration(SourceLocationFactory.ToLexicalInfo(x)); + eh.Declaration.LexicalInfo = SourceLocationFactory.ToLexicalInfo(x); eh.Declaration.Name = x.getText(); - eh.Declaration.Type = tr; } + else + { + eh.Declaration.Name = null; + eh.Flags |= ExceptionHandlerFlags.Anonymous; + } + if (tr != null) + { + eh.Declaration.LexicalInfo = tr.LexicalInfo; + } + else if (x != null) + { + eh.Declaration.LexicalInfo = eh.LexicalInfo; + } + if(tr == null) + { + eh.Flags |= ExceptionHandlerFlags.Untyped; + } + if (e != null) + { + if(u != null) + { + UnaryExpression not = new UnaryExpression(SourceLocationFactory.ToLexicalInfo(u)); + not.Operator = UnaryOperatorType.LogicalNot; + not.Operand = e; + e = not; + } + eh.FilterCondition = e; + eh.Flags |= ExceptionHandlerFlags.Filter; + } } compound_stmt[eh.Block] { Index: src/Boo.Lang/Resources/strings.txt =================================================================== --- src/Boo.Lang/Resources/strings.txt (revision 2738) +++ src/Boo.Lang/Resources/strings.txt (working copy) @@ -127,7 +127,7 @@ BCE0125=Invalid declaration type '{0}'. BCE0126=It is not possible to evaluate an expression of type '{0}'. BCE0127=A ref or out argument must be an lvalue: '{0}' -BCE0128='try' block must be followed by either 'except' or 'ensure'. +BCE0128='try' block must be followed by at least one 'except' block or either a 'failure' or 'ensure' block. BCE0129=Invalid extension definition, only static methods are allowed. BCE0130='partial' can only be applied to class definitions. BCE0131=Invalid combination of modifiers on '{0}': {1}. @@ -144,6 +144,7 @@ BCE0142=Cannot bind [default] attribute to value type parameter '{0}' in '{1}'. BCE0143=Cannot return from an ensure block. BCE0144='{0}' is obsolete. {1} +BCE0145=Cannot catch type '{0}'; 'except' blocks can only catch exceptions derived from 'System.Exception'. To catch non-CLS compliant exceptions, use a default exception handler or catch 'System.Runtime.CompilerServices.RuntimeWrappedException'. ;Compiler warnings BCW0000=WARNING: {0} Index: src/Boo.Lang.Compiler/Ast/Visitors/BooPrinterVisitor.cs =================================================================== --- src/Boo.Lang.Compiler/Ast/Visitors/BooPrinterVisitor.cs (revision 2738) +++ src/Boo.Lang.Compiler/Ast/Visitors/BooPrinterVisitor.cs (working copy) @@ -991,28 +991,72 @@ WriteIndented(); WriteKeyword("try:"); WriteLine(); - WriteBlock(node.ProtectedBlock); + Indent(); + WriteBlockStatements(node.ProtectedBlock); + Dedent(); Visit(node.ExceptionHandlers); + + if (null != node.FailureBlock) + { + WriteIndented(); + WriteKeyword("failure:"); + WriteLine(); + Indent(); + WriteBlockStatements(node.FailureBlock); + Dedent(); + } + if (null != node.EnsureBlock) { WriteIndented(); WriteKeyword("ensure:"); WriteLine(); - WriteBlock(node.EnsureBlock); + Indent(); + WriteBlockStatements(node.EnsureBlock); + Dedent(); } } override public void OnExceptionHandler(ExceptionHandler node) { WriteIndented(); WriteKeyword("except"); - if (null != node.Declaration) + if ((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None) { + if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + Write(" "); + Visit(node.Declaration); + } + else + { + WriteTypeReference(node.Declaration.Type); + } + } + else if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { Write(" "); - Visit(node.Declaration); + Write(node.Declaration.Name); } + + if((node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter) + { + UnaryExpression unless = node.FilterCondition as UnaryExpression; + if(unless != null && unless.Operator == UnaryOperatorType.LogicalNot) + { + WriteKeyword(" unless "); + Visit(unless.Operand); + } + else + { + WriteKeyword(" if "); + Visit(node.FilterCondition); + } + } WriteLine(":"); - WriteBlock(node.Block); + Indent(); + WriteBlockStatements(node.Block); + Dedent(); } override public void OnUnlessStatement(UnlessStatement node) Index: src/Boo.Lang.Compiler/Steps/CheckIdentifiers.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/CheckIdentifiers.cs (revision 2738) +++ src/Boo.Lang.Compiler/Steps/CheckIdentifiers.cs (working copy) @@ -105,7 +105,13 @@ override public void LeaveDeclaration(Declaration node) { - CheckName(node,node.Name); + // Special exemption made for anonymous exception handlers + if(!(node.ParentNode is ExceptionHandler) || + ((node.ParentNode as ExceptionHandler).Flags + & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + CheckName(node,node.Name); + } } override public void LeaveAttribute(Attribute node) Index: src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (revision 2738) +++ src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (working copy) @@ -2194,38 +2194,38 @@ return; } - // BOO-314 - if we are trying to invoke - // something, let's make sure it is - // something callable, otherwise, let's - // try to find something callable - if (AstUtil.IsTargetOfMethodInvocation(node) - && !IsCallableEntity(entity)) - { - IEntity callable = ResolveCallable(node); - if (null != callable) entity = callable; - } + // BOO-314 - if we are trying to invoke + // something, let's make sure it is + // something callable, otherwise, let's + // try to find something callable + if (AstUtil.IsTargetOfMethodInvocation(node) + && !IsCallableEntity(entity)) + { + IEntity callable = ResolveCallable(node); + if (null != callable) entity = callable; + } - IMember member = entity as IMember; - if (null != member) - { + IMember member = entity as IMember; + if (null != member) + { if (IsExtensionMethod(member)) { Bind(node, member); return; } - ResolveMemberInfo(node, member); + ResolveMemberInfo(node, member); return; - } + } - EnsureRelatedNodeWasVisited(node, entity); - node.Entity = entity; - PostProcessReferenceExpression(node); - } + EnsureRelatedNodeWasVisited(node, entity); + node.Entity = entity; + PostProcessReferenceExpression(node); + } private static bool AlreadyBound(ReferenceExpression node) - { + { return null != node.ExpressionType; - } + } private IEntity ResolveCallable(ReferenceExpression node) { @@ -2850,33 +2850,55 @@ override public void OnExceptionHandler(ExceptionHandler node) { - if (null == node.Declaration) + bool untypedException = (node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.Untyped; + bool anonymousException = (node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.Anonymous; + bool filterHandler = (node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter; + + if (untypedException) { - node.Declaration = new Declaration(node.LexicalInfo, - "___exception", - CodeBuilder.CreateTypeReference(TypeSystemServices.ExceptionType)); + // If untyped, set the handler to except System.Exception + node.Declaration.Type = CodeBuilder.CreateTypeReference(TypeSystemServices.ExceptionType); } else { - if (null == node.Declaration.Type) + Visit(node.Declaration.Type); + + // Require typed exception handlers to except only + // exceptions at least as derived as System.Exception + if(!TypeSystemServices.ExceptionType.IsAssignableFrom(GetType(node.Declaration.Type))) { - node.Declaration.Type = CodeBuilder.CreateTypeReference(TypeSystemServices.ExceptionType); + Errors.Add(CompilerErrorFactory.InvalidExceptArgument(node.Declaration.Type, GetType(node.Declaration.Type).FullName)); } - else - { - Visit(node.Declaration.Type); - } } - - node.Declaration.Entity = DeclareLocal(node.Declaration, node.Declaration.Name, GetType(node.Declaration.Type), true); - EnterNamespace(new DeclarationsNamespace(CurrentNamespace, TypeSystemServices, node.Declaration)); + + if(!anonymousException) + { + // If the exception is not anonymous, place it into a + // local variable and enter a new namespace + node.Declaration.Entity = DeclareLocal(node.Declaration, node.Declaration.Name, GetType(node.Declaration.Type), true); + EnterNamespace(new DeclarationsNamespace(CurrentNamespace, TypeSystemServices, node.Declaration)); + } + try { + // The filter handler has access to the exception if it + // is not anonymous, so it is protected to ensure + // any exception in the filter condition (a big no-no) + // will still clean up the namespace if necessary + if (filterHandler) + { + Visit(node.FilterCondition); + } + Visit(node.Block); } finally { - LeaveNamespace(); + // Clean up the namespace if necessary + if(!anonymousException) + { + LeaveNamespace(); + } } } Index: src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs (revision 2738) +++ src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs (working copy) @@ -109,7 +109,7 @@ override public void LeaveTryStatement(TryStatement node) { - if (node.EnsureBlock == null && node.ExceptionHandlers.Count == 0) + if (node.EnsureBlock == null && node.FailureBlock == null && node.ExceptionHandlers.Count == 0) { Error(CompilerErrorFactory.InvalidTryStatement(node)); } Index: src/Boo.Lang.Compiler/Steps/StricterErrorChecking.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/StricterErrorChecking.cs (revision 2738) +++ src/Boo.Lang.Compiler/Steps/StricterErrorChecking.cs (working copy) @@ -128,7 +128,9 @@ { Visit(node.ProtectedBlock); Visit(node.ExceptionHandlers); + EnterEnsureBlock(); + Visit(node.FailureBlock); Visit(node.EnsureBlock); LeaveEnsureBlock(); } Index: src/Boo.Lang.Compiler/Steps/EmitAssembly.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/EmitAssembly.cs (revision 2738) +++ src/Boo.Lang.Compiler/Steps/EmitAssembly.cs (working copy) @@ -64,6 +64,10 @@ public class EmitAssembly : AbstractVisitorCompilerStep { static ConstructorInfo DebuggableAttribute_Constructor = typeof(DebuggableAttribute).GetConstructor(new Type[] { Types.Bool, Types.Bool }); + + static ConstructorInfo RuntimeCompatibilityAttribute_Constructor = typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute).GetConstructor(new Type[0]); + + static PropertyInfo[] RuntimeCompatibilityAttribute_Property = new PropertyInfo[] { typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute).GetProperty("WrapNonExceptionThrows") }; static ConstructorInfo DuckTypedAttribute_Constructor = Types.DuckTypedAttribute.GetConstructor(new Type[0]); @@ -744,28 +748,138 @@ override public void OnTryStatement(TryStatement node) { ++_tryBlock; - _il.BeginExceptionBlock(); + Label end = _il.BeginExceptionBlock(); + + // The fault handler isn't very well supported by the + // the ILGenerator. Thus, when there is a failure block + // in the same try as an except or ensure block, we + // need to do some special brute forcing with the exception + // block context in the ILGenerator. + if(null != node.FailureBlock && null != node.EnsureBlock) + { + ++_tryBlock; + _il.BeginExceptionBlock(); + } + + if(null != node.FailureBlock && node.ExceptionHandlers.Count > 0) + { + ++_tryBlock; + _il.BeginExceptionBlock(); + } + Visit(node.ProtectedBlock); + Visit(node.ExceptionHandlers); - --_tryBlock; + + if(null != node.FailureBlock) + { + // Logic to back out of the manually forced blocks + if(node.ExceptionHandlers.Count > 0) + { + _il.EndExceptionBlock(); + --_tryBlock; + } + + _il.BeginFaultBlock(); + Visit(node.FailureBlock); + + // Logic to back out of the manually forced blocks once more + if(null != node.EnsureBlock) + { + _il.EndExceptionBlock(); + --_tryBlock; + } + } if (null != node.EnsureBlock) { _il.BeginFinallyBlock(); Visit(node.EnsureBlock); } + _il.EndExceptionBlock(); - - + --_tryBlock; } override public void OnExceptionHandler(ExceptionHandler node) { - _il.BeginCatchBlock(GetSystemType(node.Declaration)); - _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration)); + if((node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter) + { + _il.BeginExceptFilterBlock(); + + Label endLabel = _il.DefineLabel(); + + // If the filter is not untyped, then test the exception type + // before testing the filter condition + if((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None) + { + Label filterCondition = _il.DefineLabel(); + + // Test the type of the exception. + _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type)); + + // Duplicate it. If it is null, then it will be used to + // skip the filter. + _il.Emit(OpCodes.Dup); + + // If the exception is of the right type, branch + // to test the filter condition. + _il.Emit(OpCodes.Brtrue, filterCondition); + + // Otherwise, clean up the stack and prepare the stack + // to skip the filter. + EmitStoreOrPopException(node); + + _il.Emit(OpCodes.Ldc_I4_0); + _il.Emit(OpCodes.Br, endLabel); + _il.MarkLabel(filterCondition); + + } + else if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + // Cast the exception to the default except type + _il.Emit(OpCodes.Isinst, GetSystemType(node.Declaration.Type)); + } + + EmitStoreOrPopException(node); + + // Test the condition and convert to boolean if needed. + node.FilterCondition.Accept(this); + PopType(); + EmitToBoolIfNeeded(node.FilterCondition); + + // If the type is right and the condition is true, + // proceed with the handler. + _il.MarkLabel(endLabel); + _il.Emit(OpCodes.Ldc_I4_0); + _il.Emit(OpCodes.Cgt_Un); + + _il.BeginCatchBlock(null); + } + else + { + // Begin a normal catch block of the appropriate type. + _il.BeginCatchBlock(GetSystemType(node.Declaration.Type)); + + // Clean up the stack or store the exception if not anonymous. + EmitStoreOrPopException(node); + } + Visit(node.Block); } + private void EmitStoreOrPopException(ExceptionHandler node) + { + if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration)); + } + else + { + _il.Emit(OpCodes.Pop); + } + } + override public void OnUnpackStatement(UnpackStatement node) { NotImplemented("Unpacking"); @@ -783,7 +897,7 @@ // void we need to pop its return value to leave // the stack sane DiscardValueOnStack(); - AssertStackIsEmpty("stack must be empty after a statement!"); + AssertStackIsEmpty("stack must be empty after a statement! Offending statement: '" + node.ToCodeString() + "'"); } void DiscardValueOnStack() @@ -3590,6 +3704,13 @@ new object[] { true, true }); } + CustomAttributeBuilder CreateRuntimeCompatibilityAttribute() + { + return new CustomAttributeBuilder( + RuntimeCompatibilityAttribute_Constructor, new object[0], + RuntimeCompatibilityAttribute_Property, new object[] { true }); + } + void DefineEntryPoint() { if (Context.Parameters.GenerateInMemory) @@ -4688,6 +4809,7 @@ // picks up the attribute when debugging dynamically generated code. _asmBuilder.SetCustomAttribute(CreateDebuggableAttribute()); } + _asmBuilder.SetCustomAttribute(CreateRuntimeCompatibilityAttribute()); _moduleBuilder = _asmBuilder.DefineDynamicModule(asmName.Name, Path.GetFileName(outputFile), Parameters.Debug); _sreResourceService = new SREResourceService (_asmBuilder, _moduleBuilder); ContextAnnotations.SetAssemblyBuilder(Context, _asmBuilder); Index: src/Boo.Lang.Compiler/CompilerErrorFactory.cs =================================================================== --- src/Boo.Lang.Compiler/CompilerErrorFactory.cs (revision 2738) +++ src/Boo.Lang.Compiler/CompilerErrorFactory.cs (working copy) @@ -775,6 +775,11 @@ return new CompilerError("BCE0144", SafeLexicalInfo(node), memberName, message); } + public static CompilerError InvalidExceptArgument(Node node, string exceptionType) + { + return new CompilerError("BCE0145", SafeLexicalInfo(node), exceptionType); + } + public static string ToStringList(System.Collections.IEnumerable names) { StringBuilder builder = new StringBuilder(); Index: tests/testcases/regression/BOO-390-1.boo =================================================================== --- tests/testcases/regression/BOO-390-1.boo (revision 2738) +++ tests/testcases/regression/BOO-390-1.boo (working copy) @@ -1,5 +1,6 @@ """ System.Diagnostics.DebuggableAttribute +System.Runtime.CompilerServices.RuntimeCompatibilityAttribute FooAttribute """ import System Index: tests/testcases/integration/statements/failure-1.boo =================================================================== --- tests/testcases/integration/statements/failure-1.boo (revision 0) +++ tests/testcases/integration/statements/failure-1.boo (revision 0) @@ -0,0 +1,21 @@ +""" +Testing failure with caught exception +caught +ensured +""" + +def RetVal(): + return 5 + +try: + print "Testing failure with caught exception" + try: + raise System.Exception() + except if RetVal() == 5: + print "caught" + failure: + print "failed" + ensure: + print "ensured" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/failure-2.boo =================================================================== --- tests/testcases/integration/statements/failure-2.boo (revision 0) +++ tests/testcases/integration/statements/failure-2.boo (revision 0) @@ -0,0 +1,19 @@ +""" +Testing failure with uncaught exception +failed +ensured +uncaught +""" + +try: + print "Testing failure with uncaught exception" + try: + raise System.Exception("WOW") + except as System.ArithmeticException: + print "caught" + failure: + print "failed" + ensure: + print "ensured" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/failure-3.boo =================================================================== --- tests/testcases/integration/statements/failure-3.boo (revision 0) +++ tests/testcases/integration/statements/failure-3.boo (revision 0) @@ -0,0 +1,17 @@ +""" +Testing failure with no exception +ensured +""" + +try: + print "Testing failure with no exception" + try: + pass + except: + print "caught" + failure: + print "failed" + ensure: + print "ensured" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/failure-4.boo =================================================================== --- tests/testcases/integration/statements/failure-4.boo (revision 0) +++ tests/testcases/integration/statements/failure-4.boo (revision 0) @@ -0,0 +1,18 @@ +""" +Testing failure with caught exception, no ensure +caught +""" + +def RetVal(): + return 5 + +try: + print "Testing failure with caught exception, no ensure" + try: + raise System.Exception() + except if RetVal() == 5: + print "caught" + failure: + print "failed" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/failure-5.boo =================================================================== --- tests/testcases/integration/statements/failure-5.boo (revision 0) +++ tests/testcases/integration/statements/failure-5.boo (revision 0) @@ -0,0 +1,16 @@ +""" +Testing failure with uncaught exception, no ensure +failed +uncaught +""" + +try: + print "Testing failure with uncaught exception, no ensure" + try: + raise System.Exception("WOW") + except as System.ArithmeticException: + print "caught" + failure: + print "failed" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/failure-6.boo =================================================================== --- tests/testcases/integration/statements/failure-6.boo (revision 0) +++ tests/testcases/integration/statements/failure-6.boo (revision 0) @@ -0,0 +1,14 @@ +""" +Testing failure without ensure or catch +failed +uncaught +""" + +try: + print "Testing failure without ensure or catch" + try: + raise System.Exception() + failure: + print "failed" +except: + print "uncaught" \ No newline at end of file Index: tests/testcases/integration/statements/except-1.boo =================================================================== --- tests/testcases/integration/statements/except-1.boo (revision 0) +++ tests/testcases/integration/statements/except-1.boo (revision 0) @@ -0,0 +1,23 @@ +""" +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + pass +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-2.boo =================================================================== --- tests/testcases/integration/statements/except-2.boo (revision 0) +++ tests/testcases/integration/statements/except-2.boo (revision 0) @@ -0,0 +1,24 @@ +""" +Anonymous Exception handled by default handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-3.boo =================================================================== --- tests/testcases/integration/statements/except-3.boo (revision 0) +++ tests/testcases/integration/statements/except-3.boo (revision 0) @@ -0,0 +1,26 @@ +""" +Anonymous Exception handled by System.ArgumentNullException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-4.boo =================================================================== --- tests/testcases/integration/statements/except-4.boo (revision 0) +++ tests/testcases/integration/statements/except-4.boo (revision 0) @@ -0,0 +1,26 @@ +""" +Anonymous Exception handled by System.ArgumentException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-5.boo =================================================================== --- tests/testcases/integration/statements/except-5.boo (revision 0) +++ tests/testcases/integration/statements/except-5.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Anonymous Exception handled by System.ArithmeticException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.DivideByZeroException() +except as System.NotFiniteNumberException: + ExceptionCaught(System.NotFiniteNumberException) +except as System.ArithmeticException: + ExceptionCaught(System.ArithmeticException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-6.boo =================================================================== --- tests/testcases/integration/statements/except-6.boo (revision 0) +++ tests/testcases/integration/statements/except-6.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Anonymous Exception handled by System.ArgumentNullException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-7.boo =================================================================== --- tests/testcases/integration/statements/except-7.boo (revision 0) +++ tests/testcases/integration/statements/except-7.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Anonymous Exception handled by System.ArgumentException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentOutOfRangeException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/except-8.boo =================================================================== --- tests/testcases/integration/statements/except-8.boo (revision 0) +++ tests/testcases/integration/statements/except-8.boo (revision 0) @@ -0,0 +1,24 @@ +""" +Exception with type 'System.ArgumentNullException' handled by default handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-9.boo =================================================================== --- tests/testcases/integration/statements/except-9.boo (revision 0) +++ tests/testcases/integration/statements/except-9.boo (revision 0) @@ -0,0 +1,26 @@ +""" +Exception with type 'System.ArgumentNullException' handled by System.ArgumentNullException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except ex as System.ArgumentNullException: + ExceptionCaught(ex, System.ArgumentNullException) +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-10.boo =================================================================== --- tests/testcases/integration/statements/except-10.boo (revision 0) +++ tests/testcases/integration/statements/except-10.boo (revision 0) @@ -0,0 +1,26 @@ +""" +Exception with type 'System.ArgumentNullException' handled by System.ArgumentException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except ex as System.ArgumentException: + ExceptionCaught(ex, System.ArgumentException) +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-11.boo =================================================================== --- tests/testcases/integration/statements/except-11.boo (revision 0) +++ tests/testcases/integration/statements/except-11.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Exception with type 'System.DivideByZeroException' handled by System.ArithmeticException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.DivideByZeroException() +except ex as System.NotFiniteNumberException: + ExceptionCaught(ex, System.NotFiniteNumberException) +except ex as System.ArithmeticException: + ExceptionCaught(ex, System.ArithmeticException) +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-12.boo =================================================================== --- tests/testcases/integration/statements/except-12.boo (revision 0) +++ tests/testcases/integration/statements/except-12.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Exception with type 'System.ArgumentNullException' handled by System.ArgumentNullException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentNullException() +except ex as System.ArgumentNullException: + ExceptionCaught(ex, System.ArgumentNullException) +except ex as System.ArgumentException: + ExceptionCaught(ex, System.ArgumentException) +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-13.boo =================================================================== --- tests/testcases/integration/statements/except-13.boo (revision 0) +++ tests/testcases/integration/statements/except-13.boo (revision 0) @@ -0,0 +1,28 @@ +""" +Exception with type 'System.ArgumentOutOfRangeException' handled by System.ArgumentException handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentOutOfRangeException() +except ex as System.ArgumentNullException: + ExceptionCaught(ex, System.ArgumentNullException) +except ex as System.ArgumentException: + ExceptionCaught(ex, System.ArgumentException) +except ex: + ExceptionCaught(ex) \ No newline at end of file Index: tests/testcases/integration/statements/except-14.boo =================================================================== --- tests/testcases/integration/statements/except-14.boo (revision 0) +++ tests/testcases/integration/statements/except-14.boo (revision 0) @@ -0,0 +1,26 @@ +""" +Anonymous Exception handled by default handler +""" + +def ExceptionCaught(): + ExceptionCaught(null, null) +def ExceptionCaught(type as System.Type): + ExceptionCaught(null, type) +def ExceptionCaught(ex as object): + ExceptionCaught(ex, null) +def ExceptionCaught(ex as object, exHandler as System.Type): + value as string + value += "Anonymous " if ex is null + value += "Exception " + value += "with type '${ex.GetType()}' " if ex is not null + value += "handled by " + value += "${exHandler} handler" if exHandler is not null + value += "default handler" if exHandler is null + print value + +try: + raise System.ArgumentException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except: + ExceptionCaught() \ No newline at end of file Index: tests/testcases/integration/statements/filter-1.boo =================================================================== --- tests/testcases/integration/statements/filter-1.boo (revision 0) +++ tests/testcases/integration/statements/filter-1.boo (revision 0) @@ -0,0 +1,14 @@ +""" +Good +""" +def RetVal(): + return 5 + +try: + raise System.Exception() +except as System.Exception unless RetVal() >= 4: + print "What?" +except as System.Exception if RetVal().ToString() == "5": + print "Good" +except as System.Exception: + print "NO!" \ No newline at end of file Index: tests/testcases/integration/statements/filter-2.boo =================================================================== --- tests/testcases/integration/statements/filter-2.boo (revision 0) +++ tests/testcases/integration/statements/filter-2.boo (revision 0) @@ -0,0 +1,18 @@ +""" +Good +System.Exception: This is the message +""" +def RetVal(): + return 5 + +try: + raise System.Exception("This is the message") +except ex as System.Exception if RetVal() >= 4 and ex.Message != "This is the message": + print "What?" + print ex.GetType() + ": " + ex.Message +except ex as System.Exception unless RetVal().ToString() == "4": + print "Good" + print ex.GetType() + ": " + ex.Message +except ex as System.Exception: + print "NO!" + print ex.GetType() + ": " + ex.Message \ No newline at end of file Index: tests/testcases/integration/statements/filter-3.boo =================================================================== --- tests/testcases/integration/statements/filter-3.boo (revision 0) +++ tests/testcases/integration/statements/filter-3.boo (revision 0) @@ -0,0 +1,25 @@ +""" +Good +System.Exception: This is the message +""" + +def RetVal(ref catch as bool): + catch = not catch + return not catch + +catch = false + +try: + raise System.Exception("This is the message") +except ex as System.Exception if RetVal(catch): + print "What?" + print ex.GetType() + ": " + ex.Message +except ex as System.Exception unless RetVal(catch): + print "Still Bad..." + print ex.GetType() + ": " + ex.Message +except ex as System.Exception unless RetVal(catch): + print "Good" + print ex.GetType() + ": " + ex.Message +except ex as System.Exception: + print "NO!" + print ex.GetType() + ": " + ex.Message \ No newline at end of file Index: tests/testcases/errors/BCE0145-1.boo =================================================================== --- tests/testcases/errors/BCE0145-1.boo (revision 0) +++ tests/testcases/errors/BCE0145-1.boo (revision 0) @@ -0,0 +1,7 @@ +""" +BCE0145-1.boo(6,11): BCE0145: Cannot catch type 'int'; 'except' blocks can only catch exceptions derived from 'System.Exception'. To catch non-CLS compliant exceptions, use a default exception handler or catch 'System.Runtime.CompilerServices.RuntimeWrappedException'. +""" +try: + print '!' +except as int: + print "Caught Int!" Index: tests/testcases/errors/BCE0128-1.boo =================================================================== --- tests/testcases/errors/BCE0128-1.boo (revision 2738) +++ tests/testcases/errors/BCE0128-1.boo (working copy) @@ -1,5 +1,5 @@ """ -BCE0128-1.boo(4,1): BCE0128: 'try' block must be followed by either 'except' or 'ensure'. +BCE0128-1.boo(4,1): BCE0128: 'try' block must be followed by at least one 'except' block or either a 'failure' or 'ensure' block. """ try: print '!' Index: ast.model.boo =================================================================== --- ast.model.boo (revision 2738) +++ ast.model.boo (working copy) @@ -33,6 +33,13 @@ Val = 0 Ref = 1 +[Flags] +enum ExceptionHandlerFlags: + None = 0 + Anonymous = 1 + Untyped = 2 + Filter = 4 + abstract class TypeMember(Node, INodeWithAttributes): Modifiers as TypeMemberModifiers Name as string @@ -240,10 +247,13 @@ [auto] ProtectedBlock as Block ExceptionHandlers as ExceptionHandlerCollection + FailureBlock as Block EnsureBlock as Block class ExceptionHandler(Node): Declaration as Declaration + FilterCondition as Expression + Flags as ExceptionHandlerFlags [auto] Block as Block