I'm trying to implement a simple C++ function, which checks a syntax of Lua script. For that I'm using Lua's compiler function luaL_loadbufferx() and checking its return value afterwards.
Recently, I have ran into a problem, because the code, that I thought should be marked invalid, was not detected and instead the script failed later at a runtime (eg. in lua_pcall()).
Example Lua code (can be tested on official Lua demo):
function myfunc()
return "everyone"
end
-- Examples of unexpected behaviour:
-- The following lines pass the compile time check without errors.
print("Hello " .. myfunc() "!") -- Runtime error: attempt to call a string value
print("Hello " .. myfunc() {1,2,3}) -- Runtime error: attempt to call a string value
-- Other examples:
-- The following lines contain examples of invalid syntax, which IS detected by compiler.
print("Hello " myfunc() .. "!") -- Compile error: ')' expected near 'myfunc'
print("Hello " .. myfunc() 5) -- Compile error: ')' expected near '5'
print("Hello " .. myfunc() .. ) -- Compile error: unexpected symbol near ')'
The goal is obviously to catch all syntax errors at compile time. So my questions are:
What exactly is meant by calling a string value?
Why is this syntax allowed in the first place? Is it some Lua feature I'm unaware of, or the luaL_loadbufferx() is faulty in this particular example?
Is it possible to detect such errors by any other method without running it? Unfortunately, my function doesn't have access to global variables at compile time, so I can't just just run the code directly via lua_pcall().
Note: I'm using Lua version 5.3.4 (manual here).
Thank you very much for your help.
Both myfunc() "!" and myfunc(){1,2,3} are valid Lua expressions.
Lua allows calls of the form exp string. See functioncall and prefixexp in the Syntax of Lua.
So myfunc() "!" is a valid function call that calls whatever myfunc returns and call it with the string "!".
The same thing happens for a call of the form exp table-literal.
Another approach is to change string's metatable making a call to a string valid.
local mt = getmetatable ""
mt.__call = function (self, args) return self .. args end
print(("x") "y") -- outputs `xy`
Now those valid syntax calls to a string will result in string concatenation instead of runtime errors.
I'm writing answer to my own question just in case anyone else stumbles upon the similar problem in the future and also looks for solution.
Manual
Lua manual (in its section 3.4.10 – Function Calls) basically states, that there are three different ways of providing arguments to Lua function.
Arguments have the following syntax: args ::= ‘(’ [explist] ‘)’
args ::= tableconstructor
args ::= LiteralString
All argument expressions are evaluated before the call. A call of the form f{fields} is syntactic sugar for f({fields}); that is, the argument list is a single new table. A call of the form f'string' (or f"string" or f[[string]]) is syntactic sugar for f('string'); that is, the argument list is a single literal string.
Explanation
As lhf pointed out in his answer, both myfunc()"!" and myfunc(){1,2,3} are valid Lua expressions. It means the Lua compiler is doing nothing wrong, considering it doesn't know the function return value at a compile time.
The original example code given in the question:
print("Hello " .. myfunc() "!")
Could be then rewritten as:
print("Hello " .. (myfunc()) ("!"))
Which (when executed) translates to:
print("Hello " .. ("everyone") ("!"))
And thus resulting in the runtime error message attempt to call a string value (which could be rewritten as: the string everyone is not a function, so you can't call it).
Solution
As far as I understand, these two alternative ways of supplying arguments have no real benefit over the standard func(arg) syntax. That's why I ended up modyfing the Lua parser files. The disadventage of keeping this alternative syntax was too big. Here is what I've done (relevant for v5.3.4):
In file lparser.c i searched for function:
static void suffixedexp (LexState *ls, expdesc *v)
Inside this function i changed the case statement:
case '(': case TK_STRING: case '{':to case '(':
Warning! By doing this I have modified the Lua language, so as lhf stated in his comment, it can no longer be called pure Lua. If you are unsure whether it is exactly what you want, I can't recommend this approach.
With this slight modification compiler detects the two above mentioned alternative syntaxes as errors. Of course, I can no longer use them inside Lua scripts, but for my specific application it's just fine.
All I need to do is to note this change somewhere to find it in case of upgrading Lua to higher version.
Related
Somehow there seems to be a difference, when passing a string in via a variable vs. passing a string via an expression as an argument.
I am so confused right now, about how Lua evaluates expressions.
In short: I am trying to detect a word, case insensitive and I am reformatting the pattern, so it is not case sensitive. If I pass the argument directly to <string>:match (sidenote: issue persists with directly calling string.match), it doesn't give the expected behaviour, while it does, when passing it via a local variable.
I have destilled the code into a reproducable script (Windows: Lua 5.4.3 and Lua JIT 2.1.0-beta3, WSL: Lua 5.3.3, Linux: Lua 5.1):
-- Replaces each char with a charset pattern in uppercase and lowercase
local function makeCaseInsensitive(name)
return name:gsub("%a", function (c)
return string.format("[%s%s]", c:lower(), c:upper())
end)
end
local suite = "Retained widgets"
local pattern = "retained"
if suite:match(makeCaseInsensitive(pattern)) then
print("In expression ok")
else
print("In expression not ok")
end
local insensitive = makeCaseInsensitive(pattern)
if suite:match(insensitive) then
print("In variable ok")
else
print("In variable not ok")
end
The expected output would be:
In expression ok
In variable ok
instead:
In expression not ok
In variable ok
WTF is going on?
Could someone please explain to me, what is going on?
Any feedback is appreciated
As #MikeV. pointed out in the comments: makeCaseInsensitive(pattern) returns two arguments. This is due to string.gsub returning the replacement and the replaced character count: 8.
The solution is to discard the rest from gsub, either explicitly:
-- Replaces each char with a charset pattern in uppercase and lowercase
local function makeCaseInsensitive(name)
local caseInsensitivePattern, count = name:gsub("%a", function (c)
return string.format("[%s%s]", c:lower(), c:upper())
end)
return caseInsensitivePattern
end
or implicitly by adding extra parenthesis:
-- Replaces each char with a charset pattern in uppercase and lowercase
local function makeCaseInsensitive(name)
return (name:gsub("%a", function (c)
return string.format("[%s%s]", c:lower(), c:upper())
end))
end
I want to convert this python code to lua .
for i in range(1000,9999):
if str(i).endswith('9'):
print(i)
I've come this far ,,
for var=1000,9000 then
if tostring(var).endswith('9') then
print (var)
end
end
but I don't know what's the lua equivalent of endswith() is ,,, im writing an nmap script,,
working 1st time with lua so pls let me know if there are any errors ,, on my current code .
The python code is not great, you can get the last digit by using modulo %
# python code using modulo
for i in range(1000,9999):
if i % 10 == 9:
print(i)
This also works in Lua. However Lua includes the last number in the loop, unlike python.
-- lua code to do this
for i=1000, 9998 do
if i % 10 == 9 then
print(i)
end
end
However in both languages you could iterate by 10 each time
for i in range(1009, 9999, 10):
print(i)
for i=9, 9998, 10 do
print(i)
for var = 1000, 9000 do
if string.sub(var, -1) == "9" then
-- do your stuff
end
end
XY-Problem
The X problem of how to best port your code to Lua has been answered by quantumpro already, who optimized it & cleaned it up.
I'll focus on your Y problem:
What's the Lua equivalent of Python endswith?
Calling string functions, OOP-style
In Lua, strings have a metatable that indexes the global string library table. String functions are called using str:func(...) in Lua rather than str.func(...) to pass the string str as first "self" argument (see "Difference between . and : in Lua").
Furthermore, if the argument to the call is a single string, you can omit the parentheses, turning str:func("...") into str:func"...".
Constant suffix: Pattern Matching
Lua provides a more powerful pattern matching function that can be used to check whether a string ends with a suffix: string.match. str.endswith("9") in Python is equivalent to str:match"9$" in Lua: $ anchors the pattern at the end of the string and 9 matches the literal character 9.
Be careful though: This approach doesn't work with arbitrary, possibly variable suffices since certain characters - such as $ - are magic characters in Lua patterns and thus have a special meaning. Consider str.endswith("."); this is not equivalent to string:match".$" in Lua, since . matches any character.
I'd say that this is the lua-esque way of checking whether a string ends with a constant suffix. Note that it does not return a boolean, but rather a match (the suffix, a truthy value) if successful or nil (a falsey value) if unsuccessful; it can thus safely be used in ifs. To convert the result into a boolean, you could use not not string:match"9$".
Variable suffix: Rolling your own
Lua's standard library is very minimalistic; as such, you often need to roll your own functions even for basic things. There are two possible implementations for endswith, one using pattern matching and another one using substrings; the latter approach is preferable because it's shorter, possibly faster (Lua uses a naive pattern matching engine) and doesn't have to take care of pattern escaping:
function string:endswith(suffix)
return self:sub(-#suffix) == suffix
end
Explanation: self:sub(-#suffix) returns the last suffix length characters of self, the first argument. This is compared against the suffix.
You can then call this function using the colon (:) syntax:
str = "prefixsuffix"
assert(str:endswith"suffix")
assert(not str:endswith"prefix")
I noticed that the following code compiles and works in VS 2013:
let f() =
do Console.WriteLine(41)
42
But when looking at the F# 3.0 specification I can't find any mention of do being used this way. As far as I can tell, do can have the following uses:
As a part of loop (e.g. while expr do expr done), that's not the case here.
Inside computation expressions, e.g.:
seq {
for i in 1..2 do
do Console.WriteLine(i)
yield i * 2
}
That's not the case here either, f doesn't contain any computation expressions.
Though what confuses me here is that according to the specification, do should be followed by in. That in should be optional due to lightweight syntax, but adding it here causes a compile error (“Unexpected token 'in' or incomplete expression”).
Statement inside a module or class. This is also not the case here, the do is inside a function, not inside a module or a class.
I also noticed that with #light "off", the code doesn't compile (“Unexpected keyword 'do' in binding”), but I didn't find anything that would explain this in the section on lightweight syntax either.
Based on all this, I would assume that using do inside a function this way should not compile, but it does. Did I miss something in the specification? Or is this actually a bug in the compiler or in the specification?
From the documentation on MSDN:
A do binding is used to execute code without defining a function or value.
Even though the spec doesn't contain a comprehensive list of the places it is allowed, it is merely an expression asserted to be of type unit. Some examples:
if ((do ()); true) then ()
let x: unit = do ()
It is generally omitted. Each of the preceding examples are valid without do. Therefore, do serves only to assert that an expression is of type unit.
Going through the F# 3.0 specification expression syntax has do expr as a choice of class-function-or-value-defn (types) [Ch 8, A.2.5] and module-function-or-value-defn (modules) [Ch 10, A.2.1.1].
I don't actually see in the spec where function-defn can have more than one expression, as long all but the last one evaluate to unit -- or that all but the last expression is ignored in determining the functions return value.
So, it seems this is an oversight in the documentation.
I am new in Eralng . get a little query about applying functions
assumming got a funciton defined :
mysum(X) -> fun(Y)-> X + Y end.
then try to calling like this
mysum(32)(332)
getting error
* 1: syntax error before: '('
so I had to
apply(mysum(32),[333])
or
M = mysum(32), M(333)
but I would like to know a little bit more , why it is not supporting , what is the disadvantage
As you expected, mysum return a function. you must enclose the evaluation inside parenthesis to satisfy the erlang parser:
(mysum(32))(332)
this spelling is obviously not ambiguous.
Your expression seems not ambiguous because you know that mysum(32) is a function, but the types are solved at run time in erlang, so the parser has no idea of what is mysum(32), it is expecting some help here to know what it has to do: the parenthesis, the apply or the intermediate variables, but it could be an operator or a separator.
I have a situation where I perform some operations on tables, call them T and V. I have set the metatable up correctly and everything works as expected. The issue is that I usually don't need the result of the calculation. So instead of writing
for i=1,5 do
_=T+V
end
is there a way to just have
for i=1,5 do
T+V
end
?
I am not using the Lua commandline so I cannot just write =T+V.
Make a function that does nothing and pass it to it:
function NOP() end
for i=1,5 do
NOP(T+V)
end
This additionally serves to document your intentions, and that the side-effect is what you're after.
Looking at syntax of Lua in extended BNF I don't see an way to construct an expression (exp) without a equal sign or something else.
There are only 4 cases where an expression (exp) can be used:
Assigning a value e.g. p = exp
As condition e.g. while exp then
In a function call i.e. f(exp)
for indexing i.e. t[exp]