Skip to content

Commit 61a552b

Browse files
committed
New API promise.wait() now works without skipping event loop using emscripten_sleep, requires emterpreter
1 parent 99d2e34 commit 61a552b

8 files changed

+119364
-206
lines changed

index.js

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ let stdout_print = (stdout) => {
1010
if (stdout_text.indexOf('mpjsendline') > -1) {
1111
stdout_text = stdout_text.replace('mpjsendline', '');
1212
stdout_ready = true;
13-
console.log(stdout_text);
13+
//console.log(stdout_text);
1414
}
1515
}
1616
global.mpjsPrintStdout = stdout_print;
17+
global.formatString = (object) => object !== undefined ? JSON.stringify(object) : null
1718

1819
const mp = require('./lib/micropython.js');
1920
if (typeof window === 'undefined' && typeof importScripts === 'undefined') {
@@ -52,10 +53,7 @@ module.exports = (async () => {
5253
methods.init = global.mp_js_init;
5354
const do_str = global.mp_js_do_str;
5455
global._mp_js_do_str = do_str;
55-
methods.do_str = async (code, concurrent) => {
56-
code = code.replace(/async {/g, 'async_py(lambda **kwargs: """').replace(/} async/g, '""")');
57-
//code = code.replace(/async {/g, 'exec("""').replace(/} async/g, '""")');
58-
code = code.replace(/:async:/g, 'return """').replace(/return async/g, '"""');
56+
methods.do_str = async (code) => {
5957
const codes = code.split('\n');
6058
let spaces = '';
6159
for (let line of codes) {
@@ -68,47 +66,18 @@ module.exports = (async () => {
6866
}
6967
break;
7068
}
71-
if (spaces || concurrent) {
72-
if (concurrent && !spaces) spaces = ' ';
69+
if (spaces) {
7370
let index_split = 0;
7471
const new_code = [];
7572
for (let line of codes) {
7673
line = line.slice(spaces.length - 1);
7774
new_code.push(line);
7875
}
79-
if (concurrent) {
80-
const result = [];
81-
let code_cache = [];
82-
for (var each of new_code) {
83-
let await_code;
84-
if (each.indexOf('await ') > -1) each = each.replace('await', 'wait(') + ')';
85-
if (each.indexOf('wait(') > -1 && each.indexOf('def wait(promise') < 0) {
86-
if (code_cache.length > 0) {
87-
result.push(await global.mp_js_do_str(code_cache.join('\n'), false));
88-
code_cache = [];
89-
}
90-
91-
if (each.indexOf(' = wait(') > -1) {
92-
const [variable, wait] = each.split(' = ')
93-
const promise = wait.slice(5, -1);
94-
await_code = variable + ' = ' + promise + '._value';
95-
}
96-
}
97-
else {
98-
code_cache.push(each);
99-
continue;
100-
}
101-
result.push(await global.mp_js_do_str(each, false));
102-
if (await_code) await global.mp_js_do_str(await_code, false);
103-
}
104-
if (code_cache.length > 0) result.push(await global.mp_js_do_str(code_cache.join('\n'), false));
105-
return result.join('\n');
106-
}
10776
code = new_code.join('\n');
10877
}
10978
stdout_text = '';
11079
stdout_ready = false;
111-
code += "\nprint('mpjsendline')";
80+
code += "\ntry: py_print('mpjsendline')\nexcept: print('mpjsendline')";
11281
if (global.promiseWaitInterval) await wait_exist(() => !global.promiseWaitInterval);
11382
do_str(code);
11483
await wait_exist(() => stdout_ready);

js.py

Lines changed: 58 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,31 @@
11
import json
22
import js
3-
dircache = {}
4-
objcache = {}
5-
funcache = {}
6-
procache = {}
7-
8-
#Javascript's JSON Types for eliminating json.loads
9-
true = True
10-
false = False
11-
null = None
12-
undefined = None
133

144
def js_exec(code, *args):
155
code = format(code, *args)
16-
return js.exec('(async () => {\n' + code + '\n})();')
6+
result = js.exec('formatString((() => {\n' + code + '\n})());')
7+
return json.loads(result)
178

18-
def py_exec(code, *args):
19-
code = format(code, *args)
20-
return js.exec('(async () => {\nreturn await global.mp_js_do_str(`\n' + code + '\n`, true);\n})();')
21-
exec = py_exec
9+
def js_print(value):
10+
js.exec('console.log(%s)' % (json.dumps(str(value))))
11+
12+
py_print = print
13+
print = js_print
2214

2315
def format(string, *args):
2416
for index, arg in enumerate(args):
2517
string = string.replace('{%s}' % (index), str(arg))
2618
return string
2719

28-
#def print(value):
29-
# js.exec("""console.log(`%s`)""" % (str(value)))
30-
3120
def wait(promise):
32-
procache[promise._name] = promise
33-
js_exec("""
34-
global.promiseWaitInterval = setInterval(() => {
35-
const object = global.mpjscache['{0}'];
36-
//console.log(object)
37-
if (object && object.constructor !== Promise) {
38-
clearInterval(global.promiseWaitInterval);
39-
global.promiseWaitInterval = undefined;
40-
global.mp_js_do_str(`
41-
import js
42-
procache['{0}']._resolved = True
43-
procache['{0}']._value = JS('global.mpjscache["{0}"]')
44-
procache['{0}'] = procache['{0}']._value
45-
`);
46-
}
47-
}, 500);
48-
""", promise._name)
49-
exit
50-
51-
def resolve(cache, name, value):
52-
object = cache.get(name)
53-
if type(object) == JSPromise:
54-
cache[name] = object.resolve(value)
55-
else:
56-
cache[name] = value
57-
58-
async_id = 0
59-
60-
def async_py(function):
61-
def wrap(**kwargs):
62-
code_string = function(**kwargs)
63-
for key in kwargs:
64-
if key not in code_string: continue
65-
async_id += 1
66-
asycache[async_id] = kwargs[key]
67-
code_string = code_string.replace(key, 'asycache[%s]' % (async_id))
68-
exec(code_string)
69-
exit
70-
return wrap
21+
while not promise._resolved:
22+
js.sleep(250)
23+
result = js_exec('''
24+
const object = {0};
25+
if (object && object.constructor !== Promise) return true;
26+
''', promise._name)
27+
if result: promise.resolve(JS(promise._name))
28+
return promise._value
7129

7230
class JSPromise():
7331

@@ -81,6 +39,9 @@ def resolve(self, value):
8139
self._value = value
8240
return value
8341

42+
def wait(self):
43+
return wait(self)
44+
8445
class JSObject():
8546

8647
def __init__(self, name):
@@ -94,25 +55,17 @@ def __len__(self):
9455

9556
def __dir__(self):
9657
if not self._name: return []
97-
js_exec("""
98-
let keys = JSON.stringify(Object.keys({0}));
99-
global.mp_js_do_str(`
100-
import js
101-
dircache['{0}'] = ${keys}
102-
`);
103-
""", self._name)
104-
return dircache.get(self._name, [])
58+
return js_exec('''
59+
return Object.keys({0}));
60+
''', self._name)
10561

10662
def __getattr__(self, key):
10763
name = self._name + '.' + key if self._name else key
108-
js_exec("""
64+
result = js_exec('''
10965
let object = {0};
11066
if (object && object.constructor === Promise) {
111-
await global.mp_js_do_str(`
112-
import js
113-
objcache['{0}'] = JSPromise('{0}')
114-
`)
115-
object = await object;
67+
object.then((object) => global.mpjscache['{0}'] = object);
68+
return 'mpjspromiseobject:{0}';
11669
}
11770
try {
11871
if (object && [Array, Object, Number, String, Boolean, Function, AsyncFunction].indexOf(object.constructor) < 0) throw Error('Not JSON Serializable');
@@ -121,83 +74,69 @@ def __getattr__(self, key):
12174
}
12275
else if (object && (object.constructor === Function || object.constructor === AsyncFunction)) {
12376
delete global.mpjscache['{0}'];
124-
return global.mp_js_do_str(`
125-
import js
126-
resolve(objcache, '{0}', JSFunction('{0}'))
127-
`);
77+
return 'mpjsfunctionobject:{0}';
12878
}
129-
object = object !== undefined ? JSON.stringify(object) : 'null';
130-
return global.mp_js_do_str(`
131-
import js
132-
import json
133-
resolve(objcache, '{0}', ${object})
134-
`);
79+
return object;
13580
}
13681
catch(error) {
137-
return global.mp_js_do_str(`
138-
import js
139-
resolve(objcache, '{0}', JSObject('{0}'))
140-
`);
82+
return 'mpjsjavascriptobject:{0}';
14183
}
142-
""", name)
143-
return objcache.get(name)
84+
''', name)
85+
if type(result) != str: return result
86+
types = {'promise': JSPromise, 'function': JSFunction, 'javascript': JSObject}
87+
for object_type in types:
88+
if 'mpjs' + object_type + 'object' in result:
89+
result = types[object_type](result.split(':')[1])
90+
break
91+
return result
14492

14593
def __setattr__(self, key, value):
14694
if not self._name: return
14795
value = json.dumps(value)
14896
object_name = self._name + '.' + key
149-
js_exec("""
97+
js_exec('''
15098
{0} = {1};
151-
""".format(object_name, value))
99+
''', object_name, value)
152100

153101
def JSFunction(name):
154102
short_name = name.split('.')[-1]
155103
def function(*args):
156104
args = json.dumps(list(args))
157-
js_exec("""
105+
cache_name = 'global.mpjscache' + ('.' + name if '.' not in name else json.dumps([name]))
106+
result = js_exec('''
158107
let object;
159108
if (global.mpjscache['{0}']) {
160109
object = global.mpjscache['{0}'](...{1});
161110
}
162111
else if ({0}) {
163112
object = {0}(...{1});
164113
}
165-
//object = object(...{1});
166114
global.mpjscache['{0}'] = object;
167115
if (object && object.constructor === Promise) {
168-
await global.mp_js_do_str(`
169-
import js
170-
funcache['{0}'] = JSPromise('{0}')
171-
`)
172-
object = await object;
116+
object.then((object) => global.mpjscache['{0}'] = object);
117+
return 'mpjspromiseobject';
173118
}
174-
global.mpjscache['{0}'] = object;
175119
try {
176120
if (object && [Array, Object, Number, String, Boolean, Function, AsyncFunction].indexOf(object.constructor) < 0) throw Error('Not JSON Serializable');
177121
if (object && object.constructor === Object) for (let key in Object.keys(object)) {
178122
if (object.indexOf(key) < 0) throw Error('Not a JSON');
179123
}
180124
else if (object && (object.constructor === Function || object.constructor === AsyncFunction)) {
181-
return global.mp_js_do_str(`
182-
import js
183-
resolve(funcache, '{0}', JSFunction('{0}'))
184-
`);
125+
return 'mpjsfunctionobject';
185126
}
186-
object = object !== undefined ? JSON.stringify(object) : 'null';
187-
return global.mp_js_do_str(`
188-
import js
189-
import json
190-
resolve(funcache, '{0}', ${object})
191-
`);
127+
return object;
192128
}
193129
catch(error) {
194-
return global.mp_js_do_str(`
195-
import js
196-
resolve(funcache, '{0}', JSObject('global.mpjscache{2}'))
197-
`);
130+
return 'mpjsjavascriptobject';
198131
}
199-
""", name, args, '.' + name if '.' not in name else '["%s"]' % (name))
200-
return funcache.get(name)
132+
''', name, args)
133+
if type(result) != str: return result
134+
types = {'promise': JSPromise, 'function': JSFunction, 'javascript': JSObject}
135+
for object_type in types:
136+
if 'mpjs' + object_type + 'object' in result:
137+
result = types[object_type](cache_name)
138+
break
139+
return result
201140
return function
202141

203142
def JS(variable):
@@ -208,15 +147,10 @@ def JS(variable):
208147
#result = require('fs').readFileSync('./test.js').toString()
209148
#print(result)
210149

211-
#This code block is adaptable to Javascript's event loop
212-
async {
213-
214-
require = JS('require')
215-
response = require('node-fetch')('https://github.com/')
216-
response = await response
217-
print(response)
218-
result = response.text()
219-
result = await result
220-
print(result)
150+
#New API promise.wait(), now works without skipping event loop using emscripten_sleep, requires emterpreter
221151

222-
} async ()
152+
#require = JS('require')
153+
#response = require('node-fetch')('https://github.com/').wait()
154+
#print(response)
155+
#result = response.text().wait()
156+
#print(result)

0 commit comments

Comments
 (0)