Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic

This commit is contained in:
krangelov
2021-09-22 07:35:30 +02:00
13 changed files with 972 additions and 2671 deletions

4
.gitignore vendored
View File

@@ -47,8 +47,8 @@ src/runtime/c/sg/.dirstamp
src/runtime/c/stamp-h1
src/runtime/java/.libs/
src/runtime/python/build/
src/runtime/python/__pycache__/
src/runtime/python/.pytest_cache/
src/runtime/python/**/__pycache__/
src/runtime/python/**/.pytest_cache/
.cabal-sandbox
cabal.sandbox.config
.stack-work

View File

@@ -4,9 +4,10 @@
#include <pgf/pgf.h>
#include "./expr.h"
#include "./marshaller.h"
#include "./ffi.h"
// ----------------------------------------------------------------------------
// types
static TypeObject *
Type_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
@@ -135,7 +136,6 @@ static PyGetSetDef Type_getseters[] = {
{NULL} /* Sentinel */
};
/* static */
PyTypeObject pgf_TypeType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -179,6 +179,7 @@ PyTypeObject pgf_TypeType = {
};
// ----------------------------------------------------------------------------
// expressions
static PyObject *
Expr_str(ExprObject *self)
@@ -234,7 +235,6 @@ static PyGetSetDef Expr_getseters[] = {
{NULL} /* Sentinel */
};
/* static */
PyTypeObject pgf_ExprType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -327,7 +327,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprAbsType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -416,7 +415,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprAppType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -522,7 +520,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprLitType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -615,7 +612,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprMetaType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -700,7 +696,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprFunType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -793,7 +788,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -882,7 +876,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprTypedType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
@@ -967,7 +960,6 @@ done:
}
}
/* static */
PyTypeObject pgf_ExprImplArgType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/

View File

