]> mj.ucw.cz Git - leo.git/commitdiff
Initial support for LUA bindings in stylesheets
authorMartin Mares <mj@ucw.cz>
Tue, 9 Jun 2015 10:01:41 +0000 (12:01 +0200)
committerMartin Mares <mj@ucw.cz>
Tue, 9 Jun 2015 10:01:41 +0000 (12:01 +0200)
So far, only querying for tags of the current OSM object works,
but the whole thing looks very promising.

Makefile
configure
css-lex.c
css-parse.y
css.c
css.h
expr.h [new file with mode: 0644]
expr.i [new file with mode: 0644]
leo.c
poskole.css

index b1c6eee9bd45d964ff5e0241078503bfa202520c..8cff9078da6aa900dd95163eee169ce308f4ac3c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,13 +14,13 @@ BUILDSYS=$(s)/build
 include $(BUILDSYS)/Maketop
 
 PROGS+=$(o)/leo
-CFLAGS+=$(LIBUCW_CFLAGS)
+CFLAGS+=$(LIBUCW_CFLAGS) $(LUA_CFLAGS)
 
-LEO_MODULES=leo xml osm svg svg-icon css-parse css-lex style css dict sym sym-point sym-line sym-scale sym-text map shp fixed
+LEO_MODULES=leo xml osm svg svg-icon css-parse css-lex style css dict sym sym-point sym-line sym-scale sym-text map shp fixed leo_wrap
 LEO_OBJECTS=$(addprefix $(o)/, $(addsuffix .o, $(LEO_MODULES)))
 $(o)/leo: $(LEO_OBJECTS)
 
-$(o)/leo: LIBS+=$(LIBUCW_LIBS) $(LIBUCW_CHARSET_LIBS) $(LIBUCW_XML_LIBS) $(PANGOFT2_LIBS) $(FREETYPE_LIBS) -lproj -lm
+$(o)/leo: LIBS+=$(LIBUCW_LIBS) $(LIBUCW_CHARSET_LIBS) $(LIBUCW_XML_LIBS) $(PANGOFT2_LIBS) $(FREETYPE_LIBS) $(LUA_LIBS) -lproj -lm
 
 $(o)/sym-text.o: CFLAGS+=$(FREETYPE_CFLAGS) $(PANGOFT2_CFLAGS)
 $(o)/svg-icon.o: CFLAGS+=$(LIBUCW_XML_CFLAGS)
@@ -34,6 +34,12 @@ $(o)/css-parse.c: css-parse.y
 $(o)/dict-%.h: dict-%.t $(BUILDSYS)/gen-dict
        build/gen-dict <$< >$@
 
+$(o)/leo_wrap.o: $(o)/leo_wrap.c
+
+$(o)/leo_wrap.c: $(s)/expr.i
+       $(M)SWIG $<
+       $(Q)swig -I$(s) -lua -outdir $(o) -o $@ $<
+
 ifndef CONFIG_LOCAL
 install: all $(INSTALL_TARGETS)
 else
index 4b2d61e0c7c81a0fc59ee6ad18073c37be217c08..2eb7b9ea2caf4a6ea53e0798eb41abb56a51feb4 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 # Configure Script for Hic Est Leo
-# (c) 2014 Martin Mares <mj@ucw.cz>
+# (c) 2014--2015 Martin Mares <mj@ucw.cz>
 
 use warnings;
 use strict;
@@ -35,5 +35,26 @@ UCW::Configure::Pkg::PkgConfig("libucw-xml") or Fail("libucw-xml is required");
 UCW::Configure::Pkg::PkgConfig("pangoft2") or Fail("pangoft2 is required");
 UCW::Configure::Pkg::TrivConfig("freetype", script => "freetype-config") or Fail("freetype2 is required");
 
+UCW::Configure::Pkg::PkgConfig("lua5.2") or Fail("liblua5.2 is required");
+Set("LUA_CFLAGS", Get("LUA5_2_CFLAGS"));
+Set("LUA_LIBS", Get("LUA5_2_LIBS"));
+
+Log "Checking for SWIG ... ";
+my $swig = UCW::Configure::Pkg::TryCmd("swig -version");
+if (!defined $swig) {
+       Log "NO\n";
+       Fail("SWIG is required");
+} else {
+       my ($ver) = ($swig =~ /^SWIG Version (.*)$/m);
+       if (!defined $ver) {
+               Log "UNKNOWN VERSION\n";
+       } else {
+               Log "YES: version $ver\n";
+               if (UCW::Configure::Pkg::ver_norm($ver) lt UCW::Configure::Pkg::ver_norm("2.0")) {
+                       Fail "SWIG is too old, need version 2.0 or newer.";
+               }
+       }
+}
+
 Finish();
 Log "\nConfigured, run `make' to build everything.\n";
