--\r
-- TODO:\r
--\r
--- * Hygiene! this stuff is absolutely not hygienic, and lexically nested\r
--- try...with \r
---\r
--- * give a more lua-like syntax:\r
--- > try ... (catch expr then block)* (finally block)? end\r
---\r
--- * create an RAII-like feature, possibly in a separate extension:\r
--- > with v1, v2, ... = rsc1, rsc2, ... do block end ==>\r
--- > try local v1 = rsc1\r
--- > try v2 = rsc2\r
--- > ...\r
--- > finally v2:close()\r
--- > finally v1:close() end\r
---\r
--- * match.mlua refactoring: there are many other places where it\r
--- should be usable (fancy assignments...), if it were cut in\r
--- smaller, more usable functions. They should probably go in a\r
--- separate module.\r
+-- * Hygienize calls to pcall()\r
--\r
--------------------------------------------------------------------------------\r
\r
-{ extension 'H' }\r
-{ extension 'log' }\r
\r
+require 'extension.match'\r
+\r
-- Get match parsers and builder, for catch cases handling:\r
local match_alpha = require 'extension.match' \r
local H = H:new{side='inside', alpha = match_alpha }\r
\r
-- The statement builder:\r
function trycatch_builder(x)\r
+ --$log ("trycatch_builder", x, 'nohash', 60)\r
local try_code, catch_cases, finally_code = unpack(x)\r
local insert_return_catcher = false\r
\r
-- to outside macro code.\r
local caught_return = !mlp.gensym 'caught_return'\r
\r
- !try_code; !(catch_code or { }); !(finally_code or { })\r
+ !try_code; !(finally_code or { })\r
+ -- FIXME: Am I sure there's no need to hygienize inside?\r
+ --[[if catch_cases then\r
+ for case in ivalues(catch_cases) do\r
+ --$log(case,'nohash')\r
+ local patterns, guard, block = unpack(case)\r
+ ! block\r
+ end\r
+ end]]\r
\r
- --$log(try_code, catch_cases, finally_code)\r
\r
----------------------------------------------------------------\r
-- Returns in the try-block must be transformed:\r
-- Setvar's 'caught_return' code can't be hygienize by H currently.\r
local setvar = `Set{ {caught_return}, { `Table{ unpack(x) } } }\r
x <- { setvar; `Return }; x.tag = nil;\r
- $log('transformed return stat:', x, 60)\r
+ --$log('transformed return stat:', x, 60)\r
return 'break'\r
| `Function{...} -> return 'break' \r
-- inside this, returns would be the nested function's, not ours.\r
-- so we introduce a catch-all do-nothing last case:\r
----------------------------------------------------------\r
table.insert (catch_cases, { { { `Id '_' } }, false, { } }) \r
- catch_result = match_builder{ {+{user_error}}, catch_cases }\r
+ catch_result = spmatch.match_builder{ {+{user_error}}, catch_cases }\r
else\r
catch_result = { }\r
end\r
return result\r
end\r
\r
+function catch_case_builder(x)\r
+ --$log ("catch_case_builder", x, 'nohash', 60)\r
+ local patterns, guard, _, code = unpack(x)\r
+ -- patterns ought to be a pattern_group, but each expression must\r
+ -- be converted into a single-element pattern_seq.\r
+ for i = 1, #patterns do patterns[i] = {patterns[i]} end\r
+ return { patterns, guard, code }\r
+end\r
+\r
mlp.lexer:add{ 'try', 'catch', 'finally', '->' }\r
mlp.block.terminators:add{ 'catch', 'finally' }\r
-table.insert(match_cases_list_parser.terminators, 'finally')\r
\r
mlp.stat:add{\r
'try', \r
mlp.block, \r
- gg.onkeyword{ 'catch', match_cases_list_parser },\r
+ gg.onkeyword{ 'catch', \r
+ gg.list{\r
+ gg.sequence{ \r
+ mlp.expr_list,\r
+ gg.onkeyword{ 'if', mlp.expr },\r
+ gg.optkeyword 'then', \r
+ mlp.block,\r
+ builder = catch_case_builder },\r
+ separators = 'catch' } },\r
gg.onkeyword{ 'finally', mlp.block },\r
'end',\r
builder = trycatch_builder }\r