@@ -13,7 +13,7 @@ typedef struct {
PyObject *exprs; // PyListObject of ExprObject
} TypeObject;
extern PyTypeObject pgf_TypeType;
PyTypeObject pgf_TypeType;
typedef struct {
PyObject_HEAD
@@ -63,14 +63,14 @@ typedef struct {
ExprObject *expr;
} ExprImplArgObject;
extern PyTypeObject pgf_ExprType;
extern PyTypeObject pgf_ExprAbsType;
extern PyTypeObject pgf_ExprAppType;
extern PyTypeObject pgf_ExprLitType;
extern PyTypeObject pgf_ExprMetaType;
extern PyTypeObject pgf_ExprFunType;
extern PyTypeObject pgf_ExprVarType;
extern PyTypeObject pgf_ExprTypedType;
extern PyTypeObject pgf_ExprImplArgType;
PyTypeObject pgf_ExprType;
PyTypeObject pgf_ExprAbsType;
PyTypeObject pgf_ExprAppType;
PyTypeObject pgf_ExprLitType;
PyTypeObject pgf_ExprMetaType;
PyTypeObject pgf_ExprFunType;
PyTypeObject pgf_ExprVarType;
PyTypeObject pgf_ExprTypedType;
PyTypeObject pgf_ExprImplArgType;
#endif // PYPGF_EXPR_H_

View File

@@ -5,9 +5,29 @@
#include <pgf/pgf.h>
#include "./expr.h"
#include "./marshaller.h"
#include "./ffi.h"
// ----------------------------------------------------------------------------
// errors
PyObject *PGFError;
PgfExnType handleError(PgfExn err)
{
if (err.type == PGF_EXN_SYSTEM_ERROR) {
errno = err.code;
PyErr_SetFromErrnoWithFilename(PyExc_IOError, err.msg);
} else if (err.type == PGF_EXN_PGF_ERROR) {
PyErr_SetString(PGFError, err.msg);
free((char*) err.msg);
} else if (err.type == PGF_EXN_OTHER_ERROR) {
PyErr_SetString(PGFError, "an unknown error occured");
}
return err.type;
}
// ----------------------------------------------------------------------------
// string conversions
PgfText *
PyUnicode_AsPgfText(PyObject *pystr)
@@ -35,15 +55,10 @@ PyUnicode_FromPgfText(PgfText *text)
}
// ----------------------------------------------------------------------------
// unmarshaller
/* The PgfUnmarshaller structure tells the runtime how to create
* abstract syntax expressions and types in the heap of the host language.
* In Python the expressions are normal objects.
* From the point of view of the runtime, each node is a value of type object.
* For Python that would be a PyObject pointer.
*/
PgfExpr eabs(PgfUnmarshaller *this, PgfBindType btype, PgfText *name, PgfExpr body)
static PgfExpr
eabs(PgfUnmarshaller *this, PgfBindType btype, PgfText *name, PgfExpr body)
{
ExprAbsObject *pyexpr = (ExprAbsObject *)pgf_ExprAbsType.tp_alloc(&pgf_ExprAbsType, 0);
pyexpr->bindType = PyLong_FromLong(btype);
@@ -53,7 +68,8 @@ PgfExpr eabs(PgfUnmarshaller *this, PgfBindType btype, PgfText *name, PgfExpr bo
return (PgfExpr) pyexpr;
}
PgfExpr eapp(PgfUnmarshaller *this, PgfExpr fun, PgfExpr arg)
static PgfExpr
eapp(PgfUnmarshaller *this, PgfExpr fun, PgfExpr arg)
{
ExprAppObject *pyexpr = (ExprAppObject *)pgf_ExprAppType.tp_alloc(&pgf_ExprAppType, 0);
pyexpr->e1 = (ExprObject *)fun;
@@ -63,7 +79,8 @@ PgfExpr eapp(PgfUnmarshaller *this, PgfExpr fun, PgfExpr arg)
return (PgfExpr) pyexpr;
}
PgfExpr elit(PgfUnmarshaller *this, PgfLiteral lit)
static PgfExpr
elit(PgfUnmarshaller *this, PgfLiteral lit)
{
ExprLitObject *pyexpr = (ExprLitObject *)pgf_ExprLitType.tp_alloc(&pgf_ExprLitType, 0);
PyObject *pyobj = (PyObject *)lit;
@@ -72,14 +89,16 @@ PgfExpr elit(PgfUnmarshaller *this, PgfLiteral lit)
return (PgfExpr) pyexpr;
}
PgfExpr emeta(PgfUnmarshaller *this, PgfMetaId meta)
static PgfExpr
emeta(PgfUnmarshaller *this, PgfMetaId meta)
{
ExprMetaObject *pyexpr = (ExprMetaObject *)pgf_ExprMetaType.tp_alloc(&pgf_ExprMetaType, 0);
pyexpr->id = PyLong_FromLong(meta);
return (PgfExpr) pyexpr;
}
PgfExpr efun(PgfUnmarshaller *this, PgfText *name)
static PgfExpr
efun(PgfUnmarshaller *this, PgfText *name)
{
ExprFunObject *pyexpr = (ExprFunObject *)pgf_ExprFunType.tp_alloc(&pgf_ExprFunType, 0);
PyObject *pyobj = PyUnicode_FromPgfText(name);
@@ -88,14 +107,16 @@ PgfExpr efun(PgfUnmarshaller *this, PgfText *name)
return (PgfExpr) pyexpr;
}
PgfExpr evar(PgfUnmarshaller *this, int index)
static PgfExpr
evar(PgfUnmarshaller *this, int index)
{
ExprVarObject *pyexpr = (ExprVarObject *)pgf_ExprVarType.tp_alloc(&pgf_ExprVarType, 0);
pyexpr->index = PyLong_FromLong(index);
return (PgfExpr) pyexpr;
}
PgfExpr etyped(PgfUnmarshaller *this, PgfExpr expr, PgfType typ)
static PgfExpr
etyped(PgfUnmarshaller *this, PgfExpr expr, PgfType typ)
{
ExprTypedObject *pyexpr = (ExprTypedObject *)pgf_ExprTypedType.tp_alloc(&pgf_ExprTypedType, 0);
pyexpr->expr = (ExprObject *)expr;
@@ -105,7 +126,8 @@ PgfExpr etyped(PgfUnmarshaller *this, PgfExpr expr, PgfType typ)
return (PgfExpr) pyexpr;
}
PgfExpr eimplarg(PgfUnmarshaller *this, PgfExpr expr)
static PgfExpr
eimplarg(PgfUnmarshaller *this, PgfExpr expr)
{
ExprImplArgObject *pyexpr = (ExprImplArgObject *)pgf_ExprImplArgType.tp_alloc(&pgf_ExprImplArgType, 0);
pyexpr->expr = (ExprObject *)expr;
@@ -113,7 +135,8 @@ PgfExpr eimplarg(PgfUnmarshaller *this, PgfExpr expr)
return (PgfExpr) pyexpr;
}
PgfLiteral lint(PgfUnmarshaller *this, size_t size, uintmax_t *v)
static PgfLiteral
lint(PgfUnmarshaller *this, size_t size, uintmax_t *v)
{
intmax_t *v0 = (intmax_t *)v;
PyObject *i = PyLong_FromLong(*v0);
@@ -137,19 +160,22 @@ PgfLiteral lint(PgfUnmarshaller *this, size_t size, uintmax_t *v)
}
}
PgfLiteral lflt(PgfUnmarshaller *this, double v)
static PgfLiteral
lflt(PgfUnmarshaller *this, double v)
{
PyObject *d = PyFloat_FromDouble(v);
return (PgfLiteral) d;
}
PgfLiteral lstr(PgfUnmarshaller *this, PgfText *v)
static PgfLiteral
lstr(PgfUnmarshaller *this, PgfText *v)
{
PyObject *s = PyUnicode_FromStringAndSize(v->text, v->size);
return (PgfLiteral) s;
}
PgfType dtyp(PgfUnmarshaller *this, int n_hypos, PgfTypeHypo *hypos, PgfText *cat, int n_exprs, PgfExpr *exprs)
static PgfType
dtyp(PgfUnmarshaller *this, int n_hypos, PgfTypeHypo *hypos, PgfText *cat, int n_exprs, PgfExpr *exprs)
{
TypeObject *pytype = (TypeObject *)pgf_TypeType.tp_alloc(&pgf_TypeType, 0);
@@ -173,7 +199,8 @@ PgfType dtyp(PgfUnmarshaller *this, int n_hypos, PgfTypeHypo *hypos, PgfText *ca
return (PgfType) pytype;
}
void free_ref(PgfUnmarshaller *this, object x)
static void
free_ref(PgfUnmarshaller *this, object x)
{
// Py_XDECREF(x);
}
@@ -195,12 +222,13 @@ static PgfUnmarshallerVtbl unmarshallerVtbl =
free_ref
};
/* static */
PgfUnmarshaller unmarshaller = { &unmarshallerVtbl };
// ----------------------------------------------------------------------------
// marshaller
object match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit)
static object
match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit)
{
PyObject *pyobj = (PyObject *)lit;
@@ -247,7 +275,8 @@ object match_lit(PgfMarshaller *this, PgfUnmarshaller *u, PgfLiteral lit)
}
}
object match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr)
static object
match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr)
{
PyObject *pyobj = (PyObject *)expr;
@@ -288,12 +317,14 @@ object match_expr(PgfMarshaller *this, PgfUnmarshaller *u, PgfExpr expr)
}
}
object match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty)
static object
match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty)
{
TypeObject *type = (TypeObject *)ty;
Py_ssize_t n_hypos = PyList_Size(type->hypos);
PgfTypeHypo *hypos = alloca(sizeof(PgfTypeHypo)*n_hypos);
PgfTypeHypo hypos[n_hypos];
// PgfTypeHypo *hypos = alloca(sizeof(PgfTypeHypo)*n_hypos);
for (Py_ssize_t i = 0; i < n_hypos; i++) {
PyObject *hytup = (PyObject *)PyList_GetItem(type->hypos, i);
hypos[i].bind_type = PyLong_AsLong(PyTuple_GetItem(hytup, 0));
@@ -308,7 +339,8 @@ object match_type(PgfMarshaller *this, PgfUnmarshaller *u, PgfType ty)
}
Py_ssize_t n_exprs = PyList_Size(type->exprs);
PgfExpr *exprs = alloca(sizeof(PgfExpr)*n_exprs);
PgfExpr exprs[n_exprs];
// PgfExpr *exprs = alloca(sizeof(PgfExpr)*n_exprs);
for (Py_ssize_t i = 0; i < n_exprs; i++) {
exprs[i] = (PgfExpr)PyList_GetItem(type->exprs, i);
Py_INCREF(exprs[i]);
@@ -335,5 +367,4 @@ static PgfMarshallerVtbl marshallerVtbl =
match_type
};
/* static */
PgfMarshaller marshaller = { &marshallerVtbl };

24
src/runtime/python/ffi.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef PYPGF_FFI_H_
#define PYPGF_FFI_H_
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <pgf/pgf.h>
typedef struct {
PyObject_HEAD
PgfDB *db;
PgfRevision revision;
} PGFObject;
PyObject *PGFError;
PgfExnType handleError(PgfExn err);
PgfText *PyUnicode_AsPgfText(PyObject *pystr);
PyObject *PyUnicode_FromPgfText(PgfText *text);
PgfUnmarshaller unmarshaller;
PgfMarshaller marshaller;
#endif // PYPGF_FFI_H_

View File

@@ -1,15 +0,0 @@
#ifndef PYPGF_MARSHALLER_H_
#define PYPGF_MARSHALLER_H_
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <pgf/pgf.h>
PgfText *PyUnicode_AsPgfText(PyObject *pystr);
PyObject *PyUnicode_FromPgfText(PgfText *text);
extern PgfUnmarshaller unmarshaller;
extern PgfMarshaller marshaller;
#endif // PYPGF_MARSHALLER_H_

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,12 @@ if libraries==['']:
pgf_module = Extension(
'pgf',
sources = ['pypgf.c', 'marshaller.c', 'expr.c'],
sources = [
'pypgf.c',
'expr.c',
'ffi.c',
'transactions.c'
],
extra_compile_args = ['-std=c99', '-Werror', '-Wno-error=unused-variable', '-Wno-comment'],
include_dirs = includes,
library_dirs = libraries,

View File

@@ -1,421 +0,0 @@
import os
import pytest
import pgf
# readPGF
@pytest.fixture(scope="module")
def PGF():
return pgf.readPGF("../haskell/tests/basic.pgf")
def test_readPGF_non_existant():
with pytest.raises(FileNotFoundError):
pgf.readPGF("../haskell/tests/abc.pgf")
def test_readPGF_GF():
with pytest.raises(pgf.PGFError):
pgf.readPGF("../haskell/tests/basic.gf")
def test_readPGF_NGF(NGF):
with pytest.raises(pgf.PGFError):
pgf.readPGF("./basic.ngf")
# bootNGF
@pytest.fixture(scope="module")
def NGF():
ngf = pgf.bootNGF("../haskell/tests/basic.pgf", "./basic.ngf")
yield ngf
os.remove("./basic.ngf")
def test_bootNGF_non_existant():
with pytest.raises(FileNotFoundError):
pgf.bootNGF("../haskell/tests/abc.pgf", "./abc.ngf")
def test_bootNGF_GF():
with pytest.raises(pgf.PGFError):
pgf.bootNGF("../haskell/tests/basic.gf", "./abc.ngf")
def test_bootNGF_NGF(NGF):
with pytest.raises(pgf.PGFError):
pgf.bootNGF("./basic.ngf", "./abc.ngf")
def test_bootNGF_existing(NGF):
with pytest.raises(FileExistsError):
pgf.bootNGF("../haskell/tests/basic.pgf", "./basic.ngf")
# readNGF
def test_readNGF_non_existant():
with pytest.raises(FileNotFoundError):
pgf.readNGF("./abc.ngf")
def test_readNGF_GF():
with pytest.raises(pgf.PGFError):
pgf.readNGF("../haskell/tests/basic.gf")
def test_readNGF_PGF():
with pytest.raises(pgf.PGFError):
pgf.readNGF("../haskell/tests/basic.pgf")
def test_readNGF(NGF):
PGF = pgf.readNGF("./basic.ngf")
assert len(PGF.categories) > 0
# newNGF
def test_newNGF_file(NGF):
PGF = pgf.newNGF("empty", "./empty.ngf")
assert len(PGF.categories) == 0
os.remove("./empty.ngf") # cleanup
def test_newNGF_memory(NGF):
PGF = pgf.newNGF("empty")
assert len(PGF.categories) == 0
def test_newNGF_existing(NGF):
with pytest.raises(FileExistsError):
pgf.newNGF("empty", "./basic.ngf")
# abstract syntax
def test_abstractName(PGF):
assert PGF.abstractName == "basic"
def test_categories(PGF):
assert PGF.categories == ["Float","Int","N","P","S","String"]
def test_functions(PGF):
assert PGF.functions == ["c","ind","s","z"]
def test_functionsByCat_1(PGF):
assert PGF.functionsByCat("N") == ["s","z"]
def test_functionsByCat_2(PGF):
assert PGF.functionsByCat("S") == ["c"]
def test_functionsByCat_non_existant(PGF):
assert PGF.functionsByCat("X") == []
def test_categoryContext_1(PGF):
assert PGF.categoryContext("N") == []
def test_categoryContext_2(PGF):
assert PGF.categoryContext("S") == []
def test_categoryContext_3(PGF):
cxt = PGF.categoryContext("P")
assert len(cxt) == 1
tup = cxt[0]
assert tup[0] == 0 # explicit
assert tup[1] == "_" # cid
assert tup[2] == pgf.readType("N")
def test_categoryContext_4(PGF):
assert PGF.categoryContext("X") == None
def test_functionIsConstructor_1(PGF):
assert PGF.functionIsConstructor("s") == True
def test_functionIsConstructor_2(PGF):
assert PGF.functionIsConstructor("z") == True
def test_functionIsConstructor_3(PGF):
assert PGF.functionIsConstructor("c") == True
def test_functionIsConstructor_4(PGF):
assert PGF.functionIsConstructor("ind") == False
# types
def test_readType_invalid():
with pytest.raises(pgf.PGFError):
pgf.readType("->")
def test_readType_equality_1():
assert pgf.readType("A") == pgf.readType("A")
def test_readType_equality_2():
assert pgf.readType("A -> B") == pgf.readType("A->B")
def test_readType_equality_3():
assert pgf.readType("A -> B -> C") == pgf.readType("A->B -> C")
def test_readType_inequality_1():
assert pgf.readType("A") != pgf.readType("B")
def test_readType_inequality_2():
assert pgf.readType("A -> B") != pgf.readType("B->B")
def test_readType_str():
assert str(pgf.readType("A-> BÄ->C")) == "A -> BÄ -> C"
def test_functionType_1(PGF):
assert PGF.functionType("z") == pgf.readType("N")
def test_functionType_2(PGF):
assert PGF.functionType("s") == pgf.readType("N->N")
def test_functionType_3(PGF):
assert PGF.functionType("c") == pgf.readType("N -> S")
def test_functionType_non_existant(PGF):
with pytest.raises(KeyError):
assert PGF.functionType("cbx")
def test_functionType_wrong(PGF):
assert PGF.functionType("c") != pgf.readType("N -> S -> X")
def test_startCat(PGF):
assert PGF.startCat == pgf.readType("S")
def test_showType_1(PGF):
type = pgf.Type([], "N", [])
assert pgf.showType([], type) == "N"
def test_showType_2(PGF):
type = pgf.Type([pgf.mkHypo(pgf.Type([], "N", []))], "N", [])
assert pgf.showType([], type) == "N -> N"
def test_showType_3(PGF):
type = pgf.Type([pgf.mkHypo(pgf.Type([pgf.mkHypo(pgf.Type([], "N", []))], "N", []))], "N", [])
assert pgf.showType([], type) == "(N -> N) -> N"
def test_showType_4(PGF):
type = pgf.Type([pgf.mkDepHypo("x", pgf.Type([], "N", []))], "P", [pgf.ExprVar(0)])
assert pgf.showType([], type) == "(x : N) -> P x"
def test_showType_5(PGF):
type = pgf.Type([pgf.mkDepHypo("f", pgf.Type([pgf.mkHypo(pgf.Type([], "N", []))], "N", []))], "P", [pgf.ExprApp(pgf.ExprVar(0), pgf.ExprFun("z"))])
assert pgf.showType([], type) == "(f : N -> N) -> P (f z)"
def test_showType_6(PGF):
type = pgf.Type([pgf.mkDepHypo("f", pgf.Type([pgf.mkHypo(pgf.Type([], "N", []))], "N", []))], "P", [pgf.ExprApp(pgf.ExprVar(0), pgf.ExprVar(1))])
assert pgf.showType(["n"], type) == "(f : N -> N) -> P (f n)"
def test_showType_7(PGF):
type = pgf.Type([pgf.mkImplHypo("f", pgf.Type([pgf.mkHypo(pgf.Type([], "N", []))], "N", []))], "P", [pgf.ExprApp(pgf.ExprVar(0), pgf.ExprVar(1))])
assert pgf.showType(["n"], type) == "({f} : N -> N) -> P (f n)"
def test_showType_8(PGF):
type = pgf.Type([pgf.mkDepHypo("x", pgf.Type([], "N", [])), pgf.mkHypo(pgf.Type([], "P", [pgf.ExprVar(0)]))], "S", [])
assert pgf.showType(["n"], type) == "(x : N) -> P x -> S"
def test_showType_9(PGF):
type = pgf.Type([pgf.mkDepHypo("x", pgf.Type([], "N", [])), pgf.mkDepHypo("y", pgf.Type([], "P", [pgf.ExprVar(0)]))], "S", [])
assert pgf.showType(["n"], type) == "(x : N) -> (y : P x) -> S"
# expressions
def test_readExpr_invalid():
with pytest.raises(pgf.PGFError):
pgf.readExpr("->")
# expressions: literals
def test_readExpr_lint_equality():
assert pgf.readExpr("123") == pgf.ExprLit(123)
def test_readExpr_lint_equality_neg():
assert pgf.readExpr("-123") == pgf.ExprLit(-123)
def test_readExpr_lint_equality_big2():
assert pgf.readExpr("774763251095801167872") == pgf.ExprLit(774763251095801167872)
def test_readExpr_lint_equality_big2_neg():
assert pgf.readExpr("-774763251095801167872") == pgf.ExprLit(-774763251095801167872)
def test_readExpr_lint_inequality():
assert pgf.readExpr("123") != pgf.ExprLit(456)
def test_readExpr_lflt_equality():
assert pgf.readExpr("3.142") == pgf.ExprLit(3.142)
def test_readExpr_lflt_inequality():
assert pgf.readExpr("3.142") != pgf.ExprLit(3)
def test_readExpr_lstr_equality():
assert pgf.readExpr("\"abc\"") == pgf.ExprLit("abc")
def test_readExpr_lstr_inequality():
assert pgf.readExpr("\"abc\"") != pgf.ExprLit("def")
def test_readExpr_lint_str():
assert str(pgf.readExpr("123")) == "123"
def test_readExpr_lint_str_neg():
assert str(pgf.readExpr("-123")) == "-123"
def test_readExpr_lint_str_big2():
assert str(pgf.readExpr("774763251095801167872")) == "774763251095801167872"
def test_readExpr_lint_str_big3():
assert str(pgf.readExpr("7747632510958011678729003251095801167999")) == "7747632510958011678729003251095801167999"
def test_readExpr_lint_str_big2_neg():
assert str(pgf.readExpr("-774763251095801167872")) == "-774763251095801167872"
def test_readExpr_lint_str_big3_neg():
assert str(pgf.readExpr("-7747632510958011678729003251095801167999")) == "-7747632510958011678729003251095801167999"
def test_readExpr_lflt_str():
assert str(pgf.readExpr("3.142")) == "3.142"
def test_readExpr_lstr_str_unicode():
assert str(pgf.readExpr("\"açġħ\"")) == "\"açġħ\""
def test_readExpr_lstr_null():
assert str(pgf.ExprLit("ab\0c")) == "\"ab\\0c\""
def test_readExpr_lstr_newline():
assert str(pgf.ExprLit("ab\nc")) == "\"ab\\nc\""
# expressions: functions
def test_readExpr_efun_equality_1():
assert pgf.readExpr("f") == pgf.ExprFun("f")
def test_readExpr_efun_equality_2():
assert \
pgf.readExpr("f x y") == \
pgf.ExprApp(
pgf.ExprApp(
pgf.ExprFun("f"),
pgf.ExprFun("x")
),
pgf.ExprFun("y")
)
def test_readExpr_efun_equality_3():
assert \
pgf.readExpr("f (g x)") == \
pgf.ExprApp(
pgf.ExprFun("f"),
pgf.ExprApp(
pgf.ExprFun("g"),
pgf.ExprFun("x")
)
)
def test_readExpr_efun_equality_4():
assert \
pgf.readExpr("f {g x}") == \
pgf.ExprApp(
pgf.ExprFun("f"),
pgf.ExprImplArg(
pgf.ExprApp(
pgf.ExprFun("g"),
pgf.ExprFun("x")
)
)
)
def test_readExpr_efun_str_unicode_1():
assert str(pgf.readExpr("'абв'")) == "'абв'"
@pytest.mark.skip(reason="failing")
def test_readExpr_efun_str_unicode_2():
assert str(pgf.readExpr("'аb'")) == "аb"
@pytest.mark.skip(reason="failing")
def test_readExpr_efun_str_unicode_3():
assert str(pgf.readExpr("'а\\'b'")) == "а'b"
def test_readExpr_efun_str_unicode_4():
assert str(pgf.readExpr("'а\\'б'")) == "'а\\'б'"
# expressions: variables
# def test_readExpr_evar_equality_1():
# assert pgf.readExpr("#0") == pgf.ExprVar()
# assert pgf.readExpr("#0") == pgf.ExprVar(0)
# def test_readExpr_evar_equality_2():
# assert pgf.readExpr("#42") == pgf.ExprVar(42)
def test_readExpr_evar_str_1():
assert str(pgf.ExprVar(0)) == "#0"
def test_readExpr_evar_str_2():
assert str(pgf.ExprVar(42)) == "#42"
def test_showExpr_evar_1():
assert pgf.showExpr(["x"], pgf.ExprVar(0)) == "x"
def test_showExpr_evar_2():
assert pgf.showExpr(["x"], pgf.ExprVar(1)) == "#1"
def test_showExpr_evar_3():
assert pgf.showExpr(["z", "y", "x"], pgf.ExprVar(0)) == "z"
def test_showExpr_evar_4():
assert pgf.showExpr(["z", "y", "x"], pgf.ExprVar(1)) == "y"
# expressions: lambda abstractions
def test_showExpr_eabs_1():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "w", pgf.ExprVar(0))
assert pgf.showExpr(["z", "y", "x"], expr) == "\\w->w"
def test_showExpr_eabs_2():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "w", pgf.ExprVar(2)))
assert pgf.showExpr(["z", "y", "x"], expr) == "\\v,w->z"
def test_showExpr_eabs_3():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "w", pgf.ExprVar(2)))
assert pgf.showExpr(["z", "y", "x"], expr) == "\\v,{w}->z"
def test_showExpr_eabs_4():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "w", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "z", pgf.ExprVar(0))))
assert pgf.showExpr(["y", "x"], expr) == "\\v,{w},z->z"
def test_showExpr_eabs_5():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "w", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "z", pgf.ExprVar(2))))
assert pgf.showExpr(["y", "x"], expr) == "\\v,{w,z}->v"
def test_showExpr_eabs_6():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "w", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "z", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "t", pgf.ExprVar(3)))))
assert pgf.showExpr(["y", "x"], expr) == "\\v,{w,z},t->v"
def test_showExpr_eabs_7():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "u", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "w", pgf.ExprAbs(pgf.BIND_TYPE_IMPLICIT, "z", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "t", pgf.ExprVar(3))))))
assert pgf.showExpr(["y", "x"], expr) == "\\u,v,{w,z},t->v"
def test_showExpr_eabs_8():
expr = pgf.ExprApp(pgf.ExprFun("f"), pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "x", pgf.ExprVar(0)))
assert pgf.showExpr([], expr) == "f (\\x->x)"
def test_showExpr_eabs_freshvars_1():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprVar(0)))
assert pgf.showExpr([], expr) == "\\v,v1->v1"
def test_showExpr_eabs_freshvars_2():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprVar(1)))
assert pgf.showExpr([], expr) == "\\v,v1->v"
def test_showExpr_eabs_freshvars_3():
expr = pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprAbs(pgf.BIND_TYPE_EXPLICIT, "v", pgf.ExprVar(1))))
assert pgf.showExpr([], expr) == "\\v,v1,v2->v1"
# expressions: meta variables
def test_readExpr_emeta_1():
assert pgf.readExpr("?") == pgf.ExprMeta()
assert pgf.readExpr("?") == pgf.ExprMeta(0)
def test_readExpr_emeta_2():
assert pgf.readExpr("?42") == pgf.ExprMeta(42)
def test_readExpr_emeta_str_1():
assert str(pgf.readExpr("?")) == "?"
def test_readExpr_emeta_str_2():
assert str(pgf.readExpr("?42")) == "?42"
# expressions: typed expressions
def test_readExpr_emeta_equality():
assert pgf.readExpr("<z : N>") == pgf.ExprTyped(pgf.ExprFun("z"), pgf.readType("N"))
def test_readExpr_emeta_str():
assert str(pgf.readExpr("<z : N>")) == "<z : N>"

