diff --git a/contrib/py-bindings/PyGF.hsc b/contrib/py-bindings/PyGF.hsc index 27c87b1a0..6ac5b05d7 100644 --- a/contrib/py-bindings/PyGF.hsc +++ b/contrib/py-bindings/PyGF.hsc @@ -127,10 +127,7 @@ gf_showExpr pexpr = do listToPy :: Storable a => IO (Ptr a) -> [a] -> IO (Ptr ()) -- opaque -- IO (Ptr (Ptr Language)) listToPy mk ls = do - let bufl = length ls + 1 - -- buf <- mallocBytes $ (#size PyGF) * bufl pyls <- pyList - -- pokeElemOff buf (length ls) nullPtr mapM_ (mpoke pyls) ls return pyls where mpoke pyl l = do @@ -138,7 +135,6 @@ listToPy mk ls = do poke pl l pyl << pl - -- foreign export ccall "gf_freeArray" free :: Ptr a -> IO () @@ -194,9 +190,38 @@ gf_showCId pcid = do cid <- peek pcid newCString $ showCId cid +foreign export ccall gf_unapp :: Ptr Expr -> IO (Ptr ()) +foreign export ccall gf_unint :: Ptr Expr -> IO CInt +foreign export ccall gf_unstr :: Ptr Expr -> IO CString + +gf_unapp pexp = do + exp <- peek pexp + case unApp exp of + Just (f,args) -> do + puexp <- pyList + pf <- pyCId + poke pf f + puexp << pf + mapM_ (\e -> do + pe <- pyExpr + poke pe e + puexp << pe) args + return puexp + Nothing -> return nullPtr +gf_unint pexp = do + exp <- peek pexp + return $ fromIntegral $ case unInt exp of + Just n -> n + _ -> (-9) +gf_unstr pexp = do + exp <- peek pexp + case unStr exp of + Just s -> newCString s + _ -> return nullPtr foreign import ccall "newLang" pyLang :: IO (Ptr Language) foreign import ccall "newTree" pyTree :: IO (Ptr Tree) foreign import ccall "newCId" pyCId :: IO (Ptr CId) +foreign import ccall "newExpr" pyExpr :: IO (Ptr Expr) foreign import ccall "newList" pyList :: IO (Ptr ()) foreign import ccall "append" (<<) :: Ptr () -> Ptr a -> IO () diff --git a/contrib/py-bindings/gfmodule.c b/contrib/py-bindings/gfmodule.c index 8c04de5d2..06896b9ba 100644 --- a/contrib/py-bindings/gfmodule.c +++ b/contrib/py-bindings/gfmodule.c @@ -225,6 +225,38 @@ DEALLOCFN(expr_dealloc, Expr, gf_freeExpr, "freeExpr") REPRCB(expr_repr, Expr, gf_showExpr) +static PyObject* +unapp(Expr *self) { + PyObject* obj = gf_unapp(self); + if (!obj) { + char* s = gf_unstr(self); + if (s) { + obj = PyString_FromString(s); + free(s); + } else { + long n = gf_unint(self); + if (n != -9) { + obj = PyInt_FromLong(n); + } else { + PyErr_Format(PyExc_TypeError, "Cannot unapply expr."); + } + } + } + return obj; +} + +static PyMethodDef tree_methods[] = { + {"unapply", (PyCFunction)unapp, METH_NOARGS,"Unapply a tree."}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static PyMethodDef expr_methods[] = { + {"unapply", (PyCFunction)unapp, METH_NOARGS,"Unapply an expression."}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + + /* tree typr: methods, constructor and destructor */ // Are Expr and Tree equivalent ? @@ -232,6 +264,9 @@ REPRCB(tree_repr, Tree, gf_showExpr) DEALLOCFN(Tree_dealloc, Tree, gf_freeTree, "freeTree") + + + /* gf module methods */ static PyMethodDef gf_methods[] = { @@ -260,7 +295,9 @@ initgf(void) READYTYPE(PGFType, pgf_repr, PGF_dealloc) READYTYPE(LangType, lang_repr, Lang_dealloc) READYTYPE(gfTypeType, gfType_repr, gfType_dealloc) + ExprType.tp_methods = expr_methods; READYTYPE(ExprType, expr_repr, expr_dealloc) + TreeType.tp_methods = tree_methods; READYTYPE(TreeType, tree_repr, Tree_dealloc) m = Py_InitModule3("gf", gf_methods, diff --git a/contrib/py-bindings/test.py b/contrib/py-bindings/test.py index 716aba6c3..69b1f000a 100644 --- a/contrib/py-bindings/test.py +++ b/contrib/py-bindings/test.py @@ -101,6 +101,19 @@ class TestTranslate(unittest.TestCase): assert len(parsed) == 1 lin = self.pgf.lin(m,parsed[0]) self.assertEqual(lin,cnc[j]) - + +class TestUnapplyExpr(unittest.TestCase): + def setUp(self): + self.pgf = gf.read_pgf('Query.pgf') + self.langs = dict([(lang2iso(l),l) for l in self.pgf.languages()]) + + def test_unapply(self): + ps = self.pgf.parse('is 23 odd',self.langs['eng']) + f,es = ps[0].unapply() + self.assertEqual(`f`,'Odd') + f,es = es.unapply() + self.assertEqual(`f`,'Number') + self.assertEqual(es.unapply(),23) + if __name__ == '__main__': unittest.main()