diff options
Diffstat (limited to 'acf/error.lua')
-rw-r--r-- | acf/error.lua | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/acf/error.lua b/acf/error.lua new file mode 100644 index 0000000..26dfb86 --- /dev/null +++ b/acf/error.lua @@ -0,0 +1,97 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local object = require('acf.object') +local class = object.class + +local util = require('acf.util') + +require 'json' + + +local function pack(...) return arg end + + +local ErrorTable = class() + +function ErrorTable:init() self.errors = {} end + +function ErrorTable:success() return not next(self.errors) end + +function ErrorTable:raise() + if not self:success() then error(json.encode(self.errors)) end +end + + +ErrorList = class(ErrorTable) + +function ErrorList:init(label) + object.super(self, ErrorList):init() + self.label = label +end + +function ErrorList:insert(msg) + table.insert(util.setdefault(self.errors, self.label, {}), msg) +end + + +ErrorDict = class(ErrorTable) + +function ErrorDict:collect(func, ...) + local function pack(success, ...) + return success, success and arg or arg[1] + end + + local success, res = pack( + xpcall( + function() return func(unpack(arg)) end, + function(err) + local _, _, data = string.find(err, '.-: (.+)') + local success, res = pcall(json.decode, data) + if success and type(res) == 'table' then return res end + return data..'\n'..debug.traceback() + end + ) + ) + + if success then return unpack(res) end + + if type(res) == 'table' then + for label, errors in pairs(res) do + for _, err in ipairs(errors) do + table.insert(util.setdefault(self.errors, label, {}), err) + end + end + else error(res) end +end + + +function raise(label, msg) + local err = ErrorList(label) + err:insert(msg) + err:raise() +end + +function relabel(label, ...) + local err = ErrorDict() + local res = pack(err:collect(unpack(arg))) + if err:success() then return unpack(res) end + + elist = ErrorList(label) + for lbl, el in pairs(err.errors) do + for _, e in ipairs(el) do elist:insert(lbl..': '..e) end + end + elist:raise() +end + +function call(...) + local err = ErrorDict() + local res = pack(err:collect(unpack(arg))) + if err:success() then return true, unpack(res) end + if err.errors.system then error(err.errors.system[1]) end + return false, err.errors +end |