View File

@@ -0,0 +1,421 @@
import os
import pytest
from pgf import *
# readPGF
@pytest.fixture(scope="module")
def PGF():
return readPGF("../haskell/tests/basic.pgf")
def test_readPGF_non_existant():
with pytest.raises(FileNotFoundError):
readPGF("../haskell/tests/abc.pgf")
def test_readPGF_GF():
with pytest.raises(PGFError):
readPGF("../haskell/tests/basic.gf")
def test_readPGF_NGF(NGF):
with pytest.raises(PGFError):
readPGF("./basic.ngf")
# bootNGF
@pytest.fixture(scope="module")
def NGF():
ngf = bootNGF("../haskell/tests/basic.pgf", "./basic.ngf")
yield ngf
os.remove("./basic.ngf")
def test_bootNGF_non_existant():
with pytest.raises(FileNotFoundError):
bootNGF("../haskell/tests/abc.pgf", "./abc.ngf")
def test_bootNGF_GF():
with pytest.raises(PGFError):
bootNGF("../haskell/tests/basic.gf", "./abc.ngf")
def test_bootNGF_NGF(NGF):
with pytest.raises(PGFError):
bootNGF("./basic.ngf", "./abc.ngf")
def test_bootNGF_existing(NGF):
with pytest.raises(FileExistsError):
bootNGF("../haskell/tests/basic.pgf", "./basic.ngf")
# readNGF
def test_readNGF_non_existant():
with pytest.raises(FileNotFoundError):
readNGF("./abc.ngf")
def test_readNGF_GF():
with pytest.raises(PGFError):
readNGF("../haskell/tests/basic.gf")
def test_readNGF_PGF():
with pytest.raises(PGFError):
readNGF("../haskell/tests/basic.pgf")
def test_readNGF(NGF):
PGF = readNGF("./basic.ngf")
assert len(PGF.categories) > 0
# newNGF
def test_newNGF_file(NGF):
PGF = newNGF("empty", "./empty.ngf")
assert len(PGF.categories) == 0
os.remove("./empty.ngf") # cleanup
def test_newNGF_memory(NGF):
PGF = newNGF("empty")
assert len(PGF.categories) == 0
def test_newNGF_existing(NGF):
with pytest.raises(FileExistsError):
newNGF("empty", "./basic.ngf")
# abstract syntax
def test_abstractName(PGF):
assert PGF.abstractName == "basic"
def test_categories(PGF):
assert PGF.categories == ["Float","Int","N","P","S","String"]
def test_functions(PGF):
assert PGF.functions == ["c","ind","s","z"]
def test_functionsByCat_1(PGF):
assert PGF.functionsByCat("N") == ["s","z"]
def test_functionsByCat_2(PGF):
assert PGF.functionsByCat("S") == ["c"]
def test_functionsByCat_non_existant(PGF):
assert PGF.functionsByCat("X") == []
def test_categoryContext_1(PGF):
assert PGF.categoryContext("N") == []
def test_categoryContext_2(PGF):
assert PGF.categoryContext("S") == []
def test_categoryContext_3(PGF):
cxt = PGF.categoryContext("P")
assert len(cxt) == 1
tup = cxt[0]
assert tup[0] == 0 # explicit
assert tup[1] == "_" # cid
assert tup[2] == readType("N")
def test_categoryContext_4(PGF):
assert PGF.categoryContext("X") == None
def test_functionIsConstructor_1(PGF):
assert PGF.functionIsConstructor("s") == True
def test_functionIsConstructor_2(PGF):
assert PGF.functionIsConstructor("z") == True
def test_functionIsConstructor_3(PGF):
assert PGF.functionIsConstructor("c") == True
def test_functionIsConstructor_4(PGF):
assert PGF.functionIsConstructor("ind") == False
# types
def test_readType_invalid():
with pytest.raises(PGFError):
readType("->")
def test_readType_equality_1():
assert readType("A") == readType("A")
def test_readType_equality_2():
assert readType("A -> B") == readType("A->B")
def test_readType_equality_3():
assert readType("A -> B -> C") == readType("A->B -> C")
def test_readType_inequality_1():
assert readType("A") != readType("B")
def test_readType_inequality_2():
assert readType("A -> B") != readType("B->B")
def test_readType_str():
assert str(readType("A-> BÄ->C")) == "A -> BÄ -> C"
def test_functionType_1(PGF):
assert PGF.functionType("z") == readType("N")
def test_functionType_2(PGF):
assert PGF.functionType("s") == readType("N->N")
def test_functionType_3(PGF):
assert PGF.functionType("c") == readType("N -> S")
def test_functionType_non_existant(PGF):
with pytest.raises(KeyError):
assert PGF.functionType("cbx")
def test_functionType_wrong(PGF):
assert PGF.functionType("c") != readType("N -> S -> X")
def test_startCat(PGF):
assert PGF.startCat == readType("S")
def test_showType_1(PGF):
type = Type([], "N", [])
assert showType([], type) == "N"
def test_showType_2(PGF):
type = Type([mkHypo(Type([], "N", []))], "N", [])
assert showType([], type) == "N -> N"
def test_showType_3(PGF):
type = Type([mkHypo(Type([mkHypo(Type([], "N", []))], "N", []))], "N", [])
assert showType([], type) == "(N -> N) -> N"
def test_showType_4(PGF):
type = Type([mkDepHypo("x", Type([], "N", []))], "P", [ExprVar(0)])
assert showType([], type) == "(x : N) -> P x"
def test_showType_5(PGF):
type = Type([mkDepHypo("f", Type([mkHypo(Type([], "N", []))], "N", []))], "P", [ExprApp(ExprVar(0), ExprFun("z"))])
assert showType([], type) == "(f : N -> N) -> P (f z)"
def test_showType_6(PGF):
type = Type([mkDepHypo("f", Type([mkHypo(Type([], "N", []))], "N", []))], "P", [ExprApp(ExprVar(0), ExprVar(1))])
assert showType(["n"], type) == "(f : N -> N) -> P (f n)"
def test_showType_7(PGF):
type = Type([mkImplHypo("f", Type([mkHypo(Type([], "N", []))], "N", []))], "P", [ExprApp(ExprVar(0), ExprVar(1))])
assert showType(["n"], type) == "({f} : N -> N) -> P (f n)"
def test_showType_8(PGF):
type = Type([mkDepHypo("x", Type([], "N", [])), mkHypo(Type([], "P", [ExprVar(0)]))], "S", [])
assert showType(["n"], type) == "(x : N) -> P x -> S"
def test_showType_9(PGF):
type = Type([mkDepHypo("x", Type([], "N", [])), mkDepHypo("y", Type([], "P", [ExprVar(0)]))], "S", [])
assert showType(["n"], type) == "(x : N) -> (y : P x) -> S"
# expressions
def test_readExpr_invalid():
with pytest.raises(PGFError):
readExpr("->")
# expressions: literals
def test_readExpr_lint_equality():
assert readExpr("123") == ExprLit(123)
def test_readExpr_lint_equality_neg():
assert readExpr("-123") == ExprLit(-123)
def test_readExpr_lint_equality_big2():
assert readExpr("774763251095801167872") == ExprLit(774763251095801167872)
def test_readExpr_lint_equality_big2_neg():
assert readExpr("-774763251095801167872") == ExprLit(-774763251095801167872)
def test_readExpr_lint_inequality():
assert readExpr("123") != ExprLit(456)
def test_readExpr_lflt_equality():
assert readExpr("3.142") == ExprLit(3.142)
def test_readExpr_lflt_inequality():
assert readExpr("3.142") != ExprLit(3)
def test_readExpr_lstr_equality():
assert readExpr("\"abc\"") == ExprLit("abc")
def test_readExpr_lstr_inequality():
assert readExpr("\"abc\"") != ExprLit("def")
def test_readExpr_lint_str():
assert str(readExpr("123")) == "123"
def test_readExpr_lint_str_neg():
assert str(readExpr("-123")) == "-123"
def test_readExpr_lint_str_big2():
assert str(readExpr("774763251095801167872")) == "774763251095801167872"
def test_readExpr_lint_str_big3():
assert str(readExpr("7747632510958011678729003251095801167999")) == "7747632510958011678729003251095801167999"
def test_readExpr_lint_str_big2_neg():
assert str(readExpr("-774763251095801167872")) == "-774763251095801167872"
def test_readExpr_lint_str_big3_neg():
assert str(readExpr("-7747632510958011678729003251095801167999")) == "-7747632510958011678729003251095801167999"
def test_readExpr_lflt_str():
assert str(readExpr("3.142")) == "3.142"
def test_readExpr_lstr_str_unicode():
assert str(readExpr("\"açġħ\"")) == "\"açġħ\""
def test_readExpr_lstr_null():
assert str(ExprLit("ab\0c")) == "\"ab\\0c\""
def test_readExpr_lstr_newline():
assert str(ExprLit("ab\nc")) == "\"ab\\nc\""
# expressions: functions
def test_readExpr_efun_equality_1():
assert readExpr("f") == ExprFun("f")
def test_readExpr_efun_equality_2():
assert \
readExpr("f x y") == \
ExprApp(
ExprApp(
ExprFun("f"),
ExprFun("x")
),
ExprFun("y")
)
def test_readExpr_efun_equality_3():
assert \
readExpr("f (g x)") == \
ExprApp(
ExprFun("f"),
ExprApp(
ExprFun("g"),
ExprFun("x")
)
)
def test_readExpr_efun_equality_4():
assert \
readExpr("f {g x}") == \
ExprApp(
ExprFun("f"),
ExprImplArg(
ExprApp(
ExprFun("g"),
ExprFun("x")
)
)
)
def test_readExpr_efun_str_unicode_1():
assert str(readExpr("'абв'")) == "'абв'"
@pytest.mark.skip(reason="failing")
def test_readExpr_efun_str_unicode_2():
assert str(readExpr("'аb'")) == "аb"
@pytest.mark.skip(reason="failing")
def test_readExpr_efun_str_unicode_3():
assert str(readExpr("'а\\'b'")) == "а'b"
def test_readExpr_efun_str_unicode_4():
assert str(readExpr("'а\\'б'")) == "'а\\'б'"
# expressions: variables
# def test_readExpr_evar_equality_1():
# assert readExpr("#0") == ExprVar()
# assert readExpr("#0") == ExprVar(0)
# def test_readExpr_evar_equality_2():
# assert readExpr("#42") == ExprVar(42)
def test_readExpr_evar_str_1():
assert str(ExprVar(0)) == "#0"
def test_readExpr_evar_str_2():
assert str(ExprVar(42)) == "#42"
def test_showExpr_evar_1():
assert showExpr(["x"], ExprVar(0)) == "x"
def test_showExpr_evar_2():
assert showExpr(["x"], ExprVar(1)) == "#1"
def test_showExpr_evar_3():
assert showExpr(["z", "y", "x"], ExprVar(0)) == "z"
def test_showExpr_evar_4():
assert showExpr(["z", "y", "x"], ExprVar(1)) == "y"
# expressions: lambda abstractions
def test_showExpr_eabs_1():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "w", ExprVar(0))
assert showExpr(["z", "y", "x"], expr) == "\\w->w"
def test_showExpr_eabs_2():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "w", ExprVar(2)))
assert showExpr(["z", "y", "x"], expr) == "\\v,w->z"
def test_showExpr_eabs_3():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_IMPLICIT, "w", ExprVar(2)))
assert showExpr(["z", "y", "x"], expr) == "\\v,{w}->z"
def test_showExpr_eabs_4():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_IMPLICIT, "w", ExprAbs(BIND_TYPE_EXPLICIT, "z", ExprVar(0))))
assert showExpr(["y", "x"], expr) == "\\v,{w},z->z"
def test_showExpr_eabs_5():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_IMPLICIT, "w", ExprAbs(BIND_TYPE_IMPLICIT, "z", ExprVar(2))))
assert showExpr(["y", "x"], expr) == "\\v,{w,z}->v"
def test_showExpr_eabs_6():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_IMPLICIT, "w", ExprAbs(BIND_TYPE_IMPLICIT, "z", ExprAbs(BIND_TYPE_EXPLICIT, "t", ExprVar(3)))))
assert showExpr(["y", "x"], expr) == "\\v,{w,z},t->v"
def test_showExpr_eabs_7():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "u", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_IMPLICIT, "w", ExprAbs(BIND_TYPE_IMPLICIT, "z", ExprAbs(BIND_TYPE_EXPLICIT, "t", ExprVar(3))))))
assert showExpr(["y", "x"], expr) == "\\u,v,{w,z},t->v"
def test_showExpr_eabs_8():
expr = ExprApp(ExprFun("f"), ExprAbs(BIND_TYPE_EXPLICIT, "x", ExprVar(0)))
assert showExpr([], expr) == "f (\\x->x)"
def test_showExpr_eabs_freshvars_1():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprVar(0)))
assert showExpr([], expr) == "\\v,v1->v1"
def test_showExpr_eabs_freshvars_2():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprVar(1)))
assert showExpr([], expr) == "\\v,v1->v"
def test_showExpr_eabs_freshvars_3():
expr = ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprAbs(BIND_TYPE_EXPLICIT, "v", ExprVar(1))))
assert showExpr([], expr) == "\\v,v1,v2->v1"
# expressions: meta variables
def test_readExpr_emeta_1():
assert readExpr("?") == ExprMeta()
assert readExpr("?") == ExprMeta(0)
def test_readExpr_emeta_2():
assert readExpr("?42") == ExprMeta(42)
def test_readExpr_emeta_str_1():
assert str(readExpr("?")) == "?"
def test_readExpr_emeta_str_2():
assert str(readExpr("?42")) == "?42"
# expressions: typed expressions
def test_readExpr_emeta_equality():
assert readExpr("<z : N>") == ExprTyped(ExprFun("z"), readType("N"))
def test_readExpr_emeta_str():
assert str(readExpr("<z : N>")) == "<z : N>"

