Skip to content

Commit 540240d

Browse files
committed
[GR-9716] Implement abstract C API function.
PullRequest: graalpython-open/37
2 parents b07c135 + 924ad6e commit 540240d

26 files changed

+739
-177
lines changed

graalpython/com.oracle.graal.python.cext/src/abstract.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,58 @@ PyObject * PyIter_Next(PyObject *iter) {
208208
}
209209
return to_sulong(result);
210210
}
211+
212+
int PySequence_Check(PyObject *s) {
213+
if (s == NULL) {
214+
return 0;
215+
}
216+
return polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_Check", to_java(s)));
217+
}
218+
219+
Py_ssize_t PySequence_Size(PyObject *s) {
220+
return polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyObject_Size", to_java(s)));
221+
}
222+
223+
// taken from CPython "Objects/abstract.c"
224+
#undef PySequence_Length
225+
Py_ssize_t PySequence_Length(PyObject *s) {
226+
return PySequence_Size(s);
227+
}
228+
#define PySequence_Length PySequence_Size
229+
230+
PyObject* PySequence_GetItem(PyObject *s, Py_ssize_t i) {
231+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_GetItem", to_java(s), i, ERROR_MARKER);
232+
if(result == ERROR_MARKER) {
233+
return NULL;
234+
}
235+
return to_sulong(result);
236+
}
237+
238+
int PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) {
239+
return polyglot_as_i32(polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_SetItem", to_java(s), i, to_java(o)));
240+
}
241+
242+
PyObject* PySequence_Tuple(PyObject *v) {
243+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_Tuple", to_java(v), ERROR_MARKER);
244+
if(result == ERROR_MARKER) {
245+
return NULL;
246+
}
247+
return to_sulong(result);
248+
}
249+
250+
PyObject * PySequence_Fast(PyObject *v, const char *m) {
251+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_Fast", to_java(v), polyglot_from_string(m, "ascii"), ERROR_MARKER);
252+
if(result == ERROR_MARKER) {
253+
return NULL;
254+
}
255+
return to_sulong(result);
256+
}
257+
258+
PyObject * PyMapping_GetItemString(PyObject *o, const char *key) {
259+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PyObject_GetItem", to_java(o), polyglot_from_string(key, "utf-8"), ERROR_MARKER);
260+
if(result == ERROR_MARKER) {
261+
return NULL;
262+
}
263+
return to_sulong(result);
264+
}
265+

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static void initialize_globals() {
5252
truffle_assign_managed(&_Py_NoneStruct, jnone);
5353

5454
// NotImplemented
55-
void *jnotimpl = polyglot_as__object(polyglot_get_member(PY_BUILTIN, "NotImplemented"));
55+
void *jnotimpl = polyglot_as__object(to_sulong(polyglot_get_member(PY_BUILTIN, "NotImplemented")));
5656
truffle_assign_managed(&_Py_NotImplementedStruct, jnotimpl);
5757

5858
// True, False

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py

Lines changed: 203 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,40 @@ def _reference_next(args):
8686
raise SystemError
8787

8888

89+
def _reference_size(args):
90+
seq = args[0]
91+
if isinstance(seq, dict):
92+
return -1
93+
if not hasattr(seq, '__len__'):
94+
raise TypeError()
95+
return len(seq)
96+
97+
98+
def _reference_getitem(args):
99+
seq = args[0]
100+
idx = args[1]
101+
if not hasattr(seq, '__getitem__'):
102+
raise TypeError
103+
return seq.__getitem__(idx)
104+
105+
106+
def _reference_setitem(args):
107+
seq = args[0]
108+
idx = args[1]
109+
value = args[2]
110+
if not hasattr(seq, '__setitem__'):
111+
raise TypeError
112+
seq.__setitem__(idx, value)
113+
return seq
114+
115+
116+
def _reference_fast(args):
117+
obj = args[0]
118+
if isinstance(obj, tuple) or isinstance(obj, list):
119+
return obj
120+
return list(obj)
121+
122+
89123
class NoNumber():
90124
pass
91125

@@ -110,6 +144,15 @@ def __float__(self):
110144
return 2.71828
111145

112146

147+
class DummySequence():
148+
def __getitem__(self, idx):
149+
return idx * 10
150+
151+
152+
class DummyListSubclass(list):
153+
pass
154+
155+
113156
def _default_bin_arith_args():
114157
return (
115158
(0,0),
@@ -137,10 +180,10 @@ def _default_bin_arith_args():
137180
)
138181

139182

140-
class TestPyNumber(CPyExtTestCase):
183+
class TestAbstract(CPyExtTestCase):
141184
def compile_module(self, name):
142185
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
143-
super(TestPyNumber, self).compile_module(name)
186+
super(TestAbstract, self).compile_module(name)
144187

145188

146189
test_PyNumber_Check = CPyExtFunction(
@@ -431,11 +474,6 @@ def compile_module(self, name):
431474
cmpfunc=unhandled_error_compare
432475
)
433476

434-
class TestPySequence(CPyExtTestCase):
435-
def compile_module(self, name):
436-
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
437-
super(TestPySequence, self).compile_module(name)
438-
439477
test_PySequence_Fast_GET_SIZE = CPyExtFunction(
440478
lambda args: len(args[0]),
441479
lambda: (
@@ -531,3 +569,161 @@ def compile_module(self, name):
531569
cmpfunc=unhandled_error_compare
532570
)
533571

572+
test_PySequence_Check = CPyExtFunction(
573+
lambda args: not isinstance(args[0], dict) and hasattr(args[0], '__getitem__'),
574+
lambda: (
575+
(tuple(),),
576+
((1,2,3),),
577+
((None,),),
578+
([],),
579+
(['a','b','c'],),
580+
([None],),
581+
(dict(),),
582+
(set(),),
583+
({'a', 'b'},),
584+
({'a':0, 'b':1},),
585+
(DummySequence(),),
586+
(DummyListSubclass(),),
587+
),
588+
resultspec="i",
589+
argspec='O',
590+
arguments=["PyObject* sequence"],
591+
)
592+
593+
test_PySequence_Size = CPyExtFunction(
594+
_reference_size,
595+
lambda: (
596+
(tuple(),),
597+
((1,2,3),),
598+
((None,),),
599+
([],),
600+
(['a','b','c'],),
601+
([None],),
602+
(set(),),
603+
(DummyListSubclass(),),
604+
),
605+
resultspec="n",
606+
argspec='O',
607+
arguments=["PyObject* sequence"],
608+
cmpfunc=unhandled_error_compare
609+
)
610+
611+
# 'PySequence_Length' is just a redefinition of 'PySequence_Size'
612+
test_PySequence_Length = test_PySequence_Size
613+
614+
test_PySequence_GetItem = CPyExtFunction(
615+
_reference_getitem,
616+
lambda: (
617+
(tuple(), 10),
618+
((1,2,3), 2),
619+
((None,), 0),
620+
([], 10),
621+
(['a','b','c'], 2),
622+
([None], 0),
623+
(set(), 0),
624+
({'a', 'b'}, 0),
625+
(DummyListSubclass(), 1),
626+
),
627+
resultspec="O",
628+
argspec='On',
629+
arguments=["PyObject* sequence", "Py_ssize_t idx"],
630+
cmpfunc=unhandled_error_compare
631+
)
632+
633+
test_PySequence_SetItem = CPyExtFunction(
634+
_reference_setitem,
635+
lambda: (
636+
(tuple(), 0, 'a'),
637+
((1,2,3), 2, 99),
638+
((None,), 1, None),
639+
([], 10, 1),
640+
(['a','b','c'], 2, 'z'),
641+
),
642+
code=''' PyObject* wrap_PySequence_SetItem(PyObject* sequence, Py_ssize_t idx, PyObject* value) {
643+
if (PySequence_SetItem(sequence, idx, value) < 0) {
644+
return NULL;
645+
}
646+
return sequence;
647+
}
648+
''',
649+
resultspec="O",
650+
argspec='OnO',
651+
arguments=["PyObject* sequence", "Py_ssize_t idx", "PyObject* value"],
652+
callfunction="wrap_PySequence_SetItem",
653+
cmpfunc=unhandled_error_compare
654+
)
655+
656+
test_PySequence_Tuple = CPyExtFunction(
657+
lambda args: tuple(args[0]),
658+
lambda: (
659+
(tuple(), ),
660+
((1,2,3), ),
661+
((None,), ),
662+
([], ),
663+
(['a','b','c'],),
664+
({'a','b','c'},),
665+
({'a': 0,'b': 1,'c': 2},),
666+
(None,),
667+
(0,),
668+
),
669+
resultspec="O",
670+
argspec='O',
671+
arguments=["PyObject* sequence"],
672+
cmpfunc=unhandled_error_compare
673+
)
674+
675+
test_PySequence_Fast = CPyExtFunction(
676+
_reference_fast,
677+
lambda: (
678+
(tuple(), "should not be an error"),
679+
((1,2,3), "should not be an error"),
680+
((None,), "should not be an error"),
681+
([], "should not be an error"),
682+
(['a','b','c'],"should not be an error"),
683+
({'a','b','c'}, "should not be an error"),
684+
({'a': 0,'b': 1,'c': 2}, "should not be an error"),
685+
(None, "None cannot be a sequence"),
686+
(0, "int cannot be a sequence"),
687+
),
688+
resultspec="O",
689+
argspec='Os',
690+
arguments=["PyObject* sequence", "char* error_msg"],
691+
cmpfunc=unhandled_error_compare
692+
)
693+
694+
test_PyMapping_GetItemString = CPyExtFunction(
695+
lambda args: args[0][args[1]],
696+
lambda: (
697+
(tuple(), "hello"),
698+
((1,2,3), "1"),
699+
(['a','b','c'],"nothing"),
700+
({'a','b','c'}, "a"),
701+
({'a': 0,'b': 1,'c': 2}, "nothing"),
702+
({'a': 0,'b': 1,'c': 2}, "c"),
703+
),
704+
resultspec="O",
705+
argspec='Os',
706+
arguments=["PyObject* mapping", "char* keyStr"],
707+
cmpfunc=unhandled_error_compare
708+
)
709+
710+
test_PyIndex_Check = CPyExtFunction(
711+
lambda args: hasattr(args[0], "__index__"),
712+
lambda: (
713+
(1, ),
714+
("not a number", ),
715+
(tuple(), ),
716+
(dict(), ),
717+
(list(), ),
718+
(DummyFloatable(), ),
719+
(DummyFloatSubclass(), ),
720+
(DummyIntable(), ),
721+
(DummyIntSubclass(), ),
722+
(NoNumber(), ),
723+
),
724+
resultspec="i",
725+
argspec='O',
726+
arguments=["PyObject* obj"],
727+
cmpfunc=unhandled_error_compare
728+
)
729+

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FILE__;
4242
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ImportError;
4343
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
44-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemError;
4544

4645
import java.io.IOException;
4746
import java.net.URI;
@@ -53,8 +52,8 @@
5352
import com.oracle.graal.python.builtins.Builtin;
5453
import com.oracle.graal.python.builtins.CoreFunctions;
5554
import com.oracle.graal.python.builtins.PythonBuiltins;
56-
import com.oracle.graal.python.builtins.modules.TruffleCextBuiltins.AsPythonObjectNode;
5755
import com.oracle.graal.python.builtins.objects.PNone;
56+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.AsPythonObjectNode;
5857
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.SetItemNode;
5958
import com.oracle.graal.python.builtins.objects.dict.PDict;
6059
import com.oracle.graal.python.builtins.objects.function.PArguments;
@@ -176,7 +175,7 @@ private Object loadDynamicModuleWithSpec(String name, String path, Node readNode
176175
throw raise(ImportError, "cannot load %s");
177176
} catch (RuntimeException e) {
178177
Throwable rootCaus = getRootCause(e);
179-
throw raise(SystemError, "cannot load %s: %s", path, rootCaus.getMessage());
178+
throw raise(ImportError, "cannot load %s: %s", path, rootCaus.getMessage());
180179
}
181180
TruffleObject pyinitFunc;
182181
try {

0 commit comments

Comments
 (0)