Compare commits
3 Commits
4de0659474
...
7469383e66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7469383e66 | ||
|
|
1fee8f9f8b | ||
|
|
d18ea1b330 |
@@ -382,13 +382,13 @@ static const JSCFunctionListEntry js_reader_funcs[] = {
|
|||||||
JSValue js_miniz_use(JSContext *js)
|
JSValue js_miniz_use(JSContext *js)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&js_reader_class_id);
|
JS_NewClassID(&js_reader_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(js), js_reader_class_id, &js_reader_class);
|
JS_NewClass(js, js_reader_class_id, &js_reader_class);
|
||||||
JSValue reader_proto = JS_NewObject(js);
|
JSValue reader_proto = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, reader_proto, js_reader_funcs, sizeof(js_reader_funcs) / sizeof(JSCFunctionListEntry));
|
JS_SetPropertyFunctionList(js, reader_proto, js_reader_funcs, sizeof(js_reader_funcs) / sizeof(JSCFunctionListEntry));
|
||||||
JS_SetClassProto(js, js_reader_class_id, reader_proto);
|
JS_SetClassProto(js, js_reader_class_id, reader_proto);
|
||||||
|
|
||||||
JS_NewClassID(&js_writer_class_id);
|
JS_NewClassID(&js_writer_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(js), js_writer_class_id, &js_writer_class);
|
JS_NewClass(js, js_writer_class_id, &js_writer_class);
|
||||||
JSValue writer_proto = JS_NewObject(js);
|
JSValue writer_proto = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, writer_proto, js_writer_funcs, sizeof(js_writer_funcs) / sizeof(JSCFunctionListEntry));
|
JS_SetPropertyFunctionList(js, writer_proto, js_writer_funcs, sizeof(js_writer_funcs) / sizeof(JSCFunctionListEntry));
|
||||||
JS_SetClassProto(js, js_writer_class_id, writer_proto);
|
JS_SetClassProto(js, js_writer_class_id, writer_proto);
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
(function engine() {
|
|
||||||
// Hidden vars (os, actorsym, init, core_path) come from env
|
// Hidden vars (os, actorsym, init, core_path) come from env
|
||||||
var ACTORDATA = actorsym
|
var ACTORDATA = actorsym
|
||||||
var SYSYM = '__SYSTEM__'
|
var SYSYM = '__SYSTEM__'
|
||||||
|
|
||||||
var _cell = {}
|
var _cell = {}
|
||||||
|
var need_stop = false
|
||||||
|
|
||||||
var dylib_ext
|
var dylib_ext
|
||||||
|
|
||||||
switch(os.platform()) {
|
var cases = {
|
||||||
case 'Windows': dylib_ext = '.dll'; break;
|
Windows: '.dll',
|
||||||
case 'macOS': dylib_ext = '.dylib'; break;
|
macOS: '.dylib',
|
||||||
case 'Linux': dylib_ext = '.so'; break;
|
Linux: '.so'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(os.platform())
|
||||||
|
|
||||||
|
dylib_ext = cases[os.platform()]
|
||||||
|
|
||||||
var MOD_EXT = '.cm'
|
var MOD_EXT = '.cm'
|
||||||
var ACTOR_EXT = '.ce'
|
var ACTOR_EXT = '.ce'
|
||||||
@@ -51,14 +55,16 @@ var fd = use_embed('fd')
|
|||||||
// Get the shop path from HOME environment
|
// Get the shop path from HOME environment
|
||||||
var home = os.getenv('HOME') || os.getenv('USERPROFILE')
|
var home = os.getenv('HOME') || os.getenv('USERPROFILE')
|
||||||
if (!home) {
|
if (!home) {
|
||||||
throw Error('Could not determine home directory')
|
os.print('Could not determine home directory\n')
|
||||||
|
os.exit(1)
|
||||||
}
|
}
|
||||||
var shop_path = home + '/.cell'
|
var shop_path = home + '/.cell'
|
||||||
var packages_path = shop_path + '/packages'
|
var packages_path = shop_path + '/packages'
|
||||||
var core_path = packages_path + '/core'
|
var core_path = packages_path + '/core'
|
||||||
|
|
||||||
if (!fd.is_dir(core_path)) {
|
if (!fd.is_dir(core_path)) {
|
||||||
throw Error('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.')
|
os.print('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.\n')
|
||||||
|
os.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var use_cache = {}
|
var use_cache = {}
|
||||||
@@ -79,7 +85,7 @@ function use_core(path) {
|
|||||||
var script_blob = fd.slurp(file_path)
|
var script_blob = fd.slurp(file_path)
|
||||||
var script = text(script_blob)
|
var script = text(script_blob)
|
||||||
var mod = `(function setup_module(use){${script}})`
|
var mod = `(function setup_module(use){${script}})`
|
||||||
var fn = js.eval('core:' + path, mod)
|
var fn = mach_eval('core:' + path, mod)
|
||||||
var result = call(fn,sym, [use_core])
|
var result = call(fn,sym, [use_core])
|
||||||
use_cache[cache_key] = result;
|
use_cache[cache_key] = result;
|
||||||
return result;
|
return result;
|
||||||
@@ -133,32 +139,27 @@ function log(name, args) {
|
|||||||
var caller = caller_data(1)
|
var caller = caller_data(1)
|
||||||
var msg = args[0]
|
var msg = args[0]
|
||||||
|
|
||||||
switch(name) {
|
if (name == 'console') {
|
||||||
case 'console':
|
os.print(console_rec(caller.line, caller.file, msg))
|
||||||
os.print(console_rec(caller.line, caller.file, msg))
|
} else if (name == 'error') {
|
||||||
break
|
if (msg == null) msg = Error()
|
||||||
case 'error':
|
if (is_proto(msg, Error))
|
||||||
msg = msg ?? Error()
|
msg = msg.name + ": " + msg.message + "\n" + msg.stack
|
||||||
if (is_proto(msg, Error))
|
os.print(console_rec(caller.line, caller.file, msg))
|
||||||
msg = msg.name + ": " + msg.message + "\n" + msg.stack
|
} else if (name == 'system') {
|
||||||
os.print(console_rec(caller.line, caller.file, msg))
|
msg = "[SYSTEM] " + msg
|
||||||
break
|
os.print(console_rec(caller.line, caller.file, msg))
|
||||||
case 'system':
|
} else {
|
||||||
msg = "[SYSTEM] " + msg
|
log.console(`unknown log type: ${name}`)
|
||||||
os.print(console_rec(caller.line, caller.file, msg))
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
log.console(`unknown log type: ${name}`)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disrupt(err)
|
function actor_die(err)
|
||||||
{
|
{
|
||||||
if (is_function(err.toString)) {
|
if (err && is_function(err.toString)) {
|
||||||
os.print(err.toString())
|
os.print(err.toString())
|
||||||
os.print("\n")
|
os.print("\n")
|
||||||
os.print(err.stack)
|
if (err.stack) os.print(err.stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overling) {
|
if (overling) {
|
||||||
@@ -185,14 +186,14 @@ function disrupt(err)
|
|||||||
log.console(err.stack)
|
log.console(err.stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
actor_mod.disrupt()
|
actor_mod["disrupt"]()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
actor_mod.on_exception(disrupt)
|
actor_mod.on_exception(actor_die)
|
||||||
|
|
||||||
_cell.args = init ?? {}
|
_cell.args = init != null ? init : {}
|
||||||
_cell.id = "newguy"
|
_cell.id = "newguy"
|
||||||
|
|
||||||
function create_actor(desc = {id:guid()}) {
|
function create_actor(desc = {id:guid()}) {
|
||||||
@@ -241,11 +242,15 @@ os.runtime_env = runtime_env
|
|||||||
|
|
||||||
$_.time_limit = function(requestor, seconds)
|
$_.time_limit = function(requestor, seconds)
|
||||||
{
|
{
|
||||||
if (!pronto.is_requestor(requestor))
|
if (!pronto.is_requestor(requestor)) {
|
||||||
throw Error('time_limit: first argument must be a requestor');
|
log.error('time_limit: first argument must be a requestor')
|
||||||
if (!is_number(seconds) || seconds <= 0)
|
disrupt
|
||||||
throw Error('time_limit: seconds must be a positive number');
|
}
|
||||||
|
if (!is_number(seconds) || seconds <= 0) {
|
||||||
|
log.error('time_limit: seconds must be a positive number')
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
return function time_limit_requestor(callback, value) {
|
return function time_limit_requestor(callback, value) {
|
||||||
pronto.check_callback(callback, 'time_limit')
|
pronto.check_callback(callback, 'time_limit')
|
||||||
var finished = false
|
var finished = false
|
||||||
@@ -260,7 +265,14 @@ $_.time_limit = function(requestor, seconds)
|
|||||||
timer_cancel = null
|
timer_cancel = null
|
||||||
}
|
}
|
||||||
if (requestor_cancel) {
|
if (requestor_cancel) {
|
||||||
try { pronto.requestor_cancel(reason) } catch (_) {}
|
requestor_cancel(reason)
|
||||||
|
requestor_cancel = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function safe_cancel_requestor(reason) {
|
||||||
|
if (requestor_cancel) {
|
||||||
|
requestor_cancel(reason)
|
||||||
requestor_cancel = null
|
requestor_cancel = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,15 +280,12 @@ $_.time_limit = function(requestor, seconds)
|
|||||||
timer_cancel = $_.delay(function() {
|
timer_cancel = $_.delay(function() {
|
||||||
if (finished) return
|
if (finished) return
|
||||||
def reason = make_reason(factory, 'Timeout.', seconds)
|
def reason = make_reason(factory, 'Timeout.', seconds)
|
||||||
if (requestor_cancel) {
|
safe_cancel_requestor(reason)
|
||||||
try { requestor_cancel(reason) } catch (_) {}
|
|
||||||
requestor_cancel = null
|
|
||||||
}
|
|
||||||
finished = true
|
finished = true
|
||||||
callback(null, reason)
|
callback(null, reason)
|
||||||
}, seconds)
|
}, seconds)
|
||||||
|
|
||||||
try {
|
function do_request() {
|
||||||
requestor_cancel = requestor(function(val, reason) {
|
requestor_cancel = requestor(function(val, reason) {
|
||||||
if (finished) return
|
if (finished) return
|
||||||
finished = true
|
finished = true
|
||||||
@@ -286,16 +295,14 @@ $_.time_limit = function(requestor, seconds)
|
|||||||
}
|
}
|
||||||
callback(val, reason)
|
callback(val, reason)
|
||||||
}, value)
|
}, value)
|
||||||
} catch (ex) {
|
} disruption {
|
||||||
cancel(ex)
|
cancel(Error('requestor failed'))
|
||||||
callback(null, ex)
|
callback(null, Error('requestor failed'))
|
||||||
}
|
}
|
||||||
|
do_request()
|
||||||
|
|
||||||
return function(reason) {
|
return function(reason) {
|
||||||
if (requestor_cancel) {
|
safe_cancel_requestor(reason)
|
||||||
try { requestor_cancel(reason) } catch (_) {}
|
|
||||||
requestor_cancel = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,52 +415,54 @@ var portal_fn = null
|
|||||||
|
|
||||||
// takes a function input value that will eventually be called with the current time in number form.
|
// takes a function input value that will eventually be called with the current time in number form.
|
||||||
$_.portal = function(fn, port) {
|
$_.portal = function(fn, port) {
|
||||||
if (portal) throw Error(`Already started a portal listening on ${portal.port}`)
|
if (portal) {
|
||||||
if (!port) throw Error("Requires a valid port.")
|
log.error(`Already started a portal listening on ${portal.port}`)
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
if (!port) {
|
||||||
|
log.error("Requires a valid port.")
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
log.system(`starting a portal on port ${port}`)
|
log.system(`starting a portal on port ${port}`)
|
||||||
portal = enet.create_host({address: "any", port})
|
portal = enet.create_host({address: "any", port})
|
||||||
portal_fn = fn
|
portal_fn = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_host(e) {
|
function handle_host(e) {
|
||||||
switch (e.type) {
|
if (e.type == "connect") {
|
||||||
case "connect":
|
log.system(`connected a new peer: ${e.peer.address}:${e.peer.port}`)
|
||||||
log.system(`connected a new peer: ${e.peer.address}:${e.peer.port}`)
|
peers[`${e.peer.address}:${e.peer.port}`] = e.peer
|
||||||
peers[`${e.peer.address}:${e.peer.port}`] = e.peer
|
var queue = peer_queue.get(e.peer)
|
||||||
var queue = peer_queue.get(e.peer)
|
if (queue) {
|
||||||
if (queue) {
|
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
|
||||||
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
|
log.system(`sent ${msg} out of queue`)
|
||||||
log.system(`sent ${msg} out of queue`)
|
|
||||||
peer_queue.delete(e.peer)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case "disconnect":
|
|
||||||
peer_queue.delete(e.peer)
|
peer_queue.delete(e.peer)
|
||||||
arrfor(array(peers), function(id, index) {
|
}
|
||||||
if (peers[id] == e.peer) delete peers[id]
|
} else if (e.type == "disconnect") {
|
||||||
|
peer_queue.delete(e.peer)
|
||||||
|
arrfor(array(peers), function(id, index) {
|
||||||
|
if (peers[id] == e.peer) delete peers[id]
|
||||||
|
})
|
||||||
|
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
|
||||||
|
} else if (e.type == "receive") {
|
||||||
|
var data = nota.decode(e.data)
|
||||||
|
if (data.replycc && !data.replycc.address) {
|
||||||
|
data.replycc[ACTORDATA].address = e.peer.address
|
||||||
|
data.replycc[ACTORDATA].port = e.peer.port
|
||||||
|
}
|
||||||
|
function populate_actor_addresses(obj) {
|
||||||
|
if (!is_object(obj)) return
|
||||||
|
if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
|
||||||
|
obj[ACTORDATA].address = e.peer.address
|
||||||
|
obj[ACTORDATA].port = e.peer.port
|
||||||
|
}
|
||||||
|
arrfor(array(obj), function(key, index) {
|
||||||
|
if (key in obj)
|
||||||
|
populate_actor_addresses(obj[key])
|
||||||
})
|
})
|
||||||
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
|
}
|
||||||
break
|
if (data.data) populate_actor_addresses(data.data)
|
||||||
case "receive":
|
turn(data)
|
||||||
var data = nota.decode(e.data)
|
|
||||||
if (data.replycc && !data.replycc.address) {
|
|
||||||
data.replycc[ACTORDATA].address = e.peer.address
|
|
||||||
data.replycc[ACTORDATA].port = e.peer.port
|
|
||||||
}
|
|
||||||
function populate_actor_addresses(obj) {
|
|
||||||
if (!is_object(obj)) return
|
|
||||||
if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
|
|
||||||
obj[ACTORDATA].address = e.peer.address
|
|
||||||
obj[ACTORDATA].port = e.peer.port
|
|
||||||
}
|
|
||||||
arrfor(array(obj), function(key, index) {
|
|
||||||
if (key in obj)
|
|
||||||
populate_actor_addresses(obj[key])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (data.data) populate_actor_addresses(data.data)
|
|
||||||
turn(data)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,10 +496,14 @@ $_.stop = function stop(actor) {
|
|||||||
need_stop = true
|
need_stop = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!is_actor(actor))
|
if (!is_actor(actor)) {
|
||||||
throw Error('Can only call stop on an actor.')
|
log.error('Can only call stop on an actor.')
|
||||||
if (is_null(underlings[actor[ACTORDATA].id]))
|
disrupt
|
||||||
throw Error('Can only call stop on an underling or self.')
|
}
|
||||||
|
if (is_null(underlings[actor[ACTORDATA].id])) {
|
||||||
|
log.error('Can only call stop on an underling or self.')
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
sys_msg(actor, {kind:"stop"})
|
sys_msg(actor, {kind:"stop"})
|
||||||
}
|
}
|
||||||
@@ -527,20 +540,22 @@ function actor_prep(actor, send) {
|
|||||||
|
|
||||||
// Send a message immediately without queuing
|
// Send a message immediately without queuing
|
||||||
function actor_send_immediate(actor, send) {
|
function actor_send_immediate(actor, send) {
|
||||||
try {
|
actor_send(actor, send)
|
||||||
actor_send(actor, send);
|
|
||||||
} catch (err) {
|
|
||||||
log.error("Failed to send immediate message:", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function actor_send(actor, message) {
|
function actor_send(actor, message) {
|
||||||
if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
|
if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
|
||||||
return
|
return
|
||||||
|
|
||||||
if (!is_actor(actor) && !is_actor(actor.replycc)) throw Error(`Must send to an actor object. Attempted send to ${actor}`)
|
if (!is_actor(actor) && !is_actor(actor.replycc)) {
|
||||||
|
log.error(`Must send to an actor object. Attempted send to ${actor}`)
|
||||||
if (!is_object(message)) throw Error('Must send an object record.')
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_object(message)) {
|
||||||
|
log.error('Must send an object record.')
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
// message to self
|
// message to self
|
||||||
if (actor[ACTORDATA].id == _cell.id) {
|
if (actor[ACTORDATA].id == _cell.id) {
|
||||||
@@ -583,12 +598,10 @@ function actor_send(actor, message) {
|
|||||||
// Holds all messages queued during the current turn.
|
// Holds all messages queued during the current turn.
|
||||||
var message_queue = []
|
var message_queue = []
|
||||||
|
|
||||||
var need_stop = false
|
function send_messages() {
|
||||||
|
|
||||||
function send_messages() {
|
|
||||||
// if we've been flagged to stop, bail out before doing anything
|
// if we've been flagged to stop, bail out before doing anything
|
||||||
if (need_stop) {
|
if (need_stop) {
|
||||||
disrupt()
|
actor_die()
|
||||||
message_queue = []
|
message_queue = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -608,19 +621,26 @@ var need_stop = false
|
|||||||
var replies = {}
|
var replies = {}
|
||||||
|
|
||||||
function send(actor, message, reply) {
|
function send(actor, message, reply) {
|
||||||
if (!is_object(actor))
|
if (!is_object(actor)) {
|
||||||
throw Error(`Must send to an actor object. Provided: ${actor}`);
|
log.error(`Must send to an actor object. Provided: ${actor}`)
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_object(message))
|
if (!is_object(message)) {
|
||||||
throw Error('Message must be an object')
|
log.error('Message must be an object')
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
var send_msg = {type:"user", data: message}
|
var send_msg = {type:"user", data: message}
|
||||||
|
var target = actor
|
||||||
|
|
||||||
if (actor[HEADER] && actor[HEADER].replycc) {
|
if (actor[HEADER] && actor[HEADER].replycc) {
|
||||||
var header = actor[HEADER]
|
var header = actor[HEADER]
|
||||||
if (!header.replycc || !is_actor(header.replycc))
|
if (!header.replycc || !is_actor(header.replycc)) {
|
||||||
throw Error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`)
|
log.error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`)
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
|
||||||
actor = header.replycc
|
target = header.replycc
|
||||||
send_msg.return = header.reply
|
send_msg.return = header.reply
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,7 +658,7 @@ function send(actor, message, reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instead of sending immediately, queue it
|
// Instead of sending immediately, queue it
|
||||||
actor_prep(actor, send_msg);
|
actor_prep(target, send_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
stone(send)
|
stone(send)
|
||||||
@@ -669,7 +689,7 @@ overling = _cell.args.overling
|
|||||||
$_.overling = overling
|
$_.overling = overling
|
||||||
|
|
||||||
root = _cell.args.root
|
root = _cell.args.root
|
||||||
root ??= $_.self
|
if (root == null) root = $_.self
|
||||||
|
|
||||||
if (overling) {
|
if (overling) {
|
||||||
$_.couple(overling) // auto couple to overling
|
$_.couple(overling) // auto couple to overling
|
||||||
@@ -705,36 +725,35 @@ function handle_actor_disconnect(id) {
|
|||||||
delete greeters[id]
|
delete greeters[id]
|
||||||
}
|
}
|
||||||
log.system(`actor ${id} disconnected`)
|
log.system(`actor ${id} disconnected`)
|
||||||
if (!is_null(couplings[id])) disrupt("coupled actor died") // couplings now disrupts instead of stop
|
if (!is_null(couplings[id])) actor_die("coupled actor died") // couplings now disrupts instead of stop
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_sysym(msg)
|
function handle_sysym(msg)
|
||||||
{
|
{
|
||||||
var from
|
var from
|
||||||
switch(msg.kind) {
|
if (msg.kind == 'stop') {
|
||||||
case 'stop':
|
actor_die("got stop message")
|
||||||
disrupt("got stop message")
|
} else if (msg.kind == 'underling') {
|
||||||
break
|
from = msg.from
|
||||||
case 'underling':
|
var greeter = greeters[from[ACTORDATA].id]
|
||||||
from = msg.from
|
if (greeter) greeter(msg.message)
|
||||||
var greeter = greeters[from[ACTORDATA].id]
|
if (msg.message.type == 'disrupt')
|
||||||
if (greeter) greeter(msg.message)
|
delete underlings[from[ACTORDATA].id]
|
||||||
if (msg.message.type == 'disrupt')
|
} else if (msg.kind == 'contact') {
|
||||||
delete underlings[from[ACTORDATA].id]
|
if (portal_fn) {
|
||||||
break
|
var letter2 = msg.data
|
||||||
case 'contact':
|
letter2[HEADER] = msg
|
||||||
if (portal_fn) {
|
delete msg.data
|
||||||
var letter2 = msg.data
|
portal_fn(letter2)
|
||||||
letter2[HEADER] = msg
|
} else {
|
||||||
delete msg.data
|
log.error('Got a contact message, but no portal is established.')
|
||||||
portal_fn(letter2)
|
disrupt
|
||||||
} else throw Error('Got a contact message, but no portal is established.')
|
}
|
||||||
break
|
} else if (msg.kind == 'couple') {
|
||||||
case 'couple': // from must be notified when we die
|
// from must be notified when we die
|
||||||
from = msg.from
|
from = msg.from
|
||||||
underlings[from[ACTORDATA].id] = true
|
underlings[from[ACTORDATA].id] = true
|
||||||
log.system(`actor ${from} is coupled to me`)
|
log.system(`actor ${from} is coupled to me`)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,30 +763,27 @@ function handle_message(msg) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (msg.type) {
|
if (msg.type == "user") {
|
||||||
case "user":
|
var letter = msg.data // what the sender really sent
|
||||||
var letter = msg.data // what the sender really sent
|
_ObjectDefineProperty(letter, HEADER, {
|
||||||
_ObjectDefineProperty(letter, HEADER, {
|
value: msg, enumerable: false
|
||||||
value: msg, enumerable: false
|
})
|
||||||
})
|
_ObjectDefineProperty(letter, ACTORDATA, { // this is so is_actor == true
|
||||||
_ObjectDefineProperty(letter, ACTORDATA, { // this is so is_actor == true
|
value: { reply: msg.reply }, enumerable: false
|
||||||
value: { reply: msg.reply }, enumerable: false
|
})
|
||||||
})
|
|
||||||
|
if (msg.return) {
|
||||||
if (msg.return) {
|
var fn = replies[msg.return]
|
||||||
var fn = replies[msg.return]
|
if (fn) fn(letter)
|
||||||
if (fn) fn(letter)
|
delete replies[msg.return]
|
||||||
delete replies[msg.return]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receive_fn) receive_fn(letter)
|
|
||||||
return
|
return
|
||||||
case "stopped":
|
}
|
||||||
handle_actor_disconnect(msg.id)
|
|
||||||
break
|
if (receive_fn) receive_fn(letter)
|
||||||
|
} else if (msg.type == "stopped") {
|
||||||
|
handle_actor_disconnect(msg.id)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function enet_check()
|
function enet_check()
|
||||||
{
|
{
|
||||||
@@ -792,8 +808,10 @@ if (!locator) {
|
|||||||
locator = shop.resolve_locator(_cell.args.program + ".ce", pkg)
|
locator = shop.resolve_locator(_cell.args.program + ".ce", pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!locator)
|
if (!locator) {
|
||||||
throw Error(`Main program ${_cell.args.program} could not be found`)
|
os.print(`Main program ${_cell.args.program} could not be found\n`)
|
||||||
|
os.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
$_.clock(_ => {
|
$_.clock(_ => {
|
||||||
// Get capabilities for the main program
|
// Get capabilities for the main program
|
||||||
@@ -818,7 +836,6 @@ $_.clock(_ => {
|
|||||||
var val = call(locator.symbol, null, [_cell.args.arg, use_fn, env])
|
var val = call(locator.symbol, null, [_cell.args.arg, use_fn, env])
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
throw Error('Program must not return anything');
|
log.error('Program must not return anything')
|
||||||
|
disrupt
|
||||||
})
|
})
|
||||||
|
|
||||||
})()
|
|
||||||
@@ -577,7 +577,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||||||
|
|
||||||
JSValue js_os_use(JSContext *js) {
|
JSValue js_os_use(JSContext *js) {
|
||||||
JS_NewClassID(&js_dylib_class_id);
|
JS_NewClassID(&js_dylib_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(js), js_dylib_class_id, &js_dylib_class);
|
JS_NewClass(js, js_dylib_class_id, &js_dylib_class);
|
||||||
|
|
||||||
JSValue mod = JS_NewObject(js);
|
JSValue mod = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs));
|
JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs));
|
||||||
|
|||||||
@@ -44,7 +44,12 @@ src += [ # core
|
|||||||
'wildmatch.c',
|
'wildmatch.c',
|
||||||
'qjs_actor.c',
|
'qjs_actor.c',
|
||||||
'miniz.c',
|
'miniz.c',
|
||||||
'quickjs.c',
|
'runtime.c',
|
||||||
|
'cell_js.c',
|
||||||
|
'tokenize.c',
|
||||||
|
'parse.c',
|
||||||
|
'mach.c',
|
||||||
|
'mcode.c',
|
||||||
'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c'
|
'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -571,13 +571,13 @@ static const JSCFunctionListEntry js_enet_peer_funcs[] = {
|
|||||||
JSValue js_enet_use(JSContext *ctx)
|
JSValue js_enet_use(JSContext *ctx)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&enet_host_id);
|
JS_NewClassID(&enet_host_id);
|
||||||
JS_NewClass(JS_GetRuntime(ctx), enet_host_id, &enet_host);
|
JS_NewClass(ctx, enet_host_id, &enet_host);
|
||||||
JSValue host_proto = JS_NewObject(ctx);
|
JSValue host_proto = JS_NewObject(ctx);
|
||||||
JS_SetPropertyFunctionList(ctx, host_proto, js_enet_host_funcs, countof(js_enet_host_funcs));
|
JS_SetPropertyFunctionList(ctx, host_proto, js_enet_host_funcs, countof(js_enet_host_funcs));
|
||||||
JS_SetClassProto(ctx, enet_host_id, host_proto);
|
JS_SetClassProto(ctx, enet_host_id, host_proto);
|
||||||
|
|
||||||
JS_NewClassID(&enet_peer_class_id);
|
JS_NewClassID(&enet_peer_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(ctx), enet_peer_class_id, &enet_peer_class);
|
JS_NewClass(ctx, enet_peer_class_id, &enet_peer_class);
|
||||||
JSValue peer_proto = JS_NewObject(ctx);
|
JSValue peer_proto = JS_NewObject(ctx);
|
||||||
JS_SetPropertyFunctionList(ctx, peer_proto, js_enet_peer_funcs, countof(js_enet_peer_funcs));
|
JS_SetPropertyFunctionList(ctx, peer_proto, js_enet_peer_funcs, countof(js_enet_peer_funcs));
|
||||||
JS_SetClassProto(ctx, enet_peer_class_id, peer_proto);
|
JS_SetClassProto(ctx, enet_peer_class_id, peer_proto);
|
||||||
|
|||||||
4
qop.c
4
qop.c
@@ -458,13 +458,13 @@ static const JSCFunctionListEntry js_qop_funcs[] = {
|
|||||||
|
|
||||||
JSValue js_qop_use(JSContext *js) {
|
JSValue js_qop_use(JSContext *js) {
|
||||||
JS_NewClassID(&js_qop_archive_class_id);
|
JS_NewClassID(&js_qop_archive_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(js), js_qop_archive_class_id, &js_qop_archive_class);
|
JS_NewClass(js, js_qop_archive_class_id, &js_qop_archive_class);
|
||||||
JSValue archive_proto = JS_NewObject(js);
|
JSValue archive_proto = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, archive_proto, js_qop_archive_funcs, countof(js_qop_archive_funcs));
|
JS_SetPropertyFunctionList(js, archive_proto, js_qop_archive_funcs, countof(js_qop_archive_funcs));
|
||||||
JS_SetClassProto(js, js_qop_archive_class_id, archive_proto);
|
JS_SetClassProto(js, js_qop_archive_class_id, archive_proto);
|
||||||
|
|
||||||
JS_NewClassID(&js_qop_writer_class_id);
|
JS_NewClassID(&js_qop_writer_class_id);
|
||||||
JS_NewClass(JS_GetRuntime(js), js_qop_writer_class_id, &js_qop_writer_class);
|
JS_NewClass(js, js_qop_writer_class_id, &js_qop_writer_class);
|
||||||
JSValue writer_proto = JS_NewObject(js);
|
JSValue writer_proto = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, writer_proto, js_qop_writer_funcs, countof(js_qop_writer_funcs));
|
JS_SetPropertyFunctionList(js, writer_proto, js_qop_writer_funcs, countof(js_qop_writer_funcs));
|
||||||
JS_SetClassProto(js, js_qop_writer_class_id, writer_proto);
|
JS_SetClassProto(js, js_qop_writer_class_id, writer_proto);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ static int run_test_suite(size_t heap_size);
|
|||||||
|
|
||||||
cell_rt *root_cell = NULL;
|
cell_rt *root_cell = NULL;
|
||||||
static char *core_path = NULL;
|
static char *core_path = NULL;
|
||||||
|
static JSRuntime *g_runtime = NULL;
|
||||||
|
|
||||||
// Get the home directory
|
// Get the home directory
|
||||||
static const char* get_home_dir(void) {
|
static const char* get_home_dir(void) {
|
||||||
@@ -165,17 +166,31 @@ JSValue js_wota_use(JSContext *js);
|
|||||||
|
|
||||||
void script_startup(cell_rt *prt)
|
void script_startup(cell_rt *prt)
|
||||||
{
|
{
|
||||||
JSRuntime *rt = JS_NewRuntime();
|
if (!g_runtime) {
|
||||||
JS_SetInterruptHandler(rt, (JSInterruptHandler *)actor_interrupt_cb, prt);
|
g_runtime = JS_NewRuntime();
|
||||||
JSContext *js = JS_NewContext(rt);
|
}
|
||||||
|
JSContext *js = JS_NewContext(g_runtime);
|
||||||
|
JS_SetInterruptHandler(js, (JSInterruptHandler *)actor_interrupt_cb, prt);
|
||||||
|
|
||||||
JS_SetContextOpaque(js, prt);
|
JS_SetContextOpaque(js, prt);
|
||||||
prt->context = js;
|
prt->context = js;
|
||||||
|
|
||||||
|
/* Register all GCRef fields so the Cheney GC can relocate them. */
|
||||||
|
JS_AddGCRef(js, &prt->idx_buffer_ref);
|
||||||
|
JS_AddGCRef(js, &prt->on_exception_ref);
|
||||||
|
JS_AddGCRef(js, &prt->message_handle_ref);
|
||||||
|
JS_AddGCRef(js, &prt->unneeded_ref);
|
||||||
|
JS_AddGCRef(js, &prt->actor_sym_ref);
|
||||||
|
prt->idx_buffer_ref.val = JS_NULL;
|
||||||
|
prt->on_exception_ref.val = JS_NULL;
|
||||||
|
prt->message_handle_ref.val = JS_NULL;
|
||||||
|
prt->unneeded_ref.val = JS_NULL;
|
||||||
|
prt->actor_sym_ref.val = JS_NULL;
|
||||||
|
|
||||||
cell_rt *crt = JS_GetContextOpaque(js);
|
cell_rt *crt = JS_GetContextOpaque(js);
|
||||||
JS_FreeValue(js, js_blob_use(js));
|
JS_FreeValue(js, js_blob_use(js));
|
||||||
|
|
||||||
// Load and compile engine.cm
|
// Load and parse engine.cm to AST
|
||||||
size_t engine_size;
|
size_t engine_size;
|
||||||
char *data = load_core_file(ENGINE, &engine_size);
|
char *data = load_core_file(ENGINE, &engine_size);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -183,10 +198,15 @@ void script_startup(cell_rt *prt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue bytecode = JS_Compile(js, data, engine_size, ENGINE);
|
cJSON *ast = JS_ASTTree(data, engine_size, ENGINE);
|
||||||
free(data);
|
free(data);
|
||||||
if (JS_IsException(bytecode)) {
|
if (!ast) {
|
||||||
uncaught_exception(js, bytecode);
|
printf("ERROR: Failed to parse %s\n", ENGINE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_tree_errors(ast)) {
|
||||||
|
cJSON_Delete(ast);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +217,8 @@ void script_startup(cell_rt *prt)
|
|||||||
JS_SetPropertyStr(js, hidden_env, "nota", js_nota_use(js));
|
JS_SetPropertyStr(js, hidden_env, "nota", js_nota_use(js));
|
||||||
JS_SetPropertyStr(js, hidden_env, "wota", js_wota_use(js));
|
JS_SetPropertyStr(js, hidden_env, "wota", js_wota_use(js));
|
||||||
|
|
||||||
crt->actor_sym = JS_NewObject(js);
|
crt->actor_sym_ref.val = JS_NewObject(js);
|
||||||
JS_SetPropertyStr(js, hidden_env, "actorsym", JS_DupValue(js, crt->actor_sym));
|
JS_SetPropertyStr(js, hidden_env, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val));
|
||||||
|
|
||||||
// Always set init (even if null)
|
// Always set init (even if null)
|
||||||
if (crt->init_wota) {
|
if (crt->init_wota) {
|
||||||
@@ -216,9 +236,10 @@ void script_startup(cell_rt *prt)
|
|||||||
// Stone the environment
|
// Stone the environment
|
||||||
hidden_env = JS_Stone(js, hidden_env);
|
hidden_env = JS_Stone(js, hidden_env);
|
||||||
|
|
||||||
// Integrate and run
|
// Run through MACH VM
|
||||||
crt->state = ACTOR_RUNNING;
|
crt->state = ACTOR_RUNNING;
|
||||||
JSValue v = JS_Integrate(js, bytecode, hidden_env);
|
JSValue v = JS_RunMachTree(js, ast, hidden_env);
|
||||||
|
cJSON_Delete(ast);
|
||||||
uncaught_exception(js, v);
|
uncaught_exception(js, v);
|
||||||
crt->state = ACTOR_IDLE;
|
crt->state = ACTOR_IDLE;
|
||||||
set_actor_state(crt);
|
set_actor_state(crt);
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYP
|
|||||||
|
|
||||||
#define QJSCLASSPREP_NO_FUNCS(TYPE) \
|
#define QJSCLASSPREP_NO_FUNCS(TYPE) \
|
||||||
JS_NewClassID(&js_##TYPE##_id);\
|
JS_NewClassID(&js_##TYPE##_id);\
|
||||||
JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
|
JS_NewClass(js, js_##TYPE##_id, &js_##TYPE##_class);\
|
||||||
JSValue TYPE##_proto = JS_NewObject(js); \
|
JSValue TYPE##_proto = JS_NewObject(js); \
|
||||||
JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
|
JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
|
||||||
|
|
||||||
|
|||||||
@@ -24,21 +24,26 @@ typedef struct letter {
|
|||||||
|
|
||||||
typedef struct cell_rt {
|
typedef struct cell_rt {
|
||||||
JSContext *context;
|
JSContext *context;
|
||||||
JSValue idx_buffer;
|
|
||||||
JSValue on_exception;
|
/* JSValues on the GC heap — each paired with a JSGCRef so the
|
||||||
JSValue message_handle;
|
Cheney GC can relocate them during compaction. */
|
||||||
|
JSGCRef idx_buffer_ref;
|
||||||
|
JSGCRef on_exception_ref;
|
||||||
|
JSGCRef message_handle_ref;
|
||||||
|
JSGCRef unneeded_ref;
|
||||||
|
JSGCRef actor_sym_ref;
|
||||||
|
|
||||||
void *init_wota;
|
void *init_wota;
|
||||||
|
|
||||||
/* Protects JSContext usage */
|
/* Protects JSContext usage */
|
||||||
pthread_mutex_t *mutex; /* for everything else */
|
pthread_mutex_t *mutex; /* for everything else */
|
||||||
pthread_mutex_t *msg_mutex; /* For message queue and timers queue */
|
pthread_mutex_t *msg_mutex; /* For message queue and timers queue */
|
||||||
|
|
||||||
char *id;
|
char *id;
|
||||||
|
|
||||||
int idx_count;
|
int idx_count;
|
||||||
|
|
||||||
/* The “mailbox” for incoming messages + a dedicated lock for it: */
|
/* The "mailbox" for incoming messages + a dedicated lock for it: */
|
||||||
letter *letters;
|
letter *letters;
|
||||||
|
|
||||||
/* CHANGED FOR EVENTS: a separate lock for the actor->events queue */
|
/* CHANGED FOR EVENTS: a separate lock for the actor->events queue */
|
||||||
@@ -47,14 +52,11 @@ typedef struct cell_rt {
|
|||||||
int state;
|
int state;
|
||||||
uint32_t ar; // timer for unneeded
|
uint32_t ar; // timer for unneeded
|
||||||
double ar_secs; // time for unneeded
|
double ar_secs; // time for unneeded
|
||||||
JSValue unneeded; // fn to call before unneeded
|
|
||||||
|
|
||||||
int disrupt;
|
int disrupt;
|
||||||
int main_thread_only;
|
int main_thread_only;
|
||||||
int affinity;
|
int affinity;
|
||||||
|
|
||||||
JSValue actor_sym;
|
|
||||||
|
|
||||||
const char *name; // human friendly name
|
const char *name; // human friendly name
|
||||||
cell_hook trace_hook;
|
cell_hook trace_hook;
|
||||||
} cell_rt;
|
} cell_rt;
|
||||||
@@ -63,8 +65,6 @@ cell_rt *create_actor(void *wota);
|
|||||||
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
|
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
|
||||||
void actor_disrupt(cell_rt *actor);
|
void actor_disrupt(cell_rt *actor);
|
||||||
|
|
||||||
JSValue actor_sym(cell_rt *actor);
|
|
||||||
|
|
||||||
const char *send_message(const char *id, void *msg);
|
const char *send_message(const char *id, void *msg);
|
||||||
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
|
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
|
||||||
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds);
|
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds);
|
||||||
|
|||||||
12740
source/cell_js.c
Normal file
12740
source/cell_js.c
Normal file
File diff suppressed because it is too large
Load Diff
3316
source/mach.c
Normal file
3316
source/mach.c
Normal file
File diff suppressed because it is too large
Load Diff
3461
source/mcode.c
Normal file
3461
source/mcode.c
Normal file
File diff suppressed because it is too large
Load Diff
2087
source/parse.c
Normal file
2087
source/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,7 @@ JSC_CCALL(os_register_actor,
|
|||||||
JS_ToFloat64(js, &ar, argv[3]);
|
JS_ToFloat64(js, &ar, argv[3]);
|
||||||
const char *err = register_actor(id, rt, JS_ToBool(js, argv[2]), ar);
|
const char *err = register_actor(id, rt, JS_ToBool(js, argv[2]), ar);
|
||||||
if (err) return JS_ThrowInternalError(js, "Could not register actor: %s", err);
|
if (err) return JS_ThrowInternalError(js, "Could not register actor: %s", err);
|
||||||
rt->message_handle = JS_DupValue(js, argv[1]);
|
rt->message_handle_ref.val = argv[1];
|
||||||
rt->context = js;
|
rt->context = js;
|
||||||
JS_FreeCString(js, id);
|
JS_FreeCString(js, id);
|
||||||
)
|
)
|
||||||
@@ -106,8 +106,7 @@ JSC_SCALL(actor_setname,
|
|||||||
|
|
||||||
JSC_CCALL(actor_on_exception,
|
JSC_CCALL(actor_on_exception,
|
||||||
cell_rt *rt = JS_GetContextOpaque(js);
|
cell_rt *rt = JS_GetContextOpaque(js);
|
||||||
JS_FreeValue(js, rt->on_exception);
|
rt->on_exception_ref.val = argv[0];
|
||||||
rt->on_exception = JS_DupValue(js,argv[0]);
|
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(actor_clock,
|
JSC_CCALL(actor_clock,
|
||||||
|
|||||||
2007
source/quickjs-internal.h
Normal file
2007
source/quickjs-internal.h
Normal file
File diff suppressed because it is too large
Load Diff
38471
source/quickjs.c
38471
source/quickjs.c
File diff suppressed because it is too large
Load Diff
@@ -367,10 +367,10 @@ JSRuntime *JS_NewRuntime (void);
|
|||||||
void JS_SetRuntimeInfo (JSRuntime *rt, const char *info);
|
void JS_SetRuntimeInfo (JSRuntime *rt, const char *info);
|
||||||
void JS_SetMemoryLimit (JSRuntime *rt, size_t limit);
|
void JS_SetMemoryLimit (JSRuntime *rt, size_t limit);
|
||||||
/* use 0 to disable maximum stack size check */
|
/* use 0 to disable maximum stack size check */
|
||||||
void JS_SetMaxStackSize (JSRuntime *rt, size_t stack_size);
|
void JS_SetMaxStackSize (JSContext *ctx, size_t stack_size);
|
||||||
/* should be called when changing thread to update the stack top value
|
/* should be called when changing thread to update the stack top value
|
||||||
used to check stack overflow. */
|
used to check stack overflow. */
|
||||||
void JS_UpdateStackTop (JSRuntime *rt);
|
void JS_UpdateStackTop (JSContext *ctx);
|
||||||
void JS_FreeRuntime (JSRuntime *rt);
|
void JS_FreeRuntime (JSRuntime *rt);
|
||||||
void *JS_GetRuntimeOpaque (JSRuntime *rt);
|
void *JS_GetRuntimeOpaque (JSRuntime *rt);
|
||||||
void JS_SetRuntimeOpaque (JSRuntime *rt, void *opaque);
|
void JS_SetRuntimeOpaque (JSRuntime *rt, void *opaque);
|
||||||
@@ -429,9 +429,9 @@ JSClassID JS_NewClassID (JSClassID *pclass_id);
|
|||||||
/* Returns the class ID if `v` is an object, otherwise returns
|
/* Returns the class ID if `v` is an object, otherwise returns
|
||||||
* JS_INVALID_CLASS_ID. */
|
* JS_INVALID_CLASS_ID. */
|
||||||
JSClassID JS_GetClassID (JSValue v);
|
JSClassID JS_GetClassID (JSValue v);
|
||||||
int JS_NewClass (JSRuntime *rt, JSClassID class_id,
|
int JS_NewClass (JSContext *ctx, JSClassID class_id,
|
||||||
const JSClassDef *class_def);
|
const JSClassDef *class_def);
|
||||||
int JS_IsRegisteredClass (JSRuntime *rt, JSClassID class_id);
|
int JS_IsRegisteredClass (JSContext *ctx, JSClassID class_id);
|
||||||
|
|
||||||
extern JSClassID js_class_id_alloc;
|
extern JSClassID js_class_id_alloc;
|
||||||
|
|
||||||
@@ -740,7 +740,7 @@ JSValue JS_JSONStringify (JSContext *ctx, JSValue obj,
|
|||||||
|
|
||||||
/* return != 0 if the JS code needs to be interrupted */
|
/* return != 0 if the JS code needs to be interrupted */
|
||||||
typedef int JSInterruptHandler (JSRuntime *rt, void *opaque);
|
typedef int JSInterruptHandler (JSRuntime *rt, void *opaque);
|
||||||
void JS_SetInterruptHandler (JSRuntime *rt, JSInterruptHandler *cb,
|
void JS_SetInterruptHandler (JSContext *ctx, JSInterruptHandler *cb,
|
||||||
void *opaque);
|
void *opaque);
|
||||||
/* select which debug info is stripped from the compiled code */
|
/* select which debug info is stripped from the compiled code */
|
||||||
#define JS_STRIP_SOURCE (1 << 0) /* strip source code */
|
#define JS_STRIP_SOURCE (1 << 0) /* strip source code */
|
||||||
|
|||||||
13756
source/runtime.c
Normal file
13756
source/runtime.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -266,11 +266,11 @@ void actor_free(cell_rt *actor)
|
|||||||
|
|
||||||
JSContext *js = actor->context;
|
JSContext *js = actor->context;
|
||||||
|
|
||||||
JS_FreeValue(js, actor->idx_buffer);
|
JS_DeleteGCRef(js, &actor->idx_buffer_ref);
|
||||||
JS_FreeValue(js, actor->message_handle);
|
JS_DeleteGCRef(js, &actor->on_exception_ref);
|
||||||
JS_FreeValue(js, actor->on_exception);
|
JS_DeleteGCRef(js, &actor->message_handle_ref);
|
||||||
JS_FreeValue(js, actor->unneeded);
|
JS_DeleteGCRef(js, &actor->unneeded_ref);
|
||||||
JS_FreeValue(js, actor->actor_sym);
|
JS_DeleteGCRef(js, &actor->actor_sym_ref);
|
||||||
|
|
||||||
for (int i = 0; i < hmlen(actor->timers); i++) {
|
for (int i = 0; i < hmlen(actor->timers); i++) {
|
||||||
JS_FreeValue(js, actor->timers[i].value);
|
JS_FreeValue(js, actor->timers[i].value);
|
||||||
@@ -289,10 +289,8 @@ void actor_free(cell_rt *actor)
|
|||||||
|
|
||||||
arrfree(actor->letters);
|
arrfree(actor->letters);
|
||||||
|
|
||||||
JSRuntime *rt = JS_GetRuntime(js);
|
JS_SetInterruptHandler(js, NULL, NULL);
|
||||||
JS_SetInterruptHandler(rt, NULL, NULL);
|
|
||||||
JS_FreeContext(js);
|
JS_FreeContext(js);
|
||||||
JS_FreeRuntime(rt);
|
|
||||||
free(actor->id);
|
free(actor->id);
|
||||||
|
|
||||||
pthread_mutex_unlock(actor->mutex);
|
pthread_mutex_unlock(actor->mutex);
|
||||||
@@ -419,8 +417,8 @@ uint32_t actor_remove_cb(cell_rt *actor, uint32_t id, uint32_t interval)
|
|||||||
|
|
||||||
actor->disrupt = 1;
|
actor->disrupt = 1;
|
||||||
|
|
||||||
if (!JS_IsNull(actor->unneeded)) {
|
if (!JS_IsNull(actor->unneeded_ref.val)) {
|
||||||
JSValue ret = JS_Call(actor->context, actor->unneeded, JS_NULL, 0, NULL);
|
JSValue ret = JS_Call(actor->context, actor->unneeded_ref.val, JS_NULL, 0, NULL);
|
||||||
uncaught_exception(actor->context, ret);
|
uncaught_exception(actor->context, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,14 +432,13 @@ uint32_t actor_remove_cb(cell_rt *actor, uint32_t id, uint32_t interval)
|
|||||||
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds)
|
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds)
|
||||||
{
|
{
|
||||||
if (actor->disrupt) return;
|
if (actor->disrupt) return;
|
||||||
JS_FreeValue(actor->context, actor->unneeded);
|
|
||||||
|
|
||||||
if (!JS_IsFunction(fn)) {
|
if (!JS_IsFunction(fn)) {
|
||||||
actor->unneeded = JS_NULL;
|
actor->unneeded_ref.val = JS_NULL;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
actor->unneeded = JS_DupValue(actor->context, fn);
|
actor->unneeded_ref.val = fn;
|
||||||
actor->ar_secs = seconds;
|
actor->ar_secs = seconds;
|
||||||
|
|
||||||
END:
|
END:
|
||||||
@@ -493,11 +490,10 @@ cell_rt *create_actor(void *wota)
|
|||||||
actor->heap = mi_heap_new();
|
actor->heap = mi_heap_new();
|
||||||
#endif
|
#endif
|
||||||
actor->init_wota = wota;
|
actor->init_wota = wota;
|
||||||
actor->idx_buffer = JS_NULL;
|
/* GCRef fields are registered after JSContext creation in script_startup.
|
||||||
actor->message_handle = JS_NULL;
|
For now, zero-init from calloc is sufficient (val = 0 = JS_MKVAL(JS_TAG_INT,0),
|
||||||
actor->unneeded = JS_NULL;
|
which is not a pointer so GC-safe). The actual JS_NULL assignment and
|
||||||
actor->on_exception = JS_NULL;
|
JS_AddGCRef happen in script_startup. */
|
||||||
actor->actor_sym = JS_NULL;
|
|
||||||
|
|
||||||
arrsetcap(actor->letters, 5);
|
arrsetcap(actor->letters, 5);
|
||||||
|
|
||||||
@@ -587,7 +583,7 @@ void actor_turn(cell_rt *actor)
|
|||||||
size_t size = blob_length(l.blob_data) / 8; // Convert bits to bytes
|
size_t size = blob_length(l.blob_data) / 8; // Convert bits to bytes
|
||||||
JSValue arg = js_new_blob_stoned_copy(actor->context, (void*)blob_data(l.blob_data), size);
|
JSValue arg = js_new_blob_stoned_copy(actor->context, (void*)blob_data(l.blob_data), size);
|
||||||
blob_destroy(l.blob_data);
|
blob_destroy(l.blob_data);
|
||||||
result = JS_Call(actor->context, actor->message_handle, JS_NULL, 1, &arg);
|
result = JS_Call(actor->context, actor->message_handle_ref.val, JS_NULL, 1, &arg);
|
||||||
uncaught_exception(actor->context, result);
|
uncaught_exception(actor->context, result);
|
||||||
JS_FreeValue(actor->context, arg);
|
JS_FreeValue(actor->context, arg);
|
||||||
} else if (l.type == LETTER_CALLBACK) {
|
} else if (l.type == LETTER_CALLBACK) {
|
||||||
|
|||||||
@@ -118,11 +118,11 @@ void actor_free(cell_rt *actor)
|
|||||||
|
|
||||||
JSContext *js = actor->context;
|
JSContext *js = actor->context;
|
||||||
|
|
||||||
JS_FreeValue(js, actor->idx_buffer);
|
JS_DeleteGCRef(js, &actor->idx_buffer_ref);
|
||||||
JS_FreeValue(js, actor->message_handle);
|
JS_DeleteGCRef(js, &actor->on_exception_ref);
|
||||||
JS_FreeValue(js, actor->on_exception);
|
JS_DeleteGCRef(js, &actor->message_handle_ref);
|
||||||
JS_FreeValue(js, actor->unneeded);
|
JS_DeleteGCRef(js, &actor->unneeded_ref);
|
||||||
JS_FreeValue(js, actor->actor_sym);
|
JS_DeleteGCRef(js, &actor->actor_sym_ref);
|
||||||
|
|
||||||
/* Free timer callbacks stored in actor */
|
/* Free timer callbacks stored in actor */
|
||||||
for (int i = 0; i < hmlen(actor->timers); i++) {
|
for (int i = 0; i < hmlen(actor->timers); i++) {
|
||||||
@@ -142,10 +142,8 @@ void actor_free(cell_rt *actor)
|
|||||||
|
|
||||||
arrfree(actor->letters);
|
arrfree(actor->letters);
|
||||||
|
|
||||||
JSRuntime *rt = JS_GetRuntime(js);
|
JS_SetInterruptHandler(js, NULL, NULL);
|
||||||
JS_SetInterruptHandler(rt, NULL, NULL);
|
|
||||||
JS_FreeContext(js);
|
JS_FreeContext(js);
|
||||||
JS_FreeRuntime(rt);
|
|
||||||
free(actor->id);
|
free(actor->id);
|
||||||
|
|
||||||
free(actor);
|
free(actor);
|
||||||
@@ -157,14 +155,13 @@ void actor_free(cell_rt *actor)
|
|||||||
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds)
|
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds)
|
||||||
{
|
{
|
||||||
if (actor->disrupt) return;
|
if (actor->disrupt) return;
|
||||||
JS_FreeValue(actor->context, actor->unneeded);
|
|
||||||
|
if (!JS_IsFunction(fn)) {
|
||||||
if (!JS_IsFunction(actor->context, fn)) {
|
actor->unneeded_ref.val = JS_NULL;
|
||||||
actor->unneeded = JS_NULL;
|
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
actor->unneeded = JS_DupValue(actor->context, fn);
|
actor->unneeded_ref.val = fn;
|
||||||
actor->ar_secs = seconds;
|
actor->ar_secs = seconds;
|
||||||
|
|
||||||
END:
|
END:
|
||||||
@@ -257,8 +254,8 @@ uint32_t actor_remove_cb(cell_rt *actor, uint32_t id, uint32_t interval)
|
|||||||
|
|
||||||
actor->disrupt = 1;
|
actor->disrupt = 1;
|
||||||
|
|
||||||
if (!JS_IsNull(actor->unneeded)) {
|
if (!JS_IsNull(actor->unneeded_ref.val)) {
|
||||||
JSValue ret = JS_Call(actor->context, actor->unneeded, JS_NULL, 0, NULL);
|
JSValue ret = JS_Call(actor->context, actor->unneeded_ref.val, JS_NULL, 0, NULL);
|
||||||
uncaught_exception(actor->context, ret);
|
uncaught_exception(actor->context, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,11 +325,7 @@ cell_rt *create_actor(void *wota)
|
|||||||
{
|
{
|
||||||
cell_rt *actor = calloc(sizeof(*actor), 1);
|
cell_rt *actor = calloc(sizeof(*actor), 1);
|
||||||
actor->init_wota = wota;
|
actor->init_wota = wota;
|
||||||
actor->idx_buffer = JS_NULL;
|
/* GCRef fields are registered after JSContext creation in script_startup. */
|
||||||
actor->message_handle = JS_NULL;
|
|
||||||
actor->unneeded = JS_NULL;
|
|
||||||
actor->on_exception = JS_NULL;
|
|
||||||
actor->actor_sym = JS_NULL;
|
|
||||||
|
|
||||||
arrsetcap(actor->letters, 5);
|
arrsetcap(actor->letters, 5);
|
||||||
|
|
||||||
@@ -408,7 +401,7 @@ void actor_turn(cell_rt *actor)
|
|||||||
size_t size = blob_length(l.blob_data) / 8; // Convert bits to bytes
|
size_t size = blob_length(l.blob_data) / 8; // Convert bits to bytes
|
||||||
JSValue arg = js_new_blob_stoned_copy(actor->context, (void *)blob_data(l.blob_data), size);
|
JSValue arg = js_new_blob_stoned_copy(actor->context, (void *)blob_data(l.blob_data), size);
|
||||||
blob_destroy(l.blob_data);
|
blob_destroy(l.blob_data);
|
||||||
result = JS_Call(actor->context, actor->message_handle, JS_NULL, 1, &arg);
|
result = JS_Call(actor->context, actor->message_handle_ref.val, JS_NULL, 1, &arg);
|
||||||
uncaught_exception(actor->context, result);
|
uncaught_exception(actor->context, result);
|
||||||
JS_FreeValue(actor->context, arg);
|
JS_FreeValue(actor->context, arg);
|
||||||
} else if (l.type == LETTER_CALLBACK) {
|
} else if (l.type == LETTER_CALLBACK) {
|
||||||
|
|||||||
1432
source/tokenize.c
Normal file
1432
source/tokenize.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user