aboutsummaryrefslogtreecommitdiff
path: root/src/unary.c
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2010-12-29 16:26:25 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2010-12-29 16:26:25 +0100
commitd3148268857e01116d5d3c99ac0a43bc6a54b13c (patch)
tree6ae273025ef73942c0ac748e715a7f281a6af114 /src/unary.c
downloadlspipat-master.tar.gz
initial checkin (v0.1 release)HEADv0.1master
Diffstat (limited to 'src/unary.c')
-rw-r--r--src/unary.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/unary.c b/src/unary.c
new file mode 100644
index 0000000..b3f40ef
--- /dev/null
+++ b/src/unary.c
@@ -0,0 +1,182 @@
+/*
+ * LSPIPAT - LUA SPIPAT WRAPPER
+ * Copyright (C) 2010, Robin Haberkorn
+ * License: LGPL
+ *
+ * CORE: UNARY OPERATORS (ALSO USED AS PRIMITIVES)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "lspipat.h"
+
+static void
+setcurFncHandler(unsigned pos, void *global __attribute__((unused)), void *local)
+{
+ struct simplefncRefs *simplefnc = local;
+ lua_State *L = simplefnc->cb.L;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, simplefnc->cb.function);
+ lua_pushinteger(L, pos);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, simplefnc->cb.cookie);
+#if 0
+ lua_rawgeti(L, LUA_REGISTRYINDEX, *(int *)global);
+#endif
+
+ lua_call(L, 2, 0);
+}
+
+ /*
+ * if called as an operator, there will be a nil on top of the stack
+ */
+LUA_SIG(l_setcur)
+{
+ int top = lua_gettop(L);
+
+ PATTERN_WRAPPER *new;
+ struct simplefncRefs *simplefnc;
+
+ luaL_argcheck(L, top == 1 || top == 2, top, L_NUMBER);
+ luaL_argcheck(L, lua_isfunction(L, 1), 1, L_TYPE);
+
+ if (!(new = lua_newuserdata(L, sizeof(PATTERN_WRAPPER))))
+ L_ERROR(L_ALLOC);
+ memset(new, 0, sizeof(PATTERN_WRAPPER));
+
+ lua_insert(L, 1); /* move wrapper to bottom */
+ if (top == 1)
+ lua_pushnil(L); /* cookie will be LUA_REFNIL */
+
+ new->type = PATTERN_SIMPLEFNC;
+
+ simplefnc = &new->u.simplefnc;
+ simplefnc->cb.L = L;
+ simplefnc->cb.cookie = luaL_ref(L, LUA_REGISTRYINDEX);
+ simplefnc->cb.function = luaL_ref(L, LUA_REGISTRYINDEX);
+ /* wrapper at top again */
+
+ new->pattern = spipat_setcur_fnc(setcurFncHandler, simplefnc);
+ if (!new->pattern)
+ L_ERROR(L_ALLOC);
+
+ luaL_getmetatable(L, PATTERN_MT);
+ lua_setmetatable(L, -2);
+
+ return 1;
+}
+
+static void
+predFncHandler(void *global __attribute__((unused)), void *local, struct dynamic *ret)
+{
+ struct retfncRefs *retfnc = local;
+ lua_State *L = retfnc->cb.L;
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, retfnc->cb.function);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, retfnc->cb.cookie);
+#if 0
+ lua_rawgeti(L, LUA_REGISTRYINDEX, *(int *)global);
+#endif
+
+ lua_call(L, 1, 1);
+
+ switch (lua_type(L, -1)) {
+ case LUA_TNUMBER:
+ case LUA_TSTRING: {
+ VString *str = &ret->val.str;
+
+ ret->type = DY_VSTR;
+
+ str->ptr = lua_tolstring(L, -1, (size_t *)&str->len);
+ str->release = retfncUnrefRet;
+ str->cookie = retfnc;
+
+ /*
+ * Register value so Lua doesn't free it until spipat
+ * doesn't need it anymore (value has to be popped now)
+ */
+ retfnc->ret = luaL_ref(L, LUA_REGISTRYINDEX);
+ return;
+ }
+ case LUA_TNIL: /* default behaviour: continue matching (Succeed) */
+ ret->type = DY_BOOL;
+
+ ret->val.pred = true;
+
+ lua_pop(L, 1);
+ return;
+
+ case LUA_TBOOLEAN:
+ ret->type = DY_BOOL;
+
+ ret->val.pred = lua_toboolean(L, -1);
+
+ lua_pop(L, 1);
+ return;
+
+ case LUA_TUSERDATA: { /* FIXME: check whether it's really a Pattern */
+ PATTERN_WRAPPER *wrapper = lua_touserdata(L, -1);
+ if (!wrapper->pattern) {
+ lua_pop(L, 1);
+ L_ERROR(L_RETURN);
+ }
+
+ ret->type = DY_PAT;
+
+ ret->val.pat.p = wrapper->pattern;
+ ret->val.pat.release = retfncUnrefRet;
+ ret->val.pat.cookie = retfnc;
+
+ /*
+ * Register value so Lua doesn't free it until spipat
+ * doesn't need it anymore (value has to be popped now)
+ */
+ retfnc->ret = luaL_ref(L, LUA_REGISTRYINDEX);
+ return;
+ }
+ default:
+ lua_pop(L, 1);
+ L_ERROR(L_RETURN);
+ }
+
+ /* not reached */
+}
+
+LUA_SIG(l_pred)
+{
+ int top = lua_gettop(L);
+
+ PATTERN_WRAPPER *new;
+ struct retfncRefs *retfnc;
+
+ luaL_argcheck(L, top == 1 || top == 2, top, L_NUMBER);
+ luaL_argcheck(L, lua_isfunction(L, 1), 1, L_TYPE);
+
+ if (!(new = lua_newuserdata(L, sizeof(PATTERN_WRAPPER))))
+ L_ERROR(L_ALLOC);
+ memset(new, 0, sizeof(PATTERN_WRAPPER));
+
+ lua_insert(L, 1); /* move wrapper to bottom */
+ if (top == 1)
+ lua_pushnil(L); /* cookie will be LUA_REFNIL */
+
+ new->type = PATTERN_RETFNC;
+ retfnc = &new->u.retfnc;
+ retfnc->cb.L = L;
+ retfnc->cb.cookie = luaL_ref(L, LUA_REGISTRYINDEX);
+ retfnc->cb.function = luaL_ref(L, LUA_REGISTRYINDEX);
+ /* wrapper at top again */
+
+ new->pattern = spipat_dynamic_fnc(predFncHandler, retfnc);
+ if (!new->pattern)
+ L_ERROR(L_ALLOC);
+
+ luaL_getmetatable(L, PATTERN_MT);
+ lua_setmetatable(L, -2);
+
+ return 1;
+}