#include "lua_lsup.h" #include "stackdump.h" #define check_graph(L) \ *(LSUP_Graph **)luaL_checkudata(L, 1, "LSUP.Graph") static LSUP_Graph **allocate_graph (lua_State *L) { LSUP_Graph **gp = lua_newuserdatauv (L, sizeof (*gp), 1); luaL_getmetatable (L, "LSUP.Graph"); lua_setmetatable (L, -2); return gp; } static int l_graph_new (lua_State *L) { const LSUP_StoreType store_type = lua_tointeger (L, 1); const char *uri_str = lua_tostring (L, 2); LSUP_Graph **gp = allocate_graph (L); LSUP_Store *store = NULL; if (store_type) { const LSUP_StoreInt *sif = LSUP_store_int (store_type); if (UNLIKELY (!sif)) return luaL_error ( L, "No interface defined for store type: %d.", store_type); // TODO Move store creation fn and handle into a separate module. store = LSUP_store_new (store_type, NULL, 0); // Set up the store if a function for that is defined. if (sif->setup_fn) { if (sif->setup_fn(NULL, false) < LSUP_OK) return luaL_error (L, "Error initializing back end store."); } } // TODO Make store ID, nsm and initial size accessible. *gp = LSUP_graph_new (store, uri_str, NULL); LUA_NLCHECK (*gp, "Error creating graph."); return 1; } /* * Class methods. */ static int l_graph_gc (lua_State *L) { LSUP_Graph *gr = check_graph (L); if (gr) LSUP_graph_free (gr); return 0; } static int l_graph_to_string (lua_State *L) { const LSUP_Graph *gr = check_graph (L); lua_pushfstring ( L, "LSUP.Graph @%p <%s>: %d triples", gr, LSUP_graph_uri (gr)->data, LSUP_graph_size (gr)); return 1; } static int l_graph_len (lua_State *L) { const LSUP_Graph *gr = check_graph (L); lua_pushinteger (L, LSUP_graph_size (gr)); return 1; } static int l_graph_copy (lua_State *L) { const LSUP_Graph *src = check_graph (L); LSUP_Graph *dest = *(LSUP_Graph **)luaL_checkudata(L, 2, "LSUP.Graph"); LUA_PCHECK (LSUP_graph_copy (src, dest), "Error copying graph"); return 1; } static int l_graph_copy_contents (lua_State *L) { const LSUP_Graph *src = check_graph (L); LSUP_Graph *dest = *(LSUP_Graph **)luaL_checkudata (L, 2, "LSUP.Graph"); const LSUP_Term *s, *p, *o; if lua_isnoneornil (L, 3) s = NULL; else s = *(LSUP_Term **)luaL_checkudata (L, 3, "LSUP.Term"); if lua_isnoneornil (L, 4) p = NULL; else p = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term"); if lua_isnoneornil (L, 5) o = NULL; else o = *(LSUP_Term **)luaL_checkudata (L, 5, "LSUP.Term"); LUA_PCHECK (LSUP_graph_copy_contents ( src, dest, s, p, o), "Error copying graph."); return 1; } static int l_graph_equals (lua_State *L) { const LSUP_Graph *gr1 = check_graph (L); const LSUP_Graph *gr2 = *(LSUP_Graph **)luaL_checkudata (L, 2, "LSUP.Graph"); LOG_DEBUG ("Comparing graphs %p %p", gr1, gr2); int eq_rc = LSUP_graph_equals (gr1, gr2); lua_pushboolean (L, eq_rc); return 1; } static int l_graph_contains (lua_State *L) { const LSUP_Graph *gr = check_graph (L); const LSUP_Triple *spo = *(LSUP_Triple **)luaL_checkudata (L, 2, "LSUP.Triple"); lua_pushboolean (L, LSUP_graph_contains (gr, spo)); return 1; } static int l_graph_add (lua_State *L) { LSUP_Graph *gr = check_graph (L); LOG_DEBUG ("Triples type: %s", lua_typename (L, lua_type (L, 2))); int rc; LSUP_rc lsup_rc; size_t i = 0, ct = 0; LSUP_GraphIterator *it = LSUP_graph_add_init (gr); while ((rc = lua_rawgeti (L, 2, ++i)) != LUA_TNIL) { //LOG_DEBUG ("Triple type: %s", lua_typename (L, rc)); const LSUP_Triple *spo = *(LSUP_Triple **)luaL_checkudata (L, -1, "LSUP.Triple"); LOG_DEBUG ( "Got triple %d: {%s %s %s}\n", i, spo->s->data, spo->p->data, spo->o->data); lsup_rc = LSUP_graph_add_iter (it, spo); if (lsup_rc < LSUP_OK) break; if (lsup_rc == LSUP_OK) ct++; }; LSUP_graph_add_done (it); lua_pushinteger (L, ct); if (UNLIKELY (lsup_rc < LSUP_OK)) return luaL_error ( L, "Error adding triple at position %d: %s", i, LSUP_strerror (lsup_rc)); else return 1; } static int graph_iter_next (lua_State *L) { LSUP_GraphIterator *it = *(LSUP_GraphIterator **)lua_touserdata (L, lua_upvalueindex (1)); LSUP_Triple **spo_p = lua_newuserdatauv (L, sizeof (*spo_p), 1); luaL_getmetatable (L, "LSUP.Triple"); lua_setmetatable (L, -2); LSUP_rc rc = LSUP_graph_iter_next (it, spo_p); if (rc == LSUP_END) { lua_pushnil (L); lua_pushstring (L, "End of lookup results."); return 2; } LUA_PCHECK (rc, "Error retrieving a lookup result."); return 1; } static int l_graph_lookup (lua_State *L) { const LSUP_Graph *gr = check_graph (L); const LSUP_Term *s, *p, *o; if lua_isnoneornil (L, 2) s = NULL; else s = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term"); if lua_isnoneornil (L, 3) p = NULL; else p = *(LSUP_Term **)luaL_checkudata (L, 3, "LSUP.Term"); if lua_isnoneornil (L, 4) o = NULL; else o = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term"); LSUP_GraphIterator **it_p = (LSUP_GraphIterator **)lua_newuserdata (L, sizeof *it_p); *it_p = NULL; luaL_getmetatable (L, "LSUP.GraphIterator"); lua_setmetatable (L, -2); size_t ct; *it_p = LSUP_graph_lookup (gr, s, p, o, &ct); LUA_NLCHECK (*it_p, "Error creating graph iterator."); LOG_DEBUG ("Found triples: %d", ct); lua_pushcclosure (L, graph_iter_next, 1); return 1; } static int graph_iter_gc (lua_State *L) { LSUP_GraphIterator *it = *(LSUP_GraphIterator **)lua_touserdata (L, 1); LSUP_graph_iter_free (it); } static int conn_iter_done (lua_State *L) { LSUP_LinkMapIterator *it = *(LSUP_LinkMapIterator **)lua_touserdata (L, lua_upvalueindex (1)); LSUP_link_map_iter_free (it); return 0; } static int lmap_iter_next (lua_State *L) { LSUP_LinkMapIterator *it = *(LSUP_LinkMapIterator **)lua_touserdata (L, lua_upvalueindex (1)); LSUP_Term **link_p = (LSUP_Term **)lua_newuserdata (L, sizeof *link_p); *link_p = NULL; LSUP_TermSet *ts = NULL; LSUP_rc rc = LSUP_link_map_next (it, link_p, &ts); if (rc != LSUP_OK) { if (rc == LSUP_END) { LSUP_link_map_iter_free (it); lua_pushnil (L); lua_pushstring (L, "End of the loop."); return 2; } else LUA_PCHECK (rc, "Error iterating through link map"); } size_t i = 0; LSUP_Term *conn = NULL; lua_newtable (L); while (LSUP_term_set_next (ts, &i, &conn)) { LSUP_Term **conn_p = (LSUP_Term **)lua_newuserdata (L, sizeof *conn_p); *conn_p = conn; lua_pushboolean (L, true); lua_rawset (L, -3); } return 2; } static int l_lmap_iter_init (lua_State *L) { LSUP_LinkMap *lm = *(LSUP_LinkMap **)luaL_checkudata(L, 1, "LSUP.LinkMap"); LSUP_LinkMapIterator **lmit_p = (LSUP_LinkMapIterator **)lua_newuserdata (L, sizeof *lmit_p); *lmit_p = LSUP_link_map_iter_new (lm); luaL_getmetatable (L, "LSUP.LMapIterator"); lua_setmetatable (L, -2); stackDump (L, "After allocating LMIter"); lua_pushcclosure (L, lmap_iter_next, 1); return 1; } /** Returns a LinkMap that can be iterated over with iter(). */ static int l_graph_connections (lua_State *L) { const LSUP_Graph *gr = check_graph (L); LSUP_Term *t = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term"); const LSUP_LinkType type = luaL_checkinteger (L, 3); LSUP_LinkMap **lm_p = (LSUP_LinkMap **)lua_newuserdata (L, sizeof *lm_p); *lm_p = LSUP_graph_connections (gr, t, type); luaL_getmetatable (L, "LSUP.LinkMap"); lua_setmetatable (L, -2); return 1; } static int link_map_gc (lua_State *L) { LSUP_LinkMap *lm = *(LSUP_LinkMap **)lua_touserdata (L, 1); LSUP_link_map_free (lm); return 0; } static int lmap_iter_gc (lua_State *L) { LSUP_LinkMapIterator *it = *(LSUP_LinkMapIterator **)lua_touserdata (L, 1); LSUP_link_map_iter_free (it); return 0; } static int l_graph_term_set (lua_State *L) { const LSUP_Graph *gr = check_graph (L); return 1; } static int l_graph_unique_terms (lua_State *L) { const LSUP_Graph *gr = check_graph (L); return 1; } /* * Library setup. */ static const luaL_Reg graph_lib_fn [] = { {"new", l_graph_new}, {NULL} }; /* static const luaL_Reg graph_getters [] = { {"uri", l_graph_get_uri}, {"namespace", l_graph_get_nsm}, {NULL} }; */ /* static const luaL_Reg graph_setters [] = { {"uri", l_graph_set_uri}, {NULL} }; */ static const luaL_Reg graph_lib_meth [] = { {"__eq", l_graph_equals}, {"__gc", l_graph_gc}, //{"__index", get_attr}, //{"__newindex", set_attr}, {"__tostring", l_graph_to_string}, {"__len", l_graph_len}, {"copy", l_graph_copy}, {"copy_contents", l_graph_copy_contents}, {"contains", l_graph_contains}, {"add", l_graph_add}, {"lookup", l_graph_lookup}, {"connections", l_graph_connections}, {"term_set", l_graph_term_set}, {"unique_terms", l_graph_unique_terms}, //{"to_n3", l_graph_to_n3}, {NULL} }; static const LEnumConst graph_enums[] = { {"LINK_INBOUND", LSUP_LINK_INBOUND}, {"LINK_OUTBOUND", LSUP_LINK_OUTBOUND}, {"LINK_EDGE", LSUP_LINK_EDGE}, {NULL, 0} }; int luaopen_lsup_graph (lua_State *L) { LSUP_init(); // This is idempotent: no problem calling it multiple times. luaL_newmetatable (L, "LSUP.Graph"); lua_pushvalue (L, -1); lua_setfield (L, -2, "__index"); luaL_setfuncs (L, graph_lib_meth, 0); // Metatables for ancillary types. luaL_newmetatable (L, "LSUP.GraphIterator"); lua_pushcfunction (L, graph_iter_gc); lua_setfield (L, -2, "__gc"); luaL_newmetatable (L, "LSUP.LinkMap"); lua_pushcfunction (L, link_map_gc); lua_setfield (L, -2, "__gc"); luaL_newmetatable (L, "LSUP.LMapIterator"); lua_pushcfunction (L, lmap_iter_gc); lua_setfield (L, -2, "__gc"); /* // Getters table. lua_newtable (L); for (int i = 0; graph_getters[i].name != NULL; i++) { lua_pushcfunction (L, graph_getters[i].func); lua_setfield (L, -2, graph_getters[i].name); } // Set getters table as a value for the Graph metatable. lua_setfield (L, -2, "getters"); */ luaL_newlib (L, graph_lib_fn); // Module-level constants. push_int_const (L, graph_enums); return 1; }