Add environment variable access with $NAME syntax
Lexes $NAME as TK_ENVVAR, compiles reads as __getenv("NAME") calls
and writes ($NAME = expr) as __setenv("NAME", expr) calls. Runtime
functions wrap getenv/setenv/unsetenv with automatic tostring coercion.
This commit is contained in:
52
lparser.c
52
lparser.c
@@ -1302,8 +1302,25 @@ static void commandexp (LexState *ls, expdesc *v) {
|
||||
}
|
||||
|
||||
|
||||
static void codeenvget (LexState *ls, expdesc *v, TString *name) {
|
||||
FuncState *fs = ls->fs;
|
||||
int base, line;
|
||||
expdesc func, arg;
|
||||
TString *fname = luaX_newstring(ls, "__getenv", 8);
|
||||
line = ls->linenumber;
|
||||
buildglobal(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
luaK_exp2nextreg(fs, &arg);
|
||||
init_exp(v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 2));
|
||||
luaK_fixline(fs, line);
|
||||
fs->freereg = cast_byte(base + 1);
|
||||
}
|
||||
|
||||
|
||||
static void primaryexp (LexState *ls, expdesc *v) {
|
||||
/* primaryexp -> NAME | '(' expr ')' | COMMAND */
|
||||
/* primaryexp -> NAME | '(' expr ')' | COMMAND | ENVVAR */
|
||||
switch (ls->t.token) {
|
||||
case '(': {
|
||||
int line = ls->linenumber;
|
||||
@@ -1321,6 +1338,11 @@ static void primaryexp (LexState *ls, expdesc *v) {
|
||||
commandexp(ls, v);
|
||||
return;
|
||||
}
|
||||
case TK_ENVVAR: {
|
||||
codeenvget(ls, v, ls->t.seminfo.ts);
|
||||
luaX_next(ls);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
luaX_syntaxerror(ls, "unexpected symbol");
|
||||
}
|
||||
@@ -2160,6 +2182,30 @@ static void retstat (LexState *ls) {
|
||||
}
|
||||
|
||||
|
||||
static void envstat (LexState *ls) {
|
||||
/* envstat -> '$' NAME '=' expr */
|
||||
FuncState *fs = ls->fs;
|
||||
TString *name = ls->t.seminfo.ts;
|
||||
int base, line;
|
||||
expdesc func, arg, val;
|
||||
TString *fname;
|
||||
line = ls->linenumber;
|
||||
luaX_next(ls); /* skip TK_ENVVAR */
|
||||
checknext(ls, '=');
|
||||
fname = luaX_newstring(ls, "__setenv", 8);
|
||||
buildglobal(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
luaK_exp2nextreg(fs, &arg);
|
||||
expr(ls, &val);
|
||||
luaK_exp2nextreg(fs, &val);
|
||||
init_exp(&val, VCALL, luaK_codeABC(fs, OP_CALL, base, 3, 1));
|
||||
luaK_fixline(fs, line);
|
||||
fs->freereg = cast_byte(base);
|
||||
}
|
||||
|
||||
|
||||
static void statement (LexState *ls) {
|
||||
int line = ls->linenumber; /* may be needed for error messages */
|
||||
enterlevel(ls);
|
||||
@@ -2225,6 +2271,10 @@ static void statement (LexState *ls) {
|
||||
gotostat(ls, line);
|
||||
break;
|
||||
}
|
||||
case TK_ENVVAR: { /* stat -> '$' NAME '=' expr */
|
||||
envstat(ls);
|
||||
break;
|
||||
}
|
||||
#if defined(LUA_COMPAT_GLOBAL)
|
||||
case TK_NAME: {
|
||||
/* compatibility code to parse global keyword when "global"
|
||||
|
||||
Reference in New Issue
Block a user