As well an interesting extension to Lua would be to allow declaration of "parsing attributes" at the beginning of blocks (i.e. after keywords "do", "repeat", "then", "else", or the closing parenthesis ")" of a function definition, or the main block containing any list of statements): these attributes have local scope within the block. They could also be used just after the opening parenthesis "(" of a subexpression.
It would be simply take the form of a string constant (which will be parsed as if it was the content of a table constructor). That string value can only be used by the parser: when parsing it it will build a table containing normal key/values pairs. Each key can be a simple identifier or expressions between square braces. Values can be expressions. Expressions for keys or values are evaluated in the parser's current lexical scope: it could then call functions or reference variables defined in the script itself. This evaluation occurs only once, directly when parsing the script, not when running blocks (which may not run at all or run multiple times, depending on conditions determined by the script or the environment where it is used).
Note that a string constant cannot currently start any block (or any statement in the block), so
- it has to be itself between pairs of parentheses to be used as an object to call its string methods, for example: ('A'):len()
- a string constant directly at start of a statement or start of a subexpression between parentheses cannot be followed by any operator.
- that string constant for attributes can use the short form between quotes '...' or "...", or the long form between double squares, i.e. [[...]], or [=[...]=], etc.
- attributes at start of subexpressions between pairs of parentheses MUST be followed by an actual _expression_ (possibly nil)
- attributes are just mapping
E.g.:
[[strict]] -- example of an attribute at start of the script
local x = ('strict' 1 / 3 * 3) -- strict IEEE rounding of 1/3 (rounded down) before multiplying by 3, the result is a bit lower than 1.0
function fun(a, b, c) 'strict' -- example of attribute allowing mathematical evaluation with strict IEEE rounding
-- other statements here...
end
function fun(a, b, c) [[strict]] -- using long string syntax
-- other statements here...
end
do 'strict'
if true then 'strict' -- other statements here...
elseif 1 then "strict" -- other statements here...
elseif 2 then [==[strict]==] -- other statements here...
elseif 3 then [[strict]]
else [[strict]]
repeat [[strict]]
until true
while true do [[strict]]
break
end
end
These attributes can alter the way the block (or the subexpression) is evaluated. For example they could allow changing the role of commas "," used inside the block in lists of expressions (for function calls, or for table constructors or for assignment statements). They can change rounding modes for number expressions, assign a function to call to evaluate unary or binary operators.
Basically attributes have a name and an optional value which is the name of a function accessible in the current lexical scope. E.g.
local function add8(a,b)
return (math.floor(a)+math.floor(b))%256
end
local function strictcomma(arg1, ...)
return arg1 -- return only the 1st argument (or nil if there's none), discard other arguments
end
local function func(n)
if type(n)=='number' and n<2 then return n, n+1 end -- return two numbers
-- otherwise return an empty list; interpreted as nil in strict assignments
end
function computebytes() [[-- attributes in a "long string"
__add = add8, -- example of remapping for the "+" binary operator
__comma = strictcomma, -- change variable-length lists of values into a single value or nil
]]
local x = 256 + 1 -- will do: local x=add8(256, 1)
local y, z = func(1), func(2) -- ensures that y=(func(1)) i.e. y=1, and that z=(func(2)) i.e. z=nil
t = {func(1), func(2)} -- will do t = {[1] = 1, [2] = nil}
end