--- /dev/null
+\section{Extension {\tt trywith}: exceptions and finalization}\r
+Lua offers error handling primitives \verb+pcall()+ and\r
+\veb+xpcall()+. However, they are pretty low level, and their syntax\r
+is cumbersome to use and read back. This extension offers a proper\r
+syntax for the handling of such exceptions.\r
+\r
+\subsection{Syntax}\r
+An error handling statement has the following form:\r
+\r
+\begin{verbatim}\r
+try\r
+ <protected block>\r
+catch <exception pattern #1> then\r
+ <exception handling block #1>\r
+catch <exception pattern #2> then\r
+ <exception handling block #2>\r
+ ...\r
+catch <exception pattern #n> then\r
+ <exception handling block #n>\r
+finally\r
+ <finalization block>\r
+end\r
+\end{verbatim}\r
+\r
+\subsection{Semantics}\r
+When such a statement is executed:\r
+\begin{itemize}\r
+\item the protected code is executed\r
+\item if its execution causes an error, the error message is matched\r
+ against all exception patterns, until one matches or the last one is\r
+ reached (see the \verb+match+ extension for patterns\r
+ semantics). Patterns can include guard clauses. The block\r
+ corresponding to the first matching pattern is executed. If no\r
+ pattern matches, the error will be rethrown.\r
+\item the block following the \verb+finally+ keyword will be executed\r
+ no matter what: if the protected block executes succesfully, if it\r
+ raises an error, if it causes a \verb+return+, if an error occurs in\r
+ an exception handling block, whether an error is caught or\r
+ not... The only reason why the finalization block might not be run\r
+ is because of a sudden death of the process (call to {\tt os.exit()}\r
+ or core dump).\r
+\end{itemize}\r
+\r
+The finally block can be omitted, or there can be no error catching\r
+case. The following examples are legal:\r
+\r
+\begin{verbatim}\r
+try\r
+ f = io.open ('file.txt', 'r')\r
+ num_char = #f:read '*a'\r
+finally\r
+ f:close()\r
+end\r
+\r
+try\r
+ do_stuff()\r
+catch "mismatch" then\r
+ print "match statement failure"\r
+catch "[Ee]of"/_ then -- regexp pattern\r
+ print "An end-of-file error seems to have happened"\r
+catch x if type(x)=='table' then\r
+ print "The error is a table, not a string!"\r
+end\r
+\end{verbatim}\r
+\r
+ \subsection{RAII}\r
+ RAII, or ``Resource Acquisition Is Initialization'', is a common\r
+ programming pattern in which an object's lifetime is strictly\r
+ associated with a given lexical scope. For instance, if a file is\r
+ opened in a given scope, it must be closed as soon as this scope is\r
+ leaved, even if it's leaved due to a {\tt return} or an error. The\r
+ ``finally'' block allows this, but since it's a very common use case,\r
+ there is a dedicated extension ``with/do'': you initialize some resource\r
+ behind the ``with'' keyword, and it will be closed after the ``do''\r
+ block is left. The only constraint is that the resources must have a\r
+ {\tt:close()} method which releases them. Here is a usage example:\r
+\r
+\begin{verbatim}\r
+-{ extension 'withdo' }\r
+\r
+with f1, f2 = io.open 'file1.txt', io.open 'file2.txt' do\r
+ local t1 = f1:read '*a'\r
+ local t2 = f2:read '*a'\r
+ printf("The files contain %i and %i chars respectively", t1, t2)\r
+end\r
+\end{verbatim}\r
+\r
+++ /dev/null
--{extension "clist"}
-
--- integers from 2 to 50, by steps of 2:
-x = { i for i = 2, 50, 2 }
-
--- the same, obtained by filtering over all integers <= 50:
-y = { i for i = 1, 50 if i%2==0 }
-
--- prime numbers, implemented in an inefficient way:
-local sieve, n = { i for i=2, 100 }, 1
-while n < #sieve do
- sieve = {
- i for i in values(sieve[1 ... n]);
- i for i in values(sieve[n+1 ... #sieve]) if i%sieve[n] ~= 0 }
- n += 1
-end
-
-table.print(sieve)
-
--- /dev/null
+-{extension "clist"}
+
+-- integers from 2 to 50, by steps of 2:
+x = { i for i = 2, 50, 2 }
+
+-- the same, obtained by filtering over all integers <= 50:
+y = { i for i = 1, 50 if i%2==0 }
+
+-- prime numbers, implemented in an inefficient way:
+local sieve, n = { i for i=2, 100 }, 1
+while n < #sieve do
+ sieve = {
+ i for i in values(sieve[1 ... n]);
+ i for i in values(sieve[n+1 ... #sieve]) if i%sieve[n] ~= 0 }
+ n += 1
+end
+
+table.print(sieve)
+
print "2) caught error"
try
error "some_error"
-catch x ->
+catch x then
printf(" Successfully caught %q", x)
end
+-- [[
----------------------------------------------------------------------
print "3) no error, with a finally"
try
try
print " Hi"
error "bang"
-catch "bang" ->
- -- nothing
+catch "bang"/_ then
+ print " Bang caught"
finally
print " Finally OK"
end
try
try
error "some_error"
- catch "some_other_error" ->
+ catch "some_other_error" then
assert (false, "mismatch, this must not happen")
end
-catch "some_error"/x ->
+catch "some_error"/x then
printf(" Successfully caught %q across a try that didn't catch", x)
-| x ->
+catch x then
assert (false, "We shouldn't reach this catch-all")
end
try
try
error "some_error"
- catch "some_other_error" ->
+ catch "some_other_error" then
assert (false, "mismatch, this must not happen")
finally
print " Leaving the inner try-catch"
end
-catch "some_error"/x ->
+catch "some_error"/{x} then
printf(" Successfully caught %q across a try that didn't catch", x)
-| x ->
+catch x then
assert (false, "We shouldn't reach this catch-all")
end
print " into f:"
return "F_RESULT"
assert (false, "I'll never go there")
- catch _ ->
+ catch _ then
assert (false, "No exception should be thrown")
finally
print " I do the finally before leaving f()"
local function g() return "from g" end
printf(" g() returns %q", g())
return "from f"
- catch _ ->
+ catch _ then
assert (false, "No exception should be thrown")
end
end
----------------------------------------------------------------------
print "*) done."
+--]]
+++ /dev/null
--{ extension "types" }
--{ extension "clist" }
-
--- Uncomment this to turn typechecking code generation off:
--- -{stat: types.enabled=false}
-
-function sum (x :: table(number)) :: number
- local acc :: number = 0
- for i=1, #x do
- acc = acc + x[i] -- .. 'x' -- converts to string
- end
- --acc='bug' -- put a string in a number variable
- return acc
-end
-
-x = { i for i=1,100 }
---x[23] = 'toto' -- string in a number list, sum() will complain
-y = sum (x)
-printf ("sum 1 .. %i = %i", #x, y)
\ No newline at end of file
--- /dev/null
+-{ extension "types" }
+-{ extension "clist" }
+
+-- Uncomment this to turn typechecking code generation off:
+-- -{stat: types.enabled=false}
+
+function sum (x :: table(number)) :: number
+ local acc :: number = 0
+ for i=1, #x do
+ acc = acc + x[i] -- .. 'x' -- converts to string
+ end
+ --acc='bug' -- put a string in a number variable
+ return acc
+end
+
+x = { i for i=1,100 }
+--x[23] = 'toto' -- string in a number list, sum() will complain
+y = sum (x)
+printf ("sum 1 .. %i = %i", #x, y)
\ No newline at end of file