summaryrefslogtreecommitdiff
path: root/Tools/LuaMacro/macro/try.lua
blob: 8e49eb052b9960a84a66075acedca2191237eb2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
--- A try/except block.
-- This generates syntactical sugar around `pcal`l, and correctly
-- distinguishes between the try block finishing naturally and
-- explicitly using 'return' with no value. This is handled by
-- converting any no value `return` to `return nil`.
--
-- Apart from the usual creation of a closure, this uses a table
-- to capture all the results. Not likely to win speed contests,
-- but intended to be correct.
-- @module macro.try

local M = require 'macro'

local function pack (...)
    local args = {...}
    args.n = select('#',...)
    return args
end

function pcall_(fn,...)
    return pack(pcall(fn,...))
end

local function check_return_value(get,put)
    local t,v = get:next()
    put:space()
    if t=='keyword' and (v=='end' or v=='else' or v=='until') then
        put:keyword 'nil'
    end
    return put(t,v)
end


M.define('RR_',M.make_scoped_handler('return',check_return_value))


--- A try macro, paired with except.
--
--     try
--      maybe_something_bad()
--     except (e)
--      print(e)
--     end
-- @macro try
M.define 'try do local r_ =  pcall_(function() RR_ '
M.define 'except(e) end); if r_[1] then if r_.n > 1 then return unpack(r_,2,r_.n) end else local e = r_[2] _END_END_  '