fallback.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. ** fallback.c
  3. ** TecCGraf - PUC-Rio
  4. */
  5. char *rcs_fallback="$Id: fallback.c,v 1.35 1997/03/31 14:17:09 roberto Exp roberto $";
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "auxlib.h"
  9. #include "luamem.h"
  10. #include "fallback.h"
  11. #include "opcode.h"
  12. #include "lua.h"
  13. #include "table.h"
  14. #include "tree.h"
  15. #include "hash.h"
  16. static char *typenames[] = { /* ORDER LUA_T */
  17. "userdata", "line", "cmark", "mark", "function",
  18. "function", "table", "string", "number", "nil",
  19. NULL
  20. };
  21. void luaI_type (void)
  22. {
  23. lua_Object o = lua_getparam(1);
  24. luaL_arg_check(o != LUA_NOOBJECT, "type", 1, "no argument");
  25. lua_pushstring(typenames[-ttype(luaI_Address(o))]);
  26. lua_pushnumber(lua_tag(o));
  27. }
  28. /* -------------------------------------------
  29. ** Reference routines
  30. */
  31. static struct ref {
  32. TObject o;
  33. enum {LOCK, HOLD, FREE, COLLECTED} status;
  34. } *refArray = NULL;
  35. static int refSize = 0;
  36. int luaI_ref (TObject *object, int lock)
  37. {
  38. int i;
  39. int oldSize;
  40. if (ttype(object) == LUA_T_NIL)
  41. return -1; /* special ref for nil */
  42. for (i=0; i<refSize; i++)
  43. if (refArray[i].status == FREE)
  44. goto found;
  45. /* no more empty spaces */
  46. oldSize = refSize;
  47. refSize = growvector(&refArray, refSize, struct ref, refEM, MAX_WORD);
  48. for (i=oldSize; i<refSize; i++)
  49. refArray[i].status = FREE;
  50. i = oldSize;
  51. found:
  52. refArray[i].o = *object;
  53. refArray[i].status = lock ? LOCK : HOLD;
  54. return i;
  55. }
  56. void lua_unref (int ref)
  57. {
  58. if (ref >= 0 && ref < refSize)
  59. refArray[ref].status = FREE;
  60. }
  61. TObject *luaI_getref (int ref)
  62. {
  63. static TObject nul = {LUA_T_NIL, {0}};
  64. if (ref == -1)
  65. return &nul;
  66. if (ref >= 0 && ref < refSize &&
  67. (refArray[ref].status == LOCK || refArray[ref].status == HOLD))
  68. return &refArray[ref].o;
  69. else
  70. return NULL;
  71. }
  72. void luaI_travlock (int (*fn)(TObject *))
  73. {
  74. int i;
  75. for (i=0; i<refSize; i++)
  76. if (refArray[i].status == LOCK)
  77. fn(&refArray[i].o);
  78. }
  79. void luaI_invalidaterefs (void)
  80. {
  81. int i;
  82. for (i=0; i<refSize; i++)
  83. if (refArray[i].status == HOLD && !luaI_ismarked(&refArray[i].o))
  84. refArray[i].status = COLLECTED;
  85. }
  86. /* -------------------------------------------
  87. * Internal Methods
  88. */
  89. char *luaI_eventname[] = { /* ORDER IM */
  90. "gettable", "settable", "index", "getglobal", "setglobal", "add",
  91. "sub", "mul", "div", "pow", "unm", "lt", "le", "gt", "ge",
  92. "concat", "gc", "function",
  93. NULL
  94. };
  95. static int findstring (char *name, char *list[])
  96. {
  97. int i;
  98. for (i=0; list[i]; i++)
  99. if (strcmp(list[i], name) == 0)
  100. return i;
  101. return -1; /* name not found */
  102. }
  103. static int luaI_checkevent (char *name, char *list[])
  104. {
  105. int e = findstring(name, list);
  106. if (e < 0)
  107. luaL_verror("invalid event name `%s'", name);
  108. return e;
  109. }
  110. static struct IM {
  111. lua_Type tp;
  112. TObject int_method[IM_N];
  113. } *luaI_IMtable = NULL;
  114. static int IMtable_size = 0;
  115. static int last_tag = LUA_T_NIL; /* ORDER LUA_T */
  116. static char validevents[NUM_TYPES][IM_N] = { /* ORDER LUA_T, ORDER IM */
  117. {1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_USERDATA */
  118. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_LINE */
  119. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_CMARK */
  120. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_MARK */
  121. {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CFUNCTION */
  122. {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_FUNCTION */
  123. {0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */
  124. {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */
  125. {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, /* LUA_T_NUMBER */
  126. {0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0} /* LUA_T_NIL */
  127. };
  128. static int validevent (lua_Type t, int e)
  129. {
  130. return (t < LUA_T_NIL) ? 1 : validevents[-t][e];
  131. }
  132. static void init_entry (int tag)
  133. {
  134. int i;
  135. for (i=0; i<IM_N; i++)
  136. luaI_IMtable[-tag].int_method[i].ttype = LUA_T_NIL;
  137. }
  138. void luaI_initfallbacks (void)
  139. {
  140. if (luaI_IMtable == NULL) {
  141. int i;
  142. IMtable_size = NUM_TYPES+10;
  143. luaI_IMtable = newvector(IMtable_size, struct IM);
  144. for (i=LUA_T_NIL; i<=LUA_T_USERDATA; i++) {
  145. luaI_IMtable[-i].tp = (lua_Type)i;
  146. init_entry(i);
  147. }
  148. }
  149. }
  150. int lua_newtag (char *t)
  151. {
  152. int tp;
  153. --last_tag;
  154. if ((-last_tag) >= IMtable_size) {
  155. luaI_initfallbacks();
  156. IMtable_size = growvector(&luaI_IMtable, IMtable_size,
  157. struct IM, memEM, MAX_INT);
  158. }
  159. tp = -findstring(t, typenames);
  160. if (tp == LUA_T_ARRAY || tp == LUA_T_USERDATA)
  161. luaI_IMtable[-last_tag].tp = tp;
  162. else
  163. lua_error("invalid type for new tag");
  164. init_entry(last_tag);
  165. return last_tag;
  166. }
  167. static void checktag (int tag)
  168. {
  169. if (!(last_tag <= (tag) && (tag) <= 0))
  170. lua_error("invalid tag");
  171. }
  172. lua_Type luaI_typetag (int tag)
  173. {
  174. if (tag >= 0) return LUA_T_USERDATA;
  175. else {
  176. checktag(tag);
  177. return luaI_IMtable[-tag].tp;
  178. }
  179. }
  180. void luaI_settag (int tag, TObject *o)
  181. {
  182. if (ttype(o) != luaI_typetag(tag))
  183. lua_error("Tag is not compatible with this type");
  184. if (o->ttype == LUA_T_ARRAY)
  185. o->value.a->htag = tag;
  186. else /* must be userdata */
  187. o->value.ts->tag = tag;
  188. }
  189. int luaI_tag (TObject *o)
  190. {
  191. lua_Type t = ttype(o);
  192. if (t == LUA_T_USERDATA)
  193. return o->value.ts->tag;
  194. else if (t == LUA_T_ARRAY)
  195. return o->value.a->htag;
  196. else return t;
  197. }
  198. TObject *luaI_getim (int tag, IMS event)
  199. {
  200. if (tag > LUA_T_USERDATA)
  201. tag = LUA_T_USERDATA; /* default for non-registered tags */
  202. return &luaI_IMtable[-tag].int_method[event];
  203. }
  204. void luaI_setintmethod (void)
  205. {
  206. int t = (int)luaL_check_number(1, "setintmethod");
  207. int e = luaI_checkevent(luaL_check_string(2, "setintmethod"), luaI_eventname);
  208. lua_Object func = lua_getparam(3);
  209. checktag(t);
  210. if (!validevent(t, e))
  211. lua_error("cannot change this internal method");
  212. luaL_arg_check(lua_isnil(func) || lua_isfunction(func), "setintmethod",
  213. 3, "function expected");
  214. luaI_pushobject(&luaI_IMtable[-t].int_method[e]);
  215. luaI_IMtable[-t].int_method[e] = *luaI_Address(func);
  216. }
  217. static TObject errorim = {LUA_T_NIL, {NULL}};
  218. TObject *luaI_geterrorim (void)
  219. {
  220. return &errorim;
  221. }
  222. void luaI_seterrormethod (void)
  223. {
  224. lua_Object func = lua_getparam(1);
  225. luaL_arg_check(lua_isnil(func) || lua_isfunction(func), "seterrormethod",
  226. 1, "function expected");
  227. luaI_pushobject(&errorim);
  228. errorim = *luaI_Address(func);
  229. }
  230. char *luaI_travfallbacks (int (*fn)(TObject *))
  231. {
  232. int e;
  233. if (fn(&errorim))
  234. return "error";
  235. for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */
  236. int t;
  237. for (t=0; t>=last_tag; t--)
  238. if (fn(&luaI_IMtable[-t].int_method[e]))
  239. return luaI_eventname[e];
  240. }
  241. return NULL;
  242. }
  243. /*
  244. * ===================================================================
  245. * compatibility with old fallback system
  246. */
  247. static void errorFB (void)
  248. {
  249. lua_Object o = lua_getparam(1);
  250. if (lua_isstring(o))
  251. fprintf (stderr, "lua: %s\n", lua_getstring(o));
  252. else
  253. fprintf(stderr, "lua: unknown error\n");
  254. }
  255. static void nilFB (void) { }
  256. static void typeFB (void)
  257. {
  258. lua_error("unexpected type");
  259. }
  260. static void fillvalids (IMS e, TObject *func)
  261. {
  262. int t;
  263. for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++)
  264. if (validevent(t, e))
  265. luaI_IMtable[-t].int_method[e] = *func;
  266. }
  267. void luaI_setfallback (void)
  268. {
  269. int e;
  270. TObject oldfunc;
  271. lua_CFunction replace;
  272. char *name = luaL_check_string(1, "setfallback");
  273. lua_Object func = lua_getparam(2);
  274. luaI_initfallbacks();
  275. luaL_arg_check(lua_isfunction(func), "setfallback", 2, "function expected");
  276. if (strcmp(name, "error") == 0) { /* old error fallback */
  277. oldfunc = errorim;
  278. errorim = *luaI_Address(func);
  279. replace = errorFB;
  280. }
  281. else if (strcmp(name, "getglobal") == 0) { /* old getglobal fallback */
  282. oldfunc = luaI_IMtable[-LUA_T_NIL].int_method[IM_GETGLOBAL];
  283. luaI_IMtable[-LUA_T_NIL].int_method[IM_GETGLOBAL] = *luaI_Address(func);
  284. replace = nilFB;
  285. }
  286. else if ((e = findstring(name, luaI_eventname)) >= 0) {
  287. oldfunc = luaI_IMtable[-LUA_T_USERDATA].int_method[e];
  288. fillvalids(e, luaI_Address(func));
  289. replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB;
  290. }
  291. else if (strcmp(name, "arith") == 0) { /* old arith fallback */
  292. int i;
  293. oldfunc = luaI_IMtable[-LUA_T_USERDATA].int_method[IM_POW];
  294. for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */
  295. fillvalids(i, luaI_Address(func));
  296. replace = typeFB;
  297. }
  298. else if (strcmp(name, "order") == 0) { /* old order fallback */
  299. int i;
  300. oldfunc = luaI_IMtable[-LUA_T_USERDATA].int_method[IM_LT];
  301. for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */
  302. fillvalids(i, luaI_Address(func));
  303. replace = typeFB;
  304. }
  305. else {
  306. lua_error("invalid fallback name");
  307. replace = NULL; /* to avoid warnings */
  308. }
  309. if (oldfunc.ttype != LUA_T_NIL)
  310. luaI_pushobject(&oldfunc);
  311. else
  312. lua_pushcfunction(replace);
  313. }