diff options
| author | ruki <[email protected]> | 2016-01-19 20:54:26 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2016-02-15 19:10:24 +0800 |
| commit | d7329faff5284e07a251683fc30dcefcb27e21d0 (patch) | |
| tree | 3436953d66e2c1bbd3b0f74e8f92977a2cdfd9a9 | |
| parent | 44c7d62676ce6763d013db0c031e6f651237f510 (diff) | |
impl add/set scope and values for interpreter
| -rw-r--r-- | tests/interpreter/scope.lua | 14 | ||||
| -rw-r--r-- | tests/interpreter/tests.lua | 74 | ||||
| -rw-r--r-- | xmake/core/base/interpreter.lua | 275 | ||||
| -rw-r--r-- | xmake/core/base/utils.lua | 7 |
4 files changed, 348 insertions, 22 deletions
diff --git a/tests/interpreter/scope.lua b/tests/interpreter/scope.lua index 438470d5c..f9eaa6484 100644 --- a/tests/interpreter/scope.lua +++ b/tests/interpreter/scope.lua @@ -1,9 +1,11 @@ -print("hello") +set_kind("static") -function test() - assert(false) -end -test() +add_target("target1") -print("hello") + set_kind("static") +-- add_files("*.c", "hello.c") + +add_option("option1") + + add_option_links("pthread", "z") diff --git a/tests/interpreter/tests.lua b/tests/interpreter/tests.lua index d389f5345..9e90a2886 100644 --- a/tests/interpreter/tests.lua +++ b/tests/interpreter/tests.lua @@ -24,7 +24,8 @@ local tests = tests or {} -- load modules -local interpreter = require("base/interpreter") +local utils = require("base/utils") +local interpreter = require("base/interpreter") -- the main function function tests.main(self, file) @@ -32,13 +33,80 @@ function tests.main(self, file) -- check assert(file and #file == 1) - -- load it - local ok, errors = interpreter.load(file[1]) + -- init interpreter + local interp = interpreter.init() + assert(interp) + + -- register api for scopes + interp:register_api_set_scope("target", "option") + interp:register_api_add_scope("target", "option") + + -- register api for values + interp:register_api_set_values("target", nil, "kind" + , "config_h_prefix" + , "version" + , "strip" + , "options" + , "symbols" + , "warnings" + , "optimize" + , "languages" + , "runscript" + , "installscript" + , "packagescript") + interp:register_api_add_values("target", nil, "deps" + , "links" + , "cflags" + , "cxflags" + , "cxxflags" + , "mflags" + , "mxflags" + , "mxxflags" + , "ldflags" + , "shflags" + , "options" + , "defines" + , "undefines" + , "defines_h" + , "undefines_h" + , "languages" + , "vectorexts") + interp:register_api_set_values("option", "option", "enable" + , "showmenu" + , "category" + , "warnings" + , "optimize" + , "languages" + , "description") + interp:register_api_add_values("option", "option", "links" + , "cincludes" + , "cxxincludes" + , "cfuncs" + , "cxxfuncs" + , "ctypes" + , "cxxtypes" + , "cflags" + , "cxflags" + , "cxxflags" + , "ldflags" + , "vectorexts" + , "defines" + , "defines_if_ok" + , "defines_h_if_ok" + , "undefines" + , "undefines_if_ok" + , "undefines_h_if_ok") + + -- load interpreter + local ok, errors = interp:load(file[1]) if not ok then print(errors) return false end + -- dump interpreter + utils.dump(interp) + -- ok return true end diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua index ced71b128..92d4a0796 100644 --- a/xmake/core/base/interpreter.lua +++ b/xmake/core/base/interpreter.lua @@ -25,6 +25,7 @@ local interpreter = interpreter or {} -- load modules local os = require("base/os") +local table = require("base/table") local utils = require("base/utils") -- traceback @@ -56,6 +57,7 @@ function interpreter._traceback(errors) results = results .. string.format(" [%s:%d]: in function '%s'\n", info.short_src, info.currentline, info.name) elseif info.what == "main" then results = results .. string.format(" [%s:%d]: in main chunk\n", info.short_src, info.currentline) + break else results = results .. string.format(" [%s:%d]:\n", info.short_src, info.currentline) end @@ -68,11 +70,58 @@ function interpreter._traceback(errors) return results end +-- register api: xxx_apiname() +function interpreter._register_api_xxx_(self, action, apifunc, ...) + + -- check + assert(self and self._PUBLIC and self._PRIVATE) + assert(action and apifunc) + + -- done + for _, apiname in ipairs({...}) do + + -- check + assert(apiname) + + -- register scope api + self:register_api(action .. "_" .. apiname, function (...) + + -- check + assert(self and self._PRIVATE and apiname) + + -- the scopes + local scopes = self._PRIVATE._SCOPES + assert(scopes) + + -- call function + apifunc(scopes, apiname, ...) + end) + end +end + +-- init interpreter +function interpreter.init() + + -- init an interpreter instance + local interp = { _PUBLIC = {} + , _PRIVATE = {_SCOPES = {}}} + + -- inherit the interfaces of interpreter + for k, v in pairs(interpreter) do + if type(v) == "function" then + interp[k] = v + end + end + + -- ok? + return interp +end + -- load interpreter -function interpreter.load(file) +function interpreter.load(self, file) -- check - assert(file) + assert(self and self._PUBLIC and file) -- load the script local script = loadfile(file) @@ -80,21 +129,221 @@ function interpreter.load(file) return nil, string.format("load %s failed!", file) end - -- init the private scope - local private = {} + -- bind public scope + setfenv(script, self._PUBLIC) + + -- done interpreter + return xpcall(script, interpreter._traceback) +end + +-- register api +function interpreter.register_api(self, name, func) + + -- check + assert(self and self._PUBLIC) + assert(name and func) + + -- register it + self._PUBLIC[name] = func +end + +-- register api for set_scope() +-- +-- interp:register_api_set_scope("scope_kind1", "scope_kind2") +-- +-- api: +-- set_$(scope_kind1)("scope_name1") +-- ... +-- +-- set_$(scope_kind2)("scope_name1", "scope_name2") +-- ... +-- +-- result: +-- +-- _PRIVATE +-- { +-- _SCOPES +-- { +-- scope_kind1 +-- { +-- "scope_name1" +-- { +-- +-- } +-- } +-- +-- scope_kind2 +-- { +-- "scope_name1" +-- { +-- +-- } +-- +-- "scope_name2" <-- _SCOPES._CURRENT +-- { +-- +-- } +-- } +-- } +-- } +-- +function interpreter.register_api_set_scope(self, ...) + + -- check + assert(self and self._PUBLIC and self._PRIVATE) + + -- define implementation + local implementation = function (scopes, scope_kind, scope_name) + + -- check + if not scopes[scope_kind] then + utils.error("set_%s(\"%s\") failed, %s not found!", scope_kind, scope_name, scope_name) + utils.error("please uses add_%s(\"%s\") first!", scope_name) + utils.abort() + end + + -- init scope for kind + local scope_for_kind = scopes[scope_kind] or {} + scopes[scope_kind] = scope_for_kind + + -- init scope for name + scope_for_kind[scope_name] = scope_for_kind[scope_name] or {} + + -- save the current scope + scopes._CURRENT = scope_for_kind[scope_name] + + end + + -- register implementation + self:_register_api_xxx_("set", implementation, ...) +end + +-- register api for add_scope() +function interpreter.register_api_add_scope(self, ...) + + -- check + assert(self and self._PUBLIC and self._PRIVATE) + + -- define implementation + local implementation = function (scopes, scope_kind, scope_name) + + -- check + if scopes[scope_kind] then + utils.error("add_%s(\"%s\") failed, %s have been defined!", scope_name, scope_name) + utils.error("please uses set_%s(\"%s\")!", scope_name) + utils.abort() + end + + -- init scope for kind + local scope_for_kind = scopes[scope_kind] or {} + scopes[scope_kind] = scope_for_kind + + -- init scope for name + scope_for_kind[scope_name] = scope_for_kind[scope_name] or {} + + -- save the current scope + scopes._CURRENT = scope_for_kind[scope_name] + + end + + -- register implementation + self:_register_api_xxx_("add", implementation, ...) +end + +-- register api for set_values +-- +-- interp:api_register_set_values("scope_kind", "name1", "name2", ...) +-- +-- api: +-- set_$(name1)("value1") +-- set_$(name2)("value1", "value2", ...) +-- +-- result: +-- +-- _PRIVATE +-- { +-- _SCOPES +-- { +-- _ROOT +-- { +-- scope_kind +-- { +-- } +-- } +-- +-- scope_kind +-- { +-- "scope_name" <-- _SCOPES._CURRENT +-- { +-- name1 = {"value1"} +-- name2 = {"value1", "value2", ...} +-- } +-- } +-- } +-- } +-- +function interpreter.register_api_set_values(self, scope_kind, prefix, ...) + + -- check + assert(self and self._PUBLIC and self._PRIVATE and scope_kind) + + -- define implementation + local implementation = function (scopes, name, ...) + + -- init root scopes + scopes._ROOT = scopes._ROOT or {} + + -- init current root scope + local root = scopes._ROOT[scope_kind] or {} + scopes._ROOT[scope_kind] = root + + -- the current scope + local scope = scopes._CURRENT or root + assert(scope) + + -- update values? + scope[name] = {} + table.join2(scope[name], ...) + + end + + -- register implementation + action = "set" + if prefix then action = "set_" .. prefix end + self:_register_api_xxx_(action, implementation, ...) +end + +-- register api for add_values +function interpreter.register_api_add_values(self, scope_kind, prefix, ...) + + -- check + assert(self and self._PUBLIC and self._PRIVATE) + assert(scope_kind) + + -- define implementation + local implementation = function (scopes, name, ...) + + -- init root scopes + scopes._ROOT = scopes._ROOT or {} + + -- init current root scope + local root = scopes._ROOT[scope_kind] or {} + scopes._ROOT[scope_kind] = root + + -- the current scope + local scope = scopes._CURRENT or root + assert(scope) - -- bind the environment - local env = {_PRIVATE = private} --- setfenv(script, env) + -- append values? + scope[name] = scope[name] or {} + table.join2(scope[name], ...) - -- done the script - local ok, errors = xpcall(script, interpreter._traceback) - if not ok then - return nil, errors end - -- get results - return nil + -- register implementation + action = "add" + if prefix then action = "add_" .. prefix end + self:_register_api_xxx_(action, implementation, ...) end -- return module: interpreter diff --git a/xmake/core/base/utils.lua b/xmake/core/base/utils.lua index fd1f053d6..596826ed9 100644 --- a/xmake/core/base/utils.lua +++ b/xmake/core/base/utils.lua @@ -56,6 +56,13 @@ function utils.error(msg, ...) print("error: " .. string.format(msg, ...)) end +-- the abort function +function utils.abort() + + -- trace + error() +end + -- the warning function function utils.warning(msg, ...) |
