1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2003-2011. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: %%
   21: -module(trycatch_SUITE).
   22: 
   23: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   24: 	 init_per_testcase/2,end_per_testcase/2,
   25: 	 init_per_suite/1,end_per_suite/1,
   26: 	 basic/1,lean_throw/1,try_of/1,try_after/1,%after_bind/1,
   27: 	 catch_oops/1,after_oops/1,eclectic/1,rethrow/1,
   28: 	 nested_of/1,nested_catch/1,nested_after/1]).
   29: 
   30: -include_lib("test_server/include/test_server.hrl").
   31: 
   32: suite() -> [{ct_hooks,[ts_install_cth]}].
   33: 
   34: all() -> 
   35:     cases().
   36: 
   37: groups() -> 
   38:     [].
   39: 
   40: init_per_group(_GroupName, Config) ->
   41:     Config.
   42: 
   43: end_per_group(_GroupName, Config) ->
   44:     Config.
   45: 
   46: 
   47: cases() -> 
   48:     [basic, lean_throw, try_of, try_after, catch_oops,
   49:      after_oops, eclectic, rethrow, nested_of, nested_catch,
   50:      nested_after].
   51: 
   52: init_per_testcase(_Case, Config) ->
   53:     test_lib:interpret(?MODULE),
   54:     Dog = test_server:timetrap(?t:minutes(1)),
   55:     [{watchdog,Dog}|Config].
   56: 
   57: end_per_testcase(_Case, Config) ->
   58:     Dog = ?config(watchdog, Config),
   59:     ?t:timetrap_cancel(Dog),
   60:     ok.
   61: 
   62: init_per_suite(Config) when is_list(Config) ->
   63:     ?line test_lib:interpret(?MODULE),
   64:     ?line true = lists:member(?MODULE, int:interpreted()),
   65:     Config.
   66: 
   67: end_per_suite(Config) when is_list(Config) ->
   68:     ok.
   69: 
   70: basic(Conf) when is_list(Conf) ->
   71:     ?line 2 =
   72: 	try my_div(4, 2)
   73: 	catch
   74:             Class:Reason -> {Class,Reason}
   75: 	end,
   76:     ?line error =
   77:         try my_div(1, 0)
   78:         catch
   79:             error:badarith -> error
   80:         end,
   81:     ?line error =
   82:         try 1/0
   83:         catch
   84:             error:badarith -> error
   85:         end,
   86:     ?line ok =
   87:         try my_add(53, atom)
   88:         catch
   89:             error:badarith -> ok
   90:         end,
   91:     ?line exit_nisse =
   92:         try exit(nisse)
   93: 	catch
   94:             exit:nisse -> exit_nisse
   95:         end,
   96:     ?line ok =
   97:         try throw(kalle)
   98:         catch
   99:             kalle -> ok
  100:         end,
  101: 
  102:     %% Try some stuff where the compiler will optimize away the try.
  103: 
  104:     V = id({a,variable}),
  105:     ?line V = try V catch nisse -> error end,
  106:     ?line 42 = try 42 catch nisse -> error end,
  107:     ?line [V] = try [V] catch nisse -> error end,
  108:     ?line {ok,V} = try {ok,V} catch nisse -> error end,
  109: 
  110:     %% Same idea, but use an after too.
  111: 
  112:     ?line V = try V catch nisse -> error after after_call() end,
  113:     ?line after_clean(),
  114:     ?line 42 = try 42 after after_call() end,
  115:     ?line after_clean(),
  116:     ?line [V] = try [V] catch nisse -> error after after_call() end,
  117:     ?line after_clean(),
  118:     ?line {ok,V} = try {ok,V} after after_call() end,
  119: 
  120:     %% Try/of
  121:     ?line ok = try V of
  122:               {a,variable} -> ok
  123:               catch nisse -> erro
  124:           end,
  125: 
  126:     ok.
  127: 
  128: after_call() ->
  129:     put(basic, after_was_called).
  130: 
  131: after_clean() ->
  132:     after_was_called = erase(basic).
  133: 
  134: lean_throw(Conf) when is_list(Conf) ->
  135:     ?line {throw,kalle} =
  136:         try throw(kalle)
  137:         catch
  138:             Kalle -> {throw,Kalle}
  139:         end,
  140:     ?line {exit,kalle} =
  141:         try exit(kalle)
  142:         catch
  143:             Throw1 -> {throw,Throw1};
  144: 	    exit:Reason1 -> {exit,Reason1}
  145:         end,
  146:     ?line {exit,kalle} =
  147:         try exit(kalle)
  148:         catch
  149: 	    exit:Reason2 -> {exit,Reason2};
  150:             Throw2 -> {throw,Throw2}
  151:         end,
  152:     ?line {exit,kalle} =
  153:         try try exit(kalle)
  154:             catch
  155:                 Throw3 -> {throw,Throw3}
  156:             end
  157:         catch
  158:             exit:Reason3 -> {exit,Reason3}
  159:         end,
  160:     ok.
  161: 
  162: try_of(Conf) when is_list(Conf) ->
  163:     ?line {ok,{some,content}} =
  164: 	try_of_1({value,{good,{some,content}}}),
  165:     ?line {error,[other,content]} =
  166: 	try_of_1({value,{bad,[other,content]}}),
  167:     ?line {caught,{exit,{ex,it,[reason]}}} =
  168: 	try_of_1({exit,{ex,it,[reason]}}),
  169:     ?line {caught,{throw,[term,{in,a,{tuple}}]}} =
  170: 	try_of_1({throw,[term,{in,a,{tuple}}]}),
  171:     ?line {caught,{error,[bad,arg]}} =
  172: 	try_of_1({error,[bad,arg]}),
  173:     ?line {caught,{error,badarith}} =
  174: 	try_of_1({'div',{1,0}}),
  175:     ?line {caught,{error,badarith}} =
  176: 	try_of_1({'add',{a,0}}),
  177:     ?line {caught,{error,badarg}} =
  178: 	try_of_1({'abs',x}),
  179:     ?line {caught,{error,function_clause}} =
  180: 	try_of_1(illegal),
  181:     ?line {error,{try_clause,{some,other_garbage}}} =
  182: 	try try_of_1({value,{some,other_garbage}})
  183:         catch error:Reason -> {error,Reason}
  184:         end,
  185:     ok.
  186: 
  187: try_of_1(X) ->
  188:     try foo(X) of
  189:         {good,Y} -> {ok,Y};
  190: 	{bad,Y} -> {error,Y}
  191:     catch
  192: 	Class:Reason ->
  193:              {caught,{Class,Reason}}
  194:     end.
  195: 
  196: try_after(Conf) when is_list(Conf) ->
  197:     ?line {{ok,[some,value],undefined},finalized} =
  198: 	try_after_1({value,{ok,[some,value]}},finalized),
  199:     ?line {{error,badarith,undefined},finalized} =
  200: 	try_after_1({'div',{1,0}},finalized),
  201:     ?line {{error,badarith,undefined},finalized} =
  202: 	try_after_1({'add',{1,a}},finalized),
  203:     ?line {{error,badarg,undefined},finalized} =
  204: 	try_after_1({'abs',a},finalized),
  205:     ?line {{error,[the,{reason}],undefined},finalized} =
  206: 	try_after_1({error,[the,{reason}]},finalized),
  207:     ?line {{throw,{thrown,[reason]},undefined},finalized} =
  208: 	try_after_1({throw,{thrown,[reason]}},finalized),
  209:     ?line {{exit,{exited,{reason}},undefined},finalized} =
  210: 	try_after_1({exit,{exited,{reason}}},finalized),
  211:     ?line {{error,function_clause,undefined},finalized} =
  212: 	try_after_1(function_clause,finalized),
  213:     ?line ok =
  214: 	try try_after_1({'add',{1,1}}, finalized)
  215:         catch
  216:             error:{try_clause,2} -> ok
  217: 	end,
  218:     ?line finalized = erase(try_after),
  219:     ?line ok =
  220:         try try foo({exit,[reaso,{n}]})
  221:             after put(try_after, finalized)
  222:             end
  223:         catch
  224:             exit:[reaso,{n}] -> ok
  225:         end,
  226:     ok.
  227: 
  228: try_after_1(X, Y) ->
  229:     erase(try_after),
  230:     Try =
  231:         try foo(X) of
  232: 	    {ok,Value} -> {ok,Value,get(try_after)}
  233:         catch
  234: 	    Reason -> {throw,Reason,get(try_after)};
  235: 	    error:Reason -> {error,Reason,get(try_after)};
  236: 	    exit:Reason ->  {exit,Reason,get(try_after)}
  237:         after
  238: 	    put(try_after, Y)
  239:         end,
  240:     {Try,erase(try_after)}.
  241: 
  242: -ifdef(begone).
  243: 
  244: after_bind(Conf) when is_list(Conf) ->
  245:     V = [make_ref(),self()|value],
  246:     ?line {value,{value,V}} =
  247: 	after_bind_1({value,V}, V, {value,V}),
  248:     ok.
  249: 
  250: after_bind_1(X, V, Y) ->
  251:     try
  252:         Try =
  253:             try foo(X) of
  254:                 V -> value
  255:             catch
  256:                 C1:V -> {caught,C1}
  257:             after
  258:                 After = foo(Y)
  259: 	    end,
  260:         {Try,After}
  261:     of
  262:         V -> {value,V}
  263:     catch
  264:         C:D -> {caught,{C,D}}
  265:     end.
  266: 
  267: -endif.
  268: 
  269: catch_oops(Conf) when is_list(Conf) ->
  270:     V = {v,[a,l|u],{e},self()},
  271:     ?line {value,V} = catch_oops_1({value,V}),
  272:     ?line {value,1} = catch_oops_1({'div',{1,1}}),
  273:     ?line {error,badarith} = catch_oops_1({'div',{1,0}}),
  274:     ?line {error,function_clause} = catch_oops_1(function_clause),
  275:     ?line {throw,V} = catch_oops_1({throw,V}),
  276:     ?line {exit,V} = catch_oops_1({exit,V}),
  277:     ok.
  278: 
  279: catch_oops_1(X) ->
  280:     Ref = make_ref(),
  281:     try try foo({error,Ref})
  282:         catch
  283:             error:Ref ->
  284: 	        foo(X)
  285:         end of
  286:         Value -> {value,Value}
  287:     catch
  288:         Class:Data -> {Class,Data}
  289:     end.
  290: 
  291: 
  292: 
  293: after_oops(Conf) when is_list(Conf) ->
  294:     V = {self(),make_ref()},
  295:     ?line {{value,V},V} = after_oops_1({value,V}, {value,V}),
  296:     ?line {{exit,V},V} = after_oops_1({exit,V}, {value,V}),
  297:     ?line {{error,V},undefined} = after_oops_1({value,V}, {error,V}),
  298:     ?line {{error,function_clause},undefined} =
  299: 	after_oops_1({exit,V}, function_clause),
  300:     ok.
  301: 
  302: after_oops_1(X, Y) ->
  303:     erase(after_oops),
  304:     Try =
  305:         try try foo(X)
  306:             after
  307:                 put(after_oops, foo(Y))
  308:             end of
  309:             V -> {value,V}
  310:         catch
  311:             C:D -> {C,D}
  312:         end,
  313:     {Try,erase(after_oops)}.
  314: 
  315: 
  316: 
  317: eclectic(Conf) when is_list(Conf) ->
  318:     V = {make_ref(),3.1415926535,[[]|{}]},
  319:     ?line {{value,{value,V},V},V} =
  320: 	eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
  321:     ?line {{'EXIT',{V,[{?MODULE,foo,_,_}|_]}},V} =
  322: 	eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
  323:     ?line {{error,{exit,V},{'EXIT',V}},V} =
  324: 	eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
  325:     ?line {{value,{value,V},V},{'EXIT',{badarith,[{?MODULE,my_add,_,_}|_]}}} =
  326: 	eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
  327:     ?line {{'EXIT',V},V} =
  328: 	eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
  329:     ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,_,_}|_]}}},
  330: 	   {'EXIT',V}} =
  331: 	eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
  332:     ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},{'EXIT',V}} =
  333: 	eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
  334:     %%
  335:     ?line {{value,{value,{value,V},V}},V} =
  336: 	eclectic_2({value,{value,V}}, undefined, {value,V}),
  337:     ?line {{value,{throw,{value,V},V}},V} =
  338: 	eclectic_2({throw,{value,V}}, throw, {value,V}),
  339:     ?line {{caught,{'EXIT',V}},undefined} =
  340: 	eclectic_2({value,{value,V}}, undefined, {exit,V}),
  341:     ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},undefined} =
  342: 	eclectic_2({error,{value,V}}, throw, {error,V}),
  343:     ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
  344: 	eclectic_2({value,{'abs',V}}, undefined, {value,V}),
  345:     ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,_,_}|_]}}},V} =
  346: 	eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
  347:     ?line {{caught,{'EXIT',V}},undefined} =
  348: 	eclectic_2({value,{error,V}}, undefined, {exit,V}),
  349:     ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},undefined} =
  350: 	eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
  351:     ok.
  352: 
  353: eclectic_1(X, C, Y) ->
  354:     erase(eclectic),
  355:     Done = make_ref(),
  356:     Try =
  357:         try case X of
  358: 		{catch_foo,V} -> catch {Done,foo(V)};
  359: 		{foo,V} -> {Done,foo(V)}
  360: 	    end of
  361:             {Done,D} -> {value,D,catch foo(D)};
  362: 	    {'EXIT',_}=Exit -> Exit;
  363: 	    D -> {D,catch foo(D)}
  364:         catch
  365:             C:D -> {C,D,catch foo(D)}
  366:         after
  367:             put(eclectic, catch foo(Y))
  368:         end,
  369:     {Try,erase(eclectic)}.
  370: 
  371: eclectic_2(X, C, Y) ->
  372:     Done = make_ref(),
  373:     erase(eclectic),
  374:     Catch =
  375: 	case
  376:             catch
  377:             {Done,
  378:              try foo(X) of
  379:                  V -> {value,V,foo(V)}
  380:              catch
  381:                  C:D -> {C,D,foo(D)}
  382:              after
  383:                  put(eclectic, foo(Y))
  384:              end} of
  385:             {Done,Z} -> {value,Z};
  386:             Z -> {caught,Z}
  387:         end,
  388:     {Catch,erase(eclectic)}.
  389: 
  390: rethrow(Conf) when is_list(Conf) ->
  391:     V = {a,[b,{c,self()},make_ref]},
  392:     ?line {value2,value1} =
  393: 	rethrow_1({value,V}, V),
  394:     ?line {caught2,{error,V}} =
  395: 	rethrow_2({error,V}, undefined),
  396:     ?line {caught2,{exit,V}} =
  397: 	rethrow_1({exit,V}, error),
  398:     ?line {caught2,{throw,V}} =
  399: 	rethrow_1({throw,V}, undefined),
  400:     ?line {caught2,{throw,V}} =
  401: 	rethrow_2({throw,V}, undefined),
  402:     ?line {caught2,{error,badarith}} =
  403: 	rethrow_1({'add',{0,a}}, throw),
  404:     ?line {caught2,{error,function_clause}} =
  405: 	rethrow_2(function_clause, undefined),
  406:     ?line {caught2,{error,{try_clause,V}}} =
  407: 	rethrow_1({value,V}, exit),
  408:     ?line {value2,{caught1,V}} =
  409: 	rethrow_1({error,V}, error),
  410:     ?line {value2,{caught1,V}} =
  411: 	rethrow_1({exit,V}, exit),
  412:     ?line {value2,caught1} =
  413: 	rethrow_2({throw,V}, V),
  414:     ok.
  415: 
  416: rethrow_1(X, C1) ->
  417:     try try foo(X) of
  418:             C1 -> value1
  419:         catch
  420:             C1:D1 -> {caught1,D1}
  421:         end of
  422:         V2 -> {value2,V2}
  423:     catch
  424:         C2:D2 -> {caught2,{C2,D2}}
  425:     end.
  426: 
  427: rethrow_2(X, C1) ->
  428:     try try foo(X) of
  429:             C1 -> value1
  430:         catch
  431:             C1 -> caught1 % Implicit class throw:
  432:         end of
  433:         V2 -> {value2,V2}
  434:     catch
  435:         C2:D2 -> {caught2,{C2,D2}}
  436:     end.
  437: 
  438: 
  439: 
  440: nested_of(Conf) when is_list(Conf) ->
  441:     V = {[self()|make_ref()],1.4142136},
  442:     ?line {{value,{value1,{V,x2}}},
  443: 	   {V,x3},
  444: 	   {V,x4},
  445: 	   finalized} =
  446: 	nested_of_1({{value,{V,x1}},void,{V,x1}},
  447: 		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  448:     ?line {{caught,{throw,{V,x2}}},
  449: 	   {V,x3},
  450: 	   {V,x4},
  451: 	   finalized} =
  452: 	nested_of_1({{value,{V,x1}},void,{V,x1}},
  453: 		    {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  454:     ?line {{caught,{error,badarith}},
  455: 	   undefined,
  456: 	   {V,x4},
  457: 	   finalized} =
  458: 	nested_of_1({{value,{V,x1}},void,{V,x1}},
  459: 		    {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
  460:     ?line {{caught,{error,badarith}},
  461: 	   undefined,
  462: 	   undefined,
  463: 	   finalized} =
  464: 	nested_of_1({{value,{V,x1}},void,{V,x1}},
  465: 		    {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
  466:     %%
  467:     ?line {{caught,{error,{try_clause,{V,x1}}}},
  468: 	   {V,x3},
  469: 	   {V,x4},
  470: 	   finalized} =
  471: 	nested_of_1({{value,{V,x1}},void,try_clause},
  472: 		    void, {value,{V,x3}}, {value,{V,x4}}),
  473:     ?line {{caught,{exit,{V,x3}}},
  474: 	   undefined,
  475: 	   {V,x4},
  476: 	   finalized} =
  477: 	nested_of_1({{value,{V,x1}},void,try_clause},
  478: 		    void, {exit,{V,x3}}, {value,{V,x4}}),
  479:     ?line {{caught,{throw,{V,x4}}},
  480: 	   undefined,
  481: 	   undefined,
  482: 	   finalized} =
  483: 	nested_of_1({{value,{V,x1}},void,try_clause},
  484: 		    void, {exit,{V,x3}}, {throw,{V,x4}}),
  485:     %%
  486:     ?line {{value,{caught1,{V,x2}}},
  487: 	   {V,x3},
  488: 	   {V,x4},
  489: 	   finalized} =
  490: 	nested_of_1({{error,{V,x1}},error,{V,x1}},
  491: 		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  492:     ?line {{caught,{error,badarith}},
  493: 	   {V,x3},
  494: 	   {V,x4},
  495: 	   finalized} =
  496: 	nested_of_1({{error,{V,x1}},error,{V,x1}},
  497: 		    {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
  498:     ?line {{caught,{error,badarith}},
  499: 	   undefined,
  500: 	   {V,x4},
  501: 	   finalized} =
  502: 	nested_of_1({{error,{V,x1}},error,{V,x1}},
  503: 		    {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
  504:     ?line {{caught,{error,badarg}},
  505: 	   undefined,
  506: 	   undefined,
  507: 	   finalized} =
  508: 	nested_of_1({{error,{V,x1}},error,{V,x1}},
  509: 		    {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
  510:     %%
  511:     ?line {{caught,{error,badarith}},
  512: 	   {V,x3},
  513: 	   {V,x4},
  514: 	   finalized} =
  515: 	nested_of_1({{'add',{2,c}},rethrow,void},
  516: 		    void, {value,{V,x3}}, {value,{V,x4}}),
  517:     ?line {{caught,{error,badarg}},
  518: 	   undefined,
  519: 	   {V,x4},
  520: 	   finalized} =
  521: 	nested_of_1({{'add',{2,c}},rethrow,void},
  522: 		    void, {'abs',V}, {value,{V,x4}}),
  523:     ?line {{caught,{error,function_clause}},
  524: 	   undefined,
  525: 	   undefined,
  526: 	   finalized} =
  527: 	nested_of_1({{'add',{2,c}},rethrow,void},
  528: 		    void, {'abs',V}, function_clause),
  529:     ok.
  530: 
  531: nested_of_1({X1,C1,V1},
  532: 	    X2, X3, X4) ->
  533:     erase(nested3),
  534:     erase(nested4),
  535:     erase(nested),
  536:     Self = self(),
  537:     Try =
  538: 	try
  539:             try self()
  540:             of
  541:                 Self ->
  542:                     try
  543:                         foo(X1)
  544: 	            of
  545: 	                V1 -> {value1,foo(X2)}
  546:                     catch
  547:                         C1:V1 -> {caught1,foo(X2)}
  548: 	            after
  549:                         put(nested3, foo(X3))
  550:                     end
  551:             after
  552:                 put(nested4, foo(X4))
  553:             end
  554:         of
  555:             V -> {value,V}
  556:         catch
  557:             C:D -> {caught,{C,D}}
  558:         after
  559:             put(nested, finalized)
  560: 	end,
  561:     {Try,erase(nested3),erase(nested4),erase(nested)}.
  562: 
  563: 
  564: 
  565: nested_catch(Conf) when is_list(Conf) ->
  566:     V = {[make_ref(),1.4142136,self()]},
  567:     ?line {{value,{value1,{V,x2}}},
  568: 	   {V,x3},
  569: 	   {V,x4},
  570: 	   finalized} =
  571: 	nested_catch_1({{value,{V,x1}},void,{V,x1}},
  572: 		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  573:     ?line {{caught,{throw,{V,x2}}},
  574: 	   {V,x3},
  575: 	   {V,x4},
  576: 	   finalized} =
  577: 	nested_catch_1({{value,{V,x1}},void,{V,x1}},
  578: 		    {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  579:     ?line {{caught,{error,badarith}},
  580: 	   undefined,
  581: 	   {V,x4},
  582: 	   finalized} =
  583: 	nested_catch_1({{value,{V,x1}},void,{V,x1}},
  584: 		    {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
  585:     ?line {{caught,{error,badarith}},
  586: 	   undefined,
  587: 	   undefined,
  588: 	   finalized} =
  589: 	nested_catch_1({{value,{V,x1}},void,{V,x1}},
  590: 		    {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
  591:     %%
  592:     ?line {{caught,{error,{try_clause,{V,x1}}}},
  593: 	   {V,x3},
  594: 	   {V,x4},
  595: 	   finalized} =
  596: 	nested_catch_1({{value,{V,x1}},void,try_clause},
  597: 		    void, {value,{V,x3}}, {value,{V,x4}}),
  598:     ?line {{caught,{exit,{V,x3}}},
  599: 	   undefined,
  600: 	   {V,x4},
  601: 	   finalized} =
  602: 	nested_catch_1({{value,{V,x1}},void,try_clause},
  603: 		    void, {exit,{V,x3}}, {value,{V,x4}}),
  604:     ?line {{caught,{throw,{V,x4}}},
  605: 	   undefined,
  606: 	   undefined,
  607: 	   finalized} =
  608: 	nested_catch_1({{value,{V,x1}},void,try_clause},
  609: 		    void, {exit,{V,x3}}, {throw,{V,x4}}),
  610:     %%
  611:     ?line {{value,{caught1,{V,x2}}},
  612: 	   {V,x3},
  613: 	   {V,x4},
  614: 	   finalized} =
  615: 	nested_catch_1({{error,{V,x1}},error,{V,x1}},
  616: 		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
  617:     ?line {{caught,{error,badarith}},
  618: 	   {V,x3},
  619: 	   {V,x4},
  620: 	   finalized} =
  621: 	nested_catch_1({{error,{V,x1}},error,{V,x1}},
  622: 		    {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
  623:     ?line {{caught,{error,badarith}},
  624: 	   undefined,
  625: 	   {V,x4},
  626: 	   finalized} =
  627: 	nested_catch_1({{error,{V,x1}},error,{V,x1}},
  628: 		    {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
  629:     ?line {{caught,{error,badarg}},
  630: 	   undefined,
  631: 	   undefined,
  632: 	   finalized} =
  633: 	nested_catch_1({{error,{V,x1}},error,{V,x1}},
  634: 		    {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
  635:     %%
  636:     ?line {{caught,{error,badarith}},
  637: 	   {V,x3},
  638: 	   {V,x4},
  639: 	   finalized} =
  640: 	nested_catch_1({{'add',{2,c}},rethrow,void},
  641: 		    void, {value,{V,x3}}, {value,{V,x4}}),
  642:     ?line {{caught,{error,badarg}},
  643: 	   undefined,
  644: 	   {V,x4},
  645: 	   finalized} =
  646: 	nested_catch_1({{'add',{2,c}},rethrow,void},
  647: 		    void, {'abs',V}, {value,{V,x4}}),
  648:     ?line {{caught,{error,function_clause}},
  649: 	   undefined,
  650: 	   undefined,
  651: 	   finalized} =
  652: 	nested_catch_1({{'add',{2,c}},rethrow,void},
  653: 		    void, {'abs',V}, function_clause),
  654:     ok.
  655: 
  656: nested_catch_1({X1,C1,V1},
  657: 	    X2, X3, X4) ->
  658:     erase(nested3),
  659:     erase(nested4),
  660:     erase(nested),
  661:     Throw = make_ref(),
  662:     Try =
  663: 	try
  664:             try throw(Throw)
  665:             catch
  666: 		Throw ->
  667:                     try
  668:                         foo(X1)
  669: 	            of
  670: 	                V1 -> {value1,foo(X2)}
  671:                     catch
  672:                         C1:V1 -> {caught1,foo(X2)}
  673: 	            after
  674:                         put(nested3, foo(X3))
  675:                     end
  676:             after
  677:                 put(nested4, foo(X4))
  678:             end
  679:         of
  680:             V -> {value,V}
  681:         catch
  682:             C:D -> {caught,{C,D}}
  683:         after
  684:             put(nested, finalized)
  685: 	end,
  686:     {Try,erase(nested3),erase(nested4),erase(nested)}.
  687: 
  688: nested_after(Conf) when is_list(Conf) ->
  689:     V = [{make_ref(),1.4142136,self()}],
  690:     ?line {value,
  691: 	   {V,x3},
  692: 	   {value1,{V,x2}},
  693: 	   finalized} =
  694: 	nested_after_1({{value,{V,x1}},void,{V,x1}},
  695: 		       {value,{V,x2}}, {value,{V,x3}}),
  696:     ?line {{caught,{error,{V,x2}}},
  697: 	   {V,x3},
  698: 	   undefined,
  699: 	   finalized} =
  700: 	nested_after_1({{value,{V,x1}},void,{V,x1}},
  701: 		       {error,{V,x2}}, {value,{V,x3}}),
  702:     ?line {{caught,{exit,{V,x3}}},
  703: 	   undefined,
  704: 	   undefined,
  705: 	   finalized} =
  706: 	nested_after_1({{value,{V,x1}},void,{V,x1}},
  707: 		       {error,{V,x2}}, {exit,{V,x3}}),
  708:     %%
  709:     ?line {{caught,{error,{try_clause,{V,x1}}}},
  710: 	   {V,x3},
  711: 	   undefined,
  712: 	   finalized} =
  713: 	nested_after_1({{value,{V,x1}},void,try_clause},
  714: 		       void, {value,{V,x3}}),
  715:     ?line {{caught,{error,badarith}},
  716: 	   undefined,
  717: 	   undefined,
  718: 	   finalized} =
  719: 	nested_after_1({{value,{V,x1}},void,try_clause},
  720: 		       void, {'div',{17,0}}),
  721:     %%
  722:     ?line {value,
  723: 	   {V,x3},
  724: 	   {caught1,{V,x2}},
  725: 	   finalized} =
  726: 	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
  727: 		       {value,{V,x2}}, {value,{V,x3}}),
  728:     ?line {{caught,{error,badarith}},
  729: 	   {V,x3},
  730: 	   undefined,
  731: 	   finalized} =
  732: 	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
  733: 		       {'add',{a,b}}, {value,{V,x3}}),
  734:     ?line {{caught,{error,badarg}},
  735: 	   undefined,
  736: 	   undefined,
  737: 	   finalized} =
  738: 	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
  739: 		       {'add',{a,b}}, {'abs',V}),
  740:     %%
  741:     ?line {{caught,{throw,{V,x1}}},
  742: 	   {V,x3},
  743: 	   undefined,
  744: 	   finalized} =
  745: 	nested_after_1({{throw,{V,x1}},rethrow,void},
  746: 		       void, {value,{V,x3}}),
  747:     ?line {{caught,{error,badarith}},
  748: 	   undefined,
  749: 	   undefined,
  750: 	   finalized} =
  751: 	nested_after_1({{throw,{V,x1}},rethrow,void},
  752: 		       void, {'div',{1,0}}),
  753:     ok.
  754: 
  755: nested_after_1({X1,C1,V1},
  756: 	    X2, X3) ->
  757:     erase(nested3),
  758:     erase(nested4),
  759:     erase(nested),
  760:     Self = self(),
  761:     Try =
  762: 	try
  763:             try self()
  764:             after
  765:                 After =
  766:                     try
  767:                         foo(X1)
  768: 	            of
  769: 	                V1 -> {value1,foo(X2)}
  770:                     catch
  771:                         C1:V1 -> {caught1,foo(X2)}
  772: 	            after
  773:                         put(nested3, foo(X3))
  774:                     end,
  775:                 put(nested4, After)
  776:             end
  777:         of
  778:             Self -> value
  779:         catch
  780:             C:D -> {caught,{C,D}}
  781:         after
  782:             put(nested, finalized)
  783: 	end,
  784:     {Try,erase(nested3),erase(nested4),erase(nested)}.
  785: 
  786: foo({value,Value}) -> Value;
  787: foo({'div',{A,B}}) ->
  788:     my_div(A, B);
  789: foo({'add',{A,B}}) ->
  790:     my_add(A, B);
  791: foo({'abs',X}) ->
  792:     my_abs(X);
  793: foo({error,Error}) ->
  794:     erlang:error(Error);
  795: foo({throw,Throw}) ->
  796:     erlang:throw(Throw);
  797: foo({exit,Exit}) ->
  798:     erlang:exit(Exit);
  799: foo({raise,{Class,Reason}}) ->
  800:     erlang:raise(Class, Reason).
  801: %%foo(function_clause) -> % must not be defined!
  802: 
  803: my_div(A, B) ->
  804:     A div B.
  805: 
  806: my_add(A, B) ->
  807:     A + B.
  808: 
  809: my_abs(X) -> abs(X).
  810: 
  811: id(I) -> I.