Skip to content

Commit 09c5167

Browse files
committed
convert to eerie package
0 parents  commit 09c5167

File tree

13 files changed

+467
-0
lines changed

13 files changed

+467
-0
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Python
2+
This object provides access the world of python.
3+
4+
# Installation
5+
Python should be installed in your system. Then:
6+
```
7+
eerie install https://github.com/IoLanguage/Python.git
8+
```

build.io

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
AddonBuilder clone do(
2+
3+
pyConfigCall := System runCommand("python3-config --prefix")
4+
5+
if(pyConfigCall succeeded,
6+
pythonPrefix := pyConfigCall stdout asMutable strip
7+
8+
version := list("3.6", "3.5", "3.4", "3.3", "3.2", "3.1", "3.0") detect(v, System system("python" .. v .. " -V 2> /dev/null") == 0)
9+
10+
dependsOnHeader("Python.h")
11+
dependsOnLib("python" .. version)
12+
13+
if(platform == "darwin",
14+
appendHeaderSearchPath("#{pythonPrefix}/include/" interpolate)
15+
appendLibSearchPath("#{pythonPrefix}/lib" interpolate)
16+
)
17+
headerSearchPaths foreach(headerSearchPath, appendHeaderSearchPath(headerSearchPath .. "/python" .. version))
18+
headerSearchPaths foreach(headerSearchPath, appendHeaderSearchPath(headerSearchPath .. "/python" .. version .. "m"))
19+
20+
,
21+
Error withShow("Can't run python3-config")
22+
return
23+
)
24+
25+
)

depends

Whitespace-only changes.

io/Python.io

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* Python */

package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "Python",
3+
"version": "0.1",
4+
"description": "This object provides access the world of python.",
5+
"author": "Aslak Gronflaten",
6+
"website": "http://iolanguage.org/",
7+
"readme": "README.md",
8+
"protos": ["Python"],
9+
"dependencies": {
10+
"libs": [],
11+
"headers": ["Python.h"],
12+
"protos": [],
13+
"packages": []
14+
}
15+
}

protos

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Python

samples/UsingPython.io

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env io
2+
3+
# Import a module
4+
sys := Python import("sys")
5+
6+
"Which version of python are we running?" println
7+
sys version println
8+
9+
"System path is returned as a list" println
10+
sys path foreach(p, p println)
11+
12+
"Load the string module" println
13+
string := Python import("string")
14+
15+
"Split a string" println
16+
str := "Brave brave Sir Robin"
17+
str println
18+
string split(str) println
19+
20+
"Load a C module (.so)" println
21+
t := Python import("time")
22+
23+
writeln("Current time is: ", t time)
24+
25+
"Another way to invoke a method" println
26+
str = "UPPERlower"
27+
write(str, " --> ")
28+
string invoke("swapcase", str) println
29+

source/IoPython.c

