Skeleton of the rule engine and type system.
This commit is contained in:
parent
df1372ab35
commit
cb0111b290
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
local environment = {}
|
local environment = {}
|
||||||
local rules = {}
|
local rules = {}
|
||||||
|
local targets = {}
|
||||||
|
local buildfiles = {}
|
||||||
|
local globals
|
||||||
|
local cwd = "."
|
||||||
|
|
||||||
local function subenv(old, cb)
|
local function subenv(old, cb)
|
||||||
if not old then
|
if not old then
|
||||||
|
@ -49,37 +53,169 @@ local function emit(...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function definerule(name, cb)
|
local function loadbuildfile(filename)
|
||||||
if rules[name] then
|
local data, chunk, e
|
||||||
error(string.format("rule '%s' is already defined", name))
|
data = io.open(filename):read("*a")
|
||||||
|
if not e then
|
||||||
|
local thisglobals = {_G = thisglobals}
|
||||||
|
setmetatable(thisglobals, {__index = globals})
|
||||||
|
chunk, e = loadstring(data, filename, "text", thisglobals)
|
||||||
|
end
|
||||||
|
if e then
|
||||||
|
error(string.format("couldn't load '%s': %s", filename, e))
|
||||||
|
end
|
||||||
|
|
||||||
|
chunk()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loadtarget(targetname)
|
||||||
|
if targets[target] then
|
||||||
|
return targets[targetname]
|
||||||
|
end
|
||||||
|
|
||||||
|
local target
|
||||||
|
if not target:find(":") then
|
||||||
|
target = {
|
||||||
|
outs = {targetname},
|
||||||
|
is = {
|
||||||
|
__implicitfile = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets[targetname] = target
|
||||||
|
else
|
||||||
|
local _, _, filepart, targetpart = targetname:find("^([^:]+):(%w+)$")
|
||||||
|
if not filepart or not targetpart then
|
||||||
|
error(string.format("malformed target name '%s'", targetname))
|
||||||
|
end
|
||||||
|
if not buildfiles[filepart] then
|
||||||
|
buildfiles[filepart] = true
|
||||||
|
|
||||||
|
local oldcwd = cwd
|
||||||
|
cwd = filepart
|
||||||
|
loadbuildfile(filepart.."/build.lua")
|
||||||
|
cwd = oldcwd
|
||||||
|
end
|
||||||
|
|
||||||
|
target = targets[targetname]
|
||||||
|
if not target then
|
||||||
|
error(string.format("build file '%s' contains no rule '%s'",
|
||||||
|
filepart, targetpart))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return target
|
||||||
|
end
|
||||||
|
|
||||||
|
local typeconverters = {
|
||||||
|
targets = function(propname, i)
|
||||||
|
if (type(i) == "string") then
|
||||||
|
i = {i}
|
||||||
|
elseif (type(i) ~= "table") then
|
||||||
|
error(string.format("property '%s' must be a target list", propname))
|
||||||
|
end
|
||||||
|
|
||||||
|
local o = {}
|
||||||
|
for _, s in ipairs(i) do
|
||||||
|
if (type(s) ~= "string") then
|
||||||
|
error(string.format("member of target list '%s' is not a string", propname))
|
||||||
|
end
|
||||||
|
|
||||||
|
if s:find("^//") then
|
||||||
|
s = s:gsub("^//", "")
|
||||||
|
elseif s:find("^[/]") then
|
||||||
|
s = concatpath(cwd, s)
|
||||||
|
end
|
||||||
|
o[#o+1] = s
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
strings = function(propname, i)
|
||||||
|
if (type(i) == "string") then
|
||||||
|
i = {i}
|
||||||
|
elseif (type(i) ~= "table") then
|
||||||
|
error(string.format("property '%s' must be a string list", propname))
|
||||||
|
end
|
||||||
|
|
||||||
|
return i
|
||||||
|
end,
|
||||||
|
|
||||||
|
string = function(propname, i)
|
||||||
|
if (type(i) ~= "string") then
|
||||||
|
error(string.format("property '%s' must be a string", propname))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function definerule(rulename, types, cb)
|
||||||
|
if rules[rulename] then
|
||||||
|
error(string.format("rule '%s' is already defined", rulename))
|
||||||
|
end
|
||||||
|
|
||||||
|
types.name = { type="string" }
|
||||||
|
|
||||||
|
for propname, typespec in pairs(types) do
|
||||||
|
if not typeconverters[typespec.type] then
|
||||||
|
error(string.format("property '%s' has unrecognised type '%s'",
|
||||||
|
propname, typespec.type))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rules[rulename] = function(e)
|
||||||
|
local args = {}
|
||||||
|
for propname, typespec in pairs(types) do
|
||||||
|
if not e[propname] and not typespec.optional then
|
||||||
|
error(string.format("missing mandatory property '%s'", propname))
|
||||||
|
end
|
||||||
|
|
||||||
|
args[propname] = typeconverters[typespec.type](propname, e[propname])
|
||||||
|
e[propname] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local propname, _ = next(e)
|
||||||
|
if propname then
|
||||||
|
error(string.format("don't know what to do with property '%s'", propname))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- DEFAULT RULES --
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
definerule("simplerule",
|
||||||
|
{
|
||||||
|
ins = { type="targets" },
|
||||||
|
outs = { type="strings" },
|
||||||
|
},
|
||||||
|
function (e)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- MAIN PROGRAM --
|
-- MAIN PROGRAM --
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
local globals = {
|
globals = {
|
||||||
asstring = asstring,
|
asstring = asstring,
|
||||||
definerule = definerule,
|
definerule = definerule,
|
||||||
emit = emit,
|
emit = emit,
|
||||||
environment = environment,
|
environment = environment,
|
||||||
}
|
}
|
||||||
setmetatable(globals, {__index = _G})
|
setmetatable(globals,
|
||||||
|
{
|
||||||
|
__index = function(self, k)
|
||||||
|
local rule = rules[k]
|
||||||
|
if rule then
|
||||||
|
return rule
|
||||||
|
else
|
||||||
|
return _G[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
emit("hide=@\n")
|
emit("hide=@\n")
|
||||||
for _, file in ipairs({...}) do
|
for _, file in ipairs({...}) do
|
||||||
local data, chunk, e
|
loadbuildfile(file)
|
||||||
data = io.open(file):read("*a")
|
|
||||||
if not e then
|
|
||||||
local thisglobals = {_G = thisglobals}
|
|
||||||
setmetatable(thisglobals, {__index = globals})
|
|
||||||
chunk, e = loadstring(data, file, "text", thisglobals)
|
|
||||||
end
|
|
||||||
if e then
|
|
||||||
error(string.format("couldn't load '%s': %s", file, e))
|
|
||||||
end
|
|
||||||
|
|
||||||
local _, e = pcall(chunk)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue