Parenless calls for function literals
"'TopchetoEU' via lua-l" <[email protected]> Thu, 28 May 2026 17:41:31 +0000
| Newsgroups | gmane.comp.lang.lua.general |
|---|---|
| Message-ID | <CdBAYNQgpj1uPWQzg0HKplvAgP1X0NrYOGXDK7oL1vyBzKcClWibJWsM7O_r9PziqO0wzsq99Kxzaa9OA1IUAd5r9EZGHDQUMJDuZDYMMbo=@proton.me> |
Hello list,
Lua allows calls with table and string literals to omit the call parens, which enables some very elegant and concise DSL-styled syntax. I have been experimenting with extending that idea to function literals, too. This is the core of the syntax:
called_function begin
body_of_function_literal
end
I chose to introduce `begin` as a keyword, as opposed to using the existing `function` keyword, as syntax like this:
print("Hello, world")
function test() end
Would be difficult to parse (not impossible, but would require a look ahead, which would complicate needlessly the parser for such a small feature).
I'm not terribly attached to the `begin` keyword, and I even fear that it could break existing code, as `begin` could be a common variable/field name, so I'm open to suggestions.
Otherwise, I think this would make DSLs much cleaner in some cases, where you need to pass functions, instead of tables. For example, a testing framework could declare its cases like this:
describe "My example test" begin
it "Should be true" begin
assert.truthy(true)
end
end
I have attached a patch file, so you can experiment with it. Note that I haven't spent much time testing it, but nothing *should* break, as it changes about 15 LoC.
Comments and criticism are welcome.
--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/lua-l/CdBAYNQgpj1uPWQzg0HKplvAgP1X0NrYOGXDK7oL1vyBzKcClWibJWsM7O_r9PziqO0wzsq99Kxzaa9OA1IUAd5r9EZGHDQUMJDuZDYMMbo%3D%40proton.me.
lua-begin.patch
(text/x-patch, 2.6 KB)
diff --git a/llex.c b/llex.c
index 5fc39a5c..898ac8d7 100644
--- a/llex.c
+++ b/llex.c
@@ -38,7 +38,7 @@
/* ORDER RESERVED */
static const char *const luaX_tokens [] = {
- "and", "break", "do", "else", "elseif",
+ "and", "begin", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
diff --git a/llex.h b/llex.h
index 389d2f86..6d625e3e 100644
--- a/llex.h
+++ b/llex.h
@@ -31,7 +31,7 @@
*/
enum RESERVED {
/* terminal symbols denoted by reserved words */
- TK_AND = FIRST_RESERVED, TK_BREAK,
+ TK_AND = FIRST_RESERVED, TK_BEGIN, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
diff --git a/lparser.c b/lparser.c
index f4bfc963..ac406d26 100644
--- a/lparser.c
+++ b/lparser.c
@@ -988,23 +988,28 @@ static void parlist (LexState *ls) {
}
-static void body (LexState *ls, expdesc *e, int ismethod, int line) {
+static void body (LexState *ls, expdesc *e, int kind, int line) {
/* body -> '(' parlist ')' block END */
FuncState new_fs;
BlockCnt bl;
new_fs.f = addprototype(ls);
new_fs.f->linedefined = line;
open_func(ls, &new_fs, &bl);
- checknext(ls, '(');
- if (ismethod) {
- new_localvarliteral(ls, "self"); /* create 'self' parameter */
- adjustlocalvars(ls, 1);
+ if (kind == 2) {
+ setvararg(ls->fs, 0);
+ }
+ else {
+ checknext(ls, '(');
+ if (kind == 1) {
+ new_localvarliteral(ls, "self"); /* create 'self' parameter */
+ adjustlocalvars(ls, 1);
+ }
+ parlist(ls);
+ checknext(ls, ')');
}
- parlist(ls);
- checknext(ls, ')');
statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
- check_match(ls, TK_END, TK_FUNCTION, line);
+ check_match(ls, TK_END, kind == 2 ? TK_BEGIN : TK_FUNCTION, line);
codeclosure(ls, e);
close_func(ls);
}
@@ -1050,6 +1055,11 @@ static void funcargs (LexState *ls, expdesc *f) {
luaX_next(ls); /* must use 'seminfo' before 'next' */
break;
}
+ case TK_BEGIN: {
+ luaX_next(ls);
+ body(ls, &args, 2, line);
+ break;
+ }
default: {
luaX_syntaxerror(ls, "function arguments expected");
}
@@ -1127,7 +1137,7 @@ static void suffixedexp (LexState *ls, expdesc *v) {
funcargs(ls, v);
break;
}
- case '(': case TK_STRING: case '{': { /* funcargs */
+ case '(': case TK_STRING: case '{': case TK_BEGIN: { /* funcargs */
luaK_exp2nextreg(fs, v);
funcargs(ls, v);
break;