Skip to content

Instantly share code, notes, and snippets.

@Synthetica9
Created April 3, 2015 05:30
Show Gist options
  • Save Synthetica9/bf8c30cbf2f34d50d034 to your computer and use it in GitHub Desktop.
Save Synthetica9/bf8c30cbf2f34d50d034 to your computer and use it in GitHub Desktop.
for Joebo
__author__ = 'Synthetica'
from ctypes import *
import numpy as np
import itertools
import os
from inspect import getsourcefile
type_table = {1: c_bool,
2: c_char,
4: c_int,
8: c_double
}
_path = os.path.abspath(os.path.dirname(getsourcefile(lambda: None)))
if os.name == 'nt':
try:
std_lib = oledll.LoadLibrary(os.path.join(_path, 'j64.dll'))
except WindowsError:
std_lib = oledll.LoadLibrary(os.path.join(_path, 'j32.dll'))
elif os.name == 'posix':
std_lib = CDLL(os.path.join(_path, 'libj.so'))
else:
raise OSError('Unsupported os {o}'.format(repr(os.name)))
class JInstance(object):
def __init__(self, support_unix_pipe=True):
self.j_dll = std_lib
self.start_address = self.j_dll.JInit()
def __call__(self, command):
temp_name = 'TMP__'
type_name = 'TYPE__'
kind_name = 'KIND__'
error_name = 'ERROR__'
command = str(command)
#Delete all variables that are going to be used:
self.delete_var(temp_name, type_name, kind_name)
self.execute_command(command, temp_name, return_result=False)
return_type = self.execute_command(
"4!:0 < '{tmp}'".format(tmp=temp_name), type_name)
# Return the result, or raise an error:
if return_type == -2:
raise Exception("Invalid. That's all we know, sorry. "
"It would probably be wise to contact your "
"friendly neighbourhood library developer about "
"this error, because this shouldn't ever happen")
elif return_type == -1:
error_text = ''.join(
self.execute_command(
"(13 !: 12)''",
var_name=error_name
)
)
raise Exception("Undefined, an error probably "
"occurred somewhere along the way.\n"
"The last error raised:\n:"
"{t}".format(t=error_text))
if return_type == 0: # Only nouns allowed.
# self.JGetM(temp_name, *data_pointers)
# return JRepr(*data_pointers)
return self.get_var(temp_name)
else:
raise TypeError(
"Impossible to return type {0}, must be 0.\n"
"(Piece of advice: are you trying to return a "
"verb/adverb/conjuction? Don't.)".format(return_type)
)
def __del__(self):
self.JFree()
def delete_var(self, *names):
if len(names) == 0:
return
elif len(names) == 1:
query = "4!:55 <'{name}'".format(name=names[0])
else:
names = ["'{}'".format(name) for name in
names] # Surround with quotes
query = "4!:55 {names}".format(names='; '.join(names))
self.execute_command(query)
def execute_command(self, command, var_name=None, return_result=True):
if var_name is not None:
self.set_var_raw(var_name, command)
if return_result:
return self.get_var(var_name)
else:
self.JDo(command)
if var_name is not None:
if return_result:
return self.get_var(var_name)
def set_var(self, name, value):
self.execute_command('{n} =: {v}'.format(n=name, v=pyToJ(value)))
def set_var_raw(self, name, value):
self.execute_command('{n} =: {v}'.format(n=name, v=value))
def get_var(self, var_name):
pointers = [pointer(c_int()) for _ in range(4)]
self.JGetM(var_name, *pointers)
data = JRepr(*pointers)
return data
def __getattr__(self, item):
def wrapper(*args, **kwargs):
return getattr(self.j_dll, item)(self.start_address, *args,
**kwargs)
wrapper.__name__ = item
return wrapper
def JRepr(tpe, rnk, shp, pos, typelist=type_table):
tpe, rnk, shp, pos = (int(i.contents.value) for i in (tpe, rnk, shp, pos))
shape = tuple(typelist[4].from_address(shp + i*sizeof(typelist[4])).value
for i in range(rnk))
datalen = np.product(shape) if shape else 1
ctype = typelist[tpe]
ctypesize = sizeof(ctype)
array = np.fromiter(
(ctype.from_address(pos + i*ctypesize).value
for i in itertools.count()),
dtype=ctype,
count=datalen
)
return np.resize(array, shape)
J = JInstance()
#Just for the console
def execute(command):
return J(command)
def debug(command):
return compile(command, '<string>', 'single')()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment