-
Notifications
You must be signed in to change notification settings - Fork 43
/
entry_point.js
146 lines (132 loc) · 4.85 KB
/
entry_point.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
this['Python'] = {
// Initializes the Python runtime with optional standard I/O callbacks.
'initialize': function(input, output, error) {
if (this.isInitialized) {
console.log('Ignoring repeated Python initialization.');
return;
}
FS.init(input, output, error);
ENV['PYTHONHOME'] = '/:/';
run();
setValue(_Py_NoSiteFlag, 1, 'i32');
setValue(_Py_DontWriteBytecodeFlag, 1, 'i32');
_Py_Initialize();
var cmd = this.allocateString('python');
_PySys_SetArgv(1, allocate([cmd], 'i8*', ALLOC_NORMAL));
this.module = _PyImport_AddModule(this.allocateString('__main__'));
this.filename = this.allocateString('<stdin>');
this.flags = allocate([0], 'i32', ALLOC_NORMAL);
this.globals = _PyModule_GetDict(this.module);
this.isInitialized = true;
// Hijack traceback printer to give live indicator of whether an error has
// occurred. Useful for deciding whether to print stderr or buffer it.
var old_PyTraceBack_Print = _PyTraceBack_Print;
var that = this;
_PyTraceBack_Print = function() {
that.isHandlingError = true;
return old_PyTraceBack_Print.apply(null, arguments);
};
var help = ('def help(x):\n' +
' print getattr(x, "__doc__", "No documentation.")\n' +
' print ""\n' +
' print "For detailed help, run \'from pydoc import help\' (slow)."');
this['eval'](help);
},
// Evaluates Python code. Returns:
// 1. If an expression is passed, returns the representation of the value of
// this expression, or null if the value is None.
// 2. If a statement of set of statements is passed, returns null.
// 3. If a Python exception occurs while evaluating, returns undefined.
'eval': function(command) {
if (!this.isInitialized) throw new Error('Python runtime not initialized.');
this.isHandlingError = false;
var commandPtr = this.allocateString(command);
// Compile.
var compiled = _Py_CompileStringFlags(
commandPtr, this.filename, this.Py_eval_input, this.flags);
if (compiled === 0) {
_PyErr_Clear();
compiled = _Py_CompileStringFlags(
commandPtr, this.filename, this.Py_file_input, this.flags);
}
if (compiled === 0) {
_PyErr_Print();
_free(commandPtr);
return undefined;
}
// Evaluate.
var result = _PyEval_EvalCode(
compiled, this.globals, this.globals);
if (result === 0) {
_PyErr_Print();
_Py_DecRef(compiled);
_free(commandPtr);
return undefined;
}
// Get result representation.
var reprStr = Pointer_stringify(_PyString_AsString(_PyObject_Repr(result)));
if (reprStr === 'None') reprStr = null; // A little hacky, but will do.
// Cleanup.
_Py_DecRef(compiled);
_Py_DecRef(result);
_free(commandPtr);
// Return the final result.
return reprStr;
},
// Checks whether a command is finished and does not require more input.
// Useful when running a REPL.
'isFinished': function(command) {
if (!this.isInitialized) throw new Error('Python runtime not initialized.');
// Based on http://docs.python.org/faq/extending.html#how-do-i-tell-incomplete-input-from-invalid-input.
// WARNING: This is pretty broken at the moment.
var commandPtr = this.allocateString(command);
var compiled = _Py_CompileStringFlags(
commandPtr, this.filename, this.Py_eval_input, this.flags);
if (compiled === 0) {
_PyErr_Clear();
compiled = _Py_CompileStringFlags(
commandPtr, this.filename, this.Py_file_input, this.flags);
}
if (compiled !== 0) {
_free(commandPtr);
return true;
}
var exc = allocate([0], 'void*', ALLOC_NORMAL);
var val = allocate([0], 'void*', ALLOC_NORMAL);
var trb = allocate([0], 'void*', ALLOC_NORMAL);
var obj = allocate([0], 'void*', ALLOC_NORMAL);
var msg = allocate([0], 'i8*', ALLOC_NORMAL);
var idx = this.allocateString('sO');
_PyErr_Fetch(exc, val, trb);
var varargs = allocate([msg, 0, 0, 0, obj, 0, 0, 0],
['i8**', 0, 0, 0, 'void*', 0, 0, 0],
ALLOC_NORMAL);
_PyArg_ParseTuple(getValue(val, 'void*'), idx, varargs);
var msgStr = Pointer_stringify(getValue(msg, 'i8*'));
var ret = (msgStr != 'unexpected EOF while parsing' &&
msgStr != 'EOF while scanning triple-quoted string literal');
_Py_DecRef(exc);
_Py_DecRef(val);
_Py_DecRef(trb);
_free(varargs);
_free(commandPtr);
_free(idx);
_free(msg);
_free(obj);
_free(trb);
_free(val);
_free(exc);
return ret;
},
isHandlingError: false,
isInitialized: false,
flags: null,
filename: null,
module: null,
Py_single_input: 256,
Py_file_input: 257,
Py_eval_input: 258,
allocateString: function(str) {
return allocate(intArrayFromString(str), 'i8', ALLOC_NORMAL);
}
};