index 1a287f247b48120738bbc5447b3d690faf03fae3..129b1be740900c520fcd67657db9bd3887a46952 100644 (file)
--- a/css-lex.c
+++ b/css-lex.c
@@ -1,5 +1,5 @@
 /*
- *     Experimental Map Renderer -- MapCSS Lexer
+ *     Hic Est Leo -- MapCSS Lexer
  *
  *     (c) 2014--2015 Martin Mares <mj@ucw.cz>
  */
@@ -19,7 +19,7 @@ static struct fastbuf *fb;
 static struct fastbuf fbbuf;
 static int lino;
 
-void css_error(char *err, ...)
+void css_error(const char *err, ...)
 {
   va_list args;
   va_start(args, err);
@@ -49,7 +49,7 @@ int css_lex(void)
 {
   struct mempool *mp = css_this->pool;
   char *p;
-  int c, next, len, tok;
+  int c, next, len, tok, nesting;
 
   if (tok = css_this->pushed_token)
     {
@@ -198,6 +198,32 @@ int css_lex(void)
          css_lval.s = p;
          return RGB;
 
+       case '@':
+         if (next != '{')
+           return '@';
+         // Lua block
+         p = mp_start(mp, 1);
+         // FIXME p = mp_append_string(mp, p, "function () ");
+         nesting = 1;
+         bgetc(fb);
+         for (;;)
+           {
+             c = bgetc(fb);
+             if (c < 0)
+               css_error("Unterminated Lua block");
+             if (c == '{')
+               nesting++;
+             else if (c == '}')
+               {
+                 nesting--;
+                 if (!nesting)
+                   break;
+               }
+             p = mp_append_char(mp, p, c);
+           }
+         css_lval.s = mp_end_string(mp, p);
+         return LUA;
+
          // One-character operators
        case '{':
        case '}':
index 33293217ddad9f66feffc3f0cf64000a06f2310c..b9937bbaa409e2e1e3287463271cfa90ea284159 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Hic Est Leo -- MapCSS Parser
  *
- *     (c) 2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014--2015 Martin Mares <mj@ucw.cz>
  */
 
 %{
@@ -13,6 +13,7 @@
 
 #include "leo.h"
 #include "css.h"
+#include "expr.h"
 
 static void *css_alloc(size_t n)
 {
@@ -49,7 +50,7 @@ static void css_add_to_val_list(struct style_prop *list, struct style_prop *elt)
 
 %token LE GE NE CC
 %token SINGLE_PROP
-%token <s> NUMBER IDENT QUOTED RGB
+%token <s> NUMBER IDENT QUOTED RGB LUA
 
 %type <s> ident_or_quoted
 %type <rule> rule rule_start rule_selectors rule_start_actions rule_actions
@@ -237,9 +238,16 @@ action:
     ident_or_quoted ':' prop_value
       {
        $$ = css_alloc(sizeof(struct css_action));
+       $$->type = CSS_ACTION_SET;
        $$->prop = $3;
        $$->prop.key = style_prop_encode($1);
       }
+  | LUA
+      {
+       $$ = css_alloc(sizeof(struct css_action));
+       $$->type = CSS_ACTION_EXPR;
+       expr_compile($$, $1);
+      }
   ;
 
 prop_value:
diff --git a/css.c b/css.c
index 38464aaa6fca475145736939c8914060d0730832..c05fae77a2210f12846b917291bb710691e2ebab 100644 (file)
--- a/css.c
+++ b/css.c
@@ -1,12 +1,13 @@
 /*
  *     Hic Est Leo -- MapCSS Stylesheets
  *
- *     (c) 2014 Martin Mares <mj@ucw.cz>
+ *     (c) 2014--2015 Martin Mares <mj@ucw.cz>
  */
 
 #include "leo.h"
 #include "style.h"
 #include "css.h"
+#include "expr.h"
 
 #include <ucw/mempool.h>
 
@@ -44,7 +45,16 @@ void css_dump_selector(struct css_selector *s)
 void css_dump_action(struct css_action *a)
 {
   printf("\tAction: ");
-  style_dump_prop(&a->prop);
+  switch (a->type)
+    {
+    case CSS_ACTION_SET:
+      style_dump_prop(&a->prop);
+      break;
+    case CSS_ACTION_EXPR:
+      printf("<expr>\n");
+    default:
+      ASSERT(0);
+    }
 }
 
 static bool css_match_condition(struct css_condition *c, struct osm_object *o)
@@ -150,7 +160,17 @@ static bool css_match_selector(struct css_selector *s, struct style_results *r)
 
 static void css_apply_action(struct css_action *sa, struct style_results *r, layer_t layer)
 {
-  style_set_by_layer(r, layer, &sa->prop);
+  switch (sa->type)
+    {
+    case CSS_ACTION_SET:
+      style_set_by_layer(r, layer, &sa->prop);
+      break;
+    case CSS_ACTION_EXPR:
+      expr_execute(sa, r, layer);
+      break;
+    default:
+      ASSERT(0);
+    }
 }
 
 void css_apply(struct css_sheet *ss, struct style_results *r)
diff --git a/css.h b/css.h
index 8ec18963de4a94ec5b7a8c8bf5215158b0e5f83b..2ae99fbdda276ad4bc7076a88f38265a38076757 100644 (file)
--- a/css.h
+++ b/css.h
@@ -73,9 +73,15 @@ struct css_condition {
   osm_val_t val;
 };
 
+enum css_action_type {
+  CSS_ACTION_SET,
+  CSS_ACTION_EXPR,
+};
+
 struct css_action {
   cnode n;
-  struct style_prop prop;
+  enum css_action_type type;
+  struct style_prop prop;      // for CSS_ACTION_SET
 };
 
 /* css-parse.y */
@@ -87,7 +93,7 @@ struct style_prop *css_parse_prop(struct mempool *mp, char *objname, const char
 
 /* css-lex.c */
 
-void css_error(char *err, ...);
+void css_error(const char *err, ...);
 int css_lex(void);
 void css_lex_open(void);
 void css_lex_close(void);
diff --git a/expr.h b/expr.h
new file mode 100644 (file)
index 0000000..e3d0770
--- /dev/null
+++ b/expr.h
@@ -0,0 +1,18 @@
+/*
+ *     Hic Est Leo -- Expression Evaluation via Lua
+ *
+ *     (c) 2015 Martin Mares <mj@ucw.cz>
+ */
+
+#ifndef _LEO_EXPR_H
+#define _LEO_EXPR_H
+
+#include <lua.h>
+
+int luaopen_leo(lua_State *L);
+
+void expr_init(void);
+void expr_compile(void *key, char *source);
+void expr_execute(void *key, struct style_results *r, layer_t layer);
+
+#endif
diff --git a/expr.i b/expr.i
new file mode 100644 (file)
index 0000000..14baf32
--- /dev/null
+++ b/expr.i
@@ -0,0 +1,183 @@
+/*
+ *     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: --
+}
+
+%}
diff --git a/leo.c b/leo.c
index a221a941b6f86b3c6f7a2cff0dc0eaa59cee7a90..3508cbdf1bdd4cd652f7d258cf8f453a53d42198 100644 (file)
--- a/leo.c
+++ b/leo.c
@@ -11,6 +11,7 @@
 #include "css.h"
 #include "sym.h"
 #include "map.h"
+#include "expr.h"
 
 #include <ucw/conf.h>
 #include <ucw/opt.h>
@@ -52,6 +53,7 @@ int main(int argc UNUSED, char **argv)
 
   osm_init();
   styles_init();
+  expr_init();
   map_load_styles();
   map_load_sources();
   map_set_scale();
index 30631f5ae39eff668a51fbc5984c1bc4e9d1a105..49cc444f1df55f9f82a19f358982e6d83dc7aad1 100644 (file)
@@ -705,3 +705,9 @@ node[hack=raisetext],
 way[hack=raisetext] {
        text-offset: 3;
 }
+
+/*** Experiments ***/
+
+node {
+       @{print(t.name)} ;
+}