lua_term.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. #include "lua_lsup.h"
  2. #include "stackdump.h"
  3. #define check_term(L) \
  4. *(LSUP_Term **)luaL_checkudata(L, 1, "LSUP.Term")
  5. LSUP_Term **allocate_term (lua_State *L)
  6. {
  7. LSUP_Term **tp = lua_newuserdatauv (L, sizeof (*tp), 1);
  8. luaL_getmetatable (L, "LSUP.Term");
  9. lua_setmetatable (L, -2);
  10. return tp;
  11. }
  12. LSUP_TermSet **allocate_tset (lua_State *L)
  13. {
  14. LSUP_TermSet **ts_p = lua_newuserdatauv (L, sizeof (*ts_p), 1);
  15. luaL_getmetatable (L, "LSUP.TermSet");
  16. lua_setmetatable (L, -2);
  17. return ts_p;
  18. }
  19. /*
  20. * Factory methods.
  21. */
  22. static int l_new_iriref (lua_State *L)
  23. {
  24. const char *data = luaL_checkstring (L, 1);
  25. // TODO handle nsm.
  26. LSUP_NSMap *nsm = lua_touserdata (L, 2);
  27. LSUP_Term **tp = allocate_term (L);
  28. *tp = LSUP_iriref_new (data, nsm);
  29. LUA_NLCHECK (*tp, "Error creating term.");
  30. return 1;
  31. }
  32. static int l_new_iriref_abs (lua_State *L)
  33. {
  34. LSUP_Term
  35. *root = check_term (L),
  36. *iri = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  37. LSUP_Term **tp = allocate_term (L);
  38. *tp = LSUP_iriref_absolute (root, iri);
  39. LUA_NLCHECK (*tp, "Error creating term.");
  40. return 1;
  41. }
  42. static int l_new_iriref_rel (lua_State *L)
  43. {
  44. LSUP_Term
  45. *root = check_term (L),
  46. *iri = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  47. LSUP_Term **tp = allocate_term (L);
  48. *tp = LSUP_iriref_relative (root, iri);
  49. LUA_NLCHECK (*tp, "Error creating term.");
  50. return 1;
  51. }
  52. /** @brief create a new literal.
  53. *
  54. * Argument 2 (data type) and 3 (lang) are exclusive. If both are specified,
  55. * datatype has precedence. If both are nil, datatype is set to the default
  56. * (xsd:string).
  57. */
  58. static int l_new_lit (lua_State *L)
  59. {
  60. const char
  61. *data = luaL_checkstring (L, 1),
  62. *dtype_str = lua_tostring (L, 2);
  63. const char *lang = lua_tostring (L, 3);
  64. LSUP_Term **tp = allocate_term (L);
  65. LSUP_Term *dtype;
  66. if (dtype_str) {
  67. // TODO check memory leak.
  68. dtype = LSUP_iriref_new (dtype_str, LSUP_default_nsm);
  69. *tp = LSUP_literal_new (data, dtype);
  70. }
  71. else if (lang) *tp = LSUP_lt_literal_new (data, (char *)lang);
  72. else *tp = LSUP_literal_new (data, NULL);
  73. LUA_NLCHECK (*tp, "Error creating term.");
  74. return 1;
  75. }
  76. static int l_new_bnode (lua_State *L)
  77. {
  78. const char *data = lua_tostring (L, 1);
  79. LSUP_Term **tp = allocate_term (L);
  80. *tp = LSUP_bnode_new (data);
  81. LUA_NLCHECK (*tp, "Error creating term.");
  82. return 1;
  83. }
  84. static int l_new_copy (lua_State *L)
  85. {
  86. LSUP_Term *src = check_term (L);
  87. LSUP_Term **tp = allocate_term (L);
  88. *tp = LSUP_term_copy (src);
  89. LUA_NLCHECK (*tp, "Error creating term.");
  90. return 1;
  91. }
  92. /*
  93. * Class methods.
  94. */
  95. static int l_term_equals (lua_State *L)
  96. {
  97. LSUP_Term
  98. *t1 = check_term (L),
  99. *t2 = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  100. lua_pushboolean (L, LSUP_term_equals (t1, t2));
  101. return 1;
  102. }
  103. static int l_term_gc (lua_State *L)
  104. {
  105. LSUP_Term **tp = luaL_checkudata(L, 1, "LSUP.Term");
  106. LOG_TRACE ("Garbage collecting term @%p", *tp);
  107. LSUP_term_free (*tp);
  108. *tp = NULL;
  109. return 0;
  110. }
  111. /*
  112. static int l_term_to_string (lua_State *L)
  113. {
  114. LSUP_Term *t = check_term (L);
  115. char *nt_term = NULL;
  116. CHECK (nt_codec.encode_term (t, NULL, &nt_term), fail);
  117. lua_pushfstring (L, "LSUP.Term @%p %s", t, nt_term);
  118. return 1;
  119. fail:
  120. if (nt_term) free (nt_term);
  121. return luaL_error (L, "Error encoding term for display!");
  122. }
  123. */
  124. static int l_term_to_n3 (lua_State *L)
  125. {
  126. LSUP_Term *t = check_term (L);
  127. char *nt_term = NULL;
  128. CHECK (nt_codec.encode_term (t, NULL, &nt_term), fail);
  129. lua_pushstring (L, nt_term);
  130. free (nt_term);
  131. return 1;
  132. fail:
  133. if (nt_term) free (nt_term);
  134. return luaL_error (L, "Error encoding term for display.");
  135. }
  136. /*
  137. * Getters.
  138. */
  139. // Forward declaration.
  140. static const luaL_Reg term_getters [];
  141. static int l_term_get_attr (lua_State *L)
  142. {
  143. const char *attr = luaL_checkstring (L, 2);
  144. //printf ("Got attr: %s\n", attr);
  145. if (luaL_getmetafield (L, 1, attr) != LUA_TNIL)
  146. return 1; // Return metamethod to be called as a function.
  147. luaL_getmetafield (L, 1, "getters");
  148. if (lua_getfield (L, -1, attr) != LUA_TNIL)
  149. return lua_tocfunction (L, -1)(L);
  150. return 0;
  151. }
  152. static int get_data (lua_State *L)
  153. {
  154. LSUP_Term *t = check_term (L);
  155. lua_pushstring (L, t->data);
  156. return 1;
  157. }
  158. static int get_type (lua_State *L)
  159. {
  160. LSUP_Term *t = check_term (L);
  161. lua_pushinteger (L, t->type);
  162. return 1;
  163. }
  164. static int get_iriref_nsm (lua_State *L)
  165. {
  166. LSUP_Term *t = check_term (L);
  167. // TODO
  168. lua_pushlightuserdata (L, LSUP_iriref_nsm (t));
  169. return 1;
  170. }
  171. static int get_iriref_prefix (lua_State *L)
  172. {
  173. LSUP_Term *t = check_term (L);
  174. lua_pushstring (L, LSUP_iriref_prefix (t));
  175. return 1;
  176. }
  177. static int get_iriref_path (lua_State *L)
  178. {
  179. LSUP_Term *t = check_term (L);
  180. lua_pushstring (L, LSUP_iriref_path (t));
  181. return 1;
  182. }
  183. static int get_iriref_frag (lua_State *L)
  184. {
  185. LSUP_Term *t = check_term (L);
  186. lua_pushstring (L, LSUP_iriref_frag (t));
  187. return 1;
  188. }
  189. static int get_lit_datatype (lua_State *L)
  190. {
  191. printf ("Getting datatype.\n");
  192. LSUP_Term *t = check_term (L);
  193. if (!LSUP_IS_LITERAL (t))
  194. return luaL_error (L, "Term is not a literal.", 2);
  195. lua_pushstring (L, t->datatype->data);
  196. return 1;
  197. }
  198. static int get_lit_lang (lua_State *L)
  199. {
  200. LSUP_Term *t = check_term (L);
  201. if (!LSUP_IS_LITERAL (t))
  202. return luaL_error (L, "Term is not a literal.", 2);
  203. lua_pushstring (L, t->lang);
  204. return 1;
  205. }
  206. static int get_hash (lua_State *L)
  207. {
  208. LSUP_Term *t = check_term (L);
  209. lua_pushinteger (L, LSUP_term_hash (t));
  210. return 1;
  211. }
  212. /*
  213. * Setters.
  214. */
  215. // Very simple for now.
  216. //static const luaL_Reg term_setters [];
  217. static int l_term_set_attr (lua_State *L)
  218. { return luaL_error (L, "Direct setting is not allowed for this type.", 2); }
  219. /*
  220. * Ancillary types
  221. */
  222. /*
  223. * Term set.
  224. */
  225. static int term_set_iter_next (lua_State *L)
  226. {
  227. LSUP_TermSet *ts =
  228. *(LSUP_TermSet **)lua_touserdata (L, lua_upvalueindex (1));
  229. size_t *ip = lua_touserdata (L, lua_upvalueindex (2));
  230. LSUP_Term *tmp;
  231. LSUP_rc rc = LSUP_term_set_next (ts, ip, &tmp);
  232. LUA_PCHECK (rc, "Error iterating over term set");
  233. if (rc == LSUP_END) {
  234. free (ip);
  235. return 0;
  236. }
  237. LSUP_Term **tp = allocate_term (L);
  238. *tp = LSUP_term_copy (tmp);
  239. if (!*tp) {
  240. free (ip);
  241. luaL_error (L, "Error allocating term.");
  242. }
  243. return 1;
  244. }
  245. static int l_term_set_iter_init (lua_State *L)
  246. {
  247. size_t *ip = malloc (sizeof (*ip));
  248. LUA_NLCHECK (ip, "Error allocating tset iterator.");
  249. *ip = 0;
  250. lua_pushlightuserdata (L, ip);
  251. STACK_DUMP(L, "Before pushing tset next closure");
  252. lua_pushcclosure (L, term_set_iter_next, 2);
  253. return 1;
  254. }
  255. static int term_set_gc (lua_State *L)
  256. {
  257. LSUP_TermSet **ts_p = lua_touserdata (L, 1);
  258. LSUP_term_set_free (*ts_p);
  259. *ts_p = NULL;
  260. return 0;
  261. }
  262. /*
  263. * Link map.
  264. */
  265. static int lmap_iter_next (lua_State *L)
  266. {
  267. LSUP_LinkMapIterator *it =
  268. *(LSUP_LinkMapIterator **)lua_touserdata (L, lua_upvalueindex (1));
  269. LSUP_Term **link_p = (LSUP_Term **)lua_newuserdata (L, sizeof *link_p);
  270. *link_p = NULL;
  271. luaL_getmetatable (L, "LSUP.Term");
  272. lua_setmetatable (L, -2);
  273. LSUP_TermSet *ts = NULL;
  274. LSUP_Term *tmp = NULL;
  275. LSUP_rc rc = LSUP_link_map_next (it, &tmp, &ts);
  276. if (rc != LSUP_OK) {
  277. if (rc == LSUP_END) return 0;
  278. else LUA_PCHECK (rc, "Error iterating over link map");
  279. }
  280. *link_p = LSUP_term_copy (tmp);
  281. LUA_NLCHECK (*link_p, "Error allocating term.");
  282. size_t i = 0;
  283. tmp = NULL;
  284. lua_newtable (L);
  285. while ((rc = LSUP_term_set_next (ts, &i, &tmp)) == LSUP_OK) {
  286. LSUP_Term **t2_p = (LSUP_Term **)lua_newuserdata (L, sizeof *t2_p);
  287. luaL_getmetatable (L, "LSUP.Term");
  288. lua_setmetatable (L, -2);
  289. *t2_p = LSUP_term_copy (tmp);
  290. lua_pushboolean (L, true);
  291. lua_rawset (L, -3);
  292. }
  293. LUA_PCHECK (rc, "Error iterating over term set");
  294. // linked term + term set.
  295. return 2;
  296. }
  297. /**
  298. * Internally this function creates a LMapIterator, which is used as the
  299. * upvalue for lmap_iter_next(). The iterator is garbage collected at the end
  300. * of the iteration loop, the link map can be reused.
  301. */
  302. static int l_lmap_iter_init (lua_State *L)
  303. {
  304. STACK_DUMP (L, "beginning of LMap iter init fn");
  305. LSUP_LinkMap *lm = *(LSUP_LinkMap **)luaL_checkudata(L, 1, "LSUP.LinkMap");
  306. LSUP_LinkMapIterator **lmit_p =
  307. (LSUP_LinkMapIterator **)lua_newuserdata (L, sizeof *lmit_p);
  308. *lmit_p = LSUP_link_map_iter_new (lm);
  309. luaL_getmetatable (L, "LSUP.LMapIterator");
  310. lua_setmetatable (L, -2);
  311. lua_pushcclosure (L, lmap_iter_next, 1);
  312. STACK_DUMP (L, "After pushing iter closure");
  313. return 1;
  314. }
  315. static int link_map_gc (lua_State *L)
  316. {
  317. LSUP_LinkMap **lm_p = lua_touserdata (L, 1);
  318. LOG_DEBUG ("Garbage collecting link map @%p", *lm_p);
  319. // FIXME This is to prevent a double-free on shutdown.
  320. // Must find the culprit instead.
  321. if (UNLIKELY (!lm_p || !*lm_p)) return 0;
  322. LSUP_link_map_free (*lm_p);
  323. *lm_p = NULL;
  324. return 0;
  325. }
  326. static int lmap_iter_gc (lua_State *L)
  327. {
  328. LSUP_LinkMapIterator *it = *(LSUP_LinkMapIterator **)lua_touserdata (L, 1);
  329. LOG_DEBUG ("Garbage collecting link map iterator @%p", it);
  330. LSUP_link_map_iter_free (it);
  331. return 0;
  332. }
  333. /*
  334. * Library setup.
  335. */
  336. static const luaL_Reg term_lib_fn [] = {
  337. {"new_iriref", l_new_iriref},
  338. {"new_iriref_abs", l_new_iriref_abs},
  339. {"new_iriref_rel", l_new_iriref_rel},
  340. {"new_lit", l_new_lit},
  341. {"new_bnode", l_new_bnode},
  342. {"new_copy", l_new_copy},
  343. {NULL}
  344. };
  345. static const luaL_Reg term_getters [] = {
  346. // General getters.
  347. {"data", get_data},
  348. {"type", get_type},
  349. // IRIRef getters.
  350. {"nsm", get_iriref_nsm},
  351. {"prefix", get_iriref_prefix},
  352. {"path", get_iriref_path},
  353. {"frag", get_iriref_frag},
  354. // Literal getters.
  355. {"datatype", get_lit_datatype},
  356. {"lang", get_lit_lang},
  357. // Generic getters.
  358. {"hash", get_hash},
  359. {NULL}
  360. };
  361. /*
  362. static const luaL_Reg term_setters [] = {
  363. {NULL}
  364. };
  365. */
  366. static const luaL_Reg term_lib_meth [] = {
  367. {"__eq", l_term_equals},
  368. {"__gc", l_term_gc},
  369. {"__index", l_term_get_attr},
  370. {"__tostring", l_term_to_n3},
  371. {"__newindex", l_term_set_attr},
  372. {NULL}
  373. };
  374. static const LEnumConst term_enums[] = {
  375. {"TYPE_IRIREF", LSUP_TERM_IRIREF},
  376. {"TYPE_NS_IRIREF", LSUP_TERM_NS_IRIREF},
  377. {"TYPE_LITERAL", LSUP_TERM_LITERAL},
  378. {"TYPE_LT_LITERAL", LSUP_TERM_LT_LITERAL},
  379. {"TYPE_BNODE", LSUP_TERM_BNODE},
  380. {"LINK_INBOUND", LSUP_LINK_INBOUND},
  381. {"LINK_OUTBOUND", LSUP_LINK_OUTBOUND},
  382. {"LINK_EDGE", LSUP_LINK_EDGE},
  383. {NULL, 0}
  384. };
  385. static const LStringConst term_strings[] = {
  386. {"RDF_TYPE", LSUP_RDF_TYPE},
  387. {"RDF_TYPE_NS", LSUP_RDF_TYPE_NS},
  388. {"DEFAULT_DTYPE", DEFAULT_DTYPE},
  389. {"DEFAULT_DTYPE_NS", DEFAULT_DTYPE_NS},
  390. {NULL, 0}
  391. };
  392. int luaopen_lsup_term (lua_State *L)
  393. {
  394. LSUP_init(); // This is idempotent: no problem calling it multiple times.
  395. luaL_newmetatable (L, "LSUP.Term");
  396. luaL_setfuncs (L, term_lib_meth, 0);
  397. // Getters table.
  398. lua_newtable (L);
  399. for (int i = 0; term_getters[i].name != NULL; i++) {
  400. lua_pushcfunction (L, term_getters[i].func);
  401. lua_setfield (L, -2, term_getters[i].name);
  402. }
  403. // Set getters table as a value for the Term metatable.
  404. lua_setfield (L, -2, "getters");
  405. /*
  406. * Metatables for ancillary types.
  407. */
  408. // Term set.
  409. luaL_newmetatable (L, "LSUP.TermSet");
  410. lua_pushcfunction (L, term_set_gc);
  411. lua_setfield (L, -2, "__gc");
  412. lua_pushcfunction (L, l_term_set_iter_init);
  413. lua_setfield (L, -2, "__pairs");
  414. // Link map.
  415. luaL_newmetatable (L, "LSUP.LinkMap");
  416. lua_pushcfunction (L, link_map_gc);
  417. lua_setfield (L, -2, "__gc");
  418. lua_pushcfunction (L, l_lmap_iter_init);
  419. lua_setfield (L, -2, "__pairs");
  420. // Link map iterator.
  421. luaL_newmetatable (L, "LSUP.LMapIterator");
  422. lua_pushcfunction (L, lmap_iter_gc);
  423. lua_setfield (L, -2, "__gc");
  424. luaL_newlib (L, term_lib_fn);
  425. // Module-level constants.
  426. push_string_const (L, term_strings);
  427. push_int_const (L, term_enums);
  428. return 1;
  429. }