+/*
+ * Hic Est Leo -- Bindings for Lua
+ *
+ * (c) 2015 Martin Mares <mj@ucw.cz>
+ */
+
+%module leo
+%nodefaultctor;
+
+%{
+#include "leo.h"
+#include "osm.h"
+#include "css.h"
+#include "expr.h"
+
+#include <lualib.h>
+#include <lauxlib.h>
+%}
+
+/*** 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 const char *proxy_style_index(struct proxy_style *s, const char *key)
+{
+ return NULL;
+}
+
+%}
+
+struct proxy_style { };
+
+%extend proxy_style {
+ const char *index(const char *key);
+};
+
+%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);
+ 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: --
+}
+
+%}