This commit is contained in:
2026-01-13 22:16:28 -06:00
parent ac4b47f075
commit 66a9ca27e2
21 changed files with 122 additions and 578 deletions

View File

@@ -579,7 +579,7 @@ Total benchmarks: ${total_benches}
} }
testlib.ensure_dir(report_dir) testlib.ensure_dir(report_dir)
fd.slurpwrite(`${report_dir}/bench.txt`, stone(new blob(txt_report))) fd.slurpwrite(`${report_dir}/bench.txt`, stone(blob(txt_report)))
log.console(`Report written to ${report_dir}/bench.txt`) log.console(`Report written to ${report_dir}/bench.txt`)
// Generate JSON per package // Generate JSON per package
@@ -596,7 +596,7 @@ Total benchmarks: ${total_benches}
} }
var json_path = `${report_dir}/${pkg_res.package.replace(/\//g, '_')}.json` var json_path = `${report_dir}/${pkg_res.package.replace(/\//g, '_')}.json`
fd.slurpwrite(json_path, stone(new blob(json.encode(pkg_benches)))) fd.slurpwrite(json_path, stone(blob(json.encode(pkg_benches))))
} }
} }

View File

@@ -2,7 +2,7 @@ var blob = use('blob')
var math = use('math/radians') var math = use('math/radians')
function eratosthenes (n) { function eratosthenes (n) {
var sieve = new blob(n, true) var sieve = blob(n, true)
var sqrtN = number.whole(math.sqrt(n)); var sqrtN = number.whole(math.sqrt(n));
for (i = 2; i <= sqrtN; i++) for (i = 2; i <= sqrtN; i++)

View File

@@ -10,7 +10,7 @@ log.console(`P4\n${w} ${h}`);
for (var y = 0; y < h; ++y) { for (var y = 0; y < h; ++y) {
// Create a blob for the row - we need w bits // Create a blob for the row - we need w bits
var row = new blob(w); var row = blob(w);
for (var x = 0; x < w; ++x) { for (var x = 0; x < w; ++x) {
zr = zi = tr = ti = 0; zr = zi = tr = ti = 0;

View File

@@ -73,7 +73,7 @@ Build.detect_host_target = function() {
// ============================================================================ // ============================================================================
function content_hash(str) { function content_hash(str) {
var bb = stone(new blob(str)) var bb = stone(blob(str))
return text(crypto.blake2(bb, 32), 'h') return text(crypto.blake2(bb, 32), 'h')
} }
@@ -107,7 +107,7 @@ Build.compile_file = function(pkg, file, target, buildtype = 'release') {
var src_path = pkg_dir + '/' + file var src_path = pkg_dir + '/' + file
if (!fd.is_file(src_path)) { if (!fd.is_file(src_path)) {
throw new Error('Source file not found: ' + src_path) throw Error('Source file not found: ' + src_path)
} }
// Get flags (with sigil replacement) // Get flags (with sigil replacement)
@@ -170,7 +170,7 @@ Build.compile_file = function(pkg, file, target, buildtype = 'release') {
log.console('Compiling ' + file) log.console('Compiling ' + file)
var ret = os.system(full_cmd) var ret = os.system(full_cmd)
if (ret != 0) { if (ret != 0) {
throw new Error('Compilation failed: ' + file) throw Error('Compilation failed: ' + file)
} }
return obj_path return obj_path
@@ -329,7 +329,7 @@ Build.build_dynamic = function(pkg, target = Build.detect_host_target(), buildty
log.console('Linking ' + lib_name + dylib_ext) log.console('Linking ' + lib_name + dylib_ext)
var ret = os.system(cmd_str) var ret = os.system(cmd_str)
if (ret != 0) { if (ret != 0) {
throw new Error('Linking failed: ' + pkg) throw Error('Linking failed: ' + pkg)
} }
// Update symlink to point to the new store file // Update symlink to point to the new store file
@@ -387,7 +387,7 @@ Build.build_static = function(packages, target = Build.detect_host_target(), out
} }
if (all_objects.length == 0) { if (all_objects.length == 0) {
throw new Error('No object files to link') throw Error('No object files to link')
} }
// Link // Link
@@ -420,7 +420,7 @@ Build.build_static = function(packages, target = Build.detect_host_target(), out
log.console('Linking ' + output) log.console('Linking ' + output)
var ret = os.system(cmd_str) var ret = os.system(cmd_str)
if (ret != 0) { if (ret != 0) {
throw new Error('Linking failed with command: ' + cmd_str) throw Error('Linking failed with command: ' + cmd_str)
} }
log.console('Built ' + output) log.console('Built ' + output)

View File

@@ -125,7 +125,7 @@ function resolve(path, must_exist) {
} }
if (!mount) { if (!mount) {
throw new Error("Unknown mount point: @" + mount_name) throw Error("Unknown mount point: @" + mount_name)
} }
return { mount: mount, path: rel_path } return { mount: mount, path: rel_path }
@@ -139,7 +139,7 @@ function resolve(path, must_exist) {
} }
if (must_exist) { if (must_exist) {
throw new Error("File not found in any mount: " + path) throw Error("File not found in any mount: " + path)
} }
} }
@@ -175,7 +175,7 @@ function mount(source, name) {
} else { } else {
var zip = miniz.read(blob) var zip = miniz.read(blob)
if (!is_object(zip) || !is_function(zip.count)) { if (!is_object(zip) || !is_function(zip.count)) {
throw new Error("Invalid archive file (not zip or qop): " + source) throw Error("Invalid archive file (not zip or qop): " + source)
} }
mount_info.type = 'zip' mount_info.type = 'zip'
@@ -183,7 +183,7 @@ function mount(source, name) {
mount_info.zip_blob = blob // keep blob alive mount_info.zip_blob = blob // keep blob alive
} }
} else { } else {
throw new Error("Unsupported mount source type: " + source) throw Error("Unsupported mount source type: " + source)
} }
mounts.push(mount_info) mounts.push(mount_info)
@@ -197,19 +197,19 @@ function unmount(name_or_source) {
return return
} }
} }
throw new Error("Mount not found: " + name_or_source) throw Error("Mount not found: " + name_or_source)
} }
// Read file // Read file
function slurp(path) { function slurp(path) {
var res = resolve(path, true) var res = resolve(path, true)
if (!res) throw new Error("File not found: " + path) if (!res) throw Error("File not found: " + path)
if (res.mount.type == 'zip') { if (res.mount.type == 'zip') {
return res.mount.handle.slurp(res.path) return res.mount.handle.slurp(res.path)
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var data = res.mount.handle.read(res.path) var data = res.mount.handle.read(res.path)
if (!data) throw new Error("File not found in qop: " + path) if (!data) throw Error("File not found in qop: " + path)
return data return data
} else { } else {
var full_path = join_paths(res.mount.source, res.path) var full_path = join_paths(res.mount.source, res.path)
@@ -238,7 +238,7 @@ function exists(path) {
// Stat // Stat
function stat(path) { function stat(path) {
var res = resolve(path, true) var res = resolve(path, true)
if (!res) throw new Error("File not found: " + path) if (!res) throw Error("File not found: " + path)
if (res.mount.type == 'zip') { if (res.mount.type == 'zip') {
var mod = res.mount.handle.mod(res.path) var mod = res.mount.handle.mod(res.path)
@@ -249,7 +249,7 @@ function stat(path) {
} }
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var s = res.mount.handle.stat(res.path) var s = res.mount.handle.stat(res.path)
if (!s) throw new Error("File not found in qop: " + path) if (!s) throw Error("File not found in qop: " + path)
return { return {
filesize: s.size, filesize: s.size,
modtime: s.modtime, modtime: s.modtime,
@@ -282,7 +282,7 @@ function mount_package(name) {
var dir = shop.get_package_dir(name) var dir = shop.get_package_dir(name)
if (!dir) { if (!dir) {
throw new Error("Package not found: " + name) throw Error("Package not found: " + name)
} }
mount(dir, name) mount(dir, name)
@@ -296,7 +296,7 @@ function match(str, pattern) {
function rm(path) { function rm(path) {
var res = resolve(path, true) var res = resolve(path, true)
if (res.mount.type != 'fs') throw new Error("Cannot delete from non-fs mount") if (res.mount.type != 'fs') throw Error("Cannot delete from non-fs mount")
var full_path = join_paths(res.mount.source, res.path) var full_path = join_paths(res.mount.source, res.path)
var st = fd.stat(full_path) var st = fd.stat(full_path)

View File

@@ -1,234 +0,0 @@
// HTTP Download Actor
// Handles download requests and progress queries
var http = use('http');
var os = use('os');
// Actor state
var state = {
downloading: false,
current_url: null,
total_bytes: 0,
downloaded_bytes: 0,
start_time: 0,
error: null,
connection: null,
download_msg: null,
chunks: []
};
// Helper to calculate progress percentage
function get_progress() {
if (state.total_bytes == 0) {
return 0;
}
return number.round((state.downloaded_bytes / state.total_bytes) * 100);
}
// Helper to format status response
function get_status() {
if (!state.downloading) {
return {
status: 'idle',
error: state.error
};
}
var elapsed = os.now() - state.start_time;
var bytes_per_sec = elapsed > 0 ? state.downloaded_bytes / elapsed : 0;
return {
status: 'downloading',
url: state.current_url,
progress: get_progress(),
downloaded_bytes: state.downloaded_bytes,
total_bytes: state.total_bytes,
elapsed_seconds: elapsed,
bytes_per_second: number.round(bytes_per_sec)
};
}
// Main message receiver
$receiver(function(msg) {
switch (msg.type) {
case 'download':
if (state.downloading) {
send(msg, {
type: 'error',
error: 'Already downloading',
current_url: state.current_url
});
return;
}
if (!msg.url) {
send(msg, {
type: 'error',
error: 'No URL provided'
});
return;
}
// Start download
state.downloading = true;
state.current_url = msg.url;
state.total_bytes = 0;
state.downloaded_bytes = 0;
state.start_time = os.now();
state.error = null;
state.download_msg = msg;
state.chunks = [];
try {
// Start the connection
state.connection = http.fetch_start(msg.url, msg.options || {});
if (!state.connection) {
throw new Error('Failed to start download');
}
// Schedule the first chunk read
$delay(read_next_chunk, 0);
} catch (e) {
state.error = e.toString();
state.downloading = false;
send(msg, {
type: 'error',
error: state.error,
url: msg.url
});
}
break;
case 'status':
log.console(`got status request. current is ${get_status()}`)
send(msg, {
type: 'status_response',
...get_status()
});
break;
case 'cancel':
if (state.downloading) {
// Cancel the download
if (state.connection) {
http.fetch_close(state.connection);
state.connection = null;
}
state.downloading = false;
state.current_url = null;
state.download_msg = null;
state.chunks = [];
send(msg, {
type: 'cancelled',
message: 'Download cancelled',
url: state.current_url
});
} else {
send(msg, {
type: 'error',
error: 'No download in progress'
});
}
break;
default:
send(msg, {
type: 'error',
error: 'Unknown message type: ' + msg.type
});
}
});
// Non-blocking chunk reader
function read_next_chunk() {
if (!state.downloading || !state.connection) {
return;
}
try {
var chunk = http.fetch_read_chunk(state.connection);
if (chunk == null) {
// Download complete
finish_download();
return;
}
// Store chunk
state.chunks.push(chunk);
// Update progress
var info = http.fetch_info(state.connection);
state.downloaded_bytes = info.bytes_read;
if (info.headers_complete && info.content_length > 0) {
state.total_bytes = info.content_length;
}
// Schedule next chunk read
$delay(read_next_chunk, 0);
} catch (e) {
// Error during download
state.error = e.toString();
if (state.connection) {
http.fetch_close(state.connection);
}
if (state.download_msg) {
send(state.download_msg, {
type: 'error',
error: state.error,
url: state.current_url
});
}
// Reset state
state.downloading = false;
state.connection = null;
state.download_msg = null;
state.chunks = [];
}
}
// Complete the download and send result
function finish_download() {
if (state.connection) {
http.fetch_close(state.connection);
}
// Combine all chunks into single ArrayBuffer
var total_size = 0;
for (var i = 0; i < state.chunks.length; i++) {
total_size += state.chunks[i].byteLength;
}
var result = new ArrayBuffer(total_size);
var view = new Uint8Array(result);
var offset = 0;
for (var i = 0; i < state.chunks.length; i++) {
var chunk_view = new Uint8Array(state.chunks[i]);
view.set(chunk_view, offset);
offset += state.chunks[i].byteLength;
}
// Send complete message
if (state.download_msg) {
send(state.download_msg, {
type: 'complete',
url: state.current_url,
data: result,
size: result.byteLength,
duration: os.now() - state.start_time
});
}
// Reset state
state.downloading = false;
state.connection = null;
state.current_url = null;
state.download_msg = null;
state.chunks = [];
}

View File

@@ -43,14 +43,14 @@ 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 new Error('Could not determine home directory') throw Error('Could not determine home directory')
} }
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 new Error('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.') throw Error('Cell shop not found at ' + shop_path + '. Run "cell install" to set up.')
} }
var use_cache = {} var use_cache = {}
@@ -104,7 +104,7 @@ function caller_data(depth = 0)
var file = "nofile" var file = "nofile"
var line = 0 var line = 0
var caller = new Error().stack.split("\n")[1+depth] var caller = Error().stack.split("\n")[1+depth]
if (caller) { if (caller) {
var md = caller.match(/\((.*)\:/) var md = caller.match(/\((.*)\:/)
var m = md ? md[1] : "SCRIPT" var m = md ? md[1] : "SCRIPT"
@@ -131,7 +131,7 @@ globalThis.log = function(name, args) {
os.print(console_rec(caller.line, caller.file, msg)) os.print(console_rec(caller.line, caller.file, msg))
break break
case 'error': case 'error':
msg = msg ?? new Error() msg = msg ?? Error()
if (is_proto(msg, Error)) if (is_proto(msg, Error))
msg = msg.name + ": " + msg.message + "\n" + msg.stack msg = msg.name + ": " + msg.message + "\n" + msg.stack
os.print(console_rec(caller.line, caller.file, msg)) os.print(console_rec(caller.line, caller.file, msg))
@@ -206,9 +206,9 @@ globalThis.sequence = pronto.sequence
$_.time_limit = function(requestor, seconds) $_.time_limit = function(requestor, seconds)
{ {
if (!pronto.is_requestor(requestor)) if (!pronto.is_requestor(requestor))
throw new Error('time_limit: first argument must be a requestor'); throw Error('time_limit: first argument must be a requestor');
if (!is_number(seconds) || seconds <= 0) if (!is_number(seconds) || seconds <= 0)
throw new Error('time_limit: seconds must be a positive number'); throw Error('time_limit: seconds must be a positive number');
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')
@@ -304,7 +304,7 @@ REPLYTIMEOUT = config.reply_timeout
function guid(bits = 256) function guid(bits = 256)
{ {
var guid = new blob(bits, os.random) var guid = blob(bits, os.random)
stone(guid) stone(guid)
return text(guid,'h') return text(guid,'h')
} }
@@ -372,8 +372,8 @@ 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 new Error(`Already started a portal listening on ${portal.port}`) if (portal) throw Error(`Already started a portal listening on ${portal.port}`)
if (!port) throw new Error("Requires a valid port.") if (!port) throw Error("Requires a valid port.")
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
@@ -453,9 +453,9 @@ $_.stop = function stop(actor) {
return return
} }
if (!is_actor(actor)) if (!is_actor(actor))
throw new Error('Can only call stop on an actor.') throw Error('Can only call stop on an actor.')
if (!underlings.has(actor[ACTORDATA].id)) if (!underlings.has(actor[ACTORDATA].id))
throw new Error('Can only call stop on an underling or self.') throw Error('Can only call stop on an underling or self.')
sys_msg(actor, {kind:"stop"}) sys_msg(actor, {kind:"stop"})
} }
@@ -508,9 +508,9 @@ 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 new Error(`Must send to an actor object. Attempted send to ${actor}`) if (!is_actor(actor) && !is_actor(actor.replycc)) throw Error(`Must send to an actor object. Attempted send to ${actor}`)
if (!is_object(message)) throw new Error('Must send an object record.') if (!is_object(message)) throw Error('Must send an object record.')
// message to self // message to self
if (actor[ACTORDATA].id == _cell.id) { if (actor[ACTORDATA].id == _cell.id) {
@@ -579,16 +579,16 @@ var replies = {}
globalThis.send = function send(actor, message, reply) { globalThis.send = function send(actor, message, reply) {
if (!is_object(actor)) if (!is_object(actor))
throw new Error(`Must send to an actor object. Provided: ${actor}`); throw Error(`Must send to an actor object. Provided: ${actor}`);
if (!is_object(message)) if (!is_object(message))
throw new Error('Message must be an object') throw Error('Message must be an object')
var send = {type:"user", data: message} var send = {type:"user", data: message}
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 new Error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`) throw Error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`)
actor = header.replycc actor = header.replycc
send.return = header.reply send.return = header.reply
@@ -699,7 +699,7 @@ function handle_sysym(msg)
letter2[HEADER] = msg letter2[HEADER] = msg
delete msg.data delete msg.data
portal_fn(letter2) portal_fn(letter2)
} else throw new Error('Got a contact message, but no portal is established.') } else throw Error('Got a contact message, but no portal is established.')
break break
case 'couple': // from must be notified when we die case 'couple': // from must be notified when we die
from = msg.from from = msg.from
@@ -764,7 +764,7 @@ if (!locator) {
} }
if (!locator) if (!locator)
throw new Error(`Main program ${_cell.args.program} could not be found`) throw Error(`Main program ${_cell.args.program} could not be found`)
stone(globalThis) stone(globalThis)
@@ -791,7 +791,7 @@ $_.clock(_ => {
var val = call(locator.symbol, null, _cell.args.arg, use_fn, ...vals) var val = call(locator.symbol, null, _cell.args.arg, use_fn, ...vals)
if (val) if (val)
throw new Error('Program must not return anything'); throw Error('Program must not return anything');
}) })
})() })()

View File

@@ -141,7 +141,7 @@ function package_in_shop(package) {
function abs_path_to_package(package_dir) function abs_path_to_package(package_dir)
{ {
if (!fd.is_file(package_dir + '/cell.toml')) if (!fd.is_file(package_dir + '/cell.toml'))
throw new Error('Not a valid package directory (no cell.toml): ' + package_dir) throw Error('Not a valid package directory (no cell.toml): ' + package_dir)
var packages_prefix = get_packages_dir() + '/' var packages_prefix = get_packages_dir() + '/'
var core_dir = packages_prefix + core_package var core_dir = packages_prefix + core_package
@@ -283,7 +283,7 @@ Shop.load_lock = function() {
// Save lock.toml configuration (to global shop) // Save lock.toml configuration (to global shop)
Shop.save_lock = function(lock) { Shop.save_lock = function(lock) {
var path = global_shop_path + '/lock.toml' var path = global_shop_path + '/lock.toml'
fd.slurpwrite(path, stone(new blob(toml.encode(lock)))); fd.slurpwrite(path, stone(blob(toml.encode(lock))));
} }
@@ -297,12 +297,12 @@ Shop.resolve_package_info = function(pkg) {
// Verify if a package name is valid and return status // Verify if a package name is valid and return status
Shop.verify_package_name = function(pkg) { Shop.verify_package_name = function(pkg) {
if (!pkg) throw new Error("Empty package name") if (!pkg) throw Error("Empty package name")
if (pkg == 'local') throw new Error("local is not a valid package name") if (pkg == 'local') throw Error("local is not a valid package name")
if (pkg == 'core') throw new Error("core is not a valid package name") if (pkg == 'core') throw Error("core is not a valid package name")
if (pkg.includes('://')) if (pkg.includes('://'))
throw new Error(`Invalid package name: ${pkg}; did you mean ${pkg.split('://')[1]}?`) throw Error(`Invalid package name: ${pkg}; did you mean ${pkg.split('://')[1]}?`)
} }
// Convert module package to download URL // Convert module package to download URL
@@ -413,7 +413,7 @@ var script_form = function(path, script, pkg, inject) {
// Resolve module function, hashing it in the process // Resolve module function, hashing it in the process
// path is the exact path to the script file // path is the exact path to the script file
function resolve_mod_fn(path, pkg) { function resolve_mod_fn(path, pkg) {
if (!fd.is_file(path)) throw new Error(`path ${path} is not a file`) if (!fd.is_file(path)) throw Error(`path ${path} is not a file`)
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
@@ -421,7 +421,7 @@ function resolve_mod_fn(path, pkg) {
var content = text(fd.slurp(path)) var content = text(fd.slurp(path))
var script = script_form(path, content, file_pkg, inject); var script = script_form(path, content, file_pkg, inject);
var obj = pull_from_cache(stone(new blob(script))) var obj = pull_from_cache(stone(blob(script)))
if (obj) { if (obj) {
var fn = js.compile_unblob(obj) var fn = js.compile_unblob(obj)
return js.eval_compile(fn) return js.eval_compile(fn)
@@ -433,7 +433,7 @@ function resolve_mod_fn(path, pkg) {
var fn = js.compile(compile_name, script) var fn = js.compile(compile_name, script)
put_into_cache(stone(new blob(script)), js.compile_blob(fn)) put_into_cache(stone(blob(script)), js.compile_blob(fn))
return js.eval_compile(fn) return js.eval_compile(fn)
} }
@@ -784,8 +784,10 @@ function make_use_fn(pkg) {
// Call a C module loader and execute the entrypoint // Call a C module loader and execute the entrypoint
function call_c_module(c_resolve) { function call_c_module(c_resolve) {
var entry = c_resolve.symbol() // load symbol (returns function) var mod = c_resolve.symbol()
return entry(null, my$_) // execute it to get exports/context // if (is_function(mod))
// return mod()
return mod
} }
function execute_module(info) function execute_module(info)
@@ -815,14 +817,14 @@ function execute_module(info)
// C only // C only
used = call_c_module(c_resolve) used = call_c_module(c_resolve)
} else { } else {
throw new Error(`Module ${info.path} could not be found`) throw Error(`Module ${info.path} could not be found`)
} }
if (is_function(used)) // if (is_function(used))
throw new Error('C module loader returned a function; did you forget to call it?') // throw Error('C module loader returned a function; did you forget to call it?')
if (!used) if (!used)
throw new Error(`Module ${info} returned null`) throw Error(`Module ${info} returned null`)
// stone(used) // stone(used)
return used return used
@@ -832,7 +834,7 @@ function get_module(path, package_context) {
var info = resolve_module_info(path, package_context) var info = resolve_module_info(path, package_context)
if (!info) if (!info)
throw new Error(`Module ${path} could not be found in ${package_context}`) throw Error(`Module ${path} could not be found in ${package_context}`)
return execute_module(info) return execute_module(info)
} }
@@ -840,7 +842,7 @@ function get_module(path, package_context) {
Shop.use = function use(path, package_context) { Shop.use = function use(path, package_context) {
var info = resolve_module_info(path, package_context) var info = resolve_module_info(path, package_context)
if (!info) if (!info)
throw new Error(`Module ${path} could not be found in ${package_context}`) throw Error(`Module ${path} could not be found in ${package_context}`)
if (use_cache[info.cache_key]) if (use_cache[info.cache_key])
return use_cache[info.cache_key] return use_cache[info.cache_key]
@@ -1007,14 +1009,14 @@ Shop.extract = function(pkg) {
var zip_blob = get_package_zip(pkg) var zip_blob = get_package_zip(pkg)
if (!zip_blob) if (!zip_blob)
throw new Error("No zip blob available for " + pkg) throw Error("No zip blob available for " + pkg)
// Extract zip for remote package // Extract zip for remote package
install_zip(zip_blob, target_dir) install_zip(zip_blob, target_dir)
// Write marker file with the extracted commit // Write marker file with the extracted commit
if (lock_entry && lock_entry.commit) { if (lock_entry && lock_entry.commit) {
fd.slurpwrite(target_dir + '/.cell_commit', stone(new blob(lock_entry.commit))) fd.slurpwrite(target_dir + '/.cell_commit', stone(blob(lock_entry.commit)))
} }
return true return true
@@ -1092,7 +1094,7 @@ Shop.update = function(pkg) {
function install_zip(zip_blob, target_dir) { function install_zip(zip_blob, target_dir) {
var zip = miniz.read(zip_blob) var zip = miniz.read(zip_blob)
if (!zip) throw new Error("Failed to read zip archive") if (!zip) throw Error("Failed to read zip archive")
if (fd.is_link(target_dir)) fd.unlink(target_dir) if (fd.is_link(target_dir)) fd.unlink(target_dir)
if (fd.is_dir(target_dir)) fd.rmdir(target_dir, 1) if (fd.is_dir(target_dir)) fd.rmdir(target_dir, 1)
@@ -1145,14 +1147,14 @@ Shop.get = function(pkg) {
if (!lock[pkg]) { if (!lock[pkg]) {
var info = Shop.resolve_package_info(pkg) var info = Shop.resolve_package_info(pkg)
if (!info) { if (!info) {
throw new Error("Invalid package: " + pkg) throw Error("Invalid package: " + pkg)
} }
var commit = null var commit = null
if (info != 'local') { if (info != 'local') {
commit = fetch_remote_hash(pkg) commit = fetch_remote_hash(pkg)
if (!commit) { if (!commit) {
throw new Error("Could not resolve commit for " + pkg) throw Error("Could not resolve commit for " + pkg)
} }
} }

View File

@@ -81,7 +81,7 @@ Link.save = function(links) {
link_cache = links link_cache = links
var cfg = { links: links } var cfg = { links: links }
var path = get_links_path() var path = get_links_path()
var b = new blob(toml.encode(cfg)) var b = blob(toml.encode(cfg))
stone(b) stone(b)
fd.slurpwrite(path, b) fd.slurpwrite(path, b)
} }
@@ -90,14 +90,14 @@ Link.add = function(canonical, target, shop) {
// Validate canonical package exists in shop // Validate canonical package exists in shop
var lock = shop.load_lock() var lock = shop.load_lock()
if (!lock[canonical]) { if (!lock[canonical]) {
throw new Error('Package ' + canonical + ' is not installed. Install it first with: cell get ' + canonical) throw Error('Package ' + canonical + ' is not installed. Install it first with: cell get ' + canonical)
} }
// Validate target is a valid package // Validate target is a valid package
if (target.startsWith('/')) { if (target.startsWith('/')) {
// Local path - must have cell.toml // Local path - must have cell.toml
if (!fd.is_file(target + '/cell.toml')) { if (!fd.is_file(target + '/cell.toml')) {
throw new Error('Target ' + target + ' is not a valid package (no cell.toml)') throw Error('Target ' + target + ' is not a valid package (no cell.toml)')
} }
} else { } else {
// Remote package target - ensure it's installed // Remote package target - ensure it's installed

View File

@@ -43,7 +43,7 @@ package.load_config = function(name)
{ {
var config_path = get_path(name) + '/cell.toml' var config_path = get_path(name) + '/cell.toml'
if (!fd.is_file(config_path)) if (!fd.is_file(config_path))
throw new Error(`${config_path} does not exist`) throw Error(`${config_path} does not exist`)
var content = text(fd.slurp(config_path)) var content = text(fd.slurp(config_path))
if (!content || content.trim().length == 0) if (!content || content.trim().length == 0)

224
parseq.cm
View File

@@ -1,224 +0,0 @@
// parseq.js (Misty edition)
// Douglas Crockford → adapted for Misty by ChatGPT, 20250529
// Better living thru eventuality!
/*
 The original parseq.js relied on the browser's setTimeout and ran in
 milliseconds. In Misty we may be given an optional @.delay capability
 (arguments[0]) and time limits are expressed in **seconds**. This rewrite
 removes the setTimeout dependency, uses the @.delay capability when it is
 present, and provides the factories described in the Misty specification:
    fallback, par_all, par_any, race, sequence
 Each factory returns a **requestor** function as described by the spec.
*/
def delay = arg[0] // may be null
// ———————————————————————————————————————— helpers
function make_reason (factory, excuse, evidence) {
def reason = new Error(`parseq.${factory}${excuse ? ': ' + excuse : ''}`)
reason.evidence = evidence
return reason
}
function is_requestor (fn) {
return is_function(fn) && (fn.length == 1 || fn.length == 2)
}
function check_requestors (list, factory) {
if (!is_array(list) || list.some(r => !is_requestor(r)))
throw make_reason(factory, 'Bad requestor list.', list)
}
function check_callback (cb, factory) {
if (!is_function(cb) || cb.length != 2)
throw make_reason(factory, 'Not a callback.', cb)
}
function schedule (fn, seconds) {
if (seconds == null || seconds <= 0) return fn()
if (is_function(delay)) return delay(fn, seconds)
throw make_reason('schedule', '@.delay capability required for timeouts.')
}
// ———————————————————————————————————————— core runner
function run (factory, requestors, initial, action, time_limit, throttle = 0) {
var cancel_list = new Array(requestors.length)
var next = 0
var timer_cancel
function cancel (reason = make_reason(factory, 'Cancel.')) {
if (timer_cancel) timer_cancel(), timer_cancel = null
if (!cancel_list) return
cancel_list.forEach(c => { try { if (is_function(c)) c(reason) } catch (_) {} })
cancel_list = null
}
function start_requestor (value) {
if (!cancel_list || next >= requestors.length) return
var idx = next++
def req = requestors[idx]
try {
cancel_list[idx] = req(function req_cb (val, reason) {
if (!cancel_list || idx == null) return
cancel_list[idx] = null
action(val, reason, idx)
idx = null
if (factory == 'sequence') start_requestor(val)
else if (throttle) start_requestor(initial)
}, value)
} catch (ex) {
action(null, ex, idx)
idx = null
if (factory == 'sequence') start_requestor(value)
else if (throttle) start_requestor(initial)
}
}
if (time_limit != null) {
if (!is_number(time_limit) || time_limit < 0)
throw make_reason(factory, 'Bad time limit.', time_limit)
if (time_limit > 0) timer_cancel = schedule(() => cancel(make_reason(factory, 'Timeout.', time_limit)), time_limit)
}
def concurrent = throttle ? number.min(throttle, requestors.length) : requestors.length
for (var i = 0; i < concurrent; i++) start_requestor(initial)
return cancel
}
// ———————————————————————————————————————— factories
function _normalize (collection, factory) {
if (is_array(collection)) return { names: null, list: collection }
if (collection && is_object(collection)) {
def names = array(collection)
def list = names.map(k => collection[k]).filter(is_requestor)
return { names, list }
}
throw make_reason(factory, 'Expected array or record.', collection)
}
function _denormalize (names, list) {
if (!names) return list
def obj = meme(null)
names.forEach((k, i) => { obj[k] = list[i] })
return obj
}
function par_all (collection, time_limit, throttle) {
def factory = 'par_all'
def { names, list } = _normalize(collection, factory)
if (list.length == 0) return (cb, v) => cb(names ? {} : [])
check_requestors(list, factory)
return function par_all_req (cb, initial) {
check_callback(cb, factory)
var pending = list.length
def results = new Array(list.length)
def cancel = run(factory, list, initial, (val, reason, idx) => {
if (val == null) {
cancel(reason)
return cb(null, reason)
}
results[idx] = val
if (--pending == 0) cb(_denormalize(names, results))
}, time_limit, throttle)
return cancel
}
}
function par_any (collection, time_limit, throttle) {
def factory = 'par_any'
def { names, list } = _normalize(collection, factory)
if (list.length == 0) return (cb, v) => cb(names ? {} : [])
check_requestors(list, factory)
return function par_any_req (cb, initial) {
check_callback(cb, factory)
var pending = list.length
def successes = new Array(list.length)
def cancel = run(factory, list, initial, (val, reason, idx) => {
pending--
if (val != null) successes[idx] = val
if (successes.some(v => v != null)) {
if (!pending) cancel(make_reason(factory, 'Finished.'))
return cb(_denormalize(names, successes.filter(v => v != null)))
}
if (!pending) cb(null, make_reason(factory, 'No successes.'))
}, time_limit, throttle)
return cancel
}
}
function race (list, time_limit, throttle) {
def factory = throttle == 1 ? 'fallback' : 'race'
if (!is_array(list) || list.length == 0)
throw make_reason(factory, 'No requestors.')
check_requestors(list, factory)
return function race_req (cb, initial) {
check_callback(cb, factory)
var done = false
def cancel = run(factory, list, initial, (val, reason, idx) => {
if (done) return
if (val != null) {
done = true
cancel(make_reason(factory, 'Loser.', idx))
cb(val)
} else if (--list.length == 0) {
done = true
cancel(reason)
cb(null, reason)
}
}, time_limit, throttle)
return cancel
}
}
function fallback (list, time_limit) {
return race(list, time_limit, 1)
}
function sequence (list, time_limit) {
def factory = 'sequence'
if (!is_array(list)) throw make_reason(factory, 'Not an array.', list)
check_requestors(list, factory)
if (list.length == 0) return (cb, v) => cb(v)
return function sequence_req (cb, initial) {
check_callback(cb, factory)
var idx = 0
function next (value) {
if (idx >= list.length) return cb(value)
try {
list[idx++](function seq_cb (val, reason) {
if (val == null) return cb(null, reason)
next(val)
}, value)
} catch (ex) {
cb(null, ex)
}
}
next(initial)
}
}
return {
fallback,
par_all,
par_any,
race,
sequence
}

View File

@@ -4,7 +4,7 @@
// Time is in seconds. // Time is in seconds.
function make_reason(factory, excuse, evidence) { function make_reason(factory, excuse, evidence) {
def reason = new Error(`pronto.${factory}${excuse ? ': ' + excuse : ''}`) def reason = Error(`pronto.${factory}${excuse ? ': ' + excuse : ''}`)
reason.evidence = evidence reason.evidence = evidence
return reason return reason
} }
@@ -14,7 +14,7 @@ function is_requestor(fn) {
} }
function check_requestors(list, factory) { function check_requestors(list, factory) {
if (!isa(list, array) || list.some(r => !is_requestor(r))) if (!is_array(list) || list.some(r => !is_requestor(r)))
throw make_reason(factory, 'Bad requestor array.', list) throw make_reason(factory, 'Bad requestor array.', list)
} }
@@ -27,7 +27,7 @@ function check_callback(cb, factory) {
// Tries each requestor in order until one succeeds. // Tries each requestor in order until one succeeds.
function fallback(requestor_array) { function fallback(requestor_array) {
def factory = 'fallback' def factory = 'fallback'
if (!isa(requestor_array, array) || requestor_array.length == 0) if (!is_array(requestor_array) || requestor_array.length == 0)
throw make_reason(factory, 'Empty requestor array.') throw make_reason(factory, 'Empty requestor array.')
check_requestors(requestor_array, factory) check_requestors(requestor_array, factory)
@@ -79,7 +79,7 @@ function fallback(requestor_array) {
// Runs requestors in parallel, collecting all results. // Runs requestors in parallel, collecting all results.
function parallel(requestor_array, throttle, need) { function parallel(requestor_array, throttle, need) {
def factory = 'parallel' def factory = 'parallel'
if (!isa(requestor_array, array)) if (!is_array(requestor_array))
throw make_reason(factory, 'Not an array.', requestor_array) throw make_reason(factory, 'Not an array.', requestor_array)
check_requestors(requestor_array, factory) check_requestors(requestor_array, factory)
@@ -96,8 +96,8 @@ function parallel(requestor_array, throttle, need) {
return function parallel_requestor(callback, value) { return function parallel_requestor(callback, value) {
check_callback(callback, factory) check_callback(callback, factory)
def results = new Array(length) def results = array(length)
def cancel_list = new Array(length) def cancel_list = array(length)
var next_index = 0 var next_index = 0
var successes = 0 var successes = 0
var failures = 0 var failures = 0
@@ -164,7 +164,7 @@ function parallel(requestor_array, throttle, need) {
// Runs requestors in parallel, returns first success(es). // Runs requestors in parallel, returns first success(es).
function race(requestor_array, throttle, need) { function race(requestor_array, throttle, need) {
def factory = 'race' def factory = 'race'
if (!isa(requestor_array, array) || requestor_array.length == 0) if (!is_array(requestor_array) || requestor_array.length == 0)
throw make_reason(factory, 'Empty requestor array.') throw make_reason(factory, 'Empty requestor array.')
check_requestors(requestor_array, factory) check_requestors(requestor_array, factory)
@@ -178,8 +178,8 @@ function race(requestor_array, throttle, need) {
return function race_requestor(callback, value) { return function race_requestor(callback, value) {
check_callback(callback, factory) check_callback(callback, factory)
def results = new Array(length) def results = array(length)
def cancel_list = new Array(length) def cancel_list = array(length)
var next_index = 0 var next_index = 0
var successes = 0 var successes = 0
var failures = 0 var failures = 0
@@ -249,7 +249,7 @@ function race(requestor_array, throttle, need) {
// Runs requestors one at a time, passing result to next. // Runs requestors one at a time, passing result to next.
function sequence(requestor_array) { function sequence(requestor_array) {
def factory = 'sequence' def factory = 'sequence'
if (!isa(requestor_array, array)) if (!is_array(requestor_array))
throw make_reason(factory, 'Not an array.', requestor_array) throw make_reason(factory, 'Not an array.', requestor_array)
check_requestors(requestor_array, factory) check_requestors(requestor_array, factory)
@@ -326,7 +326,7 @@ function objectify(factory_fn) {
throw make_reason(factory, 'Not a factory.', factory_fn) throw make_reason(factory, 'Not a factory.', factory_fn)
return function objectified_factory(object_of_requestors, ...rest) { return function objectified_factory(object_of_requestors, ...rest) {
if (!isa(object_of_requestors, object)) if (!is_object(object_of_requestors))
throw make_reason(factory, 'Expected an object.', object_of_requestors) throw make_reason(factory, 'Expected an object.', object_of_requestors)
def keys = array(object_of_requestors) def keys = array(object_of_requestors)
@@ -338,7 +338,7 @@ function objectify(factory_fn) {
return inner_requestor(function(results, reason) { return inner_requestor(function(results, reason) {
if (results == null) { if (results == null) {
callback(null, reason) callback(null, reason)
} else if (isa(results, array)) { } else if (is_array(results)) {
def obj = {} def obj = {}
keys.forEach((k, i) => { obj[k] = results[i] }) keys.forEach((k, i) => { obj[k] = results[i] })
callback(obj, reason) callback(obj, reason)

View File

@@ -40074,8 +40074,8 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
js_blob_proto_funcs, countof(js_blob_proto_funcs)); js_blob_proto_funcs, countof(js_blob_proto_funcs));
JSValue blob_ctor = JS_NewCFunction2(ctx, js_blob_constructor, "blob", 3, JSValue blob_ctor = JS_NewCFunction2(ctx, js_blob_constructor, "blob", 3,
JS_CFUNC_constructor, 0); JS_CFUNC_generic, 0);
JS_SetConstructor(ctx, blob_ctor, ctx->class_proto[JS_CLASS_BLOB]); // JS_SetConstructor(ctx, blob_ctor, ctx->class_proto[JS_CLASS_BLOB]);
JS_DefinePropertyValueStr(ctx, ctx->global_obj, "blob", blob_ctor, JS_DefinePropertyValueStr(ctx, ctx->global_obj, "blob", blob_ctor,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
} }

View File

@@ -313,7 +313,7 @@ function run_tests(package_name, specific_test) {
var ret = t.fn() var ret = t.fn()
if (is_text(ret)) { if (is_text(ret)) {
throw new Error(ret) throw Error(ret)
} else if (ret && (is_text(ret.message) || is_proto(ret, Error))) { } else if (ret && (is_text(ret.message) || is_proto(ret, Error))) {
throw ret throw ret
} }
@@ -628,7 +628,7 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
} }
} }
ensure_dir(report_dir) ensure_dir(report_dir)
fd.slurpwrite(`${report_dir}/test.txt`, stone(new blob(txt_report))) fd.slurpwrite(`${report_dir}/test.txt`, stone(blob(txt_report)))
log.console(`Report written to ${report_dir}/test.txt`) log.console(`Report written to ${report_dir}/test.txt`)
// Generate JSON per package // Generate JSON per package
@@ -645,7 +645,7 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
} }
var json_path = `${report_dir}/${pkg_res.package.replace(/\//g, '_')}.json` var json_path = `${report_dir}/${pkg_res.package.replace(/\//g, '_')}.json`
fd.slurpwrite(json_path, stone(new blob(json.encode(pkg_tests)))) fd.slurpwrite(json_path, stone(blob(json.encode(pkg_tests))))
} }
} }

View File

@@ -4,29 +4,29 @@ var os = use('os');
function assert(condition, message) { function assert(condition, message) {
if (!condition) { if (!condition) {
throw new Error(message || "Assertion failed"); throw Error(message || "Assertion failed");
} }
} }
function assertEqual(actual, expected, message) { function assertEqual(actual, expected, message) {
if (actual != expected) { if (actual != expected) {
throw new Error(message || "Expected " + expected + ", got " + actual); throw Error(message || "Expected " + expected + ", got " + actual);
} }
} }
return { return {
test_create_empty_blob: function() { test_create_empty_blob: function() {
var b = new Blob(); var b = Blob();
assertEqual(b.length, 0, "Empty blob should have length 0"); assertEqual(b.length, 0, "Empty blob should have length 0");
}, },
test_create_blob_with_capacity: function() { test_create_blob_with_capacity: function() {
var b = new Blob(100); var b = Blob(100);
assertEqual(b.length, 0, "New blob with capacity should still have length 0"); assertEqual(b.length, 0, "New blob with capacity should still have length 0");
}, },
test_write_and_read_single_bit: function() { test_write_and_read_single_bit: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
b.write_bit(false); b.write_bit(false);
b.write_bit(1); b.write_bit(1);
@@ -41,7 +41,7 @@ return {
}, },
test_out_of_range_read_throws_error: function() { test_out_of_range_read_throws_error: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
stone(b); stone(b);
@@ -63,7 +63,7 @@ return {
}, },
test_write_and_read_numbers: function() { test_write_and_read_numbers: function() {
var b = new Blob(); var b = Blob();
b.write_number(3.14159); b.write_number(3.14159);
b.write_number(-42); b.write_number(-42);
b.write_number(0); b.write_number(0);
@@ -77,7 +77,7 @@ return {
}, },
test_write_and_read_text: function() { test_write_and_read_text: function() {
var b = new Blob(); var b = Blob();
b.write_text("Hello"); b.write_text("Hello");
b.write_text("World"); b.write_text("World");
b.write_text("🎉"); b.write_text("🎉");
@@ -87,12 +87,12 @@ return {
}, },
test_write_and_read_blobs: function() { test_write_and_read_blobs: function() {
var b1 = new Blob(); var b1 = Blob();
b1.write_bit(true); b1.write_bit(true);
b1.write_bit(false); b1.write_bit(false);
b1.write_bit(true); b1.write_bit(true);
var b2 = new Blob(10); var b2 = Blob(10);
b2.write_blob(b1); b2.write_blob(b1);
b2.write_bit(false); b2.write_bit(false);
assertEqual(b2.length, 4, "Combined blob should have 4 bits"); assertEqual(b2.length, 4, "Combined blob should have 4 bits");
@@ -105,14 +105,14 @@ return {
}, },
test_blob_copy_constructor: function() { test_blob_copy_constructor: function() {
var b1 = new Blob(); var b1 = Blob();
b1.write_bit(true); b1.write_bit(true);
b1.write_bit(false); b1.write_bit(false);
b1.write_bit(true); b1.write_bit(true);
b1.write_bit(true); b1.write_bit(true);
stone(b1); stone(b1);
var b2 = new Blob(b1); var b2 = Blob(b1);
stone(b2); stone(b2);
assertEqual(b2.length, 4, "Copied blob should have same length"); assertEqual(b2.length, 4, "Copied blob should have same length");
assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(0), true);
@@ -120,13 +120,13 @@ return {
}, },
test_blob_partial_copy_constructor: function() { test_blob_partial_copy_constructor: function() {
var b1 = new Blob(); var b1 = Blob();
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
b1.write_bit(i % 2 == 0); b1.write_bit(i % 2 == 0);
} }
stone(b1); stone(b1);
var b2 = new Blob(b1, 2, 7); var b2 = Blob(b1, 2, 7);
stone(b2); stone(b2);
assertEqual(b2.length, 5, "Partial copy should have 5 bits"); assertEqual(b2.length, 5, "Partial copy should have 5 bits");
assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(0), true);
@@ -134,8 +134,8 @@ return {
}, },
test_create_blob_with_fill: function() { test_create_blob_with_fill: function() {
var b1 = new Blob(8, true); var b1 = Blob(8, true);
var b2 = new Blob(8, false); var b2 = Blob(8, false);
stone(b1); stone(b1);
stone(b2); stone(b2);
@@ -150,7 +150,7 @@ return {
var sequence = [true, false, true, true, false]; var sequence = [true, false, true, true, false];
var index = 0; var index = 0;
var b = new Blob(5, function() { var b = Blob(5, function() {
return sequence[index++] ? 1 : 0; return sequence[index++] ? 1 : 0;
}); });
@@ -161,7 +161,7 @@ return {
}, },
test_write_pad_and_check_padding: function() { test_write_pad_and_check_padding: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
b.write_bit(false); b.write_bit(false);
b.write_bit(true); b.write_bit(true);
@@ -175,7 +175,7 @@ return {
}, },
test_read_blob_from_stone_blob: function() { test_read_blob_from_stone_blob: function() {
var b1 = new Blob(); var b1 = Blob();
for (var i = 0; i < 16; i++) { for (var i = 0; i < 16; i++) {
b1.write_bit(i % 3 == 0); b1.write_bit(i % 3 == 0);
} }
@@ -190,7 +190,7 @@ return {
}, },
test_stone_blob_is_immutable: function() { test_stone_blob_is_immutable: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
stone(b); stone(b);
@@ -204,7 +204,7 @@ return {
}, },
test_multiple_stone_calls_are_safe: function() { test_multiple_stone_calls_are_safe: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
assert(!stone.p(b), "Blob should not be a stone before stone() call"); assert(!stone.p(b), "Blob should not be a stone before stone() call");
stone(b); stone(b);
@@ -218,7 +218,7 @@ return {
test_invalid_constructor_arguments: function() { test_invalid_constructor_arguments: function() {
var threw = false; var threw = false;
try { try {
var b = new Blob("invalid"); var b = Blob("invalid");
} catch (e) { } catch (e) {
threw = true; threw = true;
} }
@@ -226,7 +226,7 @@ return {
}, },
test_write_bit_validation: function() { test_write_bit_validation: function() {
var b = new Blob(); var b = Blob();
b.write_bit(0); b.write_bit(0);
b.write_bit(1); b.write_bit(1);
@@ -240,7 +240,7 @@ return {
}, },
test_complex_data_round_trip: function() { test_complex_data_round_trip: function() {
var b = new Blob(); var b = Blob();
b.write_text("Test"); b.write_text("Test");
b.write_number(123.456); b.write_number(123.456);
@@ -251,21 +251,21 @@ return {
var originalLength = b.length; var originalLength = b.length;
stone(b); stone(b);
var b2 = new Blob(b); var b2 = Blob(b);
stone(b2); stone(b2);
assertEqual(b2.length, originalLength, "Copy should have same length"); assertEqual(b2.length, originalLength, "Copy should have same length");
assertEqual(b2.read_text(0), "Test", "First text should match"); assertEqual(b2.read_text(0), "Test", "First text should match");
}, },
test_zero_capacity_blob: function() { test_zero_capacity_blob: function() {
var b = new Blob(0); var b = Blob(0);
assertEqual(b.length, 0, "Zero capacity blob should have length 0"); assertEqual(b.length, 0, "Zero capacity blob should have length 0");
b.write_bit(true); b.write_bit(true);
assertEqual(b.length, 1, "Should expand when writing"); assertEqual(b.length, 1, "Should expand when writing");
}, },
test_large_blob_handling: function() { test_large_blob_handling: function() {
var b = new Blob(); var b = Blob();
var testSize = 1000; var testSize = 1000;
for (var i = 0; i < testSize; i++) { for (var i = 0; i < testSize; i++) {
@@ -282,7 +282,7 @@ return {
}, },
test_non_stone_blob_read_methods_should_throw: function() { test_non_stone_blob_read_methods_should_throw: function() {
var b = new Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
b.write_number(42); b.write_number(42);
b.write_text("test"); b.write_text("test");
@@ -329,14 +329,14 @@ return {
}, },
test_empty_text_write_and_read: function() { test_empty_text_write_and_read: function() {
var b = new Blob(); var b = Blob();
b.write_text(""); b.write_text("");
stone(b); stone(b);
assertEqual(b.read_text(0), "", "Empty string should round-trip"); assertEqual(b.read_text(0), "", "Empty string should round-trip");
}, },
test_invalid_read_positions: function() { test_invalid_read_positions: function() {
var b = new Blob(); var b = Blob();
b.write_number(42); b.write_number(42);
stone(b); stone(b);

View File

@@ -12,7 +12,7 @@ return {
fd.write(f, bigdata) fd.write(f, bigdata)
fd.close(f) fd.close(f)
var data = new blob var data = blob()
var st = time.number() var st = time.number()
var f2 = fd.open(tmp, 'r') var f2 = fd.open(tmp, 'r')
var chunksize = 1024 // reduced for test var chunksize = 1024 // reduced for test

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 = 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 @@ var EPSILON = 1e-12
function stone_if_needed(b) { if (!stone.p(b)) stone(b) } function stone_if_needed(b) { if (!stone.p(b)) stone(b) }
function bytes_to_blob(bytes) { function bytes_to_blob(bytes) {
var b = new blob() var b = blob()
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
var byte = bytes[i] var byte = bytes[i]
for (var bit = 7; bit >= 0; bit--) b.write_bit((byte >> bit) & 1) for (var bit = 7; bit >= 0; bit--) b.write_bit((byte >> bit) & 1)
@@ -155,7 +155,7 @@ var testCases = [
str: "test", str: "test",
obj: { x: true } obj: { x: true }
}] }, }] },
{ name: 'empty_buffer', input: new blob() }, { name: 'empty_buffer', input: blob() },
{ name: 'nested_empty_array', input: [[]] }, { name: 'nested_empty_array', input: [[]] },
{ name: 'empty_key_value', input: { "": "" } }, { name: 'empty_key_value', input: { "": "" } },
{ name: 'small_float', input: 1e-10 }, { name: 'small_float', input: 1e-10 },

View File

@@ -1057,7 +1057,7 @@ return {
var b = meme(a) var b = meme(a)
if (!is_proto(b, a)) throw "is_proto failed on meme" if (!is_proto(b, a)) throw "is_proto failed on meme"
var c = new Error() var c = Error()
if (!is_proto(c, Error)) throw "is_proto failed new" if (!is_proto(c, Error)) throw "is_proto failed new"
}, },

View File

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

View File

@@ -101,7 +101,7 @@ var testCases = [
{ name: 'nested_object', input: { num: 42, arr: [1, -1, 2.5], str: 'test', obj: { x: true } } }, { name: 'nested_object', input: { num: 42, arr: [1, -1, 2.5], str: 'test', obj: { x: true } } },
{ name: 'empty_blob', input: new blob() }, { name: 'empty_blob', input: blob() },
{ name: 'nested_array', input: [[]] }, { name: 'nested_array', input: [[]] },
{ name: 'empty_key_val', input: { '': '' } }, { name: 'empty_key_val', input: { '': '' } },
{ name: 'small_float', input: 1e-10 } { name: 'small_float', input: 1e-10 }