Lua - 为什么允许函数调用后的字符串?
Lua - why is string after function call allowed?
我正在尝试实现一个简单的 C++ 函数,它检查 Lua 脚本的语法。为此,我正在使用 Lua 的编译器函数 luaL_loadbufferx()
并随后检查其 return 值。
最近,我 运行 遇到了一个问题,因为没有检测到 我认为应该标记为无效 的代码,脚本后来失败了运行时间(例如 lua_pcall()
)。
示例Lua代码(可以在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 ')'
目标显然是在编译时捕获所有语法错误。所以我的问题是:
- 调用字符串值到底是什么意思?
- 为什么首先允许这种语法?是我不知道的某些 Lua 功能,还是
luaL_loadbufferx()
在这个特定示例中有问题?
- 是否可以在不 运行ning 的情况下通过任何其他方法检测此类错误?不幸的是,我的函数在编译时无法访问全局变量,所以我不能直接通过
lua_pcall()
. 运行 代码
注意:我使用的是 Lua 版本 5.3.4 (manual here)。
非常感谢您的帮助。
myfunc() "!"
和 myfunc(){1,2,3}
都是有效的 Lua 表达式。
Lua 允许 exp string 形式的调用。请参阅 Syntax of Lua 中的 functioncall
和 prefixexp
。
所以 myfunc() "!"
是一个有效的函数调用,它调用任何 myfunc
returns 并使用字符串 "!"
.
调用它
对于形式为 exp table-literal.
的调用也会发生同样的事情
我正在写我自己的问题的答案,以防其他人在未来偶然发现类似的问题并寻求解决方案。
手动
Lua manual (in its section 3.4.10 – Function Calls) 基本上指出,可以通过三种不同的方式为 Lua 函数提供参数。
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.
说明
与lhf pointed out in 一样,myfunc()"!"
和myfunc(){1,2,3}
都是有效的Lua表达式。这意味着 Lua 编译器没有做错,考虑到它在编译时 不知道 函数 return 值。
问题中给出的原始示例代码:
print("Hello " .. myfunc() "!")
然后可以重写为:
print("Hello " .. (myfunc()) ("!"))
其中(执行时)转化为:
print("Hello " .. ("everyone") ("!"))
从而导致运行时错误消息 attempt to call a string value
(可以重写为:字符串 everyone
不是函数,因此您不能调用它)。
解决方案
据我所知,这两种提供参数的替代方法与标准 func(arg)
语法相比并没有真正的好处。这就是我最终修改 Lua 解析器文件的原因。保留这种替代语法的缺点太大了。这是我所做的(与 v5.3.4 相关):
- 在文件
lparser.c
中我搜索了函数:
static void suffixedexp (LexState *ls, expdesc *v)
- 在这个函数中,我更改了 case 语句:
case '(': case TK_STRING: case '{':
到case '(':
警告!通过这样做,我修改了 Lua 语言,所以正如 lhf 在他的评论中所说,它不能再被称为 pure Lua。如果你不确定它是否正是你想要的,我不推荐这种方法。
通过此轻微修改,编译器将上述两种替代语法检测为错误。当然,我不能再在 Lua 脚本中使用它们,但对于我的特定应用程序来说,这很好。
我需要做的就是在某处记录这个变化,以便在升级Lua到更高版本时找到它。
另一种方法是更改字符串的元表,使对字符串的调用有效。
local mt = getmetatable ""
mt.__call = function (self, args) return self .. args end
print(("x") "y") -- outputs `xy`
现在,那些对字符串的有效语法调用将导致字符串连接,而不是运行时错误。
我正在尝试实现一个简单的 C++ 函数,它检查 Lua 脚本的语法。为此,我正在使用 Lua 的编译器函数 luaL_loadbufferx()
并随后检查其 return 值。
最近,我 运行 遇到了一个问题,因为没有检测到 我认为应该标记为无效 的代码,脚本后来失败了运行时间(例如 lua_pcall()
)。
示例Lua代码(可以在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 ')'
目标显然是在编译时捕获所有语法错误。所以我的问题是:
- 调用字符串值到底是什么意思?
- 为什么首先允许这种语法?是我不知道的某些 Lua 功能,还是
luaL_loadbufferx()
在这个特定示例中有问题? - 是否可以在不 运行ning 的情况下通过任何其他方法检测此类错误?不幸的是,我的函数在编译时无法访问全局变量,所以我不能直接通过
lua_pcall()
. 运行 代码
注意:我使用的是 Lua 版本 5.3.4 (manual here)。
非常感谢您的帮助。
myfunc() "!"
和 myfunc(){1,2,3}
都是有效的 Lua 表达式。
Lua 允许 exp string 形式的调用。请参阅 Syntax of Lua 中的 functioncall
和 prefixexp
。
所以 myfunc() "!"
是一个有效的函数调用,它调用任何 myfunc
returns 并使用字符串 "!"
.
对于形式为 exp table-literal.
的调用也会发生同样的事情我正在写我自己的问题的答案,以防其他人在未来偶然发现类似的问题并寻求解决方案。
手动
Lua manual (in its section 3.4.10 – Function Calls) 基本上指出,可以通过三种不同的方式为 Lua 函数提供参数。
Arguments have the following syntax:
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.args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
说明
与lhf pointed out in myfunc()"!"
和myfunc(){1,2,3}
都是有效的Lua表达式。这意味着 Lua 编译器没有做错,考虑到它在编译时 不知道 函数 return 值。
问题中给出的原始示例代码:
print("Hello " .. myfunc() "!")
然后可以重写为:
print("Hello " .. (myfunc()) ("!"))
其中(执行时)转化为:
print("Hello " .. ("everyone") ("!"))
从而导致运行时错误消息 attempt to call a string value
(可以重写为:字符串 everyone
不是函数,因此您不能调用它)。
解决方案
据我所知,这两种提供参数的替代方法与标准 func(arg)
语法相比并没有真正的好处。这就是我最终修改 Lua 解析器文件的原因。保留这种替代语法的缺点太大了。这是我所做的(与 v5.3.4 相关):
- 在文件
lparser.c
中我搜索了函数:static void suffixedexp (LexState *ls, expdesc *v)
- 在这个函数中,我更改了 case 语句:
到case '(': case TK_STRING: case '{':
case '(':
警告!通过这样做,我修改了 Lua 语言,所以正如 lhf 在他的评论中所说,它不能再被称为 pure Lua。如果你不确定它是否正是你想要的,我不推荐这种方法。
通过此轻微修改,编译器将上述两种替代语法检测为错误。当然,我不能再在 Lua 脚本中使用它们,但对于我的特定应用程序来说,这很好。
我需要做的就是在某处记录这个变化,以便在升级Lua到更高版本时找到它。
另一种方法是更改字符串的元表,使对字符串的调用有效。
local mt = getmetatable ""
mt.__call = function (self, args) return self .. args end
print(("x") "y") -- outputs `xy`
现在,那些对字符串的有效语法调用将导致字符串连接,而不是运行时错误。