Browse Source

strings in C scripts may be delimited by quotes + new functionality to
set C scripts as C hooks

Roberto Ierusalimschy 15 years ago
parent
commit
df1dc3f1f5
1 changed files with 76 additions and 16 deletions
  1. 76 16
      ltests.c

+ 76 - 16
ltests.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ltests.c,v 2.79 2009/11/06 17:08:43 roberto Exp roberto $
+** $Id: ltests.c,v 2.80 2009/11/27 15:39:31 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -810,6 +810,9 @@ static int int2fb_aux (lua_State *L) {
 ** =======================================================
 ** =======================================================
 */
 */
 
 
+
+static void sethookaux (lua_State *L, int mask, int count, const char *code);
+
 static const char *const delimits = " \t\n,;";
 static const char *const delimits = " \t\n,;";
 
 
 static void skip (const char **pc) {
 static void skip (const char **pc) {
@@ -842,11 +845,21 @@ static int getnum_aux (lua_State *L, const char **pc) {
   return sig*res;
   return sig*res;
 }
 }
 
 
-static const char *getname_aux (char *buff, const char **pc) {
+static const char *getname_aux (lua_State *L, char *buff, const char **pc) {
   int i = 0;
   int i = 0;
   skip(pc);
   skip(pc);
-  while (**pc != '\0' && !strchr(delimits, **pc))
-    buff[i++] = *(*pc)++;
+  if (**pc == '"' || **pc == '\'') {  /* quoted string? */
+    int quote = *(*pc)++;
+    while (**pc != quote) {
+      if (**pc == '\0') luaL_error(L, "unfinished string in C script");
+      buff[i++] = *(*pc)++;
+    }
+    (*pc)++;
+  }
+  else {
+    while (**pc != '\0' && !strchr(delimits, **pc))
+      buff[i++] = *(*pc)++;
+  }
   buff[i] = '\0';
   buff[i] = '\0';
   return buff;
   return buff;
 }
 }
@@ -866,7 +879,7 @@ static int getindex_aux (lua_State *L, const char **pc) {
 #define EQ(s1)	(strcmp(s1, inst) == 0)
 #define EQ(s1)	(strcmp(s1, inst) == 0)
 
 
 #define getnum	(getnum_aux(L, &pc))
 #define getnum	(getnum_aux(L, &pc))
-#define getname	(getname_aux(buff, &pc))
+#define getname	(getname_aux(L, buff, &pc))
 #define getindex (getindex_aux(L, &pc))
 #define getindex (getindex_aux(L, &pc))
 
 
 
 
@@ -874,8 +887,8 @@ static int testC (lua_State *L);
 static int Cfunck (lua_State *L);
 static int Cfunck (lua_State *L);
 
 
 static int runC (lua_State *L, lua_State *L1, const char *pc) {
 static int runC (lua_State *L, lua_State *L1, const char *pc) {
-  char buff[30];
-  if (pc == NULL) return luaL_error(L, "attempt to runC null code");
+  char buff[300];
+  if (pc == NULL) return luaL_error(L, "attempt to runC null script");
   for (;;) {
   for (;;) {
     const char *inst = getname;
     const char *inst = getname;
     if EQ("") return 0;
     if EQ("") return 0;
@@ -1079,6 +1092,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
       int i = getindex;
       int i = getindex;
       lua_pushinteger(L1, lua_objlen(L1, i));
       lua_pushinteger(L1, lua_objlen(L1, i));
     }
     }
+    else if EQ("append") {
+      int t = getindex;
+      int i = lua_objlen(L1, t);
+      lua_rawseti(L1, t, i + 1);
+    }
     else if EQ("getctx") {
     else if EQ("getctx") {
       static const char *const codes[] = {"OK", "YIELD", "ERRRUN",
       static const char *const codes[] = {"OK", "YIELD", "ERRRUN",
          "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"};
          "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"};
@@ -1105,6 +1123,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
                     lua_tostring(L, b),
                     lua_tostring(L, b),
                     lua_tostring(L, c));
                     lua_tostring(L, c));
     }
     }
+    else if EQ("sethook") {
+      int mask = getnum;
+      int count = getnum;
+      sethookaux(L1, mask, count, getname);
+    }
     else if EQ("throw") {
     else if EQ("throw") {
 #if defined(__cplusplus)
 #if defined(__cplusplus)
 static struct X { int x; } x;
 static struct X { int x; } x;
@@ -1163,25 +1186,62 @@ static int makeCfunc (lua_State *L) {
 
 
 /*
 /*
 ** {======================================================
 ** {======================================================
-** tests for yield inside hooks
+** tests for C hooks
 ** =======================================================
 ** =======================================================
 */
 */
 
 
-static void yieldf (lua_State *L, lua_Debug *ar) {
-  UNUSED(ar);
-  lua_yield(L, 0);
+/*
+** C hook that runs the C script stored in registry.C_HOOK[L]
+*/
+static void Chook (lua_State *L, lua_Debug *ar) {
+  const char *scpt;
+  const char *const events [] = {"call", "ret", "line", "count", "tailcall"};
+  lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK");
+  lua_pushlightuserdata(L, L);
+  lua_gettable(L, -2);  /* get C_HOOK[L] (script saved by sethookaux) */
+  scpt = lua_tostring(L, -1);  /* not very religious (string will be popped) */
+  lua_pop(L, 2);  /* remove C_HOOK and script */
+  lua_pushstring(L, events[ar->event]);  /* may be used by script */
+  lua_pushinteger(L, ar->currentline);  /* may be used by script */
+  runC(L, L, scpt);  /* run script from C_HOOK[L] */
+}
+
+
+/*
+** sets registry.C_HOOK[L] = scpt and sets Chook as a hook
+*/
+static void sethookaux (lua_State *L, int mask, int count, const char *scpt) {
+  if (*scpt == '\0') {  /* no script? */
+    lua_sethook(L, NULL, 0, 0);  /* turn off hooks */
+    return;
+  }
+  lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK");  /* get C_HOOK table */
+  if (!lua_istable(L, -1)) {  /* no hook table? */
+    lua_pop(L, 1);  /* remove previous value */
+    lua_newtable(L);  /* create new C_HOOK table */
+    lua_pushvalue(L, -1);
+    lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK");  /* register it */
+  }
+  lua_pushlightuserdata(L, L);
+  lua_pushstring(L, scpt);
+  lua_settable(L, -3);  /* C_HOOK[L] = script */
+  lua_sethook(L, Chook, mask, count);
 }
 }
 
 
-static int setyhook (lua_State *L) {
+
+static int sethook (lua_State *L) {
   if (lua_isnoneornil(L, 1))
   if (lua_isnoneornil(L, 1))
     lua_sethook(L, NULL, 0, 0);  /* turn off hooks */
     lua_sethook(L, NULL, 0, 0);  /* turn off hooks */
   else {
   else {
-    const char *smask = luaL_checkstring(L, 1);
-    int count = luaL_optint(L, 2, 0);
+    const char *scpt = luaL_checkstring(L, 1);
+    const char *smask = luaL_checkstring(L, 2);
+    int count = luaL_optint(L, 3, 0);
     int mask = 0;
     int mask = 0;
+    if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+    if (strchr(smask, 'r')) mask |= LUA_MASKRET;
     if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
     if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
     if (count > 0) mask |= LUA_MASKCOUNT;
     if (count > 0) mask |= LUA_MASKCOUNT;
-    lua_sethook(L, yieldf, mask, count);
+    sethookaux(L, mask, count, scpt);
   }
   }
   return 0;
   return 0;
 }
 }
@@ -1232,7 +1292,7 @@ static const struct luaL_Reg tests_funcs[] = {
   {"ref", tref},
   {"ref", tref},
   {"resume", coresume},
   {"resume", coresume},
   {"s2d", s2d},
   {"s2d", s2d},
-  {"setyhook", setyhook},
+  {"sethook", sethook},
   {"stacklevel", stacklevel},
   {"stacklevel", stacklevel},
   {"testC", testC},
   {"testC", testC},
   {"makeCfunc", makeCfunc},
   {"makeCfunc", makeCfunc},