View File

@@ -0,0 +1,71 @@
import pytest
from pgf import *
import math
ty = readType("(N -> N) -> P (s z)")
prob = math.pi
@pytest.fixture(scope="module")
def gr1():
return readPGF("../haskell/tests/basic.pgf")
@pytest.fixture(scope="module")
def gr2(gr1):
t = gr1.newTransaction()
t.createFunction("foo", ty, 0, prob),
t.createCategory("Q", [(BIND_TYPE_EXPLICIT, "x", ty)], prob)
assert t.commit()
return gr1
@pytest.fixture(scope="module")
def gr3():
# TODO how to avoid reloading from file?
gr1 = readPGF("../haskell/tests/basic.pgf")
with gr1.newTransaction("bar_branch") as t:
t.createFunction("bar", ty, 0, prob),
t.createCategory("R", [(BIND_TYPE_EXPLICIT, "x", ty)], prob)
return gr1
# gr1
def test_original_functions(gr1):
assert gr1.functions == ["c", "ind", "s", "z"]
def test_original_categories(gr1):
assert gr1.categories == ["Float","Int","N","P","S","String"]
def test_original_function_type(gr1):
with pytest.raises(KeyError):
gr1.functionType("foo")
def test_original_function_prob(gr1):
# with pytest.raises(KeyError):
# gr1.functionProbability("foo")
assert gr1.functionProbability("foo") == float('inf')
# gr2
def test_extended_functions(gr2):
assert gr2.functions == ["c", "foo", "ind", "s", "z"]
def test_extended_categories(gr2):
assert gr2.categories == ["Float","Int","N","P","Q","S","String"]
def test_extended_category_context(gr2):
assert gr2.categoryContext("Q") == [(BIND_TYPE_EXPLICIT, "x", ty)]
def test_extended_function_type(gr2):
assert gr2.functionType("foo") == ty
def test_extended_function_prob(gr2):
# TODO: can't we get higher precision?
# assert gr2.functionProbability("foo") == prob
assert math.isclose(gr2.functionProbability("foo"), prob, rel_tol=1e-06)
# gr3
def test_branched_functions(gr3):
assert gr3.functions == ["bar", "c", "ind", "s", "z"]
def test_branched_function_type(gr3):
assert gr3.functionType("bar") == ty

