add BSD license
[philodendron.git] / lang_ext / lua / gazelle.c
blob3f72b8dff4850debe84f1ed98da96768a1722b6b
1 /*********************************************************************
3 Gazelle: a system for building fast, reusable grammars
5 gazelle.c
7 These are Lua wrappers for Gazelle.
9 Copyright (c) 2007 Joshua Haberman. See LICENSE for details.
11 *********************************************************************/
13 #include "bc_read_stream_lua.h"
14 #include "interpreter.h"
16 #include "lua.h"
17 #include "lualib.h"
18 #include "lauxlib.h"
20 #include <string.h>
22 struct gazelle_grammar_lua
24 struct grammar *g;
27 struct gazelle_rtn_lua
29 struct rtn *rtn;
32 struct gazelle_rtn_state_lua
34 struct rtn_state *rtn_state;
37 struct gazelle_rtn_transition_lua
39 struct rtn_transition *rtn_transition;
42 static void *newobj(lua_State *L, char *type, int size)
44 void *ptr = lua_newuserdata(L, size);
45 luaL_getmetatable(L, type);
46 lua_setmetatable(L, -2);
47 return ptr;
50 static bool get_from_cache(lua_State *L, void *ptr)
52 static const luaL_reg no_methods[] = {{NULL, NULL}};
53 luaL_register(L, "gazelle", no_methods); /* push the table for this module */
54 lua_getfield(L, -1, "ObjectCache"); /* push our object cache */
56 /* attempt to get our stored value */
57 lua_pushlightuserdata(L, ptr);
58 lua_gettable(L, -2);
60 if(lua_isnil(L, -1))
62 /* object doesn't exist in the cache yet.
63 * leave the mod table and object cache on the stack -- we'll
64 * pop them when the caller makes the (required) call to
65 * put_in_cache() */
66 lua_pop(L, 1);
67 return false;
69 else
71 /* we found the object. pop everything else off the stack and leave it at the top. */
72 lua_replace(L, -3);
73 lua_pop(L, 1);
74 return true;
79 * When this is called the stack looks like:
80 * - mod table
81 * - object cache table
82 * - val to put in cache
84 static void put_in_cache(lua_State *L, void *ptr)
86 lua_pushlightuserdata(L, ptr);
87 lua_pushvalue(L, -2);
88 lua_rawset(L, -4); /* store this in the object cache */
90 lua_replace(L, -3);
92 lua_pop(L, 1); /* pop the mod table */
95 static void get_rtn(lua_State *L, struct rtn *rtn)
97 if(!get_from_cache(L, rtn))
99 struct gazelle_rtn_lua *rtn_obj = newobj(L, "gazelle.rtn", sizeof(*rtn_obj));
100 rtn_obj->rtn = rtn;
101 put_in_cache(L, rtn);
105 static void get_rtn_state(lua_State *L, struct rtn_state *rtn_state)
107 if(!get_from_cache(L, rtn_state))
109 struct gazelle_rtn_state_lua *rtn_state_obj = newobj(L, "gazelle.rtn_state", sizeof(*rtn_state_obj));
110 rtn_state_obj->rtn_state = rtn_state;
111 put_in_cache(L, rtn_state);
117 * global functions
120 static int gazelle_load_grammar(lua_State *L)
122 struct bc_read_stream_lua *s = luaL_checkudata(L, 1, "bc_read_stream");
123 struct gazelle_grammar_lua *g = newobj(L, "gazelle.grammar", sizeof(*g));
124 g->g = load_grammar(s->s);
125 if(!g->g)
126 return luaL_error(L, "Couldn't load grammar!");
127 else
128 return 1;
131 static const luaL_reg global_functions[] =
133 {"load_grammar", gazelle_load_grammar},
134 {NULL, NULL}
138 * methods for "grammar" object
141 static int gazelle_grammar_strings(lua_State *L)
143 struct gazelle_grammar_lua *g = luaL_checkudata(L, 1, "gazelle.grammar");
144 lua_newtable(L);
145 for(int i = 0; g->g->strings[i] != NULL; i++)
147 lua_pushstring(L, g->g->strings[i]);
148 lua_rawseti(L, -2, i+1);
150 return 1;
153 static int gazelle_grammar_rtns(lua_State *L)
155 struct gazelle_grammar_lua *g = luaL_checkudata(L, 1, "gazelle.grammar");
156 lua_newtable(L);
157 for(int i = 0; i < g->g->num_rtns; i++)
159 get_rtn(L, &g->g->rtns[i]);
160 lua_rawseti(L, -2, i+1);
162 return 1;
165 static int gazelle_grammar_rtn(lua_State *L)
167 struct gazelle_grammar_lua *g = luaL_checkudata(L, 1, "gazelle.grammar");
168 const char *rtn_name = luaL_checkstring(L, 2);
169 for(int i = 0; i < g->g->num_rtns; i++)
171 if(strcmp(g->g->rtns[i].name, rtn_name) == 0)
173 get_rtn(L, &g->g->rtns[i]);
174 return 1;
177 return 0;
180 static const luaL_reg grammar_methods[] =
182 {"rtns", gazelle_grammar_rtns},
183 {"rtn", gazelle_grammar_rtn},
184 {"strings", gazelle_grammar_strings},
185 {NULL, NULL}
189 * methods for "rtn" object
192 static int gazelle_rtn_name(lua_State *L)
194 struct gazelle_rtn_lua *rtn = luaL_checkudata(L, 1, "gazelle.rtn");
195 lua_pushstring(L, rtn->rtn->name);
196 return 1;
199 static int gazelle_rtn_num_slots(lua_State *L)
201 struct gazelle_rtn_lua *rtn = luaL_checkudata(L, 1, "gazelle.rtn");
202 lua_pushnumber(L, rtn->rtn->num_slots);
203 return 1;
206 static int gazelle_rtn_ignore_terminals(lua_State *L)
208 struct gazelle_rtn_lua *rtn = luaL_checkudata(L, 1, "gazelle.rtn");
209 lua_newtable(L);
210 for(int i = 0; i < rtn->rtn->num_ignore; i++)
212 lua_pushstring(L, rtn->rtn->ignore_terminals[i]);
213 lua_rawseti(L, -2, i+1);
215 return 1;
218 static int gazelle_rtn_states(lua_State *L)
220 struct gazelle_rtn_lua *rtn = luaL_checkudata(L, 1, "gazelle.rtn");
221 lua_newtable(L);
222 for(int i = 0; i < rtn->rtn->num_states; i++)
224 get_rtn_state(L, &rtn->rtn->states[i]);
225 lua_rawseti(L, -2, i+1);
227 return 1;
230 static const luaL_reg rtn_methods[] =
232 {"name", gazelle_rtn_name},
233 {"num_slots", gazelle_rtn_num_slots},
234 {"ignore_terminals", gazelle_rtn_ignore_terminals},
235 {"states", gazelle_rtn_states},
236 {NULL, NULL}
240 * methods for "rtn_state" objects
243 static int gazelle_rtn_state_is_final(lua_State *L)
245 struct gazelle_rtn_state_lua *rtn_state = luaL_checkudata(L, 1, "gazelle.rtn_state");
246 lua_pushboolean(L, rtn_state->rtn_state->is_final);
247 return 1;
250 static int gazelle_rtn_state_transitions(lua_State *L)
252 struct gazelle_rtn_state_lua *rtn_state = luaL_checkudata(L, 1, "gazelle.rtn_state");
253 lua_newtable(L);
254 for(int i = 0; i < rtn_state->rtn_state->num_transitions; i++)
256 struct rtn_transition *t = &rtn_state->rtn_state->transitions[i];
257 lua_newtable(L);
258 if(t->transition_type == TERMINAL_TRANSITION || t->transition_type == NONTERM_TRANSITION)
260 if(t->transition_type == TERMINAL_TRANSITION)
262 lua_pushstring(L, "terminal");
263 lua_rawseti(L, -2, 1);
264 lua_pushstring(L, t->edge.terminal_name);
265 lua_rawseti(L, -2, 2);
267 else if(t->transition_type == NONTERM_TRANSITION)
269 lua_pushstring(L, "nonterm");
270 lua_rawseti(L, -2, 1);
271 get_rtn(L, t->edge.nonterminal);
272 lua_rawseti(L, -2, 2);
275 get_rtn_state(L, t->dest_state);
276 lua_rawseti(L, -2, 3);
277 lua_pushstring(L, t->slotname);
278 lua_rawseti(L, -2, 4);
279 lua_pushnumber(L, t->slotnum);
280 lua_rawseti(L, -2, 5);
282 else if(t->transition_type == DECISION)
284 lua_pushstring(L, "decision");
285 lua_rawseti(L, -2, 1);
286 lua_pushstring(L, t->edge.decision->terminal_name);
287 lua_rawseti(L, -2, 2);
289 lua_newtable(L);
290 for(int j = 0; j < t->edge.decision->num_actions; j++)
292 lua_pushnumber(L, t->edge.decision->actions[j]);
293 lua_rawseti(L, -2, j+1);
295 lua_rawseti(L, -2, 3);
297 else
299 printf("%d\n", t->transition_type);
300 return luaL_error(L, "corrupt grammar: invalid transition type!");
303 lua_rawseti(L, -2, i+1);
305 return 1;
308 static const luaL_reg rtn_state_methods[] =
310 {"is_final", gazelle_rtn_state_is_final},
311 {"transitions", gazelle_rtn_state_transitions},
312 {NULL, NULL}
316 * methods for "rtn_transition" objects
319 static const luaL_reg rtn_transition_methods[] =
321 {"is_final", gazelle_rtn_state_is_final},
322 {"transitions", gazelle_rtn_state_transitions},
323 {NULL, NULL}
326 void register_object(lua_State *L, char *obj_name, const luaL_reg *methods)
328 luaL_newmetatable(L, obj_name);
330 /* metatable.__index = metatable */
331 lua_pushvalue(L, -1); /* duplicates the metatable */
332 lua_setfield(L, -2, "__index");
334 luaL_register(L, NULL, methods);
337 int luaopen_gazelle(lua_State *L)
339 register_object(L, "gazelle.grammar", grammar_methods);
340 register_object(L, "gazelle.rtn", rtn_methods);
341 register_object(L, "gazelle.rtn_state", rtn_state_methods);
343 luaL_register(L, "gazelle", global_functions);
344 lua_newtable(L);
345 lua_setfield(L, -2, "ObjectCache");
347 return 1;
351 * Local Variables:
352 * c-file-style: "bsd"
353 * c-basic-offset: 2
354 * indent-tabs-mode: nil
355 * End:
356 * vim:et:sts=2:sw=2