summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2016-01-19 20:54:26 +0800
committerruki <[email protected]>2016-02-15 19:10:24 +0800
commitd7329faff5284e07a251683fc30dcefcb27e21d0 (patch)
tree3436953d66e2c1bbd3b0f74e8f92977a2cdfd9a9
parent44c7d62676ce6763d013db0c031e6f651237f510 (diff)
impl add/set scope and values for interpreter
-rw-r--r--tests/interpreter/scope.lua14
-rw-r--r--tests/interpreter/tests.lua74
-rw-r--r--xmake/core/base/interpreter.lua275
-rw-r--r--xmake/core/base/utils.lua7
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, ...)