Created
February 9, 2014 18:57
-
-
Save micklat/8904320 to your computer and use it in GitHub Desktop.
a version of py2.nim that triggers a compiler error: py2.nim(97, 9) Error: identifier expected, but found '`()`*'
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A high-level wrapper for python 2.x (thus the name "py2.nim" rather than "py.nim") | |
# short-term TODO: | |
# | |
# * check whether the destructor gets called at all | |
# * support more of the API | |
# | |
# mid-range TODO: | |
# | |
# * don't print exceptions, retrieve the exception information into nimrod | |
# | |
# long-range TODO: | |
# * find a better syntax for member access | |
# | |
import python except expr | |
import macros | |
type | |
# A non-borrowed (counted) reference. Avoid copying these around! Nimrod doesn't have | |
# the equivalent of an assignment constructor (yet?), so any copy of PyRef must be counted (use dup for that). | |
PyRef = object {.inheritable, byref.} | |
p: PPyObject | |
PPyRef* = ref PyRef | |
EPyException = object of E_Base | |
Context = object | |
globals*, locals*: PPyRef | |
PContext = ref Context | |
# forward declarations | |
proc getattr*(o: PPyRef, name: cstring) : PPyRef | |
proc handle_error(s : string) = | |
PyErr_Print() | |
raise newException(EPyException, s) | |
proc check(p: PPyObject) : PPyObject = | |
if p == nil: handle_error("check(nil)") | |
result = p | |
proc check(x: int) : int = | |
if x == -1: handle_error("check(-1)") | |
result = x | |
converter to_PPyRef*(p: PPyObject) : PPyRef = | |
new result | |
result.p = check(p) | |
proc new_dict*(): PPyRef = PyDict_New() | |
proc new_list*(size: int): PPyRef = PyList_New(size) | |
proc new_tuple*(size: int): PPyRef = PyTuple_New(size) | |
converter to_py*(f: float) : PPyRef = PyFloat_fromDouble(f) | |
converter to_py*(i: int) : PPyRef = PyInt_FromLong(int32(i)) | |
converter to_py*(s: cstring) : PPyRef = PyString_fromString(s) | |
converter to_py*(s: string) : PPyRef = to_py(cstring(s)) | |
converter to_list*(vals: openarray[PPyRef]): PPyRef = | |
result = new_list(len(vals)) | |
for i in 0..len(vals)-1: | |
let p = vals[i].p | |
discard check(PyList_SetItem(result.p, i, p)) | |
Py_INCREF(p) | |
converter to_py*[T](vals: openarray[T]): PPyRef = | |
to_list(map[T,PPyRef](vals, to_py)) | |
converter to_py*[T](vals: seq[T]): PPyRef = | |
to_list(map[T,PPyRef](vals, to_py)) | |
converter to_tuple*(vals: openarray[PPyRef]): PPyRef = | |
result = new_tuple(len(vals)) | |
for i in 0..len(vals)-1: | |
let p = vals[i].p | |
discard check(PyTuple_SetItem(result.p, i, p)) | |
Py_INCREF(p) # the tuple 'steals' references | |
proc `$`*(o: PPyRef) : string = | |
let s = to_PPyRef(PyObject_Str(o.p)) | |
$PyString_AsString(s.p) | |
converter from_py_int*(o: PPyRef) : int = PyInt_AsLong(o.p) | |
proc len*(o: PPyRef) : int = | |
check(PyObject_Length(o.p)) | |
proc `()`*(f: PPyRef, args: varargs[PPyRef]): PPyRef = | |
let args_tup = to_tuple(args) | |
PyObject_CallObject(f.p, args_tup.p) | |
proc `()`*(field: string, obj: PPyRef): PPyRef = | |
echo field, " in argless delegator" | |
result = getattr(obj, field) | |
proc `()`*(field: string, obj: PPyRef, args: varargs[PPyRef]): PPyRef {.delegator.} = | |
echo field, " in argful delegator" | |
let args_tup = to_tuple(args) | |
PyObject_CallObject(getattr(obj.p, field).p, args_tup.p) | |
macro `->`*(a: expr, b:expr) : expr {.immediate.} = | |
let name = toStrLit(b) | |
result = newNimNode(nnkCall) | |
result.add(newIdentNode("getattr")) | |
result.add(a) | |
result.add(name) | |
proc dup*(src: PPyRef) : PPyRef = | |
new result | |
result.p = src.p | |
Py_INCREF(result.p) | |
proc destroy(o: var PyRef) {.destructor.} = | |
if o.p != nil: | |
echo "decrefing" | |
Py_DECREF(o.p) | |
o.p = nil | |
proc getattr*(o: PPyRef, name: cstring) : PPyRef = | |
result = to_PPyRef(PyObject_GetAttrString(o.p, name)) | |
proc py_import*(name : cstring) : PPyRef = | |
PyImport_ImportModule(name) | |
proc `[]`*(v: PPyRef, key: PPyRef) : PPyRef = | |
to_PPyRef(PyObject_GetItem(v.p, key.p)) | |
proc `[]=`*(mapping, key, val: PPyRef): void = | |
discard check(PyObject_SetItem(mapping.p, key.p, val.p)) | |
proc eval*(c: PContext, src: cstring) : PPyRef = | |
PyRun_String(src, eval_input, c.globals.p, c.locals.p) | |
proc builtins*() : PPyRef = PyEval_GetBuiltins() | |
proc new_context*() : PContext = | |
new result | |
result.locals = new_dict() | |
result.globals = new_dict() | |
result.globals["__builtins__"] = builtins() | |
result.globals["__builtins__"] = builtins() | |
type | |
Interpreter = object {.bycopy.} | |
proc make_interpreter() : Interpreter = | |
Py_Initialize() | |
result = Interpreter() | |
proc destroy(interpreter : Interpreter) {.destructor.} = | |
Py_Finalize() | |
var py_interpreter = make_interpreter() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment