Another idea -- a meta mechanism for user extensible operators:
Pass a table with user defined operators (*) to loadstring() etc.
Compile this to OP_[LIGHT]{CONST|UN|BIN}OP, indexing a table of
(light) functions held in the Lua function prototype. I guess
this would be very fast.
Slight complication: for (un)dumping to/from bytecode you need to
pass the same table of user defined operators.
(*) Name, arity, precedence, (light) function, optional type
checks, optional constant folding.
Simplified, hypothetical example:
local userops = {
PI = { arity = 0, op = math.pi }, -- arity 0 are constants
sin = { arity = 1, op = math.sin },
cos = { arity = 1, op = math.cos },
["|"] = { arity = 2, op = bit.bor },
["<<"] = { arity = 2, op = bit.lshift },

` ["//"] = { arity = 2, op = function(a, b) return math.floor(a/
``b) end },
` } -- These should of course better be light functions.
loadstring([[
local a, b = ...
print( PI * sin a + cos b )
print( (a << 11) | (b << 3) | 5 )
print( "Rici buys", 1.38 // 0.16, "apples." )
]], nil, userops)(...)
[Yes, of course this works with strings or any other type, too.]