Commit 7c0457ce authored by Michael Droettboom's avatar Michael Droettboom

Add linting

parent 11a601f5
...@@ -12,7 +12,7 @@ jobs: ...@@ -12,7 +12,7 @@ jobs:
- run: - run:
name: dependencies name: dependencies
command: | command: |
sudo apt-get install node-less cmake build-essential sudo apt-get install node-less cmake build-essential clang-format flake8
# We need at least g++-8, but stretch comes with g++-6 # We need at least g++-8, but stretch comes with g++-6
# Set up the Debian testing repo, and then install g++ from there... # Set up the Debian testing repo, and then install g++ from there...
...@@ -36,6 +36,11 @@ jobs: ...@@ -36,6 +36,11 @@ jobs:
# causes Firefox to complain when loading it. Let's just add the new mime type. # causes Firefox to complain when loading it. Let's just add the new mime type.
sudo bash -c "echo 'application/wasm wasm' >> /etc/mime.types" sudo bash -c "echo 'application/wasm wasm' >> /etc/mime.types"
- run:
name: lint
command: |
make lint
- restore_cache: - restore_cache:
keys: keys:
- v1-emsdk-{{ checksum "emsdk/Makefile" }} - v1-emsdk-{{ checksum "emsdk/Makefile" }}
......
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Mozilla
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
---
Language: JavaScript
...
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_size = 2
indent_style = space
[Makefile]
indent_style = tab
\ No newline at end of file
...@@ -34,7 +34,7 @@ If you’d like to fix a currently-filed issue, please take a look at the commen ...@@ -34,7 +34,7 @@ If you’d like to fix a currently-filed issue, please take a look at the commen
We use [py.test](https://pytest.org), driving [Selenium](https://www.seleniumhq.org) as our testing framework. Every PR will automatically run through our tests, and our test framework will alert you on Github if your PR doesn’t pass all of them. If your PR fails a test, try to figure out whether or not you can update your code to make the test pass again, or ask for help. As a policy we will not accept a PR that fails any of our tests, and will likely ask you to add tests if your PR adds new functionality. Writing tests can be scary, but they make open-source contributions easier for everyone to assess. Take a moment and look through how we’ve written our tests, and try to make your tests match. If you are having trouble, we can help you get started on our test-writing journey. We use [py.test](https://pytest.org), driving [Selenium](https://www.seleniumhq.org) as our testing framework. Every PR will automatically run through our tests, and our test framework will alert you on Github if your PR doesn’t pass all of them. If your PR fails a test, try to figure out whether or not you can update your code to make the test pass again, or ask for help. As a policy we will not accept a PR that fails any of our tests, and will likely ask you to add tests if your PR adds new functionality. Writing tests can be scary, but they make open-source contributions easier for everyone to assess. Take a moment and look through how we’ve written our tests, and try to make your tests match. If you are having trouble, we can help you get started on our test-writing journey.
TODO: Code style standards and automation to follow. Just stay sand and consistent for now. All code submissions should pass `make lint`. Python is checked with the default settings of `flake8`. C and Javascript are checked against the Mozilla style in `clang-format`.
## Development Workflow ## Development Workflow
......
...@@ -133,6 +133,11 @@ test: all build/test.html ...@@ -133,6 +133,11 @@ test: all build/test.html
py.test test -v py.test test -v
lint:
flake8 src
clang-format -output-replacements-xml src/*.c src/*.h src/*.js | (! grep '<replacement ')
benchmark: all build/test.html benchmark: all build/test.html
python benchmark/benchmark.py $(HOSTPYTHON) build/benchmarks.json python benchmark/benchmark.py $(HOSTPYTHON) build/benchmarks.json
python benchmark/plot_benchmark.py build/benchmarks.json build/benchmarks.png python benchmark/plot_benchmark.py build/benchmarks.json build/benchmarks.png
......
...@@ -39,3 +39,9 @@ downloads and builds Python and third-party packages). ...@@ -39,3 +39,9 @@ downloads and builds Python and third-party packages).
1. Install the same dependencies as for testing. 1. Install the same dependencies as for testing.
2. `make benchmark` 2. `make benchmark`
# Linting
1. Python is linted with `flake8`. C and Javascript are linted with `clang-format`.
2. `make lint`
...@@ -7,14 +7,18 @@ ...@@ -7,14 +7,18 @@
It is compiled into the main module, as if it came from Python itself. It is compiled into the main module, as if it came from Python itself.
*/ */
PyThread_type_lock PyThread_allocate_lock(void) { PyThread_type_lock
PyThread_allocate_lock(void)
{
return (PyThread_type_lock)0x1; return (PyThread_type_lock)0x1;
} }
void PyThread_free_lock(PyThread_type_lock _) { void
PyThread_free_lock(PyThread_type_lock _)
{}
} int
PyThread_acquire_lock(PyThread_type_lock _, int __)
int PyThread_acquire_lock(PyThread_type_lock _, int __) { {
return PY_LOCK_ACQUIRED; return PY_LOCK_ACQUIRED;
} }
#include <emscripten.h> #include <emscripten.h>
EM_JS(void, hiwire_setup, (), { EM_JS(void, hiwire_setup, (), {
var hiwire = { var hiwire = { objects : {}, counter : 1 };
objects: {},
counter: 1
};
Module.hiwire_new_value = function(jsval) { Module.hiwire_new_value = function(jsval)
{
var objects = hiwire.objects; var objects = hiwire.objects;
while (hiwire.counter in objects) { while (hiwire.counter in objects) {
hiwire.counter = (hiwire.counter + 1) % 0x8fffffff; hiwire.counter = (hiwire.counter + 1) % 0x8fffffff;
...@@ -17,11 +15,10 @@ EM_JS(void, hiwire_setup, (), { ...@@ -17,11 +15,10 @@ EM_JS(void, hiwire_setup, (), {
return idval; return idval;
}; };
Module.hiwire_get_value = function(idval) { Module.hiwire_get_value = function(idval) { return hiwire.objects[idval]; };
return hiwire.objects[idval];
};
Module.hiwire_decref = function(idval) { Module.hiwire_decref = function(idval)
{
var objects = hiwire.objects; var objects = hiwire.objects;
delete objects[idval]; delete objects[idval];
}; };
...@@ -31,13 +28,9 @@ EM_JS(int, hiwire_incref, (int idval), { ...@@ -31,13 +28,9 @@ EM_JS(int, hiwire_incref, (int idval), {
return Module.hiwire_new_value(Module.hiwire_get_value(idval)); return Module.hiwire_new_value(Module.hiwire_get_value(idval));
}); });
EM_JS(void, hiwire_decref, (int idval), { EM_JS(void, hiwire_decref, (int idval), { Module.hiwire_decref(idval); });
Module.hiwire_decref(idval);
});
EM_JS(int, hiwire_int, (int val), { EM_JS(int, hiwire_int, (int val), { return Module.hiwire_new_value(val); });
return Module.hiwire_new_value(val);
});
EM_JS(int, hiwire_double, (double val), { EM_JS(int, hiwire_double, (double val), {
return Module.hiwire_new_value(val); return Module.hiwire_new_value(val);
...@@ -62,17 +55,11 @@ EM_JS(int, hiwire_undefined, (), { ...@@ -62,17 +55,11 @@ EM_JS(int, hiwire_undefined, (), {
return Module.hiwire_new_value(undefined); return Module.hiwire_new_value(undefined);
}); });
EM_JS(int, hiwire_null, (), { EM_JS(int, hiwire_null, (), { return Module.hiwire_new_value(null); });
return Module.hiwire_new_value(null);
});
EM_JS(int, hiwire_true, (), { EM_JS(int, hiwire_true, (), { return Module.hiwire_new_value(true); });
return Module.hiwire_new_value(true);
});
EM_JS(int, hiwire_false, (), { EM_JS(int, hiwire_false, (), { return Module.hiwire_new_value(false); });
return Module.hiwire_new_value(false);
});
EM_JS(int, hiwire_throw_error, (int idmsg), { EM_JS(int, hiwire_throw_error, (int idmsg), {
var jsmsg = Module.hiwire_get_value(idmsg); var jsmsg = Module.hiwire_get_value(idmsg);
...@@ -80,17 +67,13 @@ EM_JS(int, hiwire_throw_error, (int idmsg), { ...@@ -80,17 +67,13 @@ EM_JS(int, hiwire_throw_error, (int idmsg), {
throw new Error(jsmsg); throw new Error(jsmsg);
}); });
EM_JS(int, hiwire_array, (), { EM_JS(int, hiwire_array, (), { return Module.hiwire_new_value([]); });
return Module.hiwire_new_value([]);
});
EM_JS(void, hiwire_push_array, (int idarr, int idval), { EM_JS(void, hiwire_push_array, (int idarr, int idval), {
Module.hiwire_get_value(idarr).push(Module.hiwire_get_value(idval)); Module.hiwire_get_value(idarr).push(Module.hiwire_get_value(idval));
}); });
EM_JS(int, hiwire_object, (), { EM_JS(int, hiwire_object, (), { return Module.hiwire_new_value({}); });
return Module.hiwire_new_value({});
});
EM_JS(void, hiwire_push_object_pair, (int idobj, int idkey, int idval), { EM_JS(void, hiwire_push_object_pair, (int idobj, int idkey, int idval), {
var jsobj = Module.hiwire_get_value(idobj); var jsobj = Module.hiwire_get_value(idobj);
...@@ -140,7 +123,8 @@ EM_JS(void, hiwire_call_member, (int idobj, int ptrname, int idargs), { ...@@ -140,7 +123,8 @@ EM_JS(void, hiwire_call_member, (int idobj, int ptrname, int idargs), {
}); });
EM_JS(void, hiwire_new, (int idobj, int idargs), { EM_JS(void, hiwire_new, (int idobj, int idargs), {
function newCall(Cls) { function newCall(Cls)
{
return new (Function.prototype.bind.apply(Cls, arguments)); return new (Function.prototype.bind.apply(Cls, arguments));
} }
var jsobj = Module.hiwire_get_value(idobj); var jsobj = Module.hiwire_get_value(idobj);
...@@ -154,7 +138,9 @@ EM_JS(void, hiwire_get_length, (int idobj), { ...@@ -154,7 +138,9 @@ EM_JS(void, hiwire_get_length, (int idobj), {
}); });
EM_JS(void, hiwire_is_function, (int idobj), { EM_JS(void, hiwire_is_function, (int idobj), {
// clang-format off
return typeof Module.hiwire_get_value(idobj) === 'function'; return typeof Module.hiwire_get_value(idobj) === 'function';
// clang-format on
}); });
EM_JS(void, hiwire_to_string, (int idobj), { EM_JS(void, hiwire_to_string, (int idobj), {
......
...@@ -3,33 +3,88 @@ ...@@ -3,33 +3,88 @@
// TODO: Document me // TODO: Document me
void hiwire_setup(); void
int hiwire_incref(int idval); hiwire_setup();
void hiwire_decref(int idval);
int hiwire_int(int val); int
int hiwire_double(double val); hiwire_incref(int idval);
int hiwire_string_utf8_length(int ptr, int len);
int hiwire_string_utf8(int ptr); void
int hiwire_bytes(int ptr, int len); hiwire_decref(int idval);
int hiwire_undefined();
int hiwire_null(); int
int hiwire_true(); hiwire_int(int val);
int hiwire_false();
int hiwire_array(); int
int hiwire_push_array(int idobj, int idval); hiwire_double(double val);
int hiwire_object();
int hiwire_push_object_pair(int idobj, int idkey, int idval); int
int hiwire_throw_error(int idmsg); hiwire_string_utf8_length(int ptr, int len);
int hiwire_get_global(int ptrname);
int hiwire_get_member_string(int idobj, int ptrname); int
void hiwire_set_member_string(int idobj, int ptrname, int idval); hiwire_string_utf8(int ptr);
int hiwire_get_member_int(int idobj, int idx);
void hiwire_set_member_int(int idobj, int idx, int idval); int
int hiwire_call(int idobj, int idargs); hiwire_bytes(int ptr, int len);
int hiwire_call_member(int idobj, int ptrname, int idargs);
int hiwire_new(int idobj, int idargs); int
int hiwire_get_length(int idobj); hiwire_undefined();
int hiwire_is_function(int idobj);
int hiwire_to_string(int idobj); int
hiwire_null();
int
hiwire_true();
int
hiwire_false();
int
hiwire_array();
int
hiwire_push_array(int idobj, int idval);
int
hiwire_object();
int
hiwire_push_object_pair(int idobj, int idkey, int idval);
int
hiwire_throw_error(int idmsg);
int
hiwire_get_global(int ptrname);
int
hiwire_get_member_string(int idobj, int ptrname);
void
hiwire_set_member_string(int idobj, int ptrname, int idval);
int
hiwire_get_member_int(int idobj, int idx);
void
hiwire_set_member_int(int idobj, int idx, int idval);
int
hiwire_call(int idobj, int idargs);
int
hiwire_call_member(int idobj, int ptrname, int idargs);
int
hiwire_new(int idobj, int idargs);
int
hiwire_get_length(int idobj);
int
hiwire_is_function(int idobj);
int
hiwire_to_string(int idobj);
#endif /* HIWIRE_H */ #endif /* HIWIRE_H */
...@@ -8,45 +8,62 @@ ...@@ -8,45 +8,62 @@
// Since we're going *to* Python, just let any Python exceptions at conversion // Since we're going *to* Python, just let any Python exceptions at conversion
// bubble out to Python // bubble out to Python
int _js2python_string(char *val) { int
_js2python_string(char* val)
{
return (int)PyUnicode_FromString(val); return (int)PyUnicode_FromString(val);
} }
int _js2python_number(double val) { int
_js2python_number(double val)
{
return (int)PyFloat_FromDouble(val); return (int)PyFloat_FromDouble(val);
} }
int _js2python_none() { int
_js2python_none()
{
Py_INCREF(Py_None); Py_INCREF(Py_None);
return (int)Py_None; return (int)Py_None;
} }
int _js2python_true() { int
_js2python_true()
{
Py_INCREF(Py_True); Py_INCREF(Py_True);
return (int)Py_True; return (int)Py_True;
} }
int _js2python_false() { int
_js2python_false()
{
Py_INCREF(Py_False); Py_INCREF(Py_False);
return (int)Py_False; return (int)Py_False;
} }
int _js2python_pyproxy(PyObject *val) { int
_js2python_pyproxy(PyObject* val)
{
Py_INCREF(val); Py_INCREF(val);
return (int)val; return (int)val;
} }
int _js2python_bytes(char *bytes, int length) { int
_js2python_bytes(char* bytes, int length)
{
return (int)PyBytes_FromStringAndSize(bytes, length); return (int)PyBytes_FromStringAndSize(bytes, length);
} }
int _js2python_jsproxy(int id) { int
_js2python_jsproxy(int id)
{
return (int)JsProxy_cnew(id); return (int)JsProxy_cnew(id);
} }
// TODO: Add some meaningful order // TODO: Add some meaningful order
EM_JS(int, __js2python, (int id), { EM_JS(int, __js2python, (int id), {
// clang-format off
var value = Module.hiwire_get_value(id); var value = Module.hiwire_get_value(id);
var type = typeof value; var type = typeof value;
if (type === 'string') { if (type === 'string') {
...@@ -72,12 +89,17 @@ EM_JS(int, __js2python, (int id), { ...@@ -72,12 +89,17 @@ EM_JS(int, __js2python, (int id), {
} else { } else {
return __js2python_jsproxy(id); return __js2python_jsproxy(id);
} }
// clang-format on
}); });
PyObject *js2python(int id) { PyObject*
return (PyObject *)__js2python(id); js2python(int id)
{
return (PyObject*)__js2python(id);
} }
int js2python_init() { int
js2python_init()
{
return 0; return 0;
} }
...@@ -10,12 +10,14 @@ ...@@ -10,12 +10,14 @@
/** Convert a Javascript object to a Python object. /** Convert a Javascript object to a Python object.
* \param x The Javascript object. * \param x The Javascript object.
* \return The Python object. New reference. If NULL, a Python exception * \return The Python object. New reference. If NULL, a Python exception
* occurred during the conversion, and the Python exception API should be used * occurred during the conversion, and the Python exception API should be
* to obtain the exception. * used to obtain the exception.
*/ */
PyObject *js2python(int x); PyObject*
js2python(int x);
/** Initialize any global variables used by this module. */ /** Initialize any global variables used by this module. */
int js2python_init(); int
js2python_init();
#endif /* JS2PYTHON_H */ #endif /* JS2PYTHON_H */
...@@ -5,26 +5,29 @@ ...@@ -5,26 +5,29 @@
#include "hiwire.h" #include "hiwire.h"
#include "js2python.h" #include "js2python.h"
static PyObject *original__import__; static PyObject* original__import__;
PyObject *globals = NULL; PyObject* globals = NULL;
PyObject *original_globals = NULL; PyObject* original_globals = NULL;
typedef struct { typedef struct
{
PyObject_HEAD PyObject_HEAD
} JsImport; } JsImport;
static PyObject *JsImport_Call(PyObject *self, PyObject *args, PyObject *kwargs) { static PyObject*
PyObject *name = PyTuple_GET_ITEM(args, 0); JsImport_Call(PyObject* self, PyObject* args, PyObject* kwargs)
{
PyObject* name = PyTuple_GET_ITEM(args, 0);
if (PyUnicode_CompareWithASCIIString(name, "js") == 0) { if (PyUnicode_CompareWithASCIIString(name, "js") == 0) {
PyObject *locals = PyTuple_GET_ITEM(args, 2); PyObject* locals = PyTuple_GET_ITEM(args, 2);
PyObject *fromlist = PyTuple_GET_ITEM(args, 3); PyObject* fromlist = PyTuple_GET_ITEM(args, 3);
Py_ssize_t n = PySequence_Size(fromlist); Py_ssize_t n = PySequence_Size(fromlist);
PyObject *jsmod = PyModule_New("js"); PyObject* jsmod = PyModule_New("js");
PyObject *d = PyModule_GetDict(jsmod); PyObject* d = PyModule_GetDict(jsmod);
int is_star = 0; int is_star = 0;
if (n == 1) { if (n == 1) {
PyObject *firstfromlist = PySequence_GetItem(fromlist, 0); PyObject* firstfromlist = PySequence_GetItem(fromlist, 0);
if (PyUnicode_CompareWithASCIIString(firstfromlist, "*") == 0) { if (PyUnicode_CompareWithASCIIString(firstfromlist, "*") == 0) {
is_star = 1; is_star = 1;
} }
...@@ -36,17 +39,17 @@ static PyObject *JsImport_Call(PyObject *self, PyObject *args, PyObject *kwargs) ...@@ -36,17 +39,17 @@ static PyObject *JsImport_Call(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL; return NULL;
} else { } else {
for (Py_ssize_t i = 0; i < n; ++i) { for (Py_ssize_t i = 0; i < n; ++i) {
PyObject *key = PySequence_GetItem(fromlist, i); PyObject* key = PySequence_GetItem(fromlist, i);
if (key == NULL) { if (key == NULL) {
return NULL; return NULL;
} }
char *c = PyUnicode_AsUTF8(key); char* c = PyUnicode_AsUTF8(key);
if (c == NULL) { if (c == NULL) {
Py_DECREF(key); Py_DECREF(key);
return NULL; return NULL;
} }
int jsval = hiwire_get_global((int)c); int jsval = hiwire_get_global((int)c);
PyObject *pyval = js2python(jsval); PyObject* pyval = js2python(jsval);
hiwire_decref(jsval); hiwire_decref(jsval);
if (PyDict_SetItem(d, key, pyval)) { if (PyDict_SetItem(d, key, pyval)) {
Py_DECREF(key); Py_DECREF(key);
...@@ -73,23 +76,27 @@ static PyTypeObject JsImportType = { ...@@ -73,23 +76,27 @@ static PyTypeObject JsImportType = {
.tp_doc = "An import hook that imports things from Javascript." .tp_doc = "An import hook that imports things from Javascript."
}; };
static PyObject *JsImport_New() { static PyObject*
JsImport *self; JsImport_New()
self = (JsImport *)JsImportType.tp_alloc(&JsImportType, 0); {
return (PyObject *)self; JsImport* self;
self = (JsImport*)JsImportType.tp_alloc(&JsImportType, 0);
return (PyObject*)self;
} }
int JsImport_init() { int
JsImport_init()
{
if (PyType_Ready(&JsImportType)) { if (PyType_Ready(&JsImportType)) {
return 1; return 1;
} }
PyObject *m = PyImport_AddModule("builtins"); PyObject* m = PyImport_AddModule("builtins");
if (m == NULL) { if (m == NULL) {
return 1; return 1;
} }
PyObject *d = PyModule_GetDict(m); PyObject* d = PyModule_GetDict(m);
if (d == NULL) { if (d == NULL) {
return 1; return 1;
} }
...@@ -100,7 +107,7 @@ int JsImport_init() { ...@@ -100,7 +107,7 @@ int JsImport_init() {
} }
Py_INCREF(original__import__); Py_INCREF(original__import__);
PyObject *importer = JsImport_New(); PyObject* importer = JsImport_New();
if (importer == NULL) { if (importer == NULL) {
return 1; return 1;
} }
......
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
#include <Python.h> #include <Python.h>
/** Install the import hook to support "from js import …". */ /** Install the import hook to support "from js import …". */
int JsImport_init(); int
JsImport_init();
extern PyObject *globals; extern PyObject* globals;
#endif /* JSIMPORT_H */ #endif /* JSIMPORT_H */
...@@ -4,39 +4,47 @@ ...@@ -4,39 +4,47 @@
#include "js2python.h" #include "js2python.h"
#include "python2js.h" #include "python2js.h"
static PyObject *JsBoundMethod_cnew(int this_, const char *name); static PyObject*
JsBoundMethod_cnew(int this_, const char* name);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// JsProxy // JsProxy
// //
// This is a Python object that provides ideomatic access to a Javascript object. // This is a Python object that provides ideomatic access to a Javascript
// object.
typedef struct { typedef struct
PyObject_HEAD {
int js; PyObject_HEAD int js;
} JsProxy; } JsProxy;
static void JsProxy_dealloc(JsProxy *self) { static void
JsProxy_dealloc(JsProxy* self)
{
hiwire_decref(self->js); hiwire_decref(self->js);
Py_TYPE(self)->tp_free((PyObject *)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject *JsProxy_Repr(PyObject *o) { static PyObject*
JsProxy *self = (JsProxy *)o; JsProxy_Repr(PyObject* o)
{
JsProxy* self = (JsProxy*)o;
int idrepr = hiwire_to_string(self->js); int idrepr = hiwire_to_string(self->js);
PyObject *pyrepr = js2python(idrepr); PyObject* pyrepr = js2python(idrepr);
return pyrepr; return pyrepr;
} }
static PyObject *JsProxy_GetAttr(PyObject *o, PyObject *attr_name) { static PyObject*
JsProxy *self = (JsProxy *)o; JsProxy_GetAttr(PyObject* o, PyObject* attr_name)
{
JsProxy* self = (JsProxy*)o;
PyObject *str = PyObject_Str(attr_name); PyObject* str = PyObject_Str(attr_name);
if (str == NULL) { if (str == NULL) {
return NULL; return NULL;
} }
char *key = PyUnicode_AsUTF8(str); char* key = PyUnicode_AsUTF8(str);
if (strncmp(key, "new", 4) == 0) { if (strncmp(key, "new", 4) == 0) {
Py_DECREF(str); Py_DECREF(str);
...@@ -51,19 +59,21 @@ static PyObject *JsProxy_GetAttr(PyObject *o, PyObject *attr_name) { ...@@ -51,19 +59,21 @@ static PyObject *JsProxy_GetAttr(PyObject *o, PyObject *attr_name) {
return JsBoundMethod_cnew(self->js, key); return JsBoundMethod_cnew(self->js, key);
} }
PyObject *pyresult = js2python(idresult); PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult); hiwire_decref(idresult);
return pyresult; return pyresult;
} }
static int JsProxy_SetAttr(PyObject *o, PyObject *attr_name, PyObject *pyvalue) { static int
JsProxy *self = (JsProxy *)o; JsProxy_SetAttr(PyObject* o, PyObject* attr_name, PyObject* pyvalue)
{
JsProxy* self = (JsProxy*)o;
PyObject *attr_name_py_str = PyObject_Str(attr_name); PyObject* attr_name_py_str = PyObject_Str(attr_name);
if (attr_name_py_str == NULL) { if (attr_name_py_str == NULL) {
return -1; return -1;
} }
char *key = PyUnicode_AsUTF8(attr_name_py_str); char* key = PyUnicode_AsUTF8(attr_name_py_str);
int idvalue = python2js(pyvalue); int idvalue = python2js(pyvalue);
hiwire_set_member_string(self->js, (int)key, idvalue); hiwire_set_member_string(self->js, (int)key, idvalue);
hiwire_decref(idvalue); hiwire_decref(idvalue);
...@@ -72,8 +82,10 @@ static int JsProxy_SetAttr(PyObject *o, PyObject *attr_name, PyObject *pyvalue) ...@@ -72,8 +82,10 @@ static int JsProxy_SetAttr(PyObject *o, PyObject *attr_name, PyObject *pyvalue)
return 0; return 0;
} }
static PyObject* JsProxy_Call(PyObject *o, PyObject *args, PyObject *kwargs) { static PyObject*
JsProxy *self = (JsProxy *)o; JsProxy_Call(PyObject* o, PyObject* args, PyObject* kwargs)
{
JsProxy* self = (JsProxy*)o;
Py_ssize_t nargs = PyTuple_Size(args); Py_ssize_t nargs = PyTuple_Size(args);
...@@ -87,13 +99,15 @@ static PyObject* JsProxy_Call(PyObject *o, PyObject *args, PyObject *kwargs) { ...@@ -87,13 +99,15 @@ static PyObject* JsProxy_Call(PyObject *o, PyObject *args, PyObject *kwargs) {
int idresult = hiwire_call(self->js, idargs); int idresult = hiwire_call(self->js, idargs);
hiwire_decref(idargs); hiwire_decref(idargs);
PyObject *pyresult = js2python(idresult); PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult); hiwire_decref(idresult);
return pyresult; return pyresult;
} }
static PyObject* JsProxy_New(PyObject *o, PyObject *args, PyObject *kwargs) { static PyObject*
JsProxy *self = (JsProxy *)o; JsProxy_New(PyObject* o, PyObject* args, PyObject* kwargs)
{
JsProxy* self = (JsProxy*)o;
Py_ssize_t nargs = PyTuple_Size(args); Py_ssize_t nargs = PyTuple_Size(args);
...@@ -107,34 +121,41 @@ static PyObject* JsProxy_New(PyObject *o, PyObject *args, PyObject *kwargs) { ...@@ -107,34 +121,41 @@ static PyObject* JsProxy_New(PyObject *o, PyObject *args, PyObject *kwargs) {
int idresult = hiwire_new(self->js, idargs); int idresult = hiwire_new(self->js, idargs);
hiwire_decref(idargs); hiwire_decref(idargs);
PyObject *pyresult = js2python(idresult); PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult); hiwire_decref(idresult);
return pyresult; return pyresult;
} }
Py_ssize_t JsProxy_length(PyObject *o) { Py_ssize_t
JsProxy *self = (JsProxy *)o; JsProxy_length(PyObject* o)
{
JsProxy* self = (JsProxy*)o;
return hiwire_get_length(self->js); return hiwire_get_length(self->js);
} }
PyObject* JsProxy_item(PyObject *o, Py_ssize_t idx) { PyObject*
JsProxy *self = (JsProxy *)o; JsProxy_item(PyObject* o, Py_ssize_t idx)
{
JsProxy* self = (JsProxy*)o;
int idresult = hiwire_get_member_int(self->js, idx); int idresult = hiwire_get_member_int(self->js, idx);
PyObject *pyresult = js2python(idresult); PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult); hiwire_decref(idresult);
return pyresult; return pyresult;
} }
int JsProxy_ass_item(PyObject *o, Py_ssize_t idx, PyObject *value) { int
JsProxy *self = (JsProxy *)o; JsProxy_ass_item(PyObject* o, Py_ssize_t idx, PyObject* value)
{
JsProxy* self = (JsProxy*)o;
int idvalue = python2js(value); int idvalue = python2js(value);
hiwire_set_member_int(self->js, idx, idvalue); hiwire_set_member_int(self->js, idx, idvalue);
hiwire_decref(idvalue); hiwire_decref(idvalue);
return 0; return 0;
} }
// clang-format off
static PySequenceMethods JsProxy_SequenceMethods = { static PySequenceMethods JsProxy_SequenceMethods = {
JsProxy_length, JsProxy_length,
NULL, NULL,
...@@ -147,11 +168,13 @@ static PySequenceMethods JsProxy_SequenceMethods = { ...@@ -147,11 +168,13 @@ static PySequenceMethods JsProxy_SequenceMethods = {
NULL, NULL,
NULL NULL
}; };
// clang-format on
static PyMethodDef JsProxy_Methods[] = { static PyMethodDef JsProxy_Methods[] = { { "new",
{"new", (PyCFunction)JsProxy_New, METH_VARARGS|METH_KEYWORDS, "Construct a new instance"}, (PyCFunction)JsProxy_New,
{ NULL } METH_VARARGS | METH_KEYWORDS,
}; "Construct a new instance" },
{ NULL } };
static PyTypeObject JsProxyType = { static PyTypeObject JsProxyType = {
.tp_name = "JsProxy", .tp_name = "JsProxy",
...@@ -167,11 +190,13 @@ static PyTypeObject JsProxyType = { ...@@ -167,11 +190,13 @@ static PyTypeObject JsProxyType = {
.tp_repr = JsProxy_Repr .tp_repr = JsProxy_Repr
}; };
PyObject *JsProxy_cnew(int idobj) { PyObject*
JsProxy *self; JsProxy_cnew(int idobj)
self = (JsProxy *)JsProxyType.tp_alloc(&JsProxyType, 0); {
JsProxy* self;
self = (JsProxy*)JsProxyType.tp_alloc(&JsProxyType, 0);
self->js = hiwire_incref(idobj); self->js = hiwire_incref(idobj);
return (PyObject *)self; return (PyObject*)self;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
...@@ -181,19 +206,23 @@ PyObject *JsProxy_cnew(int idobj) { ...@@ -181,19 +206,23 @@ PyObject *JsProxy_cnew(int idobj) {
const size_t BOUND_METHOD_NAME_SIZE = 256; const size_t BOUND_METHOD_NAME_SIZE = 256;
typedef struct { typedef struct
PyObject_HEAD {
int this_; PyObject_HEAD int this_;
char name[BOUND_METHOD_NAME_SIZE]; char name[BOUND_METHOD_NAME_SIZE];
} JsBoundMethod; } JsBoundMethod;
static void JsBoundMethod_dealloc(JsBoundMethod *self) { static void
JsBoundMethod_dealloc(JsBoundMethod* self)
{
hiwire_decref(self->this_); hiwire_decref(self->this_);
Py_TYPE(self)->tp_free((PyObject *)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject* JsBoundMethod_Call(PyObject *o, PyObject *args, PyObject *kwargs) { static PyObject*
JsBoundMethod *self = (JsBoundMethod *)o; JsBoundMethod_Call(PyObject* o, PyObject* args, PyObject* kwargs)
{
JsBoundMethod* self = (JsBoundMethod*)o;
Py_ssize_t nargs = PyTuple_Size(args); Py_ssize_t nargs = PyTuple_Size(args);
...@@ -207,7 +236,7 @@ static PyObject* JsBoundMethod_Call(PyObject *o, PyObject *args, PyObject *kwarg ...@@ -207,7 +236,7 @@ static PyObject* JsBoundMethod_Call(PyObject *o, PyObject *args, PyObject *kwarg
int idresult = hiwire_call_member(self->this_, (int)self->name, idargs); int idresult = hiwire_call_member(self->this_, (int)self->name, idargs);
hiwire_decref(idargs); hiwire_decref(idargs);
PyObject *pyresult = js2python(idresult); PyObject* pyresult = js2python(idresult);
hiwire_decref(idresult); hiwire_decref(idresult);
return pyresult; return pyresult;
} }
...@@ -218,31 +247,39 @@ static PyTypeObject JsBoundMethodType = { ...@@ -218,31 +247,39 @@ static PyTypeObject JsBoundMethodType = {
.tp_dealloc = (destructor)JsBoundMethod_dealloc, .tp_dealloc = (destructor)JsBoundMethod_dealloc,
.tp_call = JsBoundMethod_Call, .tp_call = JsBoundMethod_Call,
.tp_flags = Py_TPFLAGS_DEFAULT, .tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "A proxy to make it possible to call Javascript bound methods from Python." .tp_doc = "A proxy to make it possible to call Javascript bound methods from "
"Python."
}; };
static PyObject *JsBoundMethod_cnew(int this_, const char *name) { static PyObject*
JsBoundMethod *self; JsBoundMethod_cnew(int this_, const char* name)
self = (JsBoundMethod *)JsBoundMethodType.tp_alloc(&JsBoundMethodType, 0); {
JsBoundMethod* self;
self = (JsBoundMethod*)JsBoundMethodType.tp_alloc(&JsBoundMethodType, 0);
self->this_ = hiwire_incref(this_); self->this_ = hiwire_incref(this_);
strncpy(self->name, name, BOUND_METHOD_NAME_SIZE); strncpy(self->name, name, BOUND_METHOD_NAME_SIZE);
return (PyObject *)self; return (PyObject*)self;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Public functions // Public functions
int JsProxy_Check(PyObject *x) { int
JsProxy_Check(PyObject* x)
{
return (PyObject_TypeCheck(x, &JsProxyType) || return (PyObject_TypeCheck(x, &JsProxyType) ||
PyObject_TypeCheck(x, &JsBoundMethodType)); PyObject_TypeCheck(x, &JsBoundMethodType));
} }
int JsProxy_AsJs(PyObject *x) { int
JsProxy *js_proxy = (JsProxy *)x; JsProxy_AsJs(PyObject* x)
{
JsProxy* js_proxy = (JsProxy*)x;
return hiwire_incref(js_proxy->js); return hiwire_incref(js_proxy->js);
} }
int JsProxy_init() { int
return (PyType_Ready(&JsProxyType) || JsProxy_init()
PyType_Ready(&JsBoundMethodType)); {
return (PyType_Ready(&JsProxyType) || PyType_Ready(&JsBoundMethodType));
} }
...@@ -11,21 +11,25 @@ ...@@ -11,21 +11,25 @@
* \param v The Javascript object. * \param v The Javascript object.
* \return The Python object wrapping the Javascript object. * \return The Python object wrapping the Javascript object.
*/ */
PyObject *JsProxy_cnew(int v); PyObject*
JsProxy_cnew(int v);
/** Check if a Python object is a JsProxy object. /** Check if a Python object is a JsProxy object.
* \param x The Python object * \param x The Python object
* \return 1 if the object is a JsProxy object. * \return 1 if the object is a JsProxy object.
*/ */
int JsProxy_Check(PyObject *x); int
JsProxy_Check(PyObject* x);
/** Grab the underlying Javascript object from the JsProxy object. /** Grab the underlying Javascript object from the JsProxy object.
* \param x The JsProxy object. Must confirm that it is a JsProxy object using JsProxy_Check. * \param x The JsProxy object. Must confirm that it is a JsProxy object using
* \return The Javascript object. * JsProxy_Check. \return The Javascript object.
*/ */
int JsProxy_AsJs(PyObject *x); int
JsProxy_AsJs(PyObject* x);
/** Initialize global state for the JsProxy functionality. */ /** Initialize global state for the JsProxy functionality. */
int JsProxy_init(); int
JsProxy_init();
#endif /* JSPROXY_H */ #endif /* JSPROXY_H */
#include <emscripten.h>
#include <Python.h> #include <Python.h>
#include <emscripten.h>
#include "hiwire.h" #include "hiwire.h"
#include "js2python.h" #include "js2python.h"
...@@ -18,25 +18,27 @@ ...@@ -18,25 +18,27 @@
work around the problem. work around the problem.
*/ */
void __foo(double x) { void
__foo(double x)
} {}
void __foo2(double x, double y) {
} void
__foo2(double x, double y)
void __foo3(double x, double y, double z) { {}
} void
__foo3(double x, double y, double z)
{}
void __foo4(int a, double b, int c, int d, int e) { void
__foo4(int a, double b, int c, int d, int e)
} {}
/* END WORKAROUND */ /* END WORKAROUND */
int main(int argc, char** argv) { int
main(int argc, char** argv)
{
hiwire_setup(); hiwire_setup();
setenv("PYTHONDONTWRITEBYTECODE", "1", 0); setenv("PYTHONDONTWRITEBYTECODE", "1", 0);
...@@ -46,15 +48,9 @@ int main(int argc, char** argv) { ...@@ -46,15 +48,9 @@ int main(int argc, char** argv) {
// TODO cleanup naming of these functions // TODO cleanup naming of these functions
if ( if (js2python_init() || JsImport_init() || JsProxy_init() ||
js2python_init() || pyimport_init() || pyproxy_init() || python2js_init() ||
JsImport_init() || runpython_init()) {
JsProxy_init() ||
pyimport_init() ||
pyproxy_init() ||
python2js_init() ||
runpython_init()
) {
return 1; return 1;
} }
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
#include "python2js.h" #include "python2js.h"
extern PyObject *globals; extern PyObject* globals;
int _pyimport(char *name) { int
PyObject *pyname = PyUnicode_FromString(name); _pyimport(char* name)
PyObject *pyval = PyDict_GetItem(globals, pyname); {
PyObject* pyname = PyUnicode_FromString(name);
PyObject* pyval = PyDict_GetItem(globals, pyname);
if (pyval == NULL) { if (pyval == NULL) {
Py_DECREF(pyname); Py_DECREF(pyname);
return pythonexc2js(); return pythonexc2js();
...@@ -22,7 +24,8 @@ int _pyimport(char *name) { ...@@ -22,7 +24,8 @@ int _pyimport(char *name) {
} }
EM_JS(int, pyimport_init, (), { EM_JS(int, pyimport_init, (), {
Module.pyimport = function(name) { Module.pyimport = function(name)
{
var pyname = allocate(intArrayFromString(name), 'i8', ALLOC_NORMAL); var pyname = allocate(intArrayFromString(name), 'i8', ALLOC_NORMAL);
var idresult = Module.__pyimport(pyname); var idresult = Module.__pyimport(pyname);
jsresult = Module.hiwire_get_value(idresult); jsresult = Module.hiwire_get_value(idresult);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
/** Makes `var foo = pyodide.pyimport('foo')` work in Javascript. /** Makes `var foo = pyodide.pyimport('foo')` work in Javascript.
*/ */
int pyimport_init(); int
pyimport_init();
#endif /* PYIMPORT_H */ #endif /* PYIMPORT_H */
This diff is collapsed.
...@@ -6,6 +6,7 @@ from js import XMLHttpRequest ...@@ -6,6 +6,7 @@ from js import XMLHttpRequest
import io import io
def open_url(url): def open_url(url):
""" """
Fetches a given *url* and returns a io.StringIO to access its contents. Fetches a given *url* and returns a io.StringIO to access its contents.
......
...@@ -5,18 +5,22 @@ ...@@ -5,18 +5,22 @@
#include "js2python.h" #include "js2python.h"
#include "python2js.h" #include "python2js.h"
int _pyproxy_has(int ptrobj, int idkey) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_has(int ptrobj, int idkey)
PyObject *pykey = js2python(idkey); {
int result = PyObject_HasAttr(pyobj, pykey) ? hiwire_true(): hiwire_false(); PyObject* pyobj = (PyObject*)ptrobj;
PyObject* pykey = js2python(idkey);
int result = PyObject_HasAttr(pyobj, pykey) ? hiwire_true() : hiwire_false();
Py_DECREF(pykey); Py_DECREF(pykey);
return result; return result;
} }
int _pyproxy_get(int ptrobj, int idkey) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_get(int ptrobj, int idkey)
PyObject *pykey = js2python(idkey); {
PyObject *pyattr = PyObject_GetAttr(pyobj, pykey); PyObject* pyobj = (PyObject*)ptrobj;
PyObject* pykey = js2python(idkey);
PyObject* pyattr = PyObject_GetAttr(pyobj, pykey);
Py_DECREF(pykey); Py_DECREF(pykey);
if (pyattr == NULL) { if (pyattr == NULL) {
PyErr_Clear(); PyErr_Clear();
...@@ -28,10 +32,12 @@ int _pyproxy_get(int ptrobj, int idkey) { ...@@ -28,10 +32,12 @@ int _pyproxy_get(int ptrobj, int idkey) {
return idattr; return idattr;
}; };
int _pyproxy_set(int ptrobj, int idkey, int idval) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_set(int ptrobj, int idkey, int idval)
PyObject *pykey = js2python(idkey); {
PyObject *pyval = js2python(idval); PyObject* pyobj = (PyObject*)ptrobj;
PyObject* pykey = js2python(idkey);
PyObject* pyval = js2python(idval);
int result = PyObject_SetAttr(pyobj, pykey, pyval); int result = PyObject_SetAttr(pyobj, pykey, pyval);
Py_DECREF(pykey); Py_DECREF(pykey);
Py_DECREF(pyval); Py_DECREF(pyval);
...@@ -42,9 +48,11 @@ int _pyproxy_set(int ptrobj, int idkey, int idval) { ...@@ -42,9 +48,11 @@ int _pyproxy_set(int ptrobj, int idkey, int idval) {
return idval; return idval;
} }
int _pyproxy_deleteProperty(int ptrobj, int idkey) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_deleteProperty(int ptrobj, int idkey)
PyObject *pykey = js2python(idkey); {
PyObject* pyobj = (PyObject*)ptrobj;
PyObject* pykey = js2python(idkey);
int ret = PyObject_DelAttr(pyobj, pykey); int ret = PyObject_DelAttr(pyobj, pykey);
Py_DECREF(pykey); Py_DECREF(pykey);
...@@ -56,9 +64,11 @@ int _pyproxy_deleteProperty(int ptrobj, int idkey) { ...@@ -56,9 +64,11 @@ int _pyproxy_deleteProperty(int ptrobj, int idkey) {
return hiwire_undefined(); return hiwire_undefined();
} }
int _pyproxy_ownKeys(int ptrobj) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_ownKeys(int ptrobj)
PyObject *pydir = PyObject_Dir(pyobj); {
PyObject* pyobj = (PyObject*)ptrobj;
PyObject* pydir = PyObject_Dir(pyobj);
if (pydir == NULL) { if (pydir == NULL) {
return pythonexc2js(); return pythonexc2js();
...@@ -67,7 +77,7 @@ int _pyproxy_ownKeys(int ptrobj) { ...@@ -67,7 +77,7 @@ int _pyproxy_ownKeys(int ptrobj) {
int iddir = hiwire_array(); int iddir = hiwire_array();
Py_ssize_t n = PyList_Size(pydir); Py_ssize_t n = PyList_Size(pydir);
for (Py_ssize_t i = 0; i < n; ++i) { for (Py_ssize_t i = 0; i < n; ++i) {
PyObject *pyentry = PyList_GetItem(pydir, i); PyObject* pyentry = PyList_GetItem(pydir, i);
int identry = python2js(pyentry); int identry = python2js(pyentry);
hiwire_push_array(iddir, identry); hiwire_push_array(iddir, identry);
hiwire_decref(identry); hiwire_decref(identry);
...@@ -77,21 +87,25 @@ int _pyproxy_ownKeys(int ptrobj) { ...@@ -77,21 +87,25 @@ int _pyproxy_ownKeys(int ptrobj) {
return iddir; return iddir;
} }
int _pyproxy_enumerate(int ptrobj) { int
_pyproxy_enumerate(int ptrobj)
{
return _pyproxy_ownKeys(ptrobj); return _pyproxy_ownKeys(ptrobj);
} }
int _pyproxy_apply(int ptrobj, int idargs) { int
PyObject *pyobj = (PyObject *)ptrobj; _pyproxy_apply(int ptrobj, int idargs)
{
PyObject* pyobj = (PyObject*)ptrobj;
Py_ssize_t length = hiwire_get_length(idargs); Py_ssize_t length = hiwire_get_length(idargs);
PyObject *pyargs = PyTuple_New(length); PyObject* pyargs = PyTuple_New(length);
for (Py_ssize_t i = 0; i < length; ++i) { for (Py_ssize_t i = 0; i < length; ++i) {
int iditem = hiwire_get_member_int(idargs, i); int iditem = hiwire_get_member_int(idargs, i);
PyObject *pyitem = js2python(iditem); PyObject* pyitem = js2python(iditem);
PyTuple_SET_ITEM(pyargs, i, pyitem); PyTuple_SET_ITEM(pyargs, i, pyitem);
hiwire_decref(iditem); hiwire_decref(iditem);
} }
PyObject *pyresult = PyObject_Call(pyobj, pyargs, NULL); PyObject* pyresult = PyObject_Call(pyobj, pyargs, NULL);
if (pyresult == NULL) { if (pyresult == NULL) {
Py_DECREF(pyargs); Py_DECREF(pyargs);
return pythonexc2js(); return pythonexc2js();
...@@ -109,6 +123,7 @@ EM_JS(int, pyproxy_new, (int ptrobj), { ...@@ -109,6 +123,7 @@ EM_JS(int, pyproxy_new, (int ptrobj), {
}); });
EM_JS(int, pyproxy_init, (), { EM_JS(int, pyproxy_init, (), {
// clang-format off
Module.PyProxy = { Module.PyProxy = {
getPtr: function(jsobj) { getPtr: function(jsobj) {
return jsobj['$$']['ptr']; return jsobj['$$']['ptr'];
...@@ -193,4 +208,5 @@ EM_JS(int, pyproxy_init, (), { ...@@ -193,4 +208,5 @@ EM_JS(int, pyproxy_init, (), {
}; };
return 0; return 0;
// clang-format on
}); });
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
// This implements the Javascript Proxy handler interface as defined here: // This implements the Javascript Proxy handler interface as defined here:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
int pyproxy_new(int obj); int
int pyproxy_init(); pyproxy_new(int obj);
int
pyproxy_init();
#endif /* PYPROXY_H */ #endif /* PYPROXY_H */
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# flake8: noqa
""" """
"PYSTONE" Benchmark Program "PYSTONE" Benchmark Program
......
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#include "jsproxy.h" #include "jsproxy.h"
#include "pyproxy.h" #include "pyproxy.h"
int pythonexc2js() { int
PyObject *type; pythonexc2js()
PyObject *value; {
PyObject *traceback; PyObject* type;
PyObject* value;
PyObject* traceback;
int no_traceback = 0; int no_traceback = 0;
PyErr_Fetch(&type, &value, &traceback); PyErr_Fetch(&type, &value, &traceback);
...@@ -18,17 +20,16 @@ int pythonexc2js() { ...@@ -18,17 +20,16 @@ int pythonexc2js() {
int excval = -1; int excval = -1;
int exc; int exc;
if (type == NULL || type == Py_None || if (type == NULL || type == Py_None || value == NULL || value == Py_None) {
value == NULL || value == Py_None) {
excval = hiwire_string_utf8((int)"No exception type or value"); excval = hiwire_string_utf8((int)"No exception type or value");
PyErr_Print(); PyErr_Print();
PyErr_Clear(); PyErr_Clear();
goto exit; goto exit;
} }
PyObject *tbmod = PyImport_ImportModule("traceback"); PyObject* tbmod = PyImport_ImportModule("traceback");
if (tbmod == NULL) { if (tbmod == NULL) {
PyObject *repr = PyObject_Repr(value); PyObject* repr = PyObject_Repr(value);
if (repr == NULL) { if (repr == NULL) {
excval = hiwire_string_utf8((int)"Could not get repr for exception"); excval = hiwire_string_utf8((int)"Could not get repr for exception");
} else { } else {
...@@ -36,7 +37,7 @@ int pythonexc2js() { ...@@ -36,7 +37,7 @@ int pythonexc2js() {
Py_DECREF(repr); Py_DECREF(repr);
} }
} else { } else {
PyObject *format_exception; PyObject* format_exception;
if (traceback == NULL || traceback == Py_None) { if (traceback == NULL || traceback == Py_None) {
no_traceback = 1; no_traceback = 1;
format_exception = PyObject_GetAttrString(tbmod, "format_exception_only"); format_exception = PyObject_GetAttrString(tbmod, "format_exception_only");
...@@ -44,24 +45,26 @@ int pythonexc2js() { ...@@ -44,24 +45,26 @@ int pythonexc2js() {
format_exception = PyObject_GetAttrString(tbmod, "format_exception"); format_exception = PyObject_GetAttrString(tbmod, "format_exception");
} }
if (format_exception == NULL) { if (format_exception == NULL) {
excval = hiwire_string_utf8((int)"Could not get format_exception function"); excval =
hiwire_string_utf8((int)"Could not get format_exception function");
} else { } else {
PyObject *pylines; PyObject* pylines;
if (no_traceback) { if (no_traceback) {
pylines = PyObject_CallFunctionObjArgs pylines =
(format_exception, type, value, NULL); PyObject_CallFunctionObjArgs(format_exception, type, value, NULL);
} else { } else {
pylines = PyObject_CallFunctionObjArgs pylines = PyObject_CallFunctionObjArgs(
(format_exception, type, value, traceback, NULL); format_exception, type, value, traceback, NULL);
} }
if (pylines == NULL) { if (pylines == NULL) {
excval = hiwire_string_utf8((int)"Error calling traceback.format_exception"); excval =
hiwire_string_utf8((int)"Error calling traceback.format_exception");
PyErr_Print(); PyErr_Print();
PyErr_Clear(); PyErr_Clear();
goto exit; goto exit;
} else { } else {
PyObject *newline = PyUnicode_FromString(""); PyObject* newline = PyUnicode_FromString("");
PyObject *pystr = PyUnicode_Join(newline, pylines); PyObject* pystr = PyUnicode_Join(newline, pylines);
printf("Python exception:\n"); printf("Python exception:\n");
printf("%s\n", PyUnicode_AsUTF8(pystr)); printf("%s\n", PyUnicode_AsUTF8(pystr));
excval = python2js(pystr); excval = python2js(pystr);
...@@ -74,7 +77,7 @@ int pythonexc2js() { ...@@ -74,7 +77,7 @@ int pythonexc2js() {
Py_DECREF(tbmod); Py_DECREF(tbmod);
} }
exit: exit:
Py_XDECREF(type); Py_XDECREF(type);
Py_XDECREF(value); Py_XDECREF(value);
Py_XDECREF(traceback); Py_XDECREF(traceback);
...@@ -86,15 +89,17 @@ int pythonexc2js() { ...@@ -86,15 +89,17 @@ int pythonexc2js() {
return -1; return -1;
} }
static int is_type_name(PyObject *x, const char *name) { static int
PyObject *x_type = PyObject_Type(x); is_type_name(PyObject* x, const char* name)
{
PyObject* x_type = PyObject_Type(x);
if (x_type == NULL) { if (x_type == NULL) {
// If we can't get a type, that's probably ok in this case... // If we can't get a type, that's probably ok in this case...
PyErr_Clear(); PyErr_Clear();
return 0; return 0;
} }
PyObject *x_type_name = PyObject_Repr(x_type); PyObject* x_type_name = PyObject_Repr(x_type);
Py_DECREF(x_type); Py_DECREF(x_type);
int result = (PyUnicode_CompareWithASCIIString(x_type_name, name) == 0); int result = (PyUnicode_CompareWithASCIIString(x_type_name, name) == 0);
...@@ -103,7 +108,9 @@ static int is_type_name(PyObject *x, const char *name) { ...@@ -103,7 +108,9 @@ static int is_type_name(PyObject *x, const char *name) {
return result; return result;
} }
int python2js(PyObject *x) { int
python2js(PyObject* x)
{
if (x == Py_None) { if (x == Py_None) {
return hiwire_undefined(); return hiwire_undefined();
} else if (x == Py_True) { } else if (x == Py_True) {
...@@ -124,25 +131,25 @@ int python2js(PyObject *x) { ...@@ -124,25 +131,25 @@ int python2js(PyObject *x) {
return hiwire_double(x_double); return hiwire_double(x_double);
} else if (PyUnicode_Check(x)) { } else if (PyUnicode_Check(x)) {
Py_ssize_t length; Py_ssize_t length;
char *chars = PyUnicode_AsUTF8AndSize(x, &length); char* chars = PyUnicode_AsUTF8AndSize(x, &length);
if (chars == NULL) { if (chars == NULL) {
return pythonexc2js(); return pythonexc2js();
} }
return hiwire_string_utf8_length((int)(void *)chars, length); return hiwire_string_utf8_length((int)(void*)chars, length);
} else if (PyBytes_Check(x)) { } else if (PyBytes_Check(x)) {
char *x_buff; char* x_buff;
Py_ssize_t length; Py_ssize_t length;
if (PyBytes_AsStringAndSize(x, &x_buff, &length)) { if (PyBytes_AsStringAndSize(x, &x_buff, &length)) {
return pythonexc2js(); return pythonexc2js();
} }
return hiwire_bytes((int)(void *)x_buff, length); return hiwire_bytes((int)(void*)x_buff, length);
} else if (JsProxy_Check(x)) { } else if (JsProxy_Check(x)) {
return JsProxy_AsJs(x); return JsProxy_AsJs(x);
} else if (PyList_Check(x) || is_type_name(x, "<class 'numpy.ndarray'>")) { } else if (PyList_Check(x) || is_type_name(x, "<class 'numpy.ndarray'>")) {
int jsarray = hiwire_array(); int jsarray = hiwire_array();
size_t length = PySequence_Size(x); size_t length = PySequence_Size(x);
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
PyObject *pyitem = PySequence_GetItem(x, i); PyObject* pyitem = PySequence_GetItem(x, i);
if (pyitem == NULL) { if (pyitem == NULL) {
// If something goes wrong converting the sequence (as is the case with // If something goes wrong converting the sequence (as is the case with
// Pandas data frames), fallback to the Python object proxy // Pandas data frames), fallback to the Python object proxy
...@@ -191,6 +198,8 @@ int python2js(PyObject *x) { ...@@ -191,6 +198,8 @@ int python2js(PyObject *x) {
} }
} }
int python2js_init() { int
python2js_init()
{
return 0; return 0;
} }
...@@ -9,16 +9,20 @@ ...@@ -9,16 +9,20 @@
/** Convert the active Python exception into a Javascript Error object. /** Convert the active Python exception into a Javascript Error object.
* \return A Javascript Error object * \return A Javascript Error object
*/ */
int pythonexc2js(); int
pythonexc2js();
/** Convert a Python object to a Javascript object. /** Convert a Python object to a Javascript object.
* \param The Python object * \param The Python object
* \return The Javascript object -- might be an Error object in the case of an exception. * \return The Javascript object -- might be an Error object in the case of an
* exception.
*/ */
int python2js(PyObject *x); int
python2js(PyObject* x);
/** Set up the global state for this module. /** Set up the global state for this module.
*/ */
int python2js_init(); int
python2js_init();
#endif /* PYTHON2JS_H */ #endif /* PYTHON2JS_H */
#include "runpython.h" #include "runpython.h"
#include <emscripten.h>
#include <Python.h> #include <Python.h>
#include <emscripten.h>
#include <node.h> // from Python #include <node.h> // from Python
#include "python2js.h"
#include "hiwire.h" #include "hiwire.h"
#include "python2js.h"
extern PyObject *globals; extern PyObject* globals;
static int is_whitespace(char x) { static int
is_whitespace(char x)
{
switch (x) { switch (x) {
case ' ': case ' ':
case '\n': case '\n':
case '\r': case '\r':
case '\t': case '\t':
return 1; return 1;
default: default:
return 0; return 0;
} }
} }
int _runPython(char *code) { int
char *last_line = code; _runPython(char* code)
{
char* last_line = code;
while (*last_line != 0) { while (*last_line != 0) {
++last_line; ++last_line;
} }
...@@ -39,11 +43,13 @@ int _runPython(char *code) { ...@@ -39,11 +43,13 @@ int _runPython(char *code) {
// Find the last non-whitespace-only line since that will provide the result // Find the last non-whitespace-only line since that will provide the result
// TODO: This way to find the last line will probably break in many ways // TODO: This way to find the last line will probably break in many ways
last_line--; last_line--;
for (; last_line != code && is_whitespace(*last_line); last_line--) {} for (; last_line != code && is_whitespace(*last_line); last_line--) {
for (; last_line != code && *last_line != '\n'; last_line--) {} }
for (; last_line != code && *last_line != '\n'; last_line--) {
}
int do_eval_line = 1; int do_eval_line = 1;
struct _node *co; struct _node* co;
co = PyParser_SimpleParseStringFlags(last_line, Py_eval_input, cf.cf_flags); co = PyParser_SimpleParseStringFlags(last_line, Py_eval_input, cf.cf_flags);
if (co == NULL) { if (co == NULL) {
do_eval_line = 0; do_eval_line = 0;
...@@ -51,7 +57,7 @@ int _runPython(char *code) { ...@@ -51,7 +57,7 @@ int _runPython(char *code) {
} }
PyNode_Free(co); PyNode_Free(co);
PyObject *ret; PyObject* ret;
if (do_eval_line == 0 || last_line != code) { if (do_eval_line == 0 || last_line != code) {
if (do_eval_line) { if (do_eval_line) {
*last_line = 0; *last_line = 0;
...@@ -65,16 +71,16 @@ int _runPython(char *code) { ...@@ -65,16 +71,16 @@ int _runPython(char *code) {
} }
switch (do_eval_line) { switch (do_eval_line) {
case 0: case 0:
Py_INCREF(Py_None); Py_INCREF(Py_None);
ret = Py_None; ret = Py_None;
break; break;
case 1: case 1:
ret = PyRun_StringFlags(last_line, Py_eval_input, globals, globals, &cf); ret = PyRun_StringFlags(last_line, Py_eval_input, globals, globals, &cf);
break; break;
case 2: case 2:
ret = PyRun_StringFlags(last_line, Py_file_input, globals, globals, &cf); ret = PyRun_StringFlags(last_line, Py_file_input, globals, globals, &cf);
break; break;
} }
if (ret == NULL) { if (ret == NULL) {
...@@ -87,7 +93,8 @@ int _runPython(char *code) { ...@@ -87,7 +93,8 @@ int _runPython(char *code) {
} }
EM_JS(int, runpython_init, (), { EM_JS(int, runpython_init, (), {
Module.runPython = function (code) { Module.runPython = function(code)
{
var pycode = allocate(intArrayFromString(code), 'i8', ALLOC_NORMAL); var pycode = allocate(intArrayFromString(code), 'i8', ALLOC_NORMAL);
var idresult = Module.__runPython(pycode); var idresult = Module.__runPython(pycode);
jsresult = Module.hiwire_get_value(idresult); jsresult = Module.hiwire_get_value(idresult);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/** The primary entry point function that runs Python code. /** The primary entry point function that runs Python code.
*/ */
int
int runpython_init(); runpython_init();
#endif /* RUNPYTHON_H */ #endif /* RUNPYTHON_H */
...@@ -18,7 +18,7 @@ import math ...@@ -18,7 +18,7 @@ import math
from matplotlib.backends import backend_agg from matplotlib.backends import backend_agg
from matplotlib.backend_bases import _Backend from matplotlib.backend_bases import _Backend
from matplotlib import backend_bases, interactive, _png from matplotlib import backend_bases, interactive
from js import document from js import document
from js import window from js import window
...@@ -130,14 +130,15 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg): ...@@ -130,14 +130,15 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
rubberband.setAttribute('width', width) rubberband.setAttribute('width', width)
rubberband.setAttribute('height', height) rubberband.setAttribute('height', height)
rubberband.setAttribute( rubberband.setAttribute(
'style', 'position: absolute; left: 0; top: 0; z-index: 0; outline: 0;' + 'style', 'position: absolute; left: 0; top: 0; z-index: 0; ' +
'width: {}px; height: {}px'.format( 'outline: 0; width: {}px; height: {}px'.format(
width / self._ratio, height / self._ratio) width / self._ratio, height / self._ratio)
) )
# Canvas must have a "tabindex" attr in order to receive keyboard events # Canvas must have a "tabindex" attr in order to receive keyboard
# events
rubberband.setAttribute('tabindex', '0') rubberband.setAttribute('tabindex', '0')
# Event handlers are added to the canvas "on top", even though most of the # Event handlers are added to the canvas "on top", even though most of
# activity happens in the canvas below. # the activity happens in the canvas below.
rubberband.addEventListener('mousemove', self.onmousemove) rubberband.addEventListener('mousemove', self.onmousemove)
rubberband.addEventListener('mouseup', self.onmouseup) rubberband.addEventListener('mouseup', self.onmouseup)
rubberband.addEventListener('mousedown', self.onmousedown) rubberband.addEventListener('mousedown', self.onmousedown)
...@@ -146,7 +147,7 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg): ...@@ -146,7 +147,7 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
rubberband.addEventListener('keyup', self.onkeyup) rubberband.addEventListener('keyup', self.onkeyup)
rubberband.addEventListener('keydown', self.onkeydown) rubberband.addEventListener('keydown', self.onkeydown)
context = rubberband.getContext('2d') context = rubberband.getContext('2d')
context.strokeStyle = '#000000'; context.strokeStyle = '#000000'
context.setLineDash([2, 2]) context.setLineDash([2, 2])
canvas_div.appendChild(rubberband) canvas_div.appendChild(rubberband)
...@@ -175,13 +176,13 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg): ...@@ -175,13 +176,13 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
# Copy the image buffer to the canvas # Copy the image buffer to the canvas
width, height = self.get_width_height() width, height = self.get_width_height()
canvas = self.get_element('canvas') canvas = self.get_element('canvas')
if canvas == None: if canvas is None:
return return
image_data = ImageData.new( image_data = ImageData.new(
self.buffer_rgba(), self.buffer_rgba(),
width, height); width, height)
ctx = canvas.getContext("2d"); ctx = canvas.getContext("2d")
ctx.putImageData(image_data, 0, 0); ctx.putImageData(image_data, 0, 0)
finally: finally:
self.figure.dpi = orig_dpi self.figure.dpi = orig_dpi
self._idle_scheduled = False self._idle_scheduled = False
...@@ -244,7 +245,8 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg): ...@@ -244,7 +245,8 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
} }
def set_cursor(self, cursor): def set_cursor(self, cursor):
self.get_element('rubberband').style.cursor = self._cursor_map.get(cursor, 0) self.get_element('rubberband').style.cursor = \
self._cursor_map.get(cursor, 0)
# http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes # http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
_SHIFT_LUT = { _SHIFT_LUT = {
...@@ -447,7 +449,8 @@ class NavigationToolbar2Wasm(backend_bases.NavigationToolbar2): ...@@ -447,7 +449,8 @@ class NavigationToolbar2Wasm(backend_bases.NavigationToolbar2):
button = document.createElement('button') button = document.createElement('button')
button.classList.add('fa') button.classList.add('fa')
button.classList.add(_FONTAWESOME_ICONS[image_file]) button.classList.add(_FONTAWESOME_ICONS[image_file])
button.addEventListener('click', getattr(self, name_of_method)) button.addEventListener(
'click', getattr(self, name_of_method))
div.appendChild(button) div.appendChild(button)
for format, mimetype in sorted(list(FILE_TYPES.items())): for format, mimetype in sorted(list(FILE_TYPES.items())):
......
...@@ -5,12 +5,15 @@ An implementation of the standard library webbrowser module to open webpages. ...@@ -5,12 +5,15 @@ An implementation of the standard library webbrowser module to open webpages.
Since we're already running a webbrowser, it's really simple... Since we're already running a webbrowser, it's really simple...
""" """
def open(url, new=0, autoraise=True): def open(url, new=0, autoraise=True):
from js import window from js import window
window.open(url, "_blank") window.open(url, "_blank")
def open_new(url): def open_new(url):
return open(url, 1) return open(url, 1)
def open_new_tab(url): def open_new_tab(url):
return open(url, 2) return open(url, 2)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment