summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2012-05-13 21:44:40 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2012-05-13 21:44:40 +0100
commit4a5b015f914348877b2787316cb5dbc46e1207ff (patch)
tree0aeebe57d2c879d29d3d415f33a655131b7a258a
parent9daf22f7aa8b83656388454ae447f59fc3442e2d (diff)
downloadlace-4a5b015f914348877b2787316cb5dbc46e1207ff.tar.gz
Add define builtin command
-rw-r--r--lib/lace/builtin.lua47
-rw-r--r--test/test-lace.builtin.lua76
2 files changed, 123 insertions, 0 deletions
diff --git a/lib/lace/builtin.lua b/lib/lace/builtin.lua
index 811047f..fdfcefb 100644
--- a/lib/lace/builtin.lua
+++ b/lib/lace/builtin.lua
@@ -9,6 +9,8 @@
local builtin = {}
+local engine = require "lace.engine"
+
local function compiler()
return require "lace.compiler"
end
@@ -90,6 +92,51 @@ function builtin.default(compcontext, def, result, reason, unwanted)
}
end
+--[ Definitions ]----------------------------------------------------
+
+local function _controlfn(ctx, name)
+ local ctt = ctx[".lace"].controltype or {}
+ return ctt[name]
+end
+
+function builtin.define(compcontext, define, name, controltype, ...)
+ if type(name) ~= "string" then
+ return compiler().error("Expected name, got nothing")
+ end
+
+ if name == "" or name:sub(1,1) == "!" then
+ return compiler().error("Bad name for definition", {2})
+ end
+
+ if type(controltype) ~= "string" then
+ return compiler().error("Expected control type, got nothing")
+ end
+
+ local controlfn = _controlfn(compcontext, controltype)
+ if not controlfn then
+ return compiler().error("Unknown control type", {3})
+ end
+
+ local ctrltab, msg = controlfn(compcontext, controltype, ...)
+ if type(ctrltab) ~= "table" then
+ -- offset all the words in the error by 2 (for define and name)
+ if msg.words then
+ for i = 1, #msg.words do
+ msg.words[i] = msg.words[i] + 2
+ end
+ end
+ return false, msg
+ end
+
+ -- Successfully created a control table, return a rule for it
+ return {
+ fn = engine.define,
+ args = { name, ctrltab }
+ }
+end
+
+builtin.def = builtin.define
+
return {
commands = builtin,
get_set_last_unconditional_result = get_set_last_unconditional_result,
diff --git a/test/test-lace.builtin.lua b/test/test-lace.builtin.lua
index 558f15a..b80df1c 100644
--- a/test/test-lace.builtin.lua
+++ b/test/test-lace.builtin.lua
@@ -160,6 +160,82 @@ function suite.compile_builtin_default_noreason()
assert(type(compctx[".lace"].default.fn) == "function", "Default table should have a function like a rule")
end
+function suite.compile_builtin_define_noname()
+ local compctx = {[".lace"] = {}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Expected name"), "Expected error should mention a lack of name")
+end
+
+function suite.compile_builtin_define_badname()
+ local compctx = {[".lace"] = {}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "!fish")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Bad name"), "Expected error should mention a bad name")
+end
+
+function suite.compile_builtin_define_noctype()
+ local compctx = {[".lace"] = {}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "fish")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Expected control"), "Expected error should mention a lack of control type")
+end
+
+function suite.compile_builtin_define_badctype()
+ local compctx = {[".lace"] = {}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "fish", "fish")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Unknown control"), "Expected error should mention unknown control type")
+end
+
+function suite.compile_builtin_define_ctype_errors()
+ local function _fish()
+ return false, { msg = "Argh" }
+ end
+ local compctx = {[".lace"] = { controltype = { fish = _fish }}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "fish", "fish")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Argh"), "Expected error should be passed through")
+end
+
+function suite.compile_builtin_define_ctype_errors_offset()
+ local function _fish()
+ return false, { msg = "Argh", words = {0} }
+ end
+ local compctx = {[".lace"] = { controltype = { fish = _fish }}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "fish", "fish")
+ assert(cmdtab == false, "Internal errors should return false")
+ assert(type(msg) == "table", "Internal errors should return tables")
+ assert(type(msg.msg) == "string", "Internal errors should have string messages")
+ assert(msg.msg:match("Argh"), "Expected error should be passed through")
+ assert(msg.words[1] == 2, "Error words should be offset by 2")
+end
+
+function suite.compile_builtin_define_ok()
+ local function _fish()
+ return {
+ JEFF = true
+ }
+ end
+ local compctx = {[".lace"] = { controltype = { fish = _fish }}}
+ local cmdtab, msg = builtin.commands.define(compctx, "define", "fish", "fish")
+ assert(type(cmdtab) == "table", "Successful compilation returns tables")
+ assert(type(cmdtab.fn) == "function", "With functions")
+ local ectx = {}
+ local ok, msg = cmdtab.fn(ectx, unpack(cmdtab.args))
+ assert(ok, "Running a define should work")
+ assert(ectx[".lace"].defs.fish.JEFF, "definition should have passed through")
+end
local count_ok = 0
for _, testname in ipairs(testnames) do