+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
//metadoc Python copyrigth Aslak Gronflaten, 2006
2+
//metadoc Python license BSD revised
3+
/*metadoc Python description
4+
This object provides access the world of python.
5+
*/
6+
//metadoc Python credit Based on code by Steve Dekorte
7+
//metadoc Python category API
8+
9+
#include "IoPython.h"
10+
#include "IoState.h"
11+
#include "IoNumber.h"
12+
#include "IoList.h"
13+
#include "IoMap.h"
14+
#include "IoDirectory.h"
15+
16+
#include <stdlib.h>
17+
#include <stdio.h>
18+
19+
#define DATA(self) ((PythonData *)IoObject_dataPointer(self))
20+
21+
22+
static const char *protoId = "Python";
23+
24+
IoTag *IoPython_newTag(void *state)
25+
{
26+
IoTag *tag = IoTag_newWithName_("Python");
27+
IoTag_state_(tag, state);
28+
IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoPython_rawClone);
29+
IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoPython_free);
30+
return tag;
31+
}
32+
33+
IoPython *IoPython_proto(void *state)
34+
{
35+
IoObject *self = NULL;
36+
37+
Py_Initialize();
38+
self = IoObject_new(state);
39+
IoObject_tag_(self, IoPython_newTag(state));
40+
IoObject_setDataPointer_(self, PythonData_new());
41+
fflush(stdout);
42+
IoState_registerProtoWithId_(state, self, protoId);
43+
44+
{
45+
IoMethodTable methodTable[] = {
46+
{"credits", IoPython_credits},
47+
{"forward", IoPython_forward},
48+
{"import", IoPython_import},
49+
{"invoke", IoPython_call},
50+
{"print", IoPython_print},
51+
{NULL, NULL},
52+
};
53+
IoObject_addMethodTable_(self, methodTable);
54+
}
55+
DATA(self)->data = (void *) 1; // Hack
56+
return self;
57+
}
58+
59+
IoPython *IoPython_rawClone(IoPython *proto)
60+
{
61+
IoPython *self = IoObject_rawClonePrimitive(proto);
62+
IoObject_setDataPointer_(self, PythonData_new());
63+
return self;
64+
}
65+
66+
/* ----------------------------------------------------------- */
67+
68+
IoPython *IoPython_new(void *state)
69+
{
70+
IoObject *proto = IoState_protoWithId_(state, protoId);
71+
return IOCLONE(proto);
72+
}
73+
74+
void IoPython_free(IoPython *self)
75+
{
76+
PythonData_free(DATA(self));
77+
}
78+
/* ----------------------------------------------------------- */
79+
80+
IoObject *wrap(IoPython *self, PyObject *o) {
81+
IoPython *ret = IoPython_new(IOSTATE);
82+
DATA(ret)->data = o;
83+
return ret;
84+
}
85+
86+
IoObject *IoPython_credits(IoPython *self, IoObject *locals, IoMessage *m)
87+
{
88+
return IOSYMBOL("Python/Io bridge by Aslak Gronflaten");
89+
}
90+
91+
IoObject *IoPython_print(IoPython *self, IoObject *locals, IoMessage *m)
92+
{
93+
PyObject *obj = DATA(self)->data;
94+
if(obj != NULL) {
95+
PyObject_Print(obj, stdout, 0);
96+
}
97+
return self;
98+
}
99+
100+
/**
101+
* Convert an Io object to PyObject.
102+
* At the moment, we can't pass in any objects, just those that can be translated,
103+
* until I build a python wrapper around an io object, reverse of what I did here.
104+
* TODO: Memory management!!!
105+
*
106+
* self: unused? (why is it here?)
107+
* obj: the Io object to map into a Python object
108+
* return NULL on failure -- callers should check for this case
109+
*/
110+
PyObject *convertIo(IoObject *self, IoObject *obj) {
111+
PyObject *ret = NULL;
112+
if(ISNIL(obj)) {
113+
ret = Py_None;
114+
}
115+
if(ISNUMBER(obj)) {
116+
ret = PyFloat_FromDouble(CNUMBER(obj));
117+
Py_INCREF(ret);
118+
} else if(ISSEQ(obj)) {
119+
ret = PyUnicode_FromString(CSTRING(obj));
120+
Py_INCREF(ret);
121+
} else if(ISLIST(obj)) {
122+
ret = PyList_New(IoList_rawSize(obj));
123+
Py_INCREF(ret);
124+
//todo: check for NULL returns from the recursion (and on a null, free up the half-constructed list and return NULL ourselves)
125+
//otherwise you get "Bus error", probably when Python tries to complain that you've passed it an invalid data structure
126+
LIST_SAFEFOREACH(IoList_rawList(obj), i, v, PyList_SET_ITEM(ret, i, convertIo(self, v)));
127+
} else if(ISMAP(obj)) {
128+
IoList* keys = IoMap_rawKeys(obj); //XXX do I have to free this?
129+
ret = PyDict_New();
130+
Py_INCREF(ret);
131+
//todo: check for NULL returns from the recursions
132+
LIST_SAFEFOREACH(IoList_rawList(keys), i, v, PyDict_SetItem(ret, convertIo(self, v), convertIo(self, IoMap_rawAt(obj, v))));
133+
} else {
134+
printf("Unable to convert parameter `%s` to python.\n", IoObject_name(obj));
135+
}
136+
137+
return ret;
138+
}
139+
140+
/**
141+
* Tries to convert the obj to an Io object, if possible. If not, return null.
142+
* Can't decref if this method is used on both pFunc and pValue
143+
*/
144+
IoObject *convertPy(IoObject *self, PyObject *obj) {
145+
//PyObject_Print(obj, stdout, 0);
146+
//PyObject *pType = PyObject_Type(obj);
147+
//PyObject_Print(pType, stdout, 0);
148+
IoObject *ret = NULL; // Return value
149+
150+
//I've messed with the way the return value is structured in this code, it's not cleaned up yet, sorry -- nick
151+
152+
if(obj == Py_None) {
153+
ret = IONIL(self);
154+
} else if(PyUnicode_Check(obj)) {
155+
// Convert to Io sequence and return.
156+
IoSeq *ret = IoSeq_newWithCString_(IOSTATE, PyUnicode_AsUTF8(obj));
157+
return ret;
158+
// TODO:::: Memory management! Who's responsible here! (I am, that's who)
159+
} else if(PyFloat_Check(obj)) {
160+
ret = IoNumber_newWithDouble_(IOSTATE, PyFloat_AS_DOUBLE(obj));
161+
//Py_DECREF(obj);
162+
} else if(PyLong_Check(obj)) {
163+
ret = IoNumber_newWithDouble_(IOSTATE, PyLong_AS_LONG(obj));
164+
// Decref?
165+
} else if(PyList_Check(obj)) {
166+
// We have a list. So, make an Io list, and convert every element, and insert them.
167+
int i;
168+
int len = PyList_GET_SIZE(obj);
169+
ret = IoList_new(IOSTATE);
170+
for(i=0;i<len;i++) {
171+
PyObject *o = PyList_GET_ITEM(obj, i);
172+
IoObject *x = convertPy(self, o);
173+
// insert in list
174+
IoList_rawAppend_(ret, x);
175+
}
176+
} else if(PyTuple_Check(obj)) {
177+
int i;
178+
int len = PyTuple_GET_SIZE(obj);
179+
ret = IoList_new(IOSTATE);
180+
for(i=0;i<len;i++) {
181+
PyObject *o = PyTuple_GET_ITEM(obj, i);
182+
IoObject *x = convertPy(self, o);
183+
// insert in list
184+
IoList_rawAppend_(ret, x);
185+
}
186+
} else if(PyDict_Check(obj)) {
187+
// We have a dictionary. Make an Io map, and convert all values.
188+
// or should we.... Io's map can only have string keys... hardly a replacement, now is it.
189+
// Would be better to build a good wrapper around the python dict.
190+
} else if(PyCallable_Check(obj)) {
191+
//ret = IoState_doString_(IOSTATE, "method(return self invoke(\"\")");
192+
// TODO: We should return a callable object here... Don't know how though. Yet.
193+
} else {
194+
ret = wrap(self, obj);
195+
}
196+
return ret;
197+
}
198+
199+
200+
201+
IoObject *IoPython_call_int(IoPython *self, IoObject *locals, IoMessage *m, int argOffset, char *functionName)
202+
{
203+
PyObject *pFunc = NULL;
204+
int argc = IoMessage_argCount(m);
205+
206+
PyObject *pModule = DATA(self)->data;
207+
if(!pModule) {
208+
fprintf(stderr, "We have null pModule for function %s ", functionName);
209+
return IONIL(self);
210+
}
211+
if(!PyObject_HasAttrString(pModule, functionName)){
212+
fprintf(stderr, "Module has no function %s ", functionName);
213+
return IONIL(self);
214+
}
215+
216+
pFunc = PyObject_GetAttrString(pModule, functionName);
217+
/* pFunc is a new reference */
218+
219+
if (pFunc && PyCallable_Check(pFunc)) {
220+
PyObject *pArgs = PyTuple_New(argc - argOffset); // argc
221+
PyObject *pValue = NULL;
222+
int i;
223+
for(i = argOffset;i<argc;i++) {
224+
IoObject *param = IoMessage_locals_valueArgAt_(m, locals, i);
225+
PyObject *pyValue = convertIo(self, param);
226+
PyTuple_SetItem(pArgs, i-argOffset, pyValue);
227+
}
228+
pValue = PyObject_CallObject(pFunc, pArgs);
229+
Py_DECREF(pArgs);
230+
Py_XDECREF(pFunc);
231+
if (pValue != NULL) {
232+
return convertPy(self, pValue);
233+
} else {
234+
if (PyErr_Occurred())
235+
PyErr_Print();
236+
fprintf(stderr,"Call failed\n");
237+
}
238+
} else if (PyErr_Occurred()) {
239+
fprintf(stderr, "Cannot find python function \"%s\"\n", functionName);
240+
PyErr_Print();
241+
}
242+
else {
243+
return convertPy(self, pFunc);
244+
}
245+
246+
//catchall just in case
247+
return IONIL(self);
248+
}
249+
250+
IoObject *IoPython_forward(IoPython *self, IoObject *locals, IoMessage *m)
251+
{
252+
IoSymbol *name = IoMessage_name(m);
253+
char *functionName = IoSeq_asCString(name);
254+
return IoPython_call_int(self, locals, m, 0, functionName);
255+
}
256+
257+
IoObject *IoPython_call(IoPython *self, IoObject *locals, IoMessage *m)
258+
{
259+
IoSeq *name = IoMessage_locals_seqArgAt_(m, locals, 0);
260+
char *functionName = IoSeq_asCString(name);
261+
return IoPython_call_int(self, locals, m, 1, functionName);
262+
}
263+
264+
265+
/**
266+
* Import a module, return reference to it as a Python object
267+
*/
268+
IoObject *IoPython_import(IoPython *self, IoObject *locals, IoMessage *m)
269+
{
270+
IoSeq *name = IoMessage_locals_seqArgAt_(m, locals, 0);
271+
char *nameString = IoSeq_asCString(name);
272+
273+
PyObject *pName, *pModule;
274+
pName = PyUnicode_FromString(nameString);
275+
/* Error checking of pName left out */
276+
277+
pModule = PyImport_Import(pName);
278+
279+
if(!pModule) {
280+
fprintf(stderr, "Could not find module %s\n", nameString);
281+
return IONIL(self);
282+
}
283+
284+
// Set slots (for easier introspection and use from io)
285+
/*
286+
PyObject *dict = PyModule_GetDict(pModule);
287+
PyObject *keys = PyDict_Keys(dict);
288+
int i;
289+
for(i = 0;i<PyList_Size(keys);i++) {
290+
PyObject *key = PyList_GetItem(keys, i);
291+
PyObject *value = PyDict_GetItem(dict, key);
292+
// TODO: Not allowed method vall IoSeq_newSymbolWithCString_
293+
if(!PyCallable_Check(value)) {// don't want methods blocking the forward
294+
IoObject_setSlot_to_(self, IOSYMBOL(PyUnicode_AsUTF8(key)), convertPy(self, value));
295+
}
296+
}
297+
*/
298+
//
299+
300+
Py_DECREF(pName);
301+
302+
// Now, we've got the module. Wrap it and return it.
303+
return wrap(self, pModule);
304+
}

0 commit comments

Comments
 (0)