Index: src/Boo.Lang.Parser/wsaboo.g =================================================================== --- src/Boo.Lang.Parser/wsaboo.g (revision 2702) +++ 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"; @@ -1312,28 +1313,37 @@ try_stmt returns [TryStatement s] { s = null; - Block sblock = null; Block eblock = null; + Block lastBlock = null; }: - t:TRY { s = new TryStatement(SourceLocationFactory.ToLexicalInfo(t)); } - compound_stmt[s.ProtectedBlock] + t:TRY { s = new TryStatement(SourceLocationFactory.ToLexicalInfo(t)); } begin + {s.ProtectedBlock = new Block();} block[s.ProtectedBlock.Statements] { lastBlock = s.ProtectedBlock; } + (EXCEPT|FAILURE|ENSURE)=> ( - exception_handler[s] + lastBlock = exception_handler[s] )* ( - etoken:ENSURE { eblock = new Block(SourceLocationFactory.ToLexicalInfo(etoken)); } - compound_stmt[eblock] - { s.EnsureBlock = eblock; } + 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; } + )? + end[lastBlock] ; protected -exception_handler [TryStatement t] +exception_handler [TryStatement t] returns [Block lastBlock] { ExceptionHandler eh = null; TypeReference tr = null; + Expression e = null; + lastBlock = null; }: - c:EXCEPT (x:ID (AS tr=type_reference)?)? + c:EXCEPT (x:ID)? (AS tr=type_reference)? (WHEN e=expression)? begin { eh = new ExceptionHandler(SourceLocationFactory.ToLexicalInfo(c)); @@ -1342,10 +1352,28 @@ eh.Declaration = new Declaration(SourceLocationFactory.ToLexicalInfo(x)); eh.Declaration.Name = x.getText(); eh.Declaration.Type = tr; + eh.Type = tr; } + else + { + eh.Declaration = null; + eh.Type = tr; + eh.Flags |= ExceptionHandlerFlags.Anonymous; + } + if(tr == null) + { + eh.Flags |= ExceptionHandlerFlags.Untyped; + } + if (e != null) + { + eh.FilterCondition = e; + eh.Flags |= ExceptionHandlerFlags.Filter; + } + eh.Block = new Block(SourceLocationFactory.ToLexicalInfo(c)); } - compound_stmt[eh.Block] + block[eh.Block.Statements] { + lastBlock = eh.Block; t.ExceptionHandlers.Add(eh); } ; Index: src/Boo.Lang.Parser/boo.g =================================================================== --- src/Boo.Lang.Parser/boo.g (revision 2702) +++ 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"; @@ -1411,10 +1412,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; } @@ -1426,8 +1433,9 @@ { 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)? (WHEN e=expression)? { eh = new ExceptionHandler(SourceLocationFactory.ToLexicalInfo(c)); @@ -1436,7 +1444,23 @@ eh.Declaration = new Declaration(SourceLocationFactory.ToLexicalInfo(x)); eh.Declaration.Name = x.getText(); eh.Declaration.Type = tr; + eh.Type = tr; } + else + { + eh.Declaration = null; + eh.Type = tr; + eh.Flags |= ExceptionHandlerFlags.Anonymous; + } + if(tr == null) + { + eh.Flags |= ExceptionHandlerFlags.Untyped; + } + if (e != null) + { + 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 2702) +++ 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 2702) +++ src/Boo.Lang.Compiler/Ast/Visitors/BooPrinterVisitor.cs (working copy) @@ -991,28 +991,71 @@ 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(); } + + if(IsWhiteSpaceAgnostic) + { + WriteEnd(); + } } override public void OnExceptionHandler(ExceptionHandler node) { WriteIndented(); WriteKeyword("except"); - if (null != node.Declaration) + if ((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None) { - Write(" "); - Visit(node.Declaration); + if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + Write(" "); + Visit(node.Declaration); + } + else + { + WriteTypeReference(node.Type); + } } + else + { + if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + Write(" "); + Write(node.Declaration.Name); + } + } + + if((node.Flags & ExceptionHandlerFlags.Filter) == ExceptionHandlerFlags.Filter) + { + WriteKeyword(" when "); + Visit(node.FilterCondition); + } WriteLine(":"); - WriteBlock(node.Block); + Indent(); + WriteBlockStatements(node.Block); + Dedent(); } override public void OnUnlessStatement(UnlessStatement node) Index: src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (revision 2702) +++ src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (working copy) @@ -2843,33 +2843,51 @@ 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)); + node.Type = CodeBuilder.CreateTypeReference(TypeSystemServices.ExceptionType); } else { - if (null == node.Declaration.Type) + Visit(node.Type); + if(!TypeSystemServices.ExceptionType.IsAssignableFrom(GetType(node.Type))) { - node.Declaration.Type = CodeBuilder.CreateTypeReference(TypeSystemServices.ExceptionType); + Errors.Add(CompilerErrorFactory.InvalidExceptArgument(node.Type, GetType(node.Type).FullName)); } - else - { - Visit(node.Declaration.Type); - } } + + + if(!anonymousException) + { + node.Declaration.Type = node.Type; + node.Declaration.Entity = DeclareLocal(node.Declaration, node.Declaration.Name, GetType(node.Declaration.Type), true); + } + - node.Declaration.Entity = DeclareLocal(node.Declaration, node.Declaration.Name, GetType(node.Declaration.Type), true); - EnterNamespace(new DeclarationsNamespace(CurrentNamespace, TypeSystemServices, node.Declaration)); + if (filterHandler) + { + Visit(node.FilterCondition); + } + + if(!anonymousException) + { + EnterNamespace(new DeclarationsNamespace(CurrentNamespace, TypeSystemServices, node.Declaration)); + } + try { Visit(node.Block); } finally { - LeaveNamespace(); + if(!anonymousException) + { + LeaveNamespace(); + } } } Index: src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs (revision 2702) +++ src/Boo.Lang.Compiler/Steps/PreErrorChecking.cs (working copy) @@ -114,7 +114,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 2702) +++ src/Boo.Lang.Compiler/Steps/StricterErrorChecking.cs (working copy) @@ -127,6 +127,9 @@ public override void OnTryStatement(TryStatement node) { Visit(node.ProtectedBlock); + EnterEnsureBlock(); + Visit(node.FailureBlock); + LeaveEnsureBlock(); Visit(node.ExceptionHandlers); EnterEnsureBlock(); Visit(node.EnsureBlock); Index: src/Boo.Lang.Compiler/Steps/EmitAssembly.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/EmitAssembly.cs (revision 2702) +++ 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]); @@ -743,29 +747,142 @@ override public void OnTryStatement(TryStatement node) { - ++_tryBlock; - _il.BeginExceptionBlock(); + if(null != node.EnsureBlock) + { + ++_tryBlock; + _il.BeginExceptionBlock(); + } + + if(node.ExceptionHandlers.Count > 0) + { + ++_tryBlock; + _il.BeginExceptionBlock(); + } + + if(null != node.FailureBlock) + { + ++_tryBlock; + _il.BeginExceptionBlock(); + } + Visit(node.ProtectedBlock); - Visit(node.ExceptionHandlers); - --_tryBlock; + if(null != node.FailureBlock) + { + _il.BeginFaultBlock(); + Visit(node.FailureBlock); + _il.EndExceptionBlock(); + --_tryBlock; + } + + if(node.ExceptionHandlers.Count > 0) + { + Visit(node.ExceptionHandlers); + _il.EndExceptionBlock(); + --_tryBlock; + } + if (null != node.EnsureBlock) { _il.BeginFinallyBlock(); Visit(node.EnsureBlock); + _il.EndExceptionBlock(); + --_tryBlock; } - _il.EndExceptionBlock(); - } 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((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.None) + { + Label filterCondition = _il.DefineLabel(); + + _il.Emit(OpCodes.Isinst, GetSystemType(node.Type)); + + _il.Emit(OpCodes.Dup); + + _il.Emit(OpCodes.Brtrue_S, filterCondition); + + EmitStoreOrPopException(node); + + _il.Emit(OpCodes.Ldc_I4_0); + _il.Emit(OpCodes.Br_S, endLabel); + _il.MarkLabel(filterCondition); + + } + else if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { + _il.Emit(OpCodes.Castclass, GetSystemType(node.Type)); + } + + EmitStoreOrPopException(node); + + node.FilterCondition.Accept(this); + PopType(); + EmitToBoolIfNeeded(node.FilterCondition); + + _il.Emit(OpCodes.Ldc_I4_0); + _il.Emit(OpCodes.Cgt_Un); + _il.MarkLabel(endLabel); + + _il.BeginCatchBlock(null); + //_il.Emit(OpCodes.Pop); + } + else + { + _il.BeginCatchBlock(GetSystemType(node.Type)); + + EmitStoreOrPopException(node); + } + Visit(node.Block); } + private void EmitStoreOrPopException(ExceptionHandler node) + { + if((node.Flags & ExceptionHandlerFlags.Anonymous) == ExceptionHandlerFlags.None) + { +// if((node.Flags & ExceptionHandlerFlags.Untyped) == ExceptionHandlerFlags.Untyped) +// { +// EmitRuntimeWrappedExceptionIfNeeded(); +// } + _il.Emit(OpCodes.Stloc, GetLocalBuilder(node.Declaration)); + } + else + { + _il.Emit(OpCodes.Pop); + } + } + + private void EmitRuntimeWrappedExceptionIfNeeded() + { + // The CLR Runtime does this automatically. +// Label popAndSkip = _il.DefineLabel(); +// Label exit = _il.DefineLabel(); +// +// _il.Emit(OpCodes.Dup); +// _il.Emit(OpCodes.Isinst, Types.Exception); +// _il.Emit(OpCodes.Brtrue_S, popAndSkip); +// _il.Emit(OpCodes.Pop); +// +// Type wrappedtype = typeof(System.Runtime.CompilerServices.RuntimeWrappedException); +// Type[] constructorParams = new Type[] { Types.Object }; +// ConstructorInfo ci = wrappedtype.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, constructorParams, null); +// _il.Emit(OpCodes.Newobj, ci); +// _il.Emit(OpCodes.Br_S, exit); +// +// _il.MarkLabel(popAndSkip); +// _il.Emit(OpCodes.Pop); +// _il.MarkLabel(exit); + } + override public void OnUnpackStatement(UnpackStatement node) { NotImplemented("Unpacking"); @@ -783,7 +900,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 +3707,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 +4812,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); @@ -4705,7 +4830,14 @@ AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = GetAssemblySimpleName(outputFile); assemblyName.Version = GetAssemblyVersion(); - assemblyName.KeyPair = GetAssemblyKeyPair(outputFile); + if(Parameters.DelaySign) + { + assemblyName.SetPublicKey(GetAssemblyKeyPair(outputFile).PublicKey); + } + else + { + assemblyName.KeyPair = GetAssemblyKeyPair(outputFile); + } return assemblyName; } Index: src/Boo.Lang.Compiler/CompilerErrorFactory.cs =================================================================== --- src/Boo.Lang.Compiler/CompilerErrorFactory.cs (revision 2702) +++ 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 2702) +++ 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/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 2702) +++ 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: tests/testcases/compilation/exceptions-1.boo =================================================================== --- tests/testcases/compilation/exceptions-1.boo (revision 0) +++ tests/testcases/compilation/exceptions-1.boo (revision 0) @@ -0,0 +1,137 @@ +""" +Finally +Anonymous Exception handled by default handler +Anonymous Exception handled by System.ArgumentNullException handler +Anonymous Exception handled by System.ArgumentException handler +Anonymous Exception handled by System.ArithmeticException handler +Anonymous Exception handled by System.ArgumentNullException handler +Anonymous Exception handled by System.ArgumentException handler +Exception with type 'System.ArgumentNullException' handled by default handler +Exception with type 'System.ArgumentNullException' handled by System.ArgumentNullException handler +Exception with type 'System.ArgumentNullException' handled by System.ArgumentException handler +Exception with type 'System.DivideByZeroException' handled by System.ArithmeticExcepton handler +Exception with type 'System.ArgumentNullException' handled by System.ArgumentNullException handler +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 + +def Finally(): + print "Finally" + +try: + pass +except: + ExceptionCaught() + +try: + pass +ensure: + Finally() + +try: + raise System.ArgumentNullException() +except: + ExceptionCaught() + +try: + raise System.ArgumentNullException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except: + ExceptionCaught() + +try: + raise System.ArgumentNullException() +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() + +try: + raise System.DivideByZeroException() +except as System.NotFiniteNumberException: + ExceptionCaught(System.NotFiniteNumberException) +except as System.ArithmeticException: + ExceptionCaught(System.ArithmeticException) +except: + ExceptionCaught() + +try: + raise System.ArgumentNullException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() + +try: + raise System.ArgumentOutOfRangeException() +except as System.ArgumentNullException: + ExceptionCaught(System.ArgumentNullException) +except as System.ArgumentException: + ExceptionCaught(System.ArgumentException) +except: + ExceptionCaught() + +try: + raise System.ArgumentNullException() +except ex: + ExceptionCaught(ex) + +try: + raise System.ArgumentNullException() +except ex as System.ArgumentNullException: + ExceptionCaught(ex, System.ArgumentNullException) +except ex: + ExceptionCaught(ex) + +try: + raise System.ArgumentNullException() +except ex as System.ArgumentException: + ExceptionCaught(ex, System.ArgumentException) +except ex: + ExceptionCaught(ex) + +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) + +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) + +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) + Index: tests/testcases/compilation/exceptions-2.boo =================================================================== --- tests/testcases/compilation/exceptions-2.boo (revision 0) +++ tests/testcases/compilation/exceptions-2.boo (revision 0) @@ -0,0 +1,67 @@ +""" +Failed +caught +Ensured +Good +Good +System.Exception: This is the message + at TesterModule.Main(String[] argv) in G:\exception-2.boo:line 40 +""" + +# Expose of Filter and failure. Note that the failure block executes before the exception is handled. +# If the failure block is set to execute after the catch block, then it will only execute if the exception +# goes unhandled. + +def RetVal(): + return 5 + +try: + raise System.Exception() +except when RetVal() == 5: + print "caught" +failure: + print "Failed" +ensure: + print "Ensured" + +try: + raise System.Exception() +except as System.Exception when RetVal() < 4: + print "What?" +except as System.Exception when RetVal().ToString() == "5": + print "Good" +except as System.Exception: + print "NO!" + +try: + raise System.Exception("This is the message") +except ex as System.Exception when RetVal() < 4: + print "What?" + print ex +except ex as System.Exception when RetVal().ToString() == "5": + print "Good" + print ex +except ex as System.Exception: + print "NO!" + print ex + +# Here, I have temporarily disabled the compiler checks ensuring +# that raised objects derive from System.Exception in order to test +# that the exception is wrapped at runtime (For testing purposes only!). +# Under normal conditions, Boo prevents you from doing this (and will continue to do so) + +#class Test: +# override def ToString(): +# return "Tres" + +#try: +# raise Test() +#except ex when RetVal() < 4: +# print "What?" +# print ex +#except ex when RetVal().ToString() == "5": +# print "Good" +# print ex +#except ex: +# print "NO!" +# print ex Index: ast.model.boo =================================================================== --- ast.model.boo (revision 2702) +++ 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,14 @@ [auto] ProtectedBlock as Block ExceptionHandlers as ExceptionHandlerCollection + FailureBlock as Block EnsureBlock as Block class ExceptionHandler(Node): Declaration as Declaration + Type as TypeReference + FilterCondition as Expression + Flags as ExceptionHandlerFlags [auto] Block as Block