local Grader = require("evalframe.model.grader")
local Scorer = require("evalframe.model.scorer")
local M = {}
local BINDING_TAG = {}
local function build(spec, label)
label = label or "bind"
if type(spec) ~= "table" then
error(string.format("%s: spec must be a table", label), 3)
end
local grd, scr
for _, v in ipairs(spec) do
if Grader.is_grader(v) then
if grd then error(string.format("%s: multiple GraderDef provided", label), 3) end
grd = v
elseif Scorer.is_scorer(v) then
if scr then error(string.format("%s: multiple ScorerDef provided", label), 3) end
scr = v
end
end
if not grd then
error(string.format("%s: GraderDef required", label), 3)
end
scr = scr or Scorer.default_bool
local weight = spec.weight or 1.0
if type(weight) ~= "number" or weight < 0 then
error(string.format("%s: weight must be non-negative number, got %s", label, tostring(weight)), 3)
end
return {
_tag = BINDING_TAG,
grader = grd,
scorer = scr,
weight = weight,
}
end
setmetatable(M, {
__call = function(_, first)
if type(first) == "table" then
return build(first, "bind")
elseif type(first) == "string" then
return function(spec)
return build(spec, string.format("bind '%s'", first))
end
else
error(string.format("bind: expected table or string, got %s", type(first)), 2)
end
end,
})
function M.key(b)
return b.grader.name
end
function M.is_binding(v)
return type(v) == "table" and v._tag == BINDING_TAG
end
return M