remove global

This commit is contained in:
2025-12-18 18:43:23 -06:00
parent aa18a8c8d2
commit d50f4119ee
60 changed files with 378 additions and 282 deletions

4
add.ce
View File

@@ -7,7 +7,7 @@ if (args.length < 1) {
log.console("Examples:") log.console("Examples:")
log.console(" cell get gitea.pockle.world/john/prosperon@main") log.console(" cell get gitea.pockle.world/john/prosperon@main")
log.console(" cell get github.com/user/repo@v1.0.0 myalias") log.console(" cell get github.com/user/repo@v1.0.0 myalias")
$_.stop() $stop()
return return
} }
@@ -16,4 +16,4 @@ var alias = args.length > 1 ? args[1] : null
shop.get(locator, alias) shop.get(locator, alias)
$_.stop() $stop()

View File

@@ -40,4 +40,4 @@ function bottomUpTree(depth) {
mainThread() mainThread()
$_.stop() $stop()

View File

@@ -22,4 +22,4 @@ for (var i = 0; i < sieve.length; i++)
log.console(c) log.console(c)
$_.stop() $stop()

View File

@@ -55,4 +55,4 @@ var n = arg[0] || 10
log.console(`Pfannkuchen(${n}) = ${fannkuch(n)}`) log.console(`Pfannkuchen(${n}) = ${fannkuch(n)}`)
$_.stop() $stop()

View File

@@ -13,4 +13,4 @@ for (var i in arr) {
log.console(`elapsed: ${time.number()-now}`) log.console(`elapsed: ${time.number()-now}`)
$_.stop() $stop()

View File

@@ -393,4 +393,4 @@ log.console("");
log.console("---------------------------------------------------------"); log.console("---------------------------------------------------------");
log.console("Benchmark complete.\n"); log.console("Benchmark complete.\n");
$_.stop() $stop()

View File

@@ -37,4 +37,4 @@ for (let y = 0; y < h; ++y) {
log.console(text(row, 'b')); log.console(text(row, 'b'));
} }
$_.stop() $stop()

View File

@@ -2,11 +2,11 @@ var math = use('math/radians')
var N = 1000000; var N = 1000000;
var num = 0; var num = 0;
for (var i = 0; i < N; i ++) { for (var i = 0; i < N; i ++) {
var x = 2 * $_.random(); var x = 2 * $random();
var y = $_.random(); var y = $random();
if (y < math.sine(x * x)) if (y < math.sine(x * x))
num++; num++;
} }
log.console(2 * num / N); log.console(2 * num / N);
$_.stop() $stop()

View File

@@ -185,4 +185,4 @@ log.console(` stack_size: ${fn_info.stack_size}`)
log.console(js.disassemble(advance)) log.console(js.disassemble(advance))
log.console(js.disassemble(advance).length) log.console(js.disassemble(advance).length)
$_.stop() $stop()

View File

@@ -49,4 +49,4 @@ function spectralnorm(n) {
log.console(spectralnorm(arg[0]).toFixed(9)); log.console(spectralnorm(arg[0]).toFixed(9));
$_.stop() $stop()

View File

@@ -15,7 +15,7 @@
// Parse command line arguments // Parse command line arguments
if (arg.length != 2) { if (arg.length != 2) {
log.console('Usage: cell benchmark_wota_nota_json.ce <LibraryName> <ScenarioName>'); log.console('Usage: cell benchmark_wota_nota_json.ce <LibraryName> <ScenarioName>');
$_.stop() $stop()
} }
var lib_name = arg[0]; var lib_name = arg[0];
@@ -172,13 +172,13 @@ var bench = benchmarks.find(b => b.name == scenario_name);
if (!lib) { if (!lib) {
log.console('Unknown library:', lib_name); log.console('Unknown library:', lib_name);
log.console('Available libraries:', libraries.map(l => l.name).join(', ')); log.console('Available libraries:', libraries.map(l => l.name).join(', '));
$_.stop() $stop()
} }
if (!bench) { if (!bench) {
log.console('Unknown scenario:', scenario_name); log.console('Unknown scenario:', scenario_name);
log.console('Available scenarios:', benchmarks.map(b => b.name).join(', ')); log.console('Available scenarios:', benchmarks.map(b => b.name).join(', '));
$_.stop() $stop()
} }
// Run the benchmark for this library/scenario combination // Run the benchmark for this library/scenario combination
@@ -201,4 +201,4 @@ var result = {
log.console(result); log.console(result);
$_.stop() $stop()

View File

@@ -20,25 +20,25 @@ for (var i = 0; i < args.length; i++) {
target = args[++i] target = args[++i]
} else { } else {
log.error('-t requires a target') log.error('-t requires a target')
$_.stop() $stop()
} }
} else if (args[i] == '-p' || args[i] == '--package') { } else if (args[i] == '-p' || args[i] == '--package') {
if (i + 1 < args.length) { if (i + 1 < args.length) {
target_package = args[++i] target_package = args[++i]
} else { } else {
log.error('-p requires a package name') log.error('-p requires a package name')
$_.stop() $stop()
} }
} else if (args[i] == '-b' || args[i] == '--buildtype') { } else if (args[i] == '-b' || args[i] == '--buildtype') {
if (i + 1 < args.length) { if (i + 1 < args.length) {
buildtype = args[++i] buildtype = args[++i]
if (buildtype != 'release' && buildtype != 'debug' && buildtype != 'minsize') { if (buildtype != 'release' && buildtype != 'debug' && buildtype != 'minsize') {
log.error('Invalid buildtype: ' + buildtype + '. Must be release, debug, or minsize') log.error('Invalid buildtype: ' + buildtype + '. Must be release, debug, or minsize')
$_.stop() $stop()
} }
} else { } else {
log.error('-b requires a buildtype (release, debug, minsize)') log.error('-b requires a buildtype (release, debug, minsize)')
$_.stop() $stop()
} }
} else if (args[i] == '--list-targets') { } else if (args[i] == '--list-targets') {
log.console('Available targets:') log.console('Available targets:')
@@ -46,7 +46,7 @@ for (var i = 0; i < args.length; i++) {
for (var t = 0; t < targets.length; t++) { for (var t = 0; t < targets.length; t++) {
log.console(' ' + targets[t]) log.console(' ' + targets[t])
} }
$_.stop() $stop()
} }
} }
@@ -59,7 +59,7 @@ if (!target) {
if (target && !build.has_target(target)) { if (target && !build.has_target(target)) {
log.error('Invalid target: ' + target) log.error('Invalid target: ' + target)
log.console('Available targets: ' + build.list_targets().join(', ')) log.console('Available targets: ' + build.list_targets().join(', '))
$_.stop() $stop()
} }
var packages = shop.list_packages() var packages = shop.list_packages()
@@ -79,7 +79,7 @@ if (target_package) {
} }
} catch (e) { } catch (e) {
log.error('Build failed: ' + e) log.error('Build failed: ' + e)
$_.stop() $stop()
} }
} else { } else {
// Build all packages // Build all packages
@@ -99,4 +99,4 @@ if (target_package) {
log.console(`Build complete: ${success} libraries built${failed > 0 ? `, ${failed} failed` : ''}`) log.console(`Build complete: ${success} libraries built${failed > 0 ? `, ${failed} failed` : ''}`)
} }
$_.stop() $stop()

View File

