fallback.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. ** fallback.c
  3. ** TecCGraf - PUC-Rio
  4. */
  5. char *rcs_fallback="$Id: fallback.c,v 1.34 1997/03/31 14:02:58 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", "add", "sub", "mul", "div",
  91. "pow", "unm", "lt", "le", "gt", "ge", "concat", "gc", "function",
  92. NULL
  93. };
  94. static char *geventname[] = { /* ORDER GIM */
  95. "error", "getglobal", "setglobal",
  96. NULL
  97. };
  98. static int findstring (char *name, char *list[])
  99. {
  100. int i;
  101. for (i=0; list[i]; i++)
  102. if (strcmp(list[i], name) == 0)
  103. return i;
  104. return -1; /* name not found */
  105. }
  106. static int luaI_checkevent (char *name, char *list[])
  107. {
  108. int e = findstring(name, list);
  109. if (e < 0)
  110. luaL_verror("invalid event name `%s'", name);
  111. return e;
  112. }
  113. static struct IM {
  114. lua_Type tp;
  115. TObject int_method[IM_N];
  116. } *luaI_IMtable = NULL;
  117. static int IMtable_size = 0;
  118. static int last_tag = LUA_T_NIL; /* ORDER LUA_T */
  119. static char validevents[NUM_TYPES][IM_N] = { /* ORDER LUA_T, ORDER IM */
  120. {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_USERDATA */
  121. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_LINE */
  122. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_CMARK */
  123. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* LUA_T_MARK */
  124. {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CFUNCTION */
  125. {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_FUNCTION */
  126. {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */
  127. {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */
  128. {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, /* LUA_T_NUMBER */
  129. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0} /* LUA_T_NIL */
  130. };
  131. static int validevent (lua_Type t, int e)
  132. {
  133. return (t < LUA_T_NIL) ? 1 : validevents[-t][e];
  134. }
  135. static void init_entry (int tag)
  136. {
  137. int i;
  138. for (i=0; i<IM_N; i++)
  139. luaI_IMtable[-tag].int_method[i].ttype = LUA_T_NIL;
  140. }
  141. void luaI_initfallbacks (void)
  142. {
  143. if (luaI_IMtable == NULL) {
  144. int i;
  145. IMtable_size = NUM_TYPES+10;
  146. luaI_IMtable = newvector(IMtable_size, struct IM);
  147. for (i=LUA_T_NIL; i<=LUA_T_USERDATA; i++) {
  148. luaI_IMtable[-i].tp = (lua_Type)i;
  149. init_entry(i);
  150. }
  151. }
  152. }
  153. int lua_newtag (char *t)
  154. {
  155. int tp;
  156. --last_tag;
  157. if ((-last_tag) >= IMtable_size) {
  158. luaI_initfallbacks();
  159. IMtable_size = growvector(&luaI_IMtable, IMtable_size,
  160. struct IM, memEM, MAX_INT);
  161. }
  162. tp = -findstring(t, typenames);
  163. if (tp == LUA_T_ARRAY || tp == LUA_T_USERDATA)
  164. luaI_IMtable[-last_tag].tp = tp;
  165. else
  166. lua_error("invalid type for new tag");
  167. init_entry(last_tag);
  168. return last_tag;
  169. }
  170. static void checktag (int tag)
  171. {
  172. if (!(last_tag <= (tag) && (tag) <= 0))
  173. lua_error("invalid tag");
  174. }
  175. lua_Type luaI_typetag (int tag)
  176. {
  177. if (tag >= 0) return LUA_T_USERDATA;
  178. else {
  179. checktag(tag);
  180. return luaI_IMtable[-tag].tp;
  181. }
  182. }
  183. void luaI_settag (int tag, TObject *o)
  184. {
  185. if (ttype(o) != luaI_typetag(tag))
  186. lua_error("Tag is not compatible with this type");
  187. if (o->ttype == LUA_T_ARRAY)
  188. o->value.a->htag = tag;
  189. else /* must be userdata */
  190. o->value.ts->tag = tag;
  191. }
  192. int luaI_tag (TObject *o)
  193. {
  194. lua_Type t = ttype(o);
  195. if (t == LUA_T_USERDATA)
  196. return o->value.ts->tag;
  197. else if (t == LUA_T_ARRAY)
  198. return o->value.a->htag;
  199. else return t;
  200. }
  201. TObject *luaI_getim (int tag, IMS event)
  202. {
  203. if (tag > LUA_T_USERDATA)
  204. tag = LUA_T_USERDATA; /* default for non-registered tags */
  205. return &luaI_IMtable[-tag].int_method[event];
  206. }
  207. void luaI_setintmethod (void)
  208. {
  209. int t = (int)luaL_check_number(1, "setintmethod");
  210. int e = luaI_checkevent(luaL_check_string(2, "setintmethod"), luaI_eventname);
  211. lua_Object func = lua_getparam(3);
  212. checktag(t);
  213. if (!validevent(t, e))
  214. lua_error("cannot change this internal method");
  215. luaL_arg_check(lua_isnil(func) || lua_isfunction(func), "setintmethod",
  216. 3, "function expected");
  217. luaI_pushobject(&luaI_IMtable[-t].int_method[e]);
  218. luaI_IMtable[-t].int_method[e] = *luaI_Address(func);
  219. }
  220. static TObject gmethod[GIM_N] = {
  221. {LUA_T_NIL, {NULL}}, {LUA_T_NIL, {NULL}}, {LUA_T_NIL, {NULL}}
  222. };
  223. TObject *luaI_getgim (IMGS event)
  224. {
  225. return &gmethod[event];
  226. }
  227. void luaI_setglobalmethod (void)
  228. {
  229. int e = luaI_checkevent(luaL_check_string(1, "setintmethod"), geventname);
  230. lua_Object func = lua_getparam(2);
  231. luaL_arg_check(lua_isnil(func) || lua_isfunction(func), "setintmethod",
  232. 2, "function expected");
  233. luaI_pushobject(&gmethod[e]);
  234. gmethod[e] = *luaI_Address(func);
  235. }
  236. char *luaI_travfallbacks (int (*fn)(TObject *))
  237. {
  238. int e;
  239. for (e=GIM_ERROR; e<=GIM_SETGLOBAL; e++) { /* ORDER GIM */
  240. if (fn(&gmethod[e]))
  241. return geventname[e];
  242. }
  243. for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */
  244. int t;
  245. for (t=0; t>=last_tag; t--)
  246. if (fn(&luaI_IMtable[-t].int_method[e]))
  247. return luaI_eventname[e];
  248. }
  249. return NULL;
  250. }
  251. /*
  252. * ===================================================================
  253. * compatibility with old fallback system
  254. */
  255. static void errorFB (void)
  256. {
  257. lua_Object o = lua_getparam(1);
  258. if (lua_isstring(o))
  259. fprintf (stderr, "lua: %s\n", lua_getstring(o));
  260. else
  261. fprintf(stderr, "lua: unknown error\n");
  262. }
  263. static void nilFB (void) { }
  264. static void typeFB (void)
  265. {
  266. lua_error("unexpected type");
  267. }
  268. static void fillvalids (IMS e, TObject *func)
  269. {
  270. int t;
  271. for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++)
  272. if (validevent(t, e))
  273. luaI_IMtable[-t].int_method[e] = *func;
  274. }
  275. void luaI_setfallback (void)
  276. {
  277. int e;
  278. TObject oldfunc;
  279. lua_CFunction replace;
  280. char *name = luaL_check_string(1, "setfallback");
  281. lua_Object func = lua_getparam(2);
  282. luaL_arg_check(lua_isfunction(func), "setfallback", 2, "function expected");
  283. e = findstring(name, geventname);
  284. if (e >= 0) { /* global event */
  285. oldfunc = gmethod[e];
  286. gmethod[e] = *luaI_Address(func);
  287. replace = (e == GIM_ERROR) ? errorFB : nilFB;
  288. }
  289. else if ((e = findstring(name, luaI_eventname)) >= 0) {
  290. oldfunc = luaI_IMtable[LUA_T_USERDATA].int_method[e];
  291. fillvalids(e, luaI_Address(func));
  292. replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB;
  293. }
  294. else if (strcmp(name, "arith") == 0) { /* old arith fallback */
  295. int i;
  296. oldfunc = luaI_IMtable[LUA_T_USERDATA].int_method[IM_POW];
  297. for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */
  298. fillvalids(i, luaI_Address(func));
  299. replace = typeFB;
  300. }
  301. else if (strcmp(name, "order") == 0) { /* old order fallback */
  302. int i;
  303. oldfunc = luaI_IMtable[LUA_T_USERDATA].int_method[IM_LT];
  304. for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */
  305. fillvalids(i, luaI_Address(func));
  306. replace = typeFB;
  307. }
  308. else {
  309. lua_error("invalid fallback name");
  310. replace = NULL; /* to avoid warnings */
  311. }
  312. if (oldfunc.ttype != LUA_T_NIL)
  313. luaI_pushobject(&oldfunc);
  314. else
  315. lua_pushcfunction(replace);
  316. }