/* * Hic Est Leo -- Bindings for Lua * * (c) 2015 Martin Mares */ %module leo %nodefaultctor; %{ #include "leo.h" #include "osm.h" #include "css.h" #include "expr.h" #include #include %} /*** Proxy for OSM object attributes ***/ %{ struct proxy_tag { struct osm_object *o; }; static void push_proxy_tag(lua_State *L, struct proxy_tag *t) { SWIG_NewPointerObj(L, t, SWIGTYPE_p_proxy_tag, 0); } static const char *proxy_tag_index(struct proxy_tag *t, const char *key) { osm_key_t k = osm_key_encode(key); osm_val_t v = osm_obj_find_tag(t->o, k); return osm_val_decode(v); } %} struct proxy_tag { }; %extend proxy_tag { const char *index(const char *key); }; %init %{ // This overrides default index function generated by SWIG. // The tag proxy therefore cannot have any methods. SWIG_Lua_get_class_metatable(L, "proxy_tag"); SWIG_Lua_add_function(L, "__index", _wrap_proxy_tag_index); lua_pop(L, 1); %} /*** Proxy for style properties ***/ %{ struct proxy_style { struct style_results *sr; layer_t layer; }; static void push_proxy_style(lua_State *L, struct proxy_style *s) { SWIG_NewPointerObj(L, s, SWIGTYPE_p_proxy_style, 0); } static struct style_prop *proxy_style_index(struct proxy_style *s, const char *key) { prop_t k = style_prop_encode(key); return style_get_by_layer(s->sr, s->layer, k); } static void proxy_style_newindex(struct proxy_style *s, const char *key, struct style_prop *p) { p->key = style_prop_encode(key); style_set_by_layer(s->sr, s->layer, p); } static void push_style_prop(lua_State *L, struct style_prop *p) { if (!p) { lua_pushnil(L); return; } switch (p->type) { case PROP_TYPE_STRING: lua_pushstring(L, osm_val_decode(p->val.id)); break; case PROP_TYPE_NUMBER: lua_pushnumber(L, (lua_Number) p->val.number); break; default: msg(L_WARN, "Property %s has value with no LUA representation", style_prop_decode(p->key)); lua_pushnil(L); } } static const char *decode_style_prop(lua_State *L, int idx, struct style_prop *p) { if (lua_isnil(L, idx)) return "Cannot set property to nil. Yet."; // FIXME if (lua_isnumber(L, idx)) // FIXME: numbers vs. strings { p->type = PROP_TYPE_NUMBER; p->val.number = lua_tonumber(L, idx); return NULL; } if (lua_isstring(L, idx)) { p->type = PROP_TYPE_STRING; p->val.id = osm_val_encode(lua_tostring(L, idx)); return NULL; } return "Invalid type of style property"; } %} %typemap(out) struct style_prop * { push_style_prop(L, $1); SWIG_arg++; } %typemap(in) struct style_prop * (const char *err, struct style_prop prop) { err = decode_style_prop(L, $input, &prop); if (err) { lua_pushstring(L, err); SWIG_fail; } $1 = ∝ } struct proxy_style { }; %extend proxy_style { struct style_prop *index(const char *key); void newindex(const char *key, struct style_prop *p); }; %init %{ // This overrides default index function generated by SWIG. SWIG_Lua_get_class_metatable(L, "proxy_style"); SWIG_Lua_add_function(L, "__index", _wrap_proxy_style_index); SWIG_Lua_add_function(L, "__newindex", _wrap_proxy_style_newindex); lua_pop(L, 1); %} /*** Compilation and running of expressions ***/ %{ static lua_State *lua; void expr_init(void) { lua = luaL_newstate(); lua_State *L = lua; luaL_openlibs(L); luaopen_leo(L); // SWIG init code leaves data in Lua stack. Get rid of it. lua_pop(L, lua_gettop(L)); lua_checkstack(L, 30); lua_pushliteral(L, "Leo"); lua_newtable(L); lua_settable(L, LUA_REGISTRYINDEX); } #if 0 // Not used at the moment (FIXME) static char *current_src; static const char *expr_reader(lua_State *L UNUSED, void *data UNUSED, size_t *sizep) { if (current_src) { char *res = current_src; *sizep = strlen(res); current_src = NULL; return res; } else { *sizep = 0; return NULL; } } #endif void expr_compile(void *key, char *source) { lua_State *L = lua; lua_pushliteral(L, "Leo"); // stack: "Leo" lua_gettable(L, LUA_REGISTRYINDEX); // stack: leo-table ASSERT(lua_istable(L, -1)); lua_pushlightuserdata(L, key); // stack: leo-table, key #if 0 current_src = source; int err = lua_load(L, expr_reader, NULL, "@(expr)", NULL); #else int err = luaL_loadbuffer(L, source, strlen(source), "@expression"); #endif if (err != LUA_OK) css_error(lua_tostring(L, -1)); // stack: leo-table, key, function lua_settable(L, -3); // stack: leo-table lua_pop(L, 1); // stack: -- } void expr_execute(void *key, struct style_results *r, layer_t layer) { lua_State *L = lua; struct proxy_tag pt = { .o = r->obj }; push_proxy_tag(L, &pt); // stack: proxy lua_setglobal(L, "t"); // stack: -- struct proxy_style ps = { .sr = r, .layer = layer }; push_proxy_style(L, &ps); // stack: proxy lua_setglobal(L, "s"); // stack: -- lua_pushliteral(L, "Leo"); // stack: "Leo" lua_gettable(L, LUA_REGISTRYINDEX); // stack: leo-table ASSERT(lua_istable(L, -1)); lua_pushlightuserdata(L, key); // stack: leo-table, key lua_gettable(L, -2); // stack: leo-table, function lua_remove(L, -2); // stack: function ASSERT(lua_isfunction(L, -1)); lua_call(L, 0, 0); // stack: -- } %}