View File

@@ -0,0 +1,276 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
#include <pgf/pgf.h>
#include "./expr.h"
#include "./ffi.h"
#include "./transactions.h"
TransactionObject *
PGF_newTransaction(PGFObject *self, PyObject *args)
{
PgfText *name = NULL;
const char *s = NULL;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "|s#", &s, &size))
return NULL;
if (s != NULL) {
name = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1);
memcpy(name->text, s, size+1);
name->size = size;
}
PgfExn err;
PgfRevision rev = pgf_clone_revision(self->db, self->revision, name, &err);
if (name != NULL) {
PyMem_Free(name);
}
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
TransactionObject *trans = (TransactionObject *)pgf_TransactionType.tp_alloc(&pgf_TransactionType, 0);
trans->pgf = self;
trans->revision = rev;
return trans;
}
static PyObject *
Transaction_commit(TransactionObject *self, PyObject *args)
{
PgfExn err;
pgf_commit_revision(self->pgf->db, self->revision, &err);
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
pgf_free_revision(self->pgf->db, self->pgf->revision);
self->pgf->revision = self->revision;
Py_RETURN_TRUE;
}
static PyObject *
Transaction_createFunction(TransactionObject *self, PyObject *args)
{
const char *s;
Py_ssize_t size;
TypeObject *type;
Py_ssize_t arity = 0;
float prob = 0.0;
if (!PyArg_ParseTuple(args, "s#O!nf", &s, &size, &pgf_TypeType, &type, &arity, &prob))
return NULL;
PgfText *fname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1);
memcpy(fname->text, s, size+1);
fname->size = size;
PgfExn err;
pgf_create_function(self->pgf->db, self->revision, fname, (PgfType) type, arity, prob, &marshaller, &err);
PyMem_Free(fname);
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
Transaction_dropFunction(TransactionObject *self, PyObject *args)
{
const char *s;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "s#", &s, &size))
return NULL;
PgfText *fname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1);
memcpy(fname->text, s, size+1);
fname->size = size;
PgfExn err;
pgf_drop_category(self->pgf->db, self->revision, fname, &err);
PyMem_Free(fname);
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
Transaction_createCategory(TransactionObject *self, PyObject *args)
{
const char *s;
Py_ssize_t size;
PyObject *hypos;
float prob = 0.0;
if (!PyArg_ParseTuple(args, "s#O!f", &s, &size, &PyList_Type, &hypos, prob))
return NULL;
PgfText *catname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1);
memcpy(catname->text, s, size+1);
catname->size = size;
Py_ssize_t n_hypos = PyList_Size(hypos);
PgfTypeHypo context[n_hypos];
// PgfTypeHypo *context = alloca(sizeof(PgfTypeHypo)*n_hypos);
for (Py_ssize_t i = 0; i < n_hypos; i++) {
PyObject *hytup = (PyObject *)PyList_GetItem(hypos, i);
context[i].bind_type = PyLong_AsLong(PyTuple_GetItem(hytup, 0));
context[i].cid = PyUnicode_AsPgfText(PyTuple_GetItem(hytup, 1));
context[i].type = (PgfType) PyTuple_GetItem(hytup, 2);
Py_INCREF(context[i].type);
}
PgfExn err;
pgf_create_category(self->pgf->db, self->revision, catname, n_hypos, context, prob, &marshaller, &err);
PyMem_Free(catname);
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
Transaction_dropCategory(TransactionObject *self, PyObject *args)
{
const char *s;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "s#", &s, &size))
return NULL;
PgfText *catname = (PgfText *)PyMem_Malloc(sizeof(PgfText)+size+1);
memcpy(catname->text, s, size+1);
catname->size = size;
PgfExn err;
pgf_drop_function(self->pgf->db, self->revision, catname, &err);
PyMem_Free(catname);
if (handleError(err) != PGF_EXN_NONE) {
return NULL;
}
Py_RETURN_NONE;
}
static TransactionObject *
Transaction_enter(TransactionObject *self, PyObject *Py_UNUSED(ignored))
{
return self;
}
static PyObject *
Transaction_exit(TransactionObject *self, PyObject *const *args, Py_ssize_t nargs)
{
// PyObject *exc_type = Py_None;
// PyObject *exc_value = Py_None;
// PyObject *exc_tb = Py_None;
// if (!_PyArg_CheckPositional("__exit__", nargs, 0, 3)) {
// Py_RETURN_FALSE;
// }
if (nargs < 1) {
goto skip_optional;
}
// exc_type = args[0];
// if (nargs < 2) {
// goto skip_optional;
// }
// exc_value = args[1];
// if (nargs < 3) {
// goto skip_optional;
// }
// exc_tb = args[2];
skip_optional:
// TODO check exception
return Transaction_commit(self, NULL);
}
// static void
// Transaction_dealloc(PGFObject* self)
// {
// Py_TYPE(self)->tp_free((PyObject*)self);
// }
static PyGetSetDef Transaction_getseters[] = {
{NULL} /* Sentinel */
};
static PyMemberDef Transaction_members[] = {
{NULL} /* Sentinel */
};
static PyMethodDef Transaction_methods[] = {
{"commit", (PyCFunction)Transaction_commit, METH_VARARGS,
"Commit transaction"
},
{"__enter__", (PyCFunction)Transaction_enter, METH_NOARGS,
""
},
{"__exit__", (PyCFunction)(void(*)(void))Transaction_exit, METH_FASTCALL,
""
},
{"createFunction", (PyCFunction)Transaction_createFunction, METH_VARARGS,
"Create function"
},
{"dropFunction", (PyCFunction)Transaction_dropFunction, METH_VARARGS,
"Drop function"
},
{"createCategory", (PyCFunction)Transaction_createCategory, METH_VARARGS,
"Create category"
},
{"dropCategory", (PyCFunction)Transaction_dropCategory, METH_VARARGS,
"Drop category"
},
{NULL} /* Sentinel */
};
PyTypeObject pgf_TransactionType = {
PyVarObject_HEAD_INIT(NULL, 0)
//0, /*ob_size*/
"pgf.Transaction", /*tp_name*/
sizeof(TransactionObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, //(destructor)Transaction_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, // (reprfunc) Transaction_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"Transaction object", /*tp_doc*/
0, /*tp_traverse */
0, /*tp_clear */
0, /*tp_richcompare */
0, /*tp_weaklistoffset */
0, /*tp_iter */
0, /*tp_iternext */
Transaction_methods, /*tp_methods */
Transaction_members, /*tp_members */
Transaction_getseters, /*tp_getset */
0, /*tp_base */
0, /*tp_dict */
0, /*tp_descr_get */
0, /*tp_descr_set */
0, /*tp_dictoffset */
0, /*tp_init */
0, /*tp_alloc */
0, /*tp_new */
};

View File

@@ -0,0 +1,20 @@
#ifndef PYPGF_TRANSACTIONS_H_
#define PYPGF_TRANSACTIONS_H_
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <pgf/pgf.h>
typedef struct {
PyObject_HEAD
PGFObject *pgf; // original reference, gets updated on commit
PgfRevision revision; // transient branch
} TransactionObject;
PyTypeObject pgf_TransactionType;
TransactionObject *
PGF_newTransaction(PGFObject *self, PyObject *args);
#endif // PYPGF_TRANSACTIONS_H_