Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add low-level API. E.g. to inspect/debug. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
be91a3e5fea5b80fe0d2a28711ef63a0 |
| User & Date: | imagic 2021-11-08 20:25:51.000 |
Context
|
2021-11-10
| ||
| 00:55 | Improve cdata support with __xtype field. ... (check-in: 1f1ab704d5 user: imagic tags: trunk) | |
|
2021-11-08
| ||
| 20:25 | Add low-level API. ... (check-in: be91a3e5fe user: imagic tags: trunk) | |
| 19:30 | Improve API checks. ... (check-in: 37988572a5 user: imagic tags: trunk) | |
Changes
Changes to README.adoc.
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | -- -- The created type is a table with 3 fields: xtype_name, xtype_stack and xtype_set. -- The table can be modified as long as the xtype fields are left untouched. -- A default metatable is set; it can be replaced at the condition that the -- type would still be recognized as a "xtype". -- -- name: human-readable string (doesn't have to be unique) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | -- -- The created type is a table with 3 fields: xtype_name, xtype_stack and xtype_set. -- The table can be modified as long as the xtype fields are left untouched. -- A default metatable is set; it can be replaced at the condition that the -- type would still be recognized as a "xtype". -- -- name: human-readable string (doesn't have to be unique) -- ...: base types, ordered by descending proximity, to the least specific type -- return created type xtype.create(name, ...) -- Get/bind a type to a ctype (LuaJIT FFI). -- -- This can't be changed afterwards. -- The same type can be bound to different ctypes; it can be useful when -- different ctype qualifiers should match the same type. -- -- ctype: cdata ctype object -- t: (optional) type -- return bound type xtype.ctype(ctype, t) -- Check if a value is a valid type. xtype.check(t) -- Get the name of a type. -- return string or nothing if not a type xtype.name(t) -- Get terminal type of a value. xtype.get(v) -- Check if a value is of type t. xtype.is(v, t) -- Check if a type is of type ot. xtype.of(t, ot) -- Create a multifunction. xtype.multifunction() -- Global multifunctions namespace for binary operators. -- For interoperability between third-party types. -- map of Lua binary op name => multifunction -- (add, sub, mul, div, mod, pow, concat, eq, lt, le) xtype.op -- Low-level API. -- The type's xtype_stack field is a list of types ordered from the terminal -- type to the least specific inherited types. -- Stack distance to another type from a terminal type. -- return distance or nil/nothing if not of type ot xtype.typeDist(t, ot) -- Check and return signature (list of types). -- ...: types xtype.checkSign(...) -- Distance to another signature from a call signature. -- return distance or nothing if not generalizable to osign xtype.signDist(sign, osign) -- Return formatted signature string. xtype.formatSign(sign) -- Code generation tools. -- Generate "a1, a2, a3, a4..." list string. -- tpl: string where "$" will be replaced by the index -- i: start index -- j: end index -- separator: (optional) default: ", " |
| ︙ | ︙ | |||
135 136 137 138 139 140 141 142 | -- ...: call signature, list of types -- return function or nil without a matching definition multifunction:resolve(...) -- Call the multifunction. multifunction(...) multifunction:call(...) ---- | > > > > > > > > > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
-- ...: call signature, list of types
-- return function or nil without a matching definition
multifunction:resolve(...)
-- Call the multifunction.
multifunction(...)
multifunction:call(...)
-- Low-level API.
multifunction.definitions = {} -- map of sign hash => {.f, .sign}
-- Hash function signature.
-- sign: signature, list of types
-- return number
multifunction:hashSign(sign)
----
|
Changes to src/xtype.lua.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 62 |
end
local type_mt = {
xtype = "xtype",
__tostring = xtype_tostring
}
local function check_type(v, index)
| > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
end
local type_mt = {
xtype = "xtype",
__tostring = xtype_tostring
}
local xtype_is
-- Check if a value is a valid type.
local function xtype_check(t) return type(t) == "string" or xtype_is(t, "xtype") end
xtype.check = xtype_check
-- Check if an argument is a type.
local function check_type(v, index)
if not xtype_check(v) then error_arg(index, "type") end
end
local ctype_types = {} -- map of ctype id => type
-- Get/bind a type to a ctype (LuaJIT FFI).
--
-- This can't be changed afterwards.
-- The same type can be bound to different ctypes; it can be useful when
-- different ctype qualifiers should match the same type.
--
-- ctype: cdata ctype object
-- t: (optional) type
-- return bound type
function xtype.ctype(ctype, t)
local id = tonumber(ctype)
if t and not ctype_types[id] then
check_type(t, 2)
ctype_types[id] = t
end
return ctype_types[id]
end
-- Get terminal type of a value.
local function xtype_get(v)
local v_type = type(v)
if v_type == "table" or v_type == "userdata" then
local mt = getmetatable(v)
return mt and mt.xtype or v_type
elseif v_type == "cdata" then
return ctype_types[tonumber(ffi.typeof(v))] or v_type
else return v_type end
end
xtype.get = xtype_get
-- Check if a value is of type t.
xtype_is = function(v, t)
check_type(t, 2)
local vt = xtype_get(v)
if type(vt) == "table" then return vt.xtype_set[t]
else return vt == t end
end
xtype.is = xtype_is
-- Create a type.
--
-- The created type is a table with 3 fields: xtype_name, xtype_stack and xtype_set.
-- The table can be modified as long as the xtype fields are left untouched.
-- A default metatable is set; it can be replaced at the condition that the
-- type would still be recognized as a "xtype".
--
-- name: human-readable string (doesn't have to be unique)
-- ...: base types, ordered by descending proximity, to the least specific type
-- return created type
function xtype.create(name, ...)
if type(name) ~= "string" then error_arg(1, "string") end
-- check base types
local bases = table_pack(...)
for i=1, bases.n do check_type(bases[i], i+1) end
-- create
|
| ︙ | ︙ | |||
114 115 116 117 118 119 120 |
end
end
step = step+1
end
return t
end
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
end
end
step = step+1
end
return t
end
-- Check if a type is of type ot.
function xtype.of(t, ot)
check_type(t, 1); check_type(ot, 2)
if type(t) == "table" then return t.xtype_set[ot]
else return t == ot end
end
-- Get the name of a type.
-- return string or nothing if not a type
function xtype.name(t)
if xtype_check(t) then return type(t) == "string" and t or t.xtype_name end
end
-- Multifunction.
local function multifunction_tostring(t)
local mt = getmetatable(t)
mt.__tostring = nil
local str = string.gsub(tostring(t), "table:", "multifunction:", 1)
mt.__tostring = multifunction_tostring
return str
end
local multifunction = {}
-- Check and return signature (list of types).
-- ...: types
local function check_sign(...)
local sign = table_pack(...)
for i=1, sign.n do check_type(sign[i], i) end
return sign
end
xtype.checkSign = check_sign
-- Return formatted signature string.
local function format_sign(sign)
local names = {}
for _, t in ipairs(sign) do
table.insert(names, type(t) == "string" and t or t.xtype_name)
end
return "("..table.concat(names, ", ")..")"
end
xtype.formatSign = format_sign
-- Stack distance to another type from a terminal type.
-- return distance or nil/nothing if not of type ot
local function type_dist(t, ot)
if type(t) == "string" then return t == ot and 0 or nil end
for i, st in ipairs(t.xtype_stack) do
if st == ot then return i-1 end
end
end
xtype.typeDist = type_dist
-- Distance to another signature from a call signature.
-- return distance or nothing if not generalizable to osign
local function sign_dist(sign, osign)
local dist = 0
for i=1, #sign do
local tdist = type_dist(sign[i], osign[i])
if not tdist then return end
dist = dist+tdist
end
return dist
end
xtype.signDist = sign_dist
-- Create hash sign tree.
local function new_hsign()
local count = 0
local hasher_mt
hasher_mt = {
__index = function(t, k)
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 | -- sign: signature, list of types -- return number local function mf_hash_sign(self, sign) local node = self.hsign for _, t in ipairs(sign) do node = node[t] end return node[1] end | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
-- sign: signature, list of types
-- return number
local function mf_hash_sign(self, sign)
local node = self.hsign
for _, t in ipairs(sign) do node = node[t] end
return node[1]
end
multifunction.hashSign = mf_hash_sign
-- Find candidate.
-- return candidate or nil if none found
--- candidate: {def, dist}
local function mf_find_candidate(self, sign)
-- find candidates
local candidates = {}
|
| ︙ | ︙ | |||
389 390 391 392 393 394 395 |
local default_call = gen_opt_mfcall(0)
local multifunction_mt = {
xtype = "multifunction",
__tostring = multifunction_tostring,
__index = multifunction,
__call = default_call
}
| < | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
local default_call = gen_opt_mfcall(0)
local multifunction_mt = {
xtype = "multifunction",
__tostring = multifunction_tostring,
__index = multifunction,
__call = default_call
}
return setmetatable({
hsign = new_hsign(),
definitions = {}, -- map of sign hash => {.f, .sign}
generators = {}, -- set of generator functions
candidates = {}, -- cached candidates, map of hash => {def, dist}
max_calln = 0, -- maximum call parameters
call = default_call
}, multifunction_mt)
end
-- Code generation tools.
|
| ︙ | ︙ |