]> mj.ucw.cz Git - leo.git/blob - expr.i
Lua bindings for object attributes and basic style properties
[leo.git] / expr.i
1 /*
2  *      Hic Est Leo -- Bindings for Lua
3  *
4  *      (c) 2015 Martin Mares <mj@ucw.cz>
5  */
6
7 %module leo
8 %nodefaultctor;
9
10 %{
11 #include "leo.h"
12 #include "osm.h"
13 #include "css.h"
14 #include "expr.h"
15
16 #include <lualib.h>
17 #include <lauxlib.h>
18 %}
19
20 /*** Proxy for OSM object attributes ***/
21
22 %{
23
24 struct proxy_tag {
25   struct osm_object *o;
26 };
27
28 static void push_proxy_tag(lua_State *L, struct proxy_tag *t)
29 {
30   SWIG_NewPointerObj(L, t, SWIGTYPE_p_proxy_tag, 0);
31 }
32
33 static const char *proxy_tag_index(struct proxy_tag *t, const char *key)
34 {
35   osm_key_t k = osm_key_encode(key);
36   osm_val_t v = osm_obj_find_tag(t->o, k);
37   return osm_val_decode(v);
38 }
39
40 %}
41
42 struct proxy_tag { };
43
44 %extend proxy_tag {
45   const char *index(const char *key);
46 };
47
48 %init %{
49   // This overrides default index function generated by SWIG.
50   // The tag proxy therefore cannot have any methods.
51   SWIG_Lua_get_class_metatable(L, "proxy_tag");
52   SWIG_Lua_add_function(L, "__index", _wrap_proxy_tag_index);
53   lua_pop(L, 1);
54 %}
55
56 /*** Proxy for style properties ***/
57
58 %{
59
60 struct proxy_style {
61   struct style_results *sr;
62   layer_t layer;
63 };
64
65 static void push_proxy_style(lua_State *L, struct proxy_style *s)
66 {
67   SWIG_NewPointerObj(L, s, SWIGTYPE_p_proxy_style, 0);
68 }
69
70 static struct style_prop *proxy_style_index(struct proxy_style *s, const char *key)
71 {
72   prop_t k = style_prop_encode(key);
73   return style_get_by_layer(s->sr, s->layer, k);
74 }
75
76 static void proxy_style_newindex(struct proxy_style *s, const char *key, struct style_prop *p)
77 {
78   p->key = style_prop_encode(key);
79   style_set_by_layer(s->sr, s->layer, p);
80 }
81
82 static void push_style_prop(lua_State *L, struct style_prop *p)
83 {
84   if (!p)
85     {
86       lua_pushnil(L);
87       return;
88     }
89   switch (p->type)
90     {
91     case PROP_TYPE_STRING:
92       lua_pushstring(L, osm_val_decode(p->val.id));
93       break;
94     case PROP_TYPE_NUMBER:
95       lua_pushnumber(L, (lua_Number) p->val.number);
96       break;
97     default:
98       msg(L_WARN, "Property %s has value with no LUA representation", style_prop_decode(p->key));
99       lua_pushnil(L);
100     }
101 }
102
103 static const char *decode_style_prop(lua_State *L, int idx, struct style_prop *p)
104 {
105   if (lua_isnil(L, idx))
106     return "Cannot set property to nil. Yet.";  // FIXME
107
108   if (lua_isnumber(L, idx))                     // FIXME: numbers vs. strings
109     {
110       p->type = PROP_TYPE_NUMBER;
111       p->val.number = lua_tonumber(L, idx);
112       return NULL;
113     }
114
115   if (lua_isstring(L, idx))
116     {
117       p->type = PROP_TYPE_STRING;
118       p->val.id = osm_val_encode(lua_tostring(L, idx));
119       return NULL;
120     }
121
122   return "Invalid type of style property";
123 }
124
125 %}
126
127 %typemap(out) struct style_prop * { push_style_prop(L, $1); SWIG_arg++; }
128
129 %typemap(in) struct style_prop * (const char *err, struct style_prop prop) {
130   err = decode_style_prop(L, $input, &prop);
131   if (err)
132     {
133       lua_pushstring(L, err);
134       SWIG_fail;
135     }
136   $1 = &prop;
137 }
138
139 struct proxy_style { };
140
141 %extend proxy_style {
142   struct style_prop *index(const char *key);
143   void newindex(const char *key, struct style_prop *p);
144 };
145
146 %init %{
147   // This overrides default index function generated by SWIG.
148   SWIG_Lua_get_class_metatable(L, "proxy_style");
149   SWIG_Lua_add_function(L, "__index", _wrap_proxy_style_index);
150   SWIG_Lua_add_function(L, "__newindex", _wrap_proxy_style_newindex);
151   lua_pop(L, 1);
152 %}
153
154 /*** Compilation and running of expressions ***/
155
156 %{
157
158 static lua_State *lua;
159
160 void expr_init(void)
161 {
162   lua = luaL_newstate();
163   lua_State *L = lua;
164
165   luaL_openlibs(L);
166   luaopen_leo(L);
167
168   // SWIG init code leaves data in Lua stack. Get rid of it.
169   lua_pop(L, lua_gettop(L));
170
171   lua_checkstack(L, 30);
172
173   lua_pushliteral(L, "Leo");
174   lua_newtable(L);
175   lua_settable(L, LUA_REGISTRYINDEX);
176 }
177
178 #if 0
179 // Not used at the moment (FIXME)
180
181 static char *current_src;
182
183 static const char *expr_reader(lua_State *L UNUSED, void *data UNUSED, size_t *sizep)
184 {
185   if (current_src)
186     {
187       char *res = current_src;
188       *sizep = strlen(res);
189       current_src = NULL;
190       return res;
191     }
192   else
193     {
194       *sizep = 0;
195       return NULL;
196     }
197 }
198
199 #endif
200
201 void expr_compile(void *key, char *source)
202 {
203   lua_State *L = lua;
204
205   lua_pushliteral(L, "Leo");                    // stack: "Leo"
206   lua_gettable(L, LUA_REGISTRYINDEX);           // stack: leo-table
207   ASSERT(lua_istable(L, -1));
208   lua_pushlightuserdata(L, key);                // stack: leo-table, key
209
210 #if 0
211   current_src = source;
212   int err = lua_load(L, expr_reader, NULL, "@(expr)", NULL);
213 #else
214   int err = luaL_loadbuffer(L, source, strlen(source), "@expression");
215 #endif
216   if (err != LUA_OK)
217     css_error(lua_tostring(L, -1));
218   // stack: leo-table, key, function
219
220   lua_settable(L, -3);                          // stack: leo-table
221   lua_pop(L, 1);                                // stack: --
222 }
223
224 void expr_execute(void *key, struct style_results *r, layer_t layer)
225 {
226   lua_State *L = lua;
227
228   struct proxy_tag pt = { .o = r->obj };
229   push_proxy_tag(L, &pt);                       // stack: proxy
230   lua_setglobal(L, "t");                        // stack: --
231
232   struct proxy_style ps = { .sr = r, .layer = layer };
233   push_proxy_style(L, &ps);                     // stack: proxy
234   lua_setglobal(L, "s");                        // stack: --
235
236   lua_pushliteral(L, "Leo");                    // stack: "Leo"
237   lua_gettable(L, LUA_REGISTRYINDEX);           // stack: leo-table
238   ASSERT(lua_istable(L, -1));
239   lua_pushlightuserdata(L, key);                // stack: leo-table, key
240   lua_gettable(L, -2);                          // stack: leo-table, function
241   lua_remove(L, -2);                            // stack: function
242   ASSERT(lua_isfunction(L, -1));
243
244   lua_call(L, 0, 0);                            // stack: --
245 }
246
247 %}