@@ -7,7 +7,7 @@ var build_dir = shop.get_shop_path() + '/build'
if (!fd.is_dir(build_dir)) { if (!fd.is_dir(build_dir)) {
log.console("No build directory found at " + build_dir) log.console("No build directory found at " + build_dir)
$_.stop() $stop()
return return
} }
@@ -23,4 +23,4 @@ try {
log.console("Clean complete!") log.console("Clean complete!")
$_.stop() $stop()

View File

@@ -99,14 +99,14 @@ function print_config(obj, prefix = '') {
// Main command handling // Main command handling
if (args.length == 0) { if (args.length == 0) {
print_help() print_help()
$_.stop() $stop()
return return
} }
var config = pkg.load_config() var config = pkg.load_config()
if (!config) { if (!config) {
log.error("Failed to load cell.toml") log.error("Failed to load cell.toml")
$_.stop() $stop()
return return
} }
@@ -128,7 +128,7 @@ switch (command) {
case 'get': case 'get':
if (args.length < 2) { if (args.length < 2) {
log.error("Usage: cell config get <key>") log.error("Usage: cell config get <key>")
$_.stop() $stop()
return return
} }
var key = args[1] var key = args[1]
@@ -148,7 +148,7 @@ switch (command) {
case 'set': case 'set':
if (args.length < 3) { if (args.length < 3) {
log.error("Usage: cell config set <key> <value>") log.error("Usage: cell config set <key> <value>")
$_.stop() $stop()
return return
} }
var key = args[1] var key = args[1]
@@ -164,7 +164,7 @@ switch (command) {
] ]
if (!valid_system_keys.includes(path[1])) { if (!valid_system_keys.includes(path[1])) {
log.error("Invalid system key. Valid keys: " + valid_system_keys.join(', ')) log.error("Invalid system key. Valid keys: " + valid_system_keys.join(', '))
$_.stop() $stop()
return return
} }
} }
@@ -178,7 +178,7 @@ switch (command) {
// Handle actor-specific configuration // Handle actor-specific configuration
if (args.length < 3) { if (args.length < 3) {
log.error("Usage: cell config actor <name> <command> [options]") log.error("Usage: cell config actor <name> <command> [options]")
$_.stop() $stop()
return return
} }
@@ -203,7 +203,7 @@ switch (command) {
case 'get': case 'get':
if (args.length < 4) { if (args.length < 4) {
log.error("Usage: cell config actor <name> get <key>") log.error("Usage: cell config actor <name> get <key>")
$_.stop() $stop()
return return
} }
var key = args[3] var key = args[3]
@@ -220,7 +220,7 @@ switch (command) {
case 'set': case 'set':
if (args.length < 5) { if (args.length < 5) {
log.error("Usage: cell config actor <name> set <key> <value>") log.error("Usage: cell config actor <name> set <key> <value>")
$_.stop() $stop()
return return
} }
var key = args[3] var key = args[3]
@@ -244,4 +244,4 @@ switch (command) {
print_help() print_help()
} }
$_.stop() $stop()

View File

@@ -62,7 +62,7 @@ An actor is a script that **does not return a value**. It runs as an independent
// worker.ce // worker.ce
log.console("Worker started") log.console("Worker started")
$_.on_message = function(msg) { $on_message = function(msg) {
log.console("Received:", msg) log.console("Received:", msg)
// Process message... // Process message...
} }
@@ -86,12 +86,12 @@ Reference to the current actor.
log.console($me) // actor reference log.console($me) // actor reference
``` ```
### $_.stop() ### $stop()
Stop the current actor. Stop the current actor.
```javascript ```javascript
$_.stop() $stop()
``` ```
### $send(actor, message, callback) ### $send(actor, message, callback)
@@ -207,7 +207,7 @@ $start(function(worker) {
$delay(function() { $delay(function() {
log.console("Shutting down") log.console("Shutting down")
$_.stop() $stop()
}, 10) }, 10)
``` ```

View File

@@ -17,7 +17,7 @@ Cell is an actor-based scripting language for building concurrent applications.
```javascript ```javascript
// hello.ce - A simple actor // hello.ce - A simple actor
log.console("Hello, Cell!") log.console("Hello, Cell!")
$_.stop() $stop()
``` ```
```bash ```bash

View File

@@ -48,7 +48,7 @@ function get_status() {
} }
// Main message receiver // Main message receiver
$_.receiver(function(msg) { $receiver(function(msg) {
switch (msg.type) { switch (msg.type) {
case 'download': case 'download':
if (state.downloading) { if (state.downloading) {
@@ -86,7 +86,7 @@ $_.receiver(function(msg) {
} }
// Schedule the first chunk read // Schedule the first chunk read
$_.delay(read_next_chunk, 0); $delay(read_next_chunk, 0);
} catch (e) { } catch (e) {
state.error = e.toString(); state.error = e.toString();
@@ -167,7 +167,7 @@ function read_next_chunk() {
} }
// Schedule next chunk read // Schedule next chunk read
$_.delay(read_next_chunk, 0); $delay(read_next_chunk, 0);
} catch (e) { } catch (e) {
// Error during download // Error during download

View File

@@ -7,7 +7,7 @@ var json = use('json');
var waiting_client = null; var waiting_client = null;
var match_id = 0; var match_id = 0;
$_.portal(e => { $portal(e => {
log.console("NAT server: received connection request"); log.console("NAT server: received connection request");
if (!isa(e.actor, actor)) if (!isa(e.actor, actor))

View File

@@ -1,6 +1,6 @@
log.console(`nat client starting`) log.console(`nat client starting`)
$_.contact((actor, reason) => { $contact((actor, reason) => {
if (actor) { if (actor) {
log.console(`trying to message ${actor}`) log.console(`trying to message ${actor}`)
send(actor, {type:"greet"}) send(actor, {type:"greet"})
@@ -10,10 +10,10 @@ $_.contact((actor, reason) => {
}, { }, {
address: "108.210.60.32", // NAT server's public IP address: "108.210.60.32", // NAT server's public IP
port: 4000, port: 4000,
actor: $_ actor: $self
}) })
$_.receiver(e => { $receiver(e => {
switch(e.type) { switch(e.type) {
case 'greet': case 'greet':
log.console(`hello!`) log.console(`hello!`)

View File

@@ -23,7 +23,7 @@ for (var i = 0; i < args.length; i++) {
log.console("") log.console("")
log.console("This command ensures that the zip files on disk match what's in") log.console("This command ensures that the zip files on disk match what's in")
log.console("the lock file. For local packages, this is a no-op.") log.console("the lock file. For local packages, this is a no-op.")
$_.stop() $stop()
} else if (!args[i].startsWith('-')) { } else if (!args[i].startsWith('-')) {
target_pkg = args[i] target_pkg = args[i]
} }
@@ -37,7 +37,7 @@ if (target_pkg) {
// Fetch specific package // Fetch specific package
if (!all_packages.includes(target_pkg)) { if (!all_packages.includes(target_pkg)) {
log.error("Package not found: " + target_pkg) log.error("Package not found: " + target_pkg)
$_.stop() $stop()
} }
packages_to_fetch.push(target_pkg) packages_to_fetch.push(target_pkg)
} else { } else {
@@ -83,4 +83,4 @@ for (var pkg of packages_to_fetch) {
log.console("") log.console("")
log.console("Fetch complete: " + text(success_count) + " fetched, " + text(skip_count) + " skipped, " + text(fail_count) + " failed") log.console("Fetch complete: " + text(success_count) + " fetched, " + text(skip_count) + " skipped, " + text(fail_count) + " failed")
$_.stop() $stop()

View File

@@ -15,7 +15,7 @@ if (command) {
log.error("No help available for command: " + command) log.error("No help available for command: " + command)
log.console("Run 'cell help' to see available commands.") log.console("Run 'cell help' to see available commands.")
} }
$_.stop() $stop()
return return
} }
@@ -44,4 +44,4 @@ if (stat && stat.isFile) {
log.console("Run 'cell help <command>' for more information on a command.") log.console("Run 'cell help <command>' for more information on a command.")
} }
$_.stop() $stop()

View File

@@ -6,7 +6,7 @@ var build = use('build')
if (args.length < 1) { if (args.length < 1) {
log.console("Usage: cell install <locator>") log.console("Usage: cell install <locator>")
$_.stop() $stop()
return return
} }
@@ -15,7 +15,7 @@ var locator = args[0]
log.console("Installing " + locator + "...") log.console("Installing " + locator + "...")
if (!shop.update(locator)) { if (!shop.update(locator)) {
log.console("Failed to install " + locator) log.console("Failed to install " + locator)
$_.stop() $stop()
return return
} }
@@ -29,4 +29,4 @@ for (var dep of deps) {
build.build_package(locator) build.build_package(locator)
log.console("Installed " + locator) log.console("Installed " + locator)
$_.stop() $stop()

View File

@@ -1,15 +1,19 @@
(function engine() { (function engine() {
var ACTORDATA = cell.hidden.actorsym var _cell = globalThis.cell
delete globalThis.cell
var ACTORDATA = _cell.hidden.actorsym
var SYSYM = '__SYSTEM__' var SYSYM = '__SYSTEM__'
var hidden = cell.hidden var __cell = globalThis._cell
var hidden = _cell.hidden
var os = hidden.os; var os = hidden.os;
cell.os = null _cell.os = null
var dylib_ext var dylib_ext
cell.id ??= "newguy" _cell.id ??= "newguy"
switch(os.platform()) { switch(os.platform()) {
case 'Windows': dylib_ext = '.dll'; break; case 'Windows': dylib_ext = '.dll'; break;
@@ -25,7 +29,6 @@ function use_embed(name) {
return load_internal(`js_${name}_use`) return load_internal(`js_${name}_use`)
} }
globalThis.use = use_embed
globalThis.meme = function(obj) { globalThis.meme = function(obj) {
return { return {
__proto__: obj __proto__: obj
@@ -77,9 +80,9 @@ function use_core(path) {
if (fd.is_file(file_path)) { if (fd.is_file(file_path)) {
var script_blob = fd.slurp(file_path) var script_blob = fd.slurp(file_path)
var script = utf8.decode(script_blob) var script = utf8.decode(script_blob)
var mod = `(function setup_module($_){${script}})` var mod = `(function setup_module(use){${script}})`
var fn = js.eval('core:' + path, mod) var fn = js.eval('core:' + path, mod)
var result = fn.call(sym); var result = fn.call(sym, use_core);
use_cache[cache_key] = result; use_cache[cache_key] = result;
return result; return result;
} }
@@ -88,9 +91,7 @@ function use_core(path) {
return sym; return sym;
} }
globalThis.use = use_core var blob = use_core('blob')
var blob = use('blob')
var blob_stone = blob.prototype.stone var blob_stone = blob.prototype.stone
var blob_stonep = blob.prototype.stonep; var blob_stonep = blob.prototype.stonep;
delete blob.prototype.stone; delete blob.prototype.stone;
@@ -141,16 +142,16 @@ stone.p = function(object)
return _ObjectIsFrozen(object) return _ObjectIsFrozen(object)
} }
var actor_mod = use('actor') var actor_mod = use_core('actor')
var wota = use('wota') var wota = use_core('wota')
var nota = use('nota') var nota = use_core('nota')
// Load internal modules for global functions // Load internal modules for global functions
globalThis.text = use('internal/text') globalThis.text = use_core('internal/text')
globalThis.number = use('internal/number') globalThis.number = use_core('internal/number')
globalThis.array = use('internal/array') globalThis.array = use_core('internal/array')
globalThis.object = use('internal/object') globalThis.object = use_core('internal/object')
globalThis.fn = use('internal/fn') globalThis.fn = use_core('internal/fn')
// Global utility functions (use already-captured references) // Global utility functions (use already-captured references)
var _isArray = _ArrayIsArray var _isArray = _ArrayIsArray
@@ -319,7 +320,7 @@ function caller_data(depth = 0)
} }
function console_rec(line, file, msg) { function console_rec(line, file, msg) {
return `[${cell.id.slice(0,5)}] [${file}:${line}]: ${msg}\n` return `[${_cell.id.slice(0,5)}] [${file}:${line}]: ${msg}\n`
// time: [${time.text("mb d yyyy h:nn:ss")}] // time: [${time.text("mb d yyyy h:nn:ss")}]
} }
@@ -374,9 +375,9 @@ function disrupt(err)
actor_mod.on_exception(disrupt) actor_mod.on_exception(disrupt)
cell.args = cell.hidden.init _cell.args = _cell.hidden.init
cell.args ??= {} _cell.args ??= {}
cell.id ??= "newguy" _cell.id ??= "newguy"
function create_actor(desc = {id:guid()}) { function create_actor(desc = {id:guid()}) {
var actor = {} var actor = {}
@@ -384,24 +385,85 @@ function create_actor(desc = {id:guid()}) {
return actor return actor
} }
var $_ = create_actor() var $_ = {}
$_.self = create_actor()
os.use_cache = use_cache os.use_cache = use_cache
os.global_shop_path = shop_path os.global_shop_path = shop_path
os.$_ = $_ os.$_ = $_
var shop = use('shop') var shop = use_core('shop')
globalThis.use = shop.use var json = use_core('json')
var json = use('json') var time = use_core('time')
var time = use('time')
var pronto = use('pronto') var pronto = use_core('pronto')
globalThis.fallback = pronto.fallback globalThis.fallback = pronto.fallback
globalThis.parallel = pronto.parallel globalThis.parallel = pronto.parallel
globalThis.race = pronto.race globalThis.race = pronto.race
globalThis.sequence = pronto.sequence globalThis.sequence = pronto.sequence
$_.time_limit = function(requestor, seconds)
{
if (!pronto.is_requestor(requestor))
throw new Error('time_limit: first argument must be a requestor');
if (!isa(seconds, number) || seconds <= 0)
throw new Error('time_limit: seconds must be a positive number');
return function time_limit_requestor(callback, value) {
pronto.check_callback(callback, 'time_limit')
var finished = false
var requestor_cancel = null
var timer_cancel = null
function cancel(reason) {
if (finished) return
finished = true
if (timer_cancel) {
timer_cancel()
timer_cancel = null
}
if (requestor_cancel) {
try { pronto.requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
}
timer_cancel = $_.delay(function() {
if (finished) return
def reason = make_reason(factory, 'Timeout.', seconds)
if (requestor_cancel) {
try { requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
finished = true
callback(null, reason)
}, seconds)
try {
requestor_cancel = requestor(function(val, reason) {
if (finished) return
finished = true
if (timer_cancel) {
timer_cancel()
timer_cancel = null
}
callback(val, reason)
}, value)
} catch (ex) {
cancel(ex)
callback(null, ex)
}
return function(reason) {
if (requestor_cancel) {
try { requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
}
}
}
var config = { var config = {
ar_timer: 60, ar_timer: 60,
actor_memory:0, actor_memory:0,
@@ -410,7 +472,7 @@ var config = {
main: true main: true
} }
cell.config = config _cell.config = config
ENETSERVICE = config.net_service ENETSERVICE = config.net_service
REPLYTIMEOUT = config.reply_timeout REPLYTIMEOUT = config.reply_timeout
@@ -575,7 +637,7 @@ $_.start = function start(cb, program, ...args) {
if (args.length == 1 && Array.isArray(args[0])) args = args[0] if (args.length == 1 && Array.isArray(args[0])) args = args[0]
var startup = { var startup = {
id, id,
overling: $_, overling: $_.self,
root, root,
arg: args, arg: args,
program, program,
@@ -618,14 +680,14 @@ $_.delay = function delay(fn, seconds = 0) {
return function() { actor_mod.removetimer(id) } return function() { actor_mod.removetimer(id) }
} }
var enet = use('enet') var enet = use_core('enet')
// causes this actor to stop when another actor stops. // causes this actor to stop when another actor stops.
var couplings = new Set() var couplings = new Set()
$_.couple = function couple(actor) { $_.couple = function couple(actor) {
if (actor == $_) return // can't couple to self if (actor == $_.self) return // can't couple to self
couplings.add(actor[ACTORDATA].id) couplings.add(actor[ACTORDATA].id)
sys_msg(actor, {kind:'couple', from: $_}) sys_msg(actor, {kind:'couple', from: $_.self})
log.system(`coupled to ${actor}`) log.system(`coupled to ${actor}`)
} }
@@ -651,7 +713,7 @@ function actor_send(actor, message) {
if (typeof message != 'object') throw new Error('Must send an object record.') if (typeof message != 'object') throw new Error('Must send an object record.')
// message to self // message to self
if (actor[ACTORDATA].id == cell.id) { if (actor[ACTORDATA].id == _cell.id) {
if (receive_fn) receive_fn(message.data) if (receive_fn) receive_fn(message.data)
return return
} }
@@ -742,7 +804,7 @@ globalThis.send = function send(actor, message, reply) {
} }
}, REPLYTIMEOUT) }, REPLYTIMEOUT)
send.reply = id send.reply = id
send.replycc = $_ send.replycc = $_.self
} }
// Instead of sending immediately, queue it // Instead of sending immediately, queue it
@@ -751,10 +813,10 @@ globalThis.send = function send(actor, message, reply) {
stone(send) stone(send)
if (!cell.args.id) cell.id = guid() if (!_cell.args.id) _cell.id = guid()
else cell.id = cell.args.id else _cell.id = _cell.args.id
$_[ACTORDATA].id = cell.id $_.self[ACTORDATA].id = _cell.id
// Actor's timeslice for processing a single message // Actor's timeslice for processing a single message
function turn(msg) function turn(msg)
@@ -767,7 +829,7 @@ function turn(msg)
//log.console(`FIXME: need to get main from config, not just set to true`) //log.console(`FIXME: need to get main from config, not just set to true`)
//log.console(`FIXME: remove global access (ie globalThis.use)`) //log.console(`FIXME: remove global access (ie globalThis.use)`)
//log.console(`FIXME: add freeze/unfreeze at this level, so we can do it (but scripts cannot)`) //log.console(`FIXME: add freeze/unfreeze at this level, so we can do it (but scripts cannot)`)
actor_mod.register_actor(cell.id, turn, true, config.ar_timer) actor_mod.register_actor(_cell.id, turn, true, config.ar_timer)
if (config.actor_memory) if (config.actor_memory)
js.mem_limit(config.actor_memory) js.mem_limit(config.actor_memory)
@@ -775,14 +837,16 @@ if (config.actor_memory)
if (config.stack_max) if (config.stack_max)
js.max_stacksize(config.system.stack_max); js.max_stacksize(config.system.stack_max);
overling = cell.args.overling overling = _cell.args.overling
root = cell.args.root $_.overling = overling
root ??= $_
root = _cell.args.root
root ??= $_.self
if (overling) { if (overling) {
$_.couple(overling) // auto couple to overling $_.couple(overling) // auto couple to overling
report_to_overling({type:'greet', actor: $_}) report_to_overling({type:'greet', actor: $_.self})
} }
// sys messages are always dispatched immediately // sys messages are always dispatched immediately
@@ -795,11 +859,11 @@ function sys_msg(actor, msg)
function report_to_overling(msg) function report_to_overling(msg)
{ {
if (!overling) return if (!overling) return
sys_msg(overling, {kind:'underling', message:msg, from: $_}) sys_msg(overling, {kind:'underling', message:msg, from: $_.self})
} }
// Determine the program to run from command line // Determine the program to run from command line
var program = cell.args.program var program = _cell.args.program
if (!program) { if (!program) {
log.error('No program specified. Usage: cell <program.ce> [args...]') log.error('No program specified. Usage: cell <program.ce> [args...]')
@@ -890,21 +954,21 @@ var init_end = time.number()
var load_program_start = time.number() var load_program_start = time.number()
// Finally, run the program // Finally, run the program
actor_mod.setname(cell.args.program) actor_mod.setname(_cell.args.program)
var prog = cell.args.program var prog = _cell.args.program
var package = use('package') var package = use_core('package')
var locator = shop.resolve_locator(cell.args.program + ".ce", null) var locator = shop.resolve_locator(_cell.args.program + ".ce", null)
if (!locator) { if (!locator) {
var pkg = package.find_package_dir(cell.args.program + ".ce") var pkg = package.find_package_dir(_cell.args.program + ".ce")
locator = shop.resolve_locator(cell.args.program + ".ce", pkg) locator = shop.resolve_locator(_cell.args.program + ".ce", pkg)
} }
if (!locator) if (!locator)
throw new Error(`Main program ${cell.args.program} could not be found`) throw new Error(`Main program ${_cell.args.program} could not be found`)
// Hide JavaScript built-ins - make them inaccessible // Hide JavaScript built-ins - make them inaccessible
// Store references we need internally before deleting // Store references we need internally before deleting
@@ -921,9 +985,9 @@ var _JSON = JSON
// juicing these before Math is gone // juicing these before Math is gone
use('math/radians') use_core('math/radians')
use('math/cycles') use_core('math/cycles')
use('math/degrees') use_core('math/degrees')
// Delete from globalThis // Delete from globalThis
delete globalThis.Object delete globalThis.Object
@@ -974,7 +1038,26 @@ delete globalThis.RegExp
_ObjectFreeze(globalThis) _ObjectFreeze(globalThis)
$_.clock(_ => { $_.clock(_ => {
var val = locator.symbol.call(null, $_, cell.args.arg); // Get capabilities for the main program
var file_info = shop.file_info ? shop.file_info(locator.path) : null
var inject = shop.script_inject_for ? shop.script_inject_for(file_info) : []
// Build values array for injection
var vals = []
for (var i = 0; i < inject.length; i++) {
var key = inject[i]
if (key && key[0] == '$') key = key.substring(1)
if (key == 'fd') vals.push(fd)
else vals.push($_[key])
}
// Create use function bound to the program's package
var pkg = file_info ? file_info.package : null
var use_fn = function(path) { return shop.use(path, pkg) }
// Call with signature: setup_module(args, use, ...capabilities)
// The script wrapper builds $_ from the injected capabilities for backward compatibility
var val = locator.symbol.call(null, _cell.args.arg, use_fn, ...vals)
if (val) if (val)
throw new Error('Program must not return anything'); throw new Error('Program must not return anything');

View File

@@ -1,7 +1,4 @@
/* number.cm - number conversion and math utilities */ /* number.cm - number conversion and math utilities */
var math = use('math/radians')
var _floor = Math.floor var _floor = Math.floor
var _ceil = Math.ceil var _ceil = Math.ceil
var _round = Math.round var _round = Math.round
@@ -9,7 +6,7 @@ var _abs = Math.abs
var _trunc = Math.trunc var _trunc = Math.trunc
var _min = Math.min var _min = Math.min
var _max = Math.max var _max = Math.max
var _pow = math.power var _pow = Math.pow
var _parseInt = parseInt var _parseInt = parseInt
var _parseFloat = parseFloat var _parseFloat = parseFloat

View File

@@ -1,5 +1,4 @@
/* text.cm - text conversion and formatting utilities */ /* text.cm - text conversion and formatting utilities */
var blob = use('blob') var blob = use('blob')
var utf8 = use('utf8') var utf8 = use('utf8')

18
link.ce
View File

@@ -26,7 +26,7 @@ if (args.length < 1) {
log.console(" clear Remove all links") log.console(" clear Remove all links")
log.console(" <path> Link the package in <path> to that path") log.console(" <path> Link the package in <path> to that path")
log.console(" <package> <target> Link <package> to <target> (path or package)") log.console(" <package> <target> Link <package> to <target> (path or package)")
$_.stop() $stop()
return return
} }
@@ -55,7 +55,7 @@ if (cmd == 'list') {
} else if (cmd == 'delete' || cmd == 'rm') { } else if (cmd == 'delete' || cmd == 'rm') {
if (args.length < 2) { if (args.length < 2) {
log.console("Usage: link delete <package>") log.console("Usage: link delete <package>")
$_.stop() $stop()
return return
} }
@@ -96,7 +96,7 @@ if (cmd == 'list') {
if (!arg1) { if (!arg1) {
log.console("Error: target or package required") log.console("Error: target or package required")
$_.stop() $stop()
return return
} }
@@ -136,7 +136,7 @@ if (cmd == 'list') {
if (!fd.is_file(toml_path)) { if (!fd.is_file(toml_path)) {
log.console("Error: No cell.toml found at " + target) log.console("Error: No cell.toml found at " + target)
log.console("For linking to another package, use: link <package> <target>") log.console("For linking to another package, use: link <package> <target>")
$_.stop() $stop()
return return
} }
@@ -147,12 +147,12 @@ if (cmd == 'list') {
pkg_name = content.package pkg_name = content.package
} else { } else {
log.console("Error: cell.toml at " + target + " does not define 'package'") log.console("Error: cell.toml at " + target + " does not define 'package'")
$_.stop() $stop()
return return
} }
} catch (e) { } catch (e) {
log.console("Error reading cell.toml: " + e) log.console("Error reading cell.toml: " + e)
$_.stop() $stop()
return return
} }
} }
@@ -161,7 +161,7 @@ if (cmd == 'list') {
if (target.startsWith('/')) { if (target.startsWith('/')) {
if (!fd.is_file(target + '/cell.toml')) { if (!fd.is_file(target + '/cell.toml')) {
log.console("Error: " + target + " is not a valid package (no cell.toml)") log.console("Error: " + target + " is not a valid package (no cell.toml)")
$_.stop() $stop()
return return
} }
} }
@@ -171,9 +171,9 @@ if (cmd == 'list') {
link.add(pkg_name, target, shop) link.add(pkg_name, target, shop)
} catch (e) { } catch (e) {
log.console("Error: " + e.message) log.console("Error: " + e.message)
$_.stop() $stop()
return return
} }
} }
$_.stop() $stop()

View File

@@ -17,7 +17,7 @@ if (args && args.length > 0) {
} else if (args[0] == 'package') { } else if (args[0] == 'package') {
if (args.length < 2) { if (args.length < 2) {
log.console("Usage: cell list package <name>") log.console("Usage: cell list package <name>")
$_.stop() $stop()
return return
} }
mode = 'package' mode = 'package'
@@ -28,7 +28,7 @@ if (args && args.length > 0) {
log.console(" cell list all : list all recursive packages") log.console(" cell list all : list all recursive packages")
log.console(" cell list package <name>: list dependencies of <name>") log.console(" cell list package <name>: list dependencies of <name>")
log.console(" cell list shop : list all packages in shop") log.console(" cell list shop : list all packages in shop")
$_.stop() $stop()
return return
} }
} }
@@ -82,4 +82,4 @@ function print_deps(ctx) {
} }
} }
$_.stop() $stop()

2
ls.ce
View File

@@ -31,4 +31,4 @@ if (programs.length == 0) {
} }
} }
$_.stop() $stop()

20
pack.ce
View File

@@ -23,7 +23,7 @@ if (args.length < 1) {
log.error(' -b, --buildtype <type> Build type: release, debug, minsize (default: release)') log.error(' -b, --buildtype <type> Build type: release, debug, minsize (default: release)')
log.error('') log.error('')
log.error('Available targets: ' + build.list_targets().join(', ')) log.error('Available targets: ' + build.list_targets().join(', '))
$_.stop() $stop()
return return
} }
@@ -35,25 +35,25 @@ for (var i = 1; i < args.length; i++) {
target = args[++i] target = args[++i]
} else { } else {
log.error('-t requires a target') log.error('-t requires a target')
$_.stop() $stop()
} }
} else if (args[i] == '-o' || args[i] == '--output') { } else if (args[i] == '-o' || args[i] == '--output') {
if (i + 1 < args.length) { if (i + 1 < args.length) {
output_name = args[++i] output_name = args[++i]
} else { } else {
log.error('-o requires an output name') log.error('-o requires an output name')
$_.stop() $stop()
} }
} else if (args[i] == '-b' || args[i] == '--buildtype') { } else if (args[i] == '-b' || args[i] == '--buildtype') {
if (i + 1 < args.length) { if (i + 1 < args.length) {
buildtype = args[++i] buildtype = args[++i]
if (buildtype != 'release' && buildtype != 'debug' && buildtype != 'minsize') { if (buildtype != 'release' && buildtype != 'debug' && buildtype != 'minsize') {
log.error('Invalid buildtype: ' + buildtype + '. Must be release, debug, or minsize') log.error('Invalid buildtype: ' + buildtype + '. Must be release, debug, or minsize')
$_.stop() $stop()
} }
} else { } else {
log.error('-b requires a buildtype (release, debug, minsize)') log.error('-b requires a buildtype (release, debug, minsize)')
$_.stop() $stop()
} }
} else if (args[i] == '-h' || args[i] == '--help') { } else if (args[i] == '-h' || args[i] == '--help') {
log.console('Usage: cell pack <package> [options]') log.console('Usage: cell pack <package> [options]')
@@ -64,10 +64,10 @@ for (var i = 1; i < args.length; i++) {
log.console(' -b, --buildtype <type> Build type: release, debug, minsize (default: release)') log.console(' -b, --buildtype <type> Build type: release, debug, minsize (default: release)')
log.console('') log.console('')
log.console('Available targets: ' + build.list_targets().join(', ')) log.console('Available targets: ' + build.list_targets().join(', '))
$_.stop() $stop()
} else { } else {
log.error('Unknown option: ' + args[i]) log.error('Unknown option: ' + args[i])
$_.stop() $stop()
} }
} }
@@ -80,7 +80,7 @@ if (!target) {
if (target && !build.has_target(target)) { if (target && !build.has_target(target)) {
log.error('Invalid target: ' + target) log.error('Invalid target: ' + target)
log.console('Available targets: ' + build.list_targets().join(', ')) log.console('Available targets: ' + build.list_targets().join(', '))
$_.stop() $stop()
} }
// Prepare packages: core + dependencies + target package // Prepare packages: core + dependencies + target package
@@ -117,7 +117,7 @@ try {
} catch (e) { } catch (e) {
log.error('Build failed: ') log.error('Build failed: ')
log.error(e) log.error(e)
$_.stop() $stop()
} }
$_.stop() $stop()

View File

@@ -3,9 +3,6 @@
// Based on Douglas Crockford's parseq, adapted for Cell. // Based on Douglas Crockford's parseq, adapted for Cell.
// Time is in seconds. // Time is in seconds.
var os = use('os')
var $_ = os.$_
function make_reason(factory, excuse, evidence) { function make_reason(factory, excuse, evidence) {
def reason = new Error(`pronto.${factory}${excuse ? ': ' + excuse : ''}`) def reason = new Error(`pronto.${factory}${excuse ? ': ' + excuse : ''}`)
reason.evidence = evidence reason.evidence = evidence
@@ -303,69 +300,6 @@ function sequence(requestor_array) {
} }
} }
// time_limit(requestor, seconds)
// Wraps a requestor with a time limit.
function time_limit(requestor, seconds) {
def factory = 'time_limit'
if (!is_requestor(requestor))
throw make_reason(factory, 'Not a requestor.', requestor)
if (typeof seconds != 'number' || seconds <= 0)
throw make_reason(factory, 'Bad time limit.', seconds)
return function time_limit_requestor(callback, value) {
check_callback(callback, factory)
let finished = false
let requestor_cancel = null
let timer_cancel = null
function cancel(reason) {
if (finished) return
finished = true
if (timer_cancel) {
timer_cancel()
timer_cancel = null
}
if (requestor_cancel) {
try { requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
}
timer_cancel = $_.delay(function() {
if (finished) return
def reason = make_reason(factory, 'Timeout.', seconds)
if (requestor_cancel) {
try { requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
finished = true
callback(null, reason)
}, seconds)
try {
requestor_cancel = requestor(function(val, reason) {
if (finished) return
finished = true
if (timer_cancel) {
timer_cancel()
timer_cancel = null
}
callback(val, reason)
}, value)
} catch (ex) {
cancel(ex)
callback(null, ex)
}
return function(reason) {
if (requestor_cancel) {
try { requestor_cancel(reason) } catch (_) {}
requestor_cancel = null
}
}
}
}
// requestorize(unary) // requestorize(unary)
// Converts a unary function into a requestor. // Converts a unary function into a requestor.
function requestorize(unary) { function requestorize(unary) {
@@ -421,7 +355,8 @@ return {
parallel, parallel,
race, race,
sequence, sequence,
time_limit,
requestorize, requestorize,
objectify objectify,
is_requestor,
check_callback
} }

View File

@@ -143,4 +143,4 @@ if (typeof arg == 'undefined' || arg.length < 1) {
} }
} }
$_.stop() $stop()

View File

@@ -4,10 +4,10 @@ var shop = use('shop')
if (args.length < 1) { if (args.length < 1) {
log.console("Usage: cell remove <alias|path>") log.console("Usage: cell remove <alias|path>")
$_.stop() $stop()
return return
} }
shop.remove(args[0]) shop.remove(args[0])
$_.stop() $stop()

101
shop.cm
View File

@@ -180,11 +180,12 @@ Shop.file_info = function(file) {
if (pkg_dir) { if (pkg_dir) {
info.package = abs_path_to_package(pkg_dir) info.package = abs_path_to_package(pkg_dir)
info.name = file.substring(pkg_dir.length + 1)
if (info.is_actor) if (info.is_actor)
info.name = info.path.substring(0, info.path.length - ACTOR_EXT.length) info.name = file.substring(pkg_dir.length + 1, file.length - ACTOR_EXT.length)
else if (info.is_module) else if (info.is_module)
info.name = info.path.substring(0, info.path.length - MOD_EXT.length) info.name = file.substring(pkg_dir.length + 1, file.length - MOD_EXT.length)
else
info.name = file.substring(pkg_dir.length + 1)
} }
return info return info
@@ -325,11 +326,73 @@ Shop.extract_commit_hash = function(pkg, response) {
var open_dls = {} var open_dls = {}
// Default capabilities injected into scripts
// These map to $_ properties in engine.cm
var SHOP_DEFAULT_INJECT = ['$self', '$overling', '$clock', '$delay', '$start', '$receiver', '$contact', '$portal', '$time_limit', '$couple', '$stop', '$unneeded', '$connection', '$fd']
function strip_dollar(name) {
if (name && name[0] == '$') return name.substring(1)
return name
}
// Decide what a given module is allowed to see.
// This is the capability gate - tweak as needed.
Shop.script_inject_for = function(file_info) {
if (!file_info) return []
// For now, grant everything to all scripts
// Later this can be tuned per package/script
return array(SHOP_DEFAULT_INJECT)
}
// Get capabilities for a script path (public API)
Shop.get_script_capabilities = function(path) {
var file_info = Shop.file_info(path)
return Shop.script_inject_for(file_info)
}
function inject_params(inject) {
if (!inject || !inject.length) return ''
return ', ' + inject.join(', ')
}
function inject_values(inject) {
var vals = []
for (var i = 0; i < inject.length; i++) {
var key = strip_dollar(inject[i])
if (key == 'fd') vals.push(fd)
else vals.push($_[key])
}
return vals
}
// Build the use function for a specific package context
function make_use_fn_code(pkg_arg) {
return `function(path) { return globalThis.use(path, ${pkg_arg}); }`
}
// for script forms, path is the canonical path of the module // for script forms, path is the canonical path of the module
var script_form = function(path, script, pkg) { var script_form = function(path, script, pkg, inject) {
var pkg_arg = pkg ? `'${pkg}'` : 'null' var pkg_arg = pkg ? `'${pkg}'` : 'null'
var relative_use_fn = `def PACKAGE = ${pkg_arg}; def use = function(path) { return globalThis.use(path, ${pkg_arg});}` var params = inject_params(inject)
var fn = `(function setup_module($_, args){ def arg = args; ${relative_use_fn}; ${script}})`
// Build $_ object from injected capabilities for backward compatibility
var build_compat = ''
if (inject && inject.length) {
var compat_props = []
for (var i = 0; i < inject.length; i++) {
var name = inject[i]
var key = name
if (key && key[0] == '$') key = key.substring(1)
compat_props.push(key + ': ' + name)
}
build_compat = 'var $_ = {' + compat_props.join(', ') + '};'
}
// use is passed as a parameter, not on globalThis for the script
// $fd is injected as a capability, but we still allow use('fd') for now
// $_ is built from injected capabilities for backward compatibility
var fn = `(function setup_module(args, use${params}){ def arg = args; def PACKAGE = ${pkg_arg}; ${build_compat} ${script}})`
return fn return fn
} }
@@ -340,8 +403,9 @@ function resolve_mod_fn(path, pkg) {
var file_info = Shop.file_info(path) var file_info = Shop.file_info(path)
var file_pkg = file_info.package var file_pkg = file_info.package
var inject = Shop.script_inject_for(file_info)
var content = text(fd.slurp(path)) var content = text(fd.slurp(path))
var script = script_form(path, content, file_pkg); var script = script_form(path, content, file_pkg, inject);
var obj = pull_from_cache(utf8.encode(script)) var obj = pull_from_cache(utf8.encode(script))
if (obj) { if (obj) {
@@ -570,7 +634,9 @@ function resolve_module_info(path, package_context) {
// This ensures linked packages resolve to the same cache entry // This ensures linked packages resolve to the same cache entry
// whether accessed via symlink or directly // whether accessed via symlink or directly
var cache_key var cache_key
if (mod_resolve.scope < 900 && mod_resolve.path) { if (mod_resolve.scope == SCOPE_CORE) {
cache_key = 'core/' + path
} else if (mod_resolve.scope < 900 && mod_resolve.path) {
// Use realpath to resolve symlinks and get the actual file location // Use realpath to resolve symlinks and get the actual file location
var real_path = fd.realpath(mod_resolve.path) var real_path = fd.realpath(mod_resolve.path)
if (real_path) { if (real_path) {
@@ -628,6 +694,13 @@ Shop.is_loaded = function(path, package_context) {
return use_cache[cache_key] != null return use_cache[cache_key] != null
} }
// Create a use function bound to a specific package context
function make_use_fn(pkg) {
return function(path) {
return Shop.use(path, pkg)
}
}
function execute_module(info) function execute_module(info)
{ {
var c_resolve = info.c_resolve var c_resolve = info.c_resolve
@@ -640,7 +713,17 @@ function execute_module(info)
if (c_resolve.scope < 900) { if (c_resolve.scope < 900) {
context = c_resolve.symbol(null, $_) context = c_resolve.symbol(null, $_)
} }
used = mod_resolve.symbol.call(context, $_)
// Get file info to determine inject list
var file_info = Shop.file_info(mod_resolve.path)
var inject = Shop.script_inject_for(file_info)
var vals = inject_values(inject)
var pkg = file_info.package
var use_fn = make_use_fn(pkg)
// Call with signature: setup_module(args, use, ...capabilities)
// args is null for module loading
used = mod_resolve.symbol.call(context, null, use_fn, ...vals)
} else if (c_resolve.scope < 900) { } else if (c_resolve.scope < 900) {
// C only // C only
used = c_resolve.symbol(null, $_) used = c_resolve.symbol(null, $_)

View File

@@ -146,7 +146,7 @@ void script_startup(cell_rt *prt)
JS_SetPropertyStr(js, cell, "hidden", hidden_fn); JS_SetPropertyStr(js, cell, "hidden", hidden_fn);
JS_SetPropertyStr(js, hidden_fn, "os", js_os_use(js)); JS_SetPropertyStr(js, hidden_fn, "os", js_os_use(js));
const char actorsym_script[] = "var sym = Symbol(`actordata`); sym;"; const char actorsym_script[] = "Symbol('actordata');";
JSValue actorsym = JS_Eval(js, actorsym_script, sizeof(actorsym_script)-1, "internal", 0); JSValue actorsym = JS_Eval(js, actorsym_script, sizeof(actorsym_script)-1, "internal", 0);
JS_SetPropertyStr(js, hidden_fn, "actorsym", actorsym); JS_SetPropertyStr(js, hidden_fn, "actorsym", actorsym);

20
test.ce
View File

@@ -18,7 +18,7 @@ if (args.length > 0) {
if (args[0] == 'package') { if (args[0] == 'package') {
if (args.length < 2) { if (args.length < 2) {
log.console(`Usage: cell test package <name>`) log.console(`Usage: cell test package <name>`)
$_.stop() $stop()
return return
} }
var name = args[1] var name = args[1]
@@ -28,7 +28,7 @@ if (args.length > 0) {
log.console(`Testing package: ${resolved.alias} (${resolved.pkg})`) log.console(`Testing package: ${resolved.alias} (${resolved.pkg})`)
} else { } else {
log.console(`Package not found: ${name}`) log.console(`Package not found: ${name}`)
$_.stop() $stop()
return return
} }
} else if (args[0] == 'all') { } else if (args[0] == 'all') {
@@ -36,7 +36,7 @@ if (args.length > 0) {
log.console(`Testing all packages...`) log.console(`Testing all packages...`)
} else { } else {
log.console(`Usage: cell test [package <name> | all]`) log.console(`Usage: cell test [package <name> | all]`)
$_.stop() $stop()
return return
} }
} }
@@ -95,9 +95,9 @@ function spawn_actor_test(test_info) {
try { try {
// Spawn the actor test - it should send back results // Spawn the actor test - it should send back results
// The actor receives $_.parent which it can use to send results // The actor receives $parent which it can use to send results
var actor_path = test_info.path.substring(0, test_info.path.length - 3) // remove .ce var actor_path = test_info.path.substring(0, test_info.path.length - 3) // remove .ce
entry.actor = $_.start(actor_path) entry.actor = $start(actor_path)
pending_actor_tests.push(entry) pending_actor_tests.push(entry)
} catch (e) { } catch (e) {
entry.status = "failed" entry.status = "failed"
@@ -356,7 +356,7 @@ function check_timeouts() {
} }
if (pending_actor_tests.length > 0) { if (pending_actor_tests.length > 0) {
$_.delay(check_timeouts, 1000) $delay(check_timeouts, 1000)
} }
check_completion() check_completion()
} }
@@ -424,7 +424,7 @@ function finalize_results() {
log.console(`Tests: ${totals.passed} passed, ${totals.failed} failed, ${totals.total} total`) log.console(`Tests: ${totals.passed} passed, ${totals.failed} failed, ${totals.total} total`)
generate_reports(totals) generate_reports(totals)
$_.stop() $stop()
} }
// If no actor tests, finalize immediately // If no actor tests, finalize immediately
@@ -441,7 +441,7 @@ if (all_actor_tests.length == 0) {
log.console(`Tests: ${totals.passed} passed, ${totals.failed} failed, ${totals.total} total`) log.console(`Tests: ${totals.passed} passed, ${totals.failed} failed, ${totals.total} total`)
} else { } else {
// Start timeout checker // Start timeout checker
$_.delay(check_timeouts, 1000) $delay(check_timeouts, 1000)
} }
@@ -533,10 +533,10 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
// If no actor tests, generate reports and stop immediately // If no actor tests, generate reports and stop immediately
if (all_actor_tests.length == 0) { if (all_actor_tests.length == 0) {
generate_reports(totals) generate_reports(totals)
$_.stop() $stop()
} else { } else {
// Set up portal to receive messages from actor tests // Set up portal to receive messages from actor tests
$_.portal(function(msg) { $portal(function(msg) {
handle_actor_message(msg) handle_actor_message(msg)
}) })
} }

View File

@@ -1,6 +1,6 @@
return { return {
test_clock: function() { test_clock: function() {
// Original test verified $_.clock callbacks. // Original test verified $clock callbacks.
// This cannot be easily tested in a synchronous function return. // This cannot be easily tested in a synchronous function return.
// We assume the runtime works. // We assume the runtime works.
var i = 0 var i = 0

View File

@@ -1,4 +1,4 @@
var parseq = use('parseq', $_.delay) var parseq = use('parseq', $delay)
var time = use('time') var time = use('time')
return { return {
@@ -9,14 +9,14 @@ return {
function load_comment_from_api_requestor(id) { function load_comment_from_api_requestor(id) {
return function(cb) { return function(cb) {
return $_.delay(() => cb({ id, title: `Comment #${id}` }), 0.5) return $delay(() => cb({ id, title: `Comment #${id}` }), 0.5)
// returning the $_.delay return lets them be cancelled up the chain // returning the $delay return lets them be cancelled up the chain
} }
} }
$_.receiver(tree => { $receiver(tree => {
var child_reqs = tree.children.map(child => cb => { var child_reqs = tree.children.map(child => cb => {
$_.start(e => send(e.actor, child, cb), "tests/comments") $start(e => send(e.actor, child, cb), "tests/comments")
}) })
var job = parseq.par_all({ var job = parseq.par_all({

View File

@@ -1,16 +1,16 @@
var parseq = use('parseq', $_.delay) var parseq = use('parseq', $delay)
var time = use('time') var time = use('time')
function load_comment_from_api_requestor(id) { function load_comment_from_api_requestor(id) {
return function(cb) { return function(cb) {
return $_.delay(() => cb({ id, title: `Comment #${id}` }), 0.5) return $delay(() => cb({ id, title: `Comment #${id}` }), 0.5)
// returning the $_.delay return lets them be cancelled up the chain // returning the $delay return lets them be cancelled up the chain
} }
} }
$_.receiver(tree => { $receiver(tree => {
var child_reqs = tree.children.map(child => cb => { var child_reqs = tree.children.map(child => cb => {
$_.start(e => send(e.actor, child, cb), "tests/comments") // Note: recursively calls itself? Original used "tests/comments" $start(e => send(e.actor, child, cb), "tests/comments") // Note: recursively calls itself? Original used "tests/comments"
// We should probably change this to "tests/comments_actor" if it's recursive // We should probably change this to "tests/comments_actor" if it's recursive
}) })

View File

@@ -12,7 +12,7 @@ return {
log.console(`Did not get an actor: ${reason}`) log.console(`Did not get an actor: ${reason}`)
} }
$_.contact(contact_fn, $contact(contact_fn,
{ {
address: "localhost", address: "localhost",
port: 5678, port: 5678,

View File

@@ -1,7 +1,7 @@
return { return {
test_couple: function() { test_couple: function() {
$_.start(e => { $start(e => {
$_.couple(e.actor) $couple(e.actor)
}, "tests/delay_actor") }, "tests/delay_actor")
} }
} }

View File

@@ -4,9 +4,9 @@ function loop()
count++; count++;
log.console(`loop ${count}`); log.console(`loop ${count}`);
if (count < 60) if (count < 60)
$_.delay(loop, 0.01); $delay(loop, 0.01);
else else
$_.stop() $stop()
} }
$_.delay(loop,0.01) $delay(loop,0.01)

View File

@@ -4,7 +4,7 @@ var time = use('time')
return { return {
test_guid: function() { test_guid: function() {
var st = time.number() var st = time.number()
var guid = new blob(256, $_.random_fit) var guid = new blob(256, $random_fit)
stone(guid) stone(guid)
var btime = time.number()-st var btime = time.number()-st
st = time.number() st = time.number()

View File

@@ -7,7 +7,7 @@ return {
var host = 'google.com' var host = 'google.com'
var path = '/' var path = '/'
$_.start(e => { $start(e => {
send(e.actor, { op: 'get', domain: host, port: 80}, addrs => { send(e.actor, { op: 'get', domain: host, port: 80}, addrs => {
log.console(addrs[0]) log.console(addrs[0])
}) })

View File

@@ -1,14 +1,14 @@
$_.start(e => { $start(e => {
log.console(`got message from hanger: ${e.type}`) log.console(`got message from hanger: ${e.type}`)
if (e.type == 'greet') if (e.type == 'greet')
$_.delay(_ => { $delay(_ => {
log.console(`sending stop message to hanger`) log.console(`sending stop message to hanger`)
$_.stop(e.actor) $stop(e.actor)
}, 1) }, 1)
if (e.type == 'disrupt') { if (e.type == 'disrupt') {
log.console(`underling successfully killed.`) log.console(`underling successfully killed.`)
send($_.parent, { type: "test_result", passed: true }) send($parent, { type: "test_result", passed: true })
$_.stop() $stop()
} }
}, 'tests/hang_actor') }, 'tests/hang_actor')

View File

@@ -15,14 +15,14 @@ return {
// Spawn several underlings // Spawn several underlings
for (var i = 0; i < targetCount; i++) { for (var i = 0; i < targetCount; i++) {
$_.start(function(greet) { $start(function(greet) {
underlingCount++; underlingCount++;
log.console("Underling spawned: " + underlingCount); log.console("Underling spawned: " + underlingCount);
}, "tests/underling_actor", ["test" + i]); }, "tests/underling_actor", ["test" + i]);
} }
// We can't easily wait here without a loop that yields, but this is a single threaded JS env usually. // We can't easily wait here without a loop that yields, but this is a single threaded JS env usually.
// If $_.delay is async, we return immediately. // If $delay is async, we return immediately.
log.console("Spawned " + targetCount + " underlings (async)"); log.console("Spawned " + targetCount + " underlings (async)");
} }

View File

@@ -29,9 +29,9 @@ return {
// The original 'comments.ce' was an actor script. // The original 'comments.ce' was an actor script.
// We should probably restore 'comments.ce' as 'comments_actor.ce' for this test to work if it relies on spawning it. // We should probably restore 'comments.ce' as 'comments_actor.ce' for this test to work if it relies on spawning it.
// But 'comments.cm' (the new test file) also has the logic. // But 'comments.cm' (the new test file) also has the logic.
// We need an actor file for $_.start to work with. // We need an actor file for $start to work with.
$_.start(e => { $start(e => {
if (actor) return if (actor) return
actor = e.actor actor = e.actor
send(actor, tree, (result, reason) => { send(actor, tree, (result, reason) => {

View File

@@ -1,6 +1,6 @@
return { return {
test_portal: function() { test_portal: function() {
// Starts the portal actor // Starts the portal actor
$_.start(e => {}, "tests/portal_actor") $start(e => {}, "tests/portal_actor")
} }
} }

View File

@@ -1,14 +1,14 @@
var password = "abc123" var password = "abc123"
$_.portal(e => { $portal(e => {
if (e.password != password) if (e.password != password)
send(e, {reason:"Password does not match."}); send(e, {reason:"Password does not match."});
else else
send(e, $_) send(e, $self)
}, 5678); }, 5678);
$_.receiver(e => { $receiver(e => {
log.console(`Got message: ${e}`) log.console(`Got message: ${e}`)
send(e, {greet: "Hello back!"}) send(e, {greet: "Hello back!"})
$_.delay(_ => $_.stop(), 0.2) $delay(_ => $stop(), 0.2)
}) })

View File

@@ -7,7 +7,7 @@ function make_requestor(name, delay_seconds, should_succeed) {
return function(callback, value) { return function(callback, value) {
log.console(`Starting ${name} with value: ${value}`) log.console(`Starting ${name} with value: ${value}`)
if (delay_seconds > 0) { if (delay_seconds > 0) {
$_.delay(function() { $delay(function() {
if (should_succeed) { if (should_succeed) {
log.console(`${name} succeeded with: ${value + 1}`) log.console(`${name} succeeded with: ${value + 1}`)
callback(value + 1) callback(value + 1)

View File

@@ -1 +1 @@
$_.start(e => {}, "tests/reply_actor") $start(e => {}, "tests/reply_actor")

View File

@@ -1,4 +1,4 @@
$_.receiver(e => { $receiver(e => {
log.console(`Got a message: ${e}`) log.console(`Got a message: ${e}`)
send(e, { send(e, {

View File

@@ -1,9 +1,9 @@
return { return {
test_send: function() { test_send: function() {
$_.start(e => { $start(e => {
send(e.actor, { message: "Hello! Good to go?" }, msg => { send(e.actor, { message: "Hello! Good to go?" }, msg => {
log.console(`Original sender got message back: ${msg}. Stopping!`) log.console(`Original sender got message back: ${msg}. Stopping!`)
// $_.stop() // Removed // $stop() // Removed
}) })
}, "tests/reply_actor") }, "tests/reply_actor")
} }

View File

@@ -1,6 +1,6 @@
return { return {
test_stop: function() { test_stop: function() {
log.console(`About to stop.`) log.console(`About to stop.`)
// $_.stop() // Removed // $stop() // Removed
} }
} }

View File

@@ -1,7 +1,7 @@
var cmds = { var cmds = {
stop: $_.stop, stop: $stop,
disrupt: _ => { disrupt: _ => {
$_.delay(_ => { throw new Error() }, 0.5) $delay(_ => { throw new Error() }, 0.5)
} }
} }

View File

@@ -1,5 +1,5 @@
return { return {
test_unneeded: function() { test_unneeded: function() {
$_.start(e => {}, "tests/unneeded_actor") $start(e => {}, "tests/unneeded_actor")
} }
} }

View File

@@ -1,4 +1,4 @@
$_.unneeded(_ => { $unneeded(_ => {
log.console("Unneded function fired."); log.console("Unneded function fired.");
$_.start(null, "tests/unneeded_actor") $start(null, "tests/unneeded_actor")
}, 1); }, 1);

View File

@@ -23,7 +23,7 @@ for (var i = 0; i < args.length; i++) {
log.console("") log.console("")
log.console("This command checks for updates to all packages and downloads") log.console("This command checks for updates to all packages and downloads")
log.console("new versions. For local packages, ensures the symlink is correct.") log.console("new versions. For local packages, ensures the symlink is correct.")
$_.stop() $stop()
} else if (!args[i].startsWith('-')) { } else if (!args[i].startsWith('-')) {
target_pkg = args[i] target_pkg = args[i]
} }
@@ -74,4 +74,4 @@ if (target_pkg) {
} }
} }
$_.stop() $stop()

View File

@@ -34,4 +34,4 @@ if (cmd == 'link') {
} }
} }
$_.stop() $stop()

View File

@@ -1,3 +1,2 @@
var shop = use('shop')
log.console("0.1.0") log.console("0.1.0")
$_.stop() $stop()

4
why.ce
View File

@@ -3,7 +3,7 @@ var pkg = use('package')
if (!args || args.length < 1) { if (!args || args.length < 1) {
log.console("Usage: cell why <package>") log.console("Usage: cell why <package>")
$_.stop() $stop()
return return
} }
@@ -106,4 +106,4 @@ if (!found) {
log.console("Package '" + target + "' not found in dependency tree.") log.console("Package '" + target + "' not found in dependency tree.")
} }
$_.stop() $stop()