Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Implement "any" keyword and `eq` default behavior. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
9463c12ff0f955c437268fdd86f19763 |
| User & Date: | imagic 2021-11-26 18:21:01.000 |
Context
|
2021-11-26
| ||
| 18:24 | Fix chunkname for generated code. ... (check-in: 06e6fcb534 user: imagic tags: trunk) | |
| 18:21 | Implement "any" keyword and `eq` default behavior. ... (check-in: 9463c12ff0 user: imagic tags: trunk) | |
|
2021-11-25
| ||
| 20:41 | Add warning about `eq` operator. ... (check-in: 2fe1114560 user: imagic tags: trunk) | |
Changes
Changes to README.adoc.
| ︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 | 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, idiv, band, bor, bxor, shl, shr) | > > < < < > > | 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 134 135 | xtype.of(t, ot) -- Create a multifunction. xtype.multifunction() -- Global multifunctions namespace for binary operators. -- For interoperability between third-party types. -- Equality (eq) has a default behavior defined as: eq(any, any) -> false -- -- map of Lua binary op name => multifunction -- (add, sub, mul, div, mod, pow, concat, eq, lt, le, idiv, band, bor, bxor, shl, shr) 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. -- ot: support "any" keyword -- 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. -- osign: support "any" keyword -- return distance or nothing if not generalizable to osign xtype.signDist(sign, osign) -- Return formatted signature string. xtype.formatSign(sign) -- Code generation tools. |
| ︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | ---- === Multifunction [source, lua] ---- -- Define a multifunction signature. -- f: definition function; nil to undefine -- ...: signature, list of types multifunction:define(f, ...) -- Add a generator function. -- -- All generators are called when no matching definition has been found to -- eventually define new signatures. -- -- f(multifunction, ...): called to generate new definitions | > > > | | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ---- === Multifunction [source, lua] ---- -- Define a multifunction signature. -- The keyword "any" matches any type. It is the least specific match for a -- given terminal type. -- -- f: definition function; nil to undefine -- ...: signature, list of types multifunction:define(f, ...) -- Add a generator function. -- -- All generators are called when no matching definition has been found to -- eventually define new signatures. -- -- f(multifunction, ...): called to generate new definitions --- ...: call signature, list of (terminal) types multifunction:addGenerator(f) -- Get the resolved function for a specific signature. -- ...: call signature, list of (terminal) types -- return function or nil without a matching definition multifunction:resolve(...) -- Call the multifunction. multifunction(...) multifunction:call(...) |
| ︙ | ︙ |
Changes to examples/test_multifunction.lua.
1 2 3 4 5 |
-- Test multifunction.
package.path = "src/?.lua;"..package.path
local xtype = require("xtype")
do -- Test operators.
| < < < < | | | > | | | | | | | | | | | | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
-- Test multifunction.
package.path = "src/?.lua;"..package.path
local xtype = require("xtype")
do -- Test operators.
local function build_type(t)
local ins_mt = {
xtype = t,
__add = xtype.op.add,
__mul = xtype.op.mul,
__eq = xtype.op.eq
}
local type_mt = {
xtype = "xtype",
__call = function(t, v)
return setmetatable({v = v}, ins_mt)
end
}
return setmetatable(t, type_mt)
end
local Fruits = build_type(xtype.create("Fruits"))
local Apples = build_type(xtype.create("Apples", Fruits))
local Oranges = build_type(xtype.create("Oranges", Fruits))
local Rocks = build_type(xtype.create("Rocks"))
xtype.op.add:define(function(a, b) return Apples(a.v+b.v) end, Apples, Apples)
xtype.op.add:define(function(a, b) return Oranges(a.v+b.v) end, Oranges, Oranges)
xtype.op.add:define(function(a, b) return Fruits(a.v+b.v) end, Fruits, Fruits)
xtype.op.mul:define(function(a, f) return Apples(a.v*f) end, Apples, "number")
xtype.op.mul:define(function(a, f) return Oranges(a.v*f) end, Oranges, "number")
xtype.op.mul:define(function(a, f) return Fruits(a.v*f) end, Fruits, "number")
xtype.op.eq:define(function(a, b) return a.v == b.v end, Apples, Apples)
xtype.op.eq:define(function(a, b) return a.v == b.v end, Oranges, Oranges)
xtype.op.eq:define(function(a, b)
return xtype.get(a) == xtype.get(b) and a.v == b.v
end, Fruits, Fruits)
local apples = Apples(5)
local oranges = Oranges(5)
-- checks
assert(xtype.is(xtype.op.eq, "multifunction"))
assert(xtype.get(xtype.op.eq) == "multifunction")
assert(apples+apples == Apples(10))
assert(xtype.op.add:call(apples, apples) == Apples(10)) -- alternative
assert(xtype.op.add:resolve(Apples, Apples)(apples, apples) == Apples(10)) -- alternative
assert(not (apples+oranges == Apples(10)))
assert(apples+oranges == Fruits(10))
assert(oranges+apples == Fruits(10))
assert(apples*3 == Apples(15))
--- check equality default behavior
assert(Rocks(5) ~= Apples(5))
end
do -- Test resolution order.
-- types
local animal = xtype.create("animal")
local dog = xtype.create("dog", animal)
local cat = xtype.create("cat", animal)
local chimera = xtype.create("chimera", cat, dog)
|
| ︙ | ︙ |
Changes to src/xtype.lua.
| ︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 |
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)
| > > > > | | | > > | 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 240 241 |
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.
-- ot: support "any" keyword
-- return distance or nil/nothing if not of type ot
local function type_dist(t, ot)
if ot == "any" then -- special keyword
return type(t) == "string" and 1 or #t.xtype_stack
else
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
end
xtype.typeDist = type_dist
-- Distance to another signature from a call signature.
-- osign: support "any" keyword
-- 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
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
mfcall = loadstring(code, "xtype multifunction call("..n..")")(xtype_get, mf_call)
-- cache
mfcalls[n] = mfcall
return mfcall
end
-- Define a multifunction signature.
-- f: definition function; nil to undefine
-- ...: signature, list of types
function multifunction:define(f, ...)
local sign = check_sign(...)
local hash = mf_hash_sign(self, sign)
if f then -- define
-- increase call parameters, re-compile call function
| > > > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
mfcall = loadstring(code, "xtype multifunction call("..n..")")(xtype_get, mf_call)
-- cache
mfcalls[n] = mfcall
return mfcall
end
-- Define a multifunction signature.
-- The keyword "any" matches any type. It is the least specific match for a
-- given terminal type.
--
-- f: definition function; nil to undefine
-- ...: signature, list of types
function multifunction:define(f, ...)
local sign = check_sign(...)
local hash = mf_hash_sign(self, sign)
if f then -- define
-- increase call parameters, re-compile call function
|
| ︙ | ︙ | |||
401 402 403 404 405 406 407 |
if candidate.def == def then self.candidates[chash] = nil end
end
end
end
end
-- Get the resolved function for a specific signature.
| | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
if candidate.def == def then self.candidates[chash] = nil end
end
end
end
end
-- Get the resolved function for a specific signature.
-- ...: call signature, list of (terminal) types
-- return function or nil without a matching definition
function multifunction:resolve(...)
local sign = check_sign(...)
return mf_resolve_sign(self, sign)
end
-- Add a generator function.
--
-- All generators are called when no matching definition has been found to
-- eventually define new signatures.
--
-- f(multifunction, ...): called to generate new definitions
--- ...: call signature, list of (terminal) types
function multifunction:addGenerator(f)
self.generators[f] = true
end
-- Create a multifunction.
function xtype.multifunction()
-- The metatable is per multifunction to independently update the call
|
| ︙ | ︙ | |||
463 464 465 466 467 468 469 470 471 | -- return processed template function xtype.tplsub(tpl, args) return string.gsub(tpl, "%$([%w_]+)", args) end -- 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, idiv, band, bor, bxor, shl, shr) | > > < < < > > > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
-- return processed template
function xtype.tplsub(tpl, args)
return string.gsub(tpl, "%$([%w_]+)", args)
end
-- Global multifunctions namespace for binary operators.
-- For interoperability between third-party types.
-- Equality (eq) has a default behavior defined as: eq(any, any) -> false
--
-- map of Lua binary op name => multifunction
-- (add, sub, mul, div, mod, pow, concat, eq, lt, le, idiv, band, bor, bxor, shl, shr)
xtype.op = {
add = xtype.multifunction(),
sub = xtype.multifunction(),
mul = xtype.multifunction(),
div = xtype.multifunction(),
mod = xtype.multifunction(),
pow = xtype.multifunction(),
concat = xtype.multifunction(),
eq = xtype.multifunction(),
lt = xtype.multifunction(),
le = xtype.multifunction(),
idiv = xtype.multifunction(),
band = xtype.multifunction(),
bor = xtype.multifunction(),
bxor = xtype.multifunction(),
shl = xtype.multifunction(),
shr = xtype.multifunction()
}
-- Default eq behavior.
xtype.op.eq:define(function() return false end, "any", "any")
return xtype
|