6 Commits

Author SHA1 Message Date
John Alanbrook
a1b41d5ecf rm push/pop 2026-02-26 08:13:18 -06:00
John Alanbrook
eb19b18594 slow messags 2026-02-26 00:56:43 -06:00
John Alanbrook
e203700d37 Merge branch 'fix_log_err' 2026-02-25 23:30:36 -06:00
John Alanbrook
c56444556d fix log in engine err 2026-02-25 23:30:32 -06:00
John Alanbrook
080e675d18 better update output 2026-02-25 23:29:37 -06:00
John Alanbrook
957b964d9d better disrupt message on fd 2026-02-25 20:38:34 -06:00
67 changed files with 20095 additions and 19708 deletions

View File

@@ -114,13 +114,13 @@ var run = function() {
total_scripts = total_scripts + result.total
arrfor(result.errors, function(e) {
push(all_failures, p + ": " + e)
all_failures[] = p + ": " + e
})
// Check use() resolution
resolution = shop.audit_use_resolution(p)
arrfor(resolution.unresolved, function(u) {
push(all_unresolved, p + '/' + u.script + ": use('" + u.module + "') cannot be resolved")
all_unresolved[] = p + '/' + u.script + ": use('" + u.module + "') cannot be resolved"
})
})

View File

@@ -28,7 +28,7 @@ function strip_mode_flags() {
} else if (a == '--compare') {
bench_mode = "compare"
} else {
push(filtered, a)
filtered[] = a
}
})
_args = filtered
@@ -197,7 +197,7 @@ function collect_benches(package_name, specific_bench) {
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (bench_name != match_base) return
}
push(bench_files, f)
bench_files[] = f
}
})
return bench_files
@@ -355,7 +355,7 @@ function run_single_bench(bench_fn, bench_name) {
if (teardown_fn) teardown_fn(state)
ns_per_op = is_batch ? duration / batch_size : duration
push(timings_per_op, ns_per_op)
timings_per_op[] = ns_per_op
} else {
start = os.now()
if (is_batch) {
@@ -366,7 +366,7 @@ function run_single_bench(bench_fn, bench_name) {
duration = os.now() - start
ns_per_op = is_batch ? duration / batch_size : duration
push(timings_per_op, ns_per_op)
timings_per_op[] = ns_per_op
}
}
@@ -442,11 +442,11 @@ function load_bench_module(f, package_name, mode) {
function collect_bench_fns(bench_mod) {
var benches = []
if (is_function(bench_mod)) {
push(benches, {name: 'main', fn: bench_mod})
benches[] = {name: 'main', fn: bench_mod}
} else if (is_object(bench_mod)) {
arrfor(array(bench_mod), function(k) {
if (is_function(bench_mod[k]))
push(benches, {name: k, fn: bench_mod[k]})
benches[] = {name: k, fn: bench_mod[k]}
})
}
return benches
@@ -524,7 +524,7 @@ function run_benchmarks(package_name, specific_bench) {
result = run_single_bench(b.fn, b.name)
result.package = pkg_result.package
result.mode = bench_mode == "compare" ? "bytecode" : bench_mode
push(file_result.benchmarks, result)
file_result.benchmarks[] = result
pkg_result.total++
log.console(` ${result.name}`)
@@ -538,7 +538,7 @@ function run_benchmarks(package_name, specific_bench) {
nat_result = run_single_bench(native_benches[nat_b].fn, b.name)
nat_result.package = pkg_result.package
nat_result.mode = "native"
push(file_result.benchmarks, nat_result)
file_result.benchmarks[] = nat_result
pkg_result.total++
print_bench_result(nat_result, "native ")
@@ -570,7 +570,7 @@ function run_benchmarks(package_name, specific_bench) {
name: b.name,
error: "benchmark disrupted"
}
push(file_result.benchmarks, error_result)
file_result.benchmarks[] = error_result
pkg_result.total++
}
})
@@ -586,12 +586,12 @@ function run_benchmarks(package_name, specific_bench) {
name: "load_module",
error: "error loading module"
}
push(file_result.benchmarks, error_result)
file_result.benchmarks[] = error_result
pkg_result.total++
}
if (length(file_result.benchmarks) > 0) {
push(pkg_result.files, file_result)
pkg_result.files[] = file_result
}
})
@@ -604,15 +604,15 @@ var packages = null
if (all_pkgs) {
if (testlib.is_valid_package('.')) {
push(all_results, run_benchmarks(null, null))
all_results[] = run_benchmarks(null, null)
}
packages = shop.list_packages()
arrfor(packages, function(p) {
push(all_results, run_benchmarks(p, null))
all_results[] = run_benchmarks(p, null)
})
} else {
push(all_results, run_benchmarks(target_pkg, target_bench))
all_results[] = run_benchmarks(target_pkg, target_bench)
}
// Calculate totals
@@ -688,7 +688,7 @@ Total benchmarks: ${total_benches}
var pkg_benches = []
arrfor(pkg_res.files, function(f) {
arrfor(f.benchmarks, function(benchmark) {
push(pkg_benches, benchmark)
pkg_benches[] = benchmark
})
})

View File

@@ -27,13 +27,13 @@ function send(mailbox, msg) {
function receive(mailbox) {
if (length(mailbox.queue) == 0) return null
mailbox.delivered++
return pop(mailbox.queue)
return mailbox.queue[]
}
function drain(mailbox) {
var count = 0
while (length(mailbox.queue) > 0) {
pop(mailbox.queue)
mailbox.queue[]
count++
}
return count

View File

@@ -13,13 +13,13 @@ function generate_records(n) {
var dept_vals = ["eng", "sales", "ops", "hr", "marketing"]
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(records, {
records[] = {
id: i + 1,
name: `user_${i}`,
score: (x % 1000) / 10,
status: status_vals[i % 4],
department: dept_vals[i % 5]
})
}
}
return records
}
@@ -30,7 +30,7 @@ function filter_records(records, field, value) {
var i = 0
for (i = 0; i < length(records); i++) {
if (records[i][field] == value) {
push(result, records[i])
result[] = records[i]
}
}
return result
@@ -45,7 +45,7 @@ function group_by(records, field) {
key = records[i][field]
if (!key) key = "unknown"
if (!groups[key]) groups[key] = []
push(groups[key], records[i])
groups[key][] = records[i]
}
return groups
}
@@ -70,13 +70,13 @@ function aggregate(groups) {
if (grp[j].score < mn) mn = grp[j].score
if (grp[j].score > mx) mx = grp[j].score
}
push(result, {
result[] = {
group: keys[i],
count: length(grp),
average: total / length(grp),
low: mn,
high: mx
})
}
}
return result
}

View File

@@ -57,7 +57,7 @@ function build_chain(n) {
var constraints = []
var i = 0
for (i = 0; i < n; i++) {
push(vars, make_variable(`v${i}`, 0))
vars[] = make_variable(`v${i}`, 0)
}
// Set first variable
@@ -69,8 +69,8 @@ function build_chain(n) {
self.variables[1].value = self.variables[0].value + 1
self.output = self.variables[1]
})
push(constraints, c)
push(vars[i].constraints, c)
constraints[] = c
vars[i].constraints[] = c
}
return {vars: vars, constraints: constraints}
@@ -83,8 +83,8 @@ function build_projection(n) {
var constraints = []
var i = 0
for (i = 0; i < n; i++) {
push(src, make_variable(`src${i}`, i * 10))
push(dst, make_variable(`dst${i}`, 0))
src[] = make_variable(`src${i}`, i * 10)
dst[] = make_variable(`dst${i}`, 0)
}
var scale_c = null
@@ -93,8 +93,8 @@ function build_projection(n) {
self.variables[1].value = self.variables[0].value * 2 + 1
self.output = self.variables[1]
})
push(constraints, scale_c)
push(dst[i].constraints, scale_c)
constraints[] = scale_c
dst[i].constraints[] = scale_c
}
return {src: src, dst: dst, constraints: constraints}

View File

@@ -12,7 +12,7 @@ function make_words(count) {
var words = []
var i = 0
for (i = 0; i < count; i++) {
push(words, base_words[i % length(base_words)])
words[] = base_words[i % length(base_words)]
}
return words
}
@@ -39,7 +39,7 @@ function top_n(freq, n) {
var pairs = []
var i = 0
for (i = 0; i < length(keys); i++) {
push(pairs, {word: keys[i], count: freq[keys[i]]})
pairs[] = {word: keys[i], count: freq[keys[i]]}
}
var sorted = sort(pairs, "count")
// Return last N (highest counts)
@@ -47,7 +47,7 @@ function top_n(freq, n) {
var start = length(sorted) - n
if (start < 0) start = 0
for (i = start; i < length(sorted); i++) {
push(result, sorted[i])
result[] = sorted[i]
}
return result
}
@@ -62,7 +62,7 @@ function group_by_length(words) {
w = words[i]
k = text(length(w))
if (!groups[k]) groups[k] = []
push(groups[k], w)
groups[k][] = w
}
return groups
}

View File

@@ -27,13 +27,13 @@ function make_array_data(size) {
var arr = []
var i = 0
for (i = 0; i < size; i++) {
push(arr, {
arr[] = {
id: i,
name: `item_${i}`,
active: i % 2 == 0,
score: i * 1.5,
tags: [`tag_${i % 5}`, `tag_${(i + 1) % 5}`]
})
}
}
return arr
}

View File

@@ -16,7 +16,7 @@ function make_obj_yx(x, y) {
function make_packed_array(n) {
var a = []
var i = 0
for (i = 0; i < n; i++) push(a, i)
for (i = 0; i < n; i++) a[] = i
return a
}
@@ -144,7 +144,7 @@ return {
var a = null
for (j = 0; j < n; j++) {
a = []
for (i = 0; i < 256; i++) push(a, i)
for (i = 0; i < 256; i++) a[] = i
x = (x + length(a)) | 0
}
return blackhole(sink, x)

View File

@@ -272,7 +272,7 @@ return {
for (i = 0; i < n; i++) {
push(a, i)
if (length(a) > 64) {
v = pop(a)
v = a[]
x = (x + v) | 0
}
}

View File

@@ -16,21 +16,21 @@ function tokenize(src) {
ch = chars[i]
if (ch == " " || ch == "\n" || ch == "\t") {
if (length(buf) > 0) {
push(tokens, buf)
tokens[] = buf
buf = ""
}
} else if (ch == "(" || ch == ")" || ch == "+" || ch == "-"
|| ch == "*" || ch == "=" || ch == ";" || ch == ",") {
if (length(buf) > 0) {
push(tokens, buf)
tokens[] = buf
buf = ""
}
push(tokens, ch)
tokens[] = ch
} else {
buf = buf + ch
}
}
if (length(buf) > 0) push(tokens, buf)
if (length(buf) > 0) tokens[] = buf
return tokens
}
@@ -49,21 +49,21 @@ function parse_tokens(tokens) {
i++ // skip =
i++
if (i < length(tokens)) node.value = tokens[i]
push(ast, node)
ast[] = node
} else if (tok == "return") {
node = {type: "return", value: null}
i++
if (i < length(tokens)) node.value = tokens[i]
push(ast, node)
ast[] = node
} else if (tok == "function") {
node = {type: "func", name: null, body: []}
i++
if (i < length(tokens)) node.name = tokens[i]
// Skip to matching )
while (i < length(tokens) && tokens[i] != ")") i++
push(ast, node)
ast[] = node
} else {
push(ast, {type: "expr", value: tok})
ast[] = {type: "expr", value: tok}
}
}
return ast
@@ -121,7 +121,7 @@ function simulate_build(n_modules, deps_per_module) {
// Generate all module sources
for (i = 0; i < n_modules; i++) {
src = generate_module(i, deps_per_module)
push(modules, src)
modules[] = src
}
// "Load" each module: tokenize → parse → evaluate
@@ -173,7 +173,7 @@ function topo_sort(n_modules, deps_per_module) {
for (j = 0; j < deps_per_module; j++) {
if (j < i) {
dep = "mod_" + text(j)
push(adj[dep], name)
adj[dep][] = name
in_degree[name] = in_degree[name] + 1
}
}
@@ -183,7 +183,7 @@ function topo_sort(n_modules, deps_per_module) {
var queue = []
var keys = array(in_degree)
for (i = 0; i < length(keys); i++) {
if (in_degree[keys[i]] == 0) push(queue, keys[i])
if (in_degree[keys[i]] == 0) queue[] = keys[i]
}
var order = []
@@ -193,12 +193,12 @@ function topo_sort(n_modules, deps_per_module) {
while (qi < length(queue)) {
current = queue[qi]
qi++
push(order, current)
order[] = current
neighbors = adj[current]
if (neighbors) {
for (i = 0; i < length(neighbors); i++) {
in_degree[neighbors[i]] = in_degree[neighbors[i]] - 1
if (in_degree[neighbors[i]] == 0) push(queue, neighbors[i])
if (in_degree[neighbors[i]] == 0) queue[] = neighbors[i]
}
}
}

View File

@@ -7,7 +7,7 @@ function make_random_array(n, seed) {
var i = 0
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(a, x % 10000)
a[] = x % 10000
}
return a
}
@@ -15,7 +15,7 @@ function make_random_array(n, seed) {
function make_descending(n) {
var a = []
var i = 0
for (i = n - 1; i >= 0; i--) push(a, i)
for (i = n - 1; i >= 0; i--) a[] = i
return a
}
@@ -58,19 +58,19 @@ function merge(a, b) {
var j = 0
while (i < length(a) && j < length(b)) {
if (a[i] <= b[j]) {
push(result, a[i])
result[] = a[i]
i++
} else {
push(result, b[j])
result[] = b[j]
j++
}
}
while (i < length(a)) {
push(result, a[i])
result[] = a[i]
i++
}
while (j < length(b)) {
push(result, b[j])
result[] = b[j]
j++
}
return result
@@ -97,7 +97,7 @@ function sort_records(n) {
var i = 0
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(records, {id: i, score: x % 10000, name: `item_${i}`})
records[] = {id: i, score: x % 10000, name: `item_${i}`}
}
return sort(records, "score")
}

View File

@@ -23,7 +23,7 @@ function build_index(txt) {
if (!index[w]) {
index[w] = []
}
push(index[w], i)
index[w][] = i
}
return index
}

View File

@@ -48,7 +48,7 @@ function tree_map(node, fn) {
function tree_flatten(node, result) {
if (!node) return null
tree_flatten(node.left, result)
push(result, node.val)
result[] = node.val
tree_flatten(node.right, result)
return null
}
@@ -126,7 +126,7 @@ return {
// Build a balanced BST of 1024 elements
var data = []
var i = 0
for (i = 0; i < 1024; i++) push(data, i)
for (i = 0; i < 1024; i++) data[] = i
var bst = build_balanced(data, 0, 1023)
var found = 0
for (i = 0; i < n; i++) {

View File

@@ -95,12 +95,12 @@ function benchArrayOps() {
var arr = [];
var j = 0
for (j = 0; j < iterations.medium; j++) {
push(arr, j);
arr[] = j;
}
});
var arr = [];
for (i = 0; i < 10000; i++) push(arr, i);
for (i = 0; i < 10000; i++) arr[] = i;
var accessTime = measureTime(function() {
var sum = 0;
@@ -188,7 +188,7 @@ function benchStringOps() {
});
for (i = 0; i < 1000; i++) {
push(strings, "string" + i);
strings[] = "string" + i;
}
var joinTime = measureTime(function() {
@@ -261,13 +261,13 @@ function benchClosures() {
var funcs = [];
var j = 0
for (j = 0; j < iterations.medium; j++) {
push(funcs, makeAdder(j));
funcs[] = makeAdder(j);
}
});
var adders = [];
for (i = 0; i < 1000; i++) {
push(adders, makeAdder(i));
adders[] = makeAdder(i);
}
var closureCallTime = measureTime(function() {

View File

@@ -15,7 +15,7 @@ var nll = null
var oll = null
for (i = 0; i < 10000; i++) {
accstr += i;
push(newarr, text(i))
newarr[] = text(i)
}
var jsonDecodeTimes = [];
var jsonEncodeTimes = [];
@@ -26,19 +26,19 @@ var notaSizes = [];
for (i = 0; i < 100; i++) {
start = os.now();
jll = json.decode(ll);
push(jsonDecodeTimes, (os.now() - start) * 1000);
jsonDecodeTimes[] = (os.now() - start) * 1000;
start = os.now();
jsonStr = JSON.stringify(jll);
push(jsonEncodeTimes, (os.now() - start) * 1000);
jsonEncodeTimes[] = (os.now() - start) * 1000;
start = os.now();
nll = nota.encode(jll);
push(notaEncodeTimes, (os.now() - start) * 1000);
notaEncodeTimes[] = (os.now() - start) * 1000;
start = os.now();
oll = nota.decode(nll);
push(notaDecodeTimes, (os.now() - start) * 1000);
notaDecodeTimes[] = (os.now() - start) * 1000;
}
function getStats(arr) {

View File

@@ -99,7 +99,7 @@ function runBenchmarkForLibrary(lib, bench) {
for (j = 0; j < length(bench.data); j++) {
e = lib.encode(bench.data[j]);
if (i == 0) {
push(encodedList, e);
encodedList[] = e;
totalSize += lib.getSize(e);
}
}

View File

@@ -5251,88 +5251,54 @@
["add", 29, 29, 7, 260, 17],
["jump", "while_start_360", 260, 17],
"while_end_361",
["access", 7, "bootstrap: native cache seeded\n", 262, 12],
[
"access",
11,
{
"name": "os",
"kind": "name",
"make": "intrinsic"
},
262,
3
],
["is_proxy", 12, 11, 262, 3],
["jump_false", 12, "record_path_368", 262, 3],
["null", 12, 262, 3],
["access", 14, "print", 262, 3],
["array", 31, 0, 262, 3],
["stone_text", 7],
["push", 31, 7, 262, 3],
["frame", 32, 11, 2, 262, 3],
["setarg", 32, 0, 12, 262, 3],
["stone_text", 14],
["setarg", 32, 1, 14, 262, 3],
["setarg", 32, 2, 31, 262, 3],
["invoke", 32, 12, 262, 3],
["jump", "call_done_369", 262, 3],
"record_path_368",
["load_field", 14, 11, "print", 262, 3],
["frame", 31, 14, 1, 262, 3],
["setarg", 31, 0, 11, 262, 3],
["stone_text", 7],
["setarg", 31, 1, 7, 262, 3],
["invoke", 31, 12, 262, 3],
"call_done_369",
["jump", "if_end_350", 262, 3],
["jump", "if_end_350", 260, 17],
"if_else_349",
["record", 7, 2],
["access", 11, "tokenize", 266, 12],
["store_field", 7, 11, "name", 266, 12],
["access", 11, "tokenize.cm", 266, 30],
["store_field", 7, 11, "path", 266, 30],
["access", 11, "tokenize", 265, 12],
["store_field", 7, 11, "name", 265, 12],
["access", 11, "tokenize.cm", 265, 30],
["store_field", 7, 11, "path", 265, 30],
["record", 11, 2],
["access", 12, "parse", 267, 12],
["store_field", 11, 12, "name", 267, 12],
["access", 12, "parse.cm", 267, 27],
["store_field", 11, 12, "path", 267, 27],
["access", 12, "parse", 266, 12],
["store_field", 11, 12, "name", 266, 12],
["access", 12, "parse.cm", 266, 27],
["store_field", 11, 12, "path", 266, 27],
["record", 12, 2],
["access", 14, "fold", 268, 12],
["store_field", 12, 14, "name", 268, 12],
["access", 14, "fold.cm", 268, 26],
["store_field", 12, 14, "path", 268, 26],
["access", 14, "fold", 267, 12],
["store_field", 12, 14, "name", 267, 12],
["access", 14, "fold.cm", 267, 26],
["store_field", 12, 14, "path", 267, 26],
["record", 14, 2],
["access", 31, "mcode", 269, 12],
["store_field", 14, 31, "name", 269, 12],
["access", 31, "mcode.cm", 269, 27],
["store_field", 14, 31, "path", 269, 27],
["access", 31, "mcode", 268, 12],
["store_field", 14, 31, "name", 268, 12],
["access", 31, "mcode.cm", 268, 27],
["store_field", 14, 31, "path", 268, 27],
["record", 31, 2],
["access", 32, "streamline", 270, 12],
["store_field", 31, 32, "name", 270, 12],
["access", 32, "streamline.cm", 270, 32],
["store_field", 31, 32, "path", 270, 32],
["access", 32, "streamline", 269, 12],
["store_field", 31, 32, "name", 269, 12],
["access", 32, "streamline.cm", 269, 32],
["store_field", 31, 32, "path", 269, 32],
["record", 32, 2],
["access", 33, "engine", 271, 12],
["store_field", 32, 33, "name", 271, 12],
["access", 33, "internal/engine.cm", 271, 28],
["store_field", 32, 33, "path", 271, 28],
["array", 33, 6, 271, 28],
["push", 33, 7, 271, 28],
["push", 33, 11, 271, 28],
["push", 33, 12, 271, 28],
["push", 33, 14, 271, 28],
["push", 33, 31, 271, 28],
["push", 33, 32, 271, 28],
["move", 28, 33, 271, 28],
["access", 29, 0, 273, 9],
"while_start_370",
["length", 7, 28, 274, 23],
["lt", 11, 29, 7, 274, 23],
["jump_false", 11, "while_end_371", 274, 23],
["load_dynamic", 7, 28, 29, 275, 20],
["move", 30, 7, 275, 20],
["load_field", 11, 7, "name", 276, 23],
["access", 33, "engine", 270, 12],
["store_field", 32, 33, "name", 270, 12],
["access", 33, "internal/engine.cm", 270, 28],
["store_field", 32, 33, "path", 270, 28],
["array", 33, 6, 270, 28],
["push", 33, 7, 270, 28],
["push", 33, 11, 270, 28],
["push", 33, 12, 270, 28],
["push", 33, 14, 270, 28],
["push", 33, 31, 270, 28],
["push", 33, 32, 270, 28],
["move", 28, 33, 270, 28],
["access", 29, 0, 272, 9],
"while_start_368",
["length", 7, 28, 273, 23],
["lt", 11, 29, 7, 273, 23],
["jump_false", 11, "while_end_369", 273, 23],
["load_dynamic", 7, 28, 29, 274, 20],
["move", 30, 7, 274, 20],
["load_field", 11, 7, "name", 275, 23],
[
"access",
7,
@@ -5341,24 +5307,24 @@
"kind": "name",
"make": "intrinsic"
},
276,
275,
33
],
["access", 12, "/", 276, 45],
["is_text", 14, 7, 276, 45],
["jump_false", 14, "add_cn_373", 276, 45],
["access", 12, "/", 275, 45],
["is_text", 14, 7, 275, 45],
["jump_false", 14, "add_cn_371", 275, 45],
"_nop_tc_7",
"_nop_tc_8",
["concat", 31, 7, 12, 276, 45],
["jump", "add_done_372", 276, 45],
"add_cn_373",
["is_num", 14, 7, 276, 45],
["jump_false", 14, "add_err_374", 276, 45],
["concat", 31, 7, 12, 275, 45],
["jump", "add_done_370", 275, 45],
"add_cn_371",
["is_num", 14, 7, 275, 45],
["jump_false", 14, "add_err_372", 275, 45],
"_nop_tc_9",
"_nop_dj_3",
"_nop_ucfg_6",
"_nop_ucfg_7",
"add_err_374",
"add_err_372",
[
"access",
7,
@@ -5367,38 +5333,38 @@
"kind": "name",
"make": "intrinsic"
},
276,
275,
45
],
["access", 12, "error", 276, 45],
["access", 14, "cannot apply '+': operands must both be text or both be numbers", 276, 45],
["array", 32, 0, 276, 45],
["access", 12, "error", 275, 45],
["access", 14, "cannot apply '+': operands must both be text or both be numbers", 275, 45],
["array", 32, 0, 275, 45],
["stone_text", 14],
["push", 32, 14, 276, 45],
["frame", 14, 7, 2, 276, 45],
["null", 7, 276, 45],
["setarg", 14, 0, 7, 276, 45],
["push", 32, 14, 275, 45],
["frame", 14, 7, 2, 275, 45],
["null", 7, 275, 45],
["setarg", 14, 0, 7, 275, 45],
["stone_text", 12],
["setarg", 14, 1, 12, 276, 45],
["setarg", 14, 2, 32, 276, 45],
["invoke", 14, 7, 276, 45],
["disrupt", 276, 45],
"add_done_372",
["load_field", 7, 30, "path", 276, 51],
["setarg", 14, 1, 12, 275, 45],
["setarg", 14, 2, 32, 275, 45],
["invoke", 14, 7, 275, 45],
["disrupt", 275, 45],
"add_done_370",
["load_field", 7, 30, "path", 275, 51],
"_nop_tc_4",
"_nop_tc_5",
["is_text", 12, 7, 276, 51],
["jump_false", 12, "add_cn_376", 276, 51],
["concat", 12, 31, 7, 276, 51],
["jump", "add_done_375", 276, 51],
"add_cn_376",
["is_text", 12, 7, 275, 51],
["jump_false", 12, "add_cn_374", 275, 51],
["concat", 12, 31, 7, 275, 51],
["jump", "add_done_373", 275, 51],
"add_cn_374",
"_nop_tc_6",
["jump", "add_err_377", 276, 51],
["jump", "add_err_375", 275, 51],
"_nop_ucfg_5",
"_nop_ucfg_6",
"_nop_ucfg_7",
"_nop_ucfg_8",
"add_err_377",
"add_err_375",
[
"access",
7,
@@ -5407,71 +5373,37 @@
"kind": "name",
"make": "intrinsic"
},
276,
275,
51
],
["access", 14, "error", 276, 51],
["access", 31, "cannot apply '+': operands must both be text or both be numbers", 276, 51],
["array", 32, 0, 276, 51],
["access", 14, "error", 275, 51],
["access", 31, "cannot apply '+': operands must both be text or both be numbers", 275, 51],
["array", 32, 0, 275, 51],
["stone_text", 31],
["push", 32, 31, 276, 51],
["frame", 31, 7, 2, 276, 51],
["null", 7, 276, 51],
["setarg", 31, 0, 7, 276, 51],
["push", 32, 31, 275, 51],
["frame", 31, 7, 2, 275, 51],
["null", 7, 275, 51],
["setarg", 31, 0, 7, 275, 51],
["stone_text", 14],
["setarg", 31, 1, 14, 276, 51],
["setarg", 31, 2, 32, 276, 51],
["invoke", 31, 7, 276, 51],
["disrupt", 276, 51],
"add_done_375",
["frame", 7, 10, 2, 276, 5],
["setarg", 7, 1, 11, 276, 5],
["setarg", 31, 1, 14, 275, 51],
["setarg", 31, 2, 32, 275, 51],
["invoke", 31, 7, 275, 51],
["disrupt", 275, 51],
"add_done_373",
["frame", 7, 10, 2, 275, 5],
["setarg", 7, 1, 11, 275, 5],
["stone_text", 12],
["setarg", 7, 2, 12, 276, 5],
["invoke", 7, 11, 276, 5],
["access", 7, 1, 277, 17],
["add", 29, 29, 7, 277, 17],
["jump", "while_start_370", 277, 17],
"while_end_371",
["access", 7, "bootstrap: cache seeded\n", 279, 12],
[
"access",
10,
{
"name": "os",
"kind": "name",
"make": "intrinsic"
},
279,
3
],
["is_proxy", 11, 10, 279, 3],
["jump_false", 11, "record_path_378", 279, 3],
["null", 11, 279, 3],
["access", 12, "print", 279, 3],
["array", 14, 0, 279, 3],
["stone_text", 7],
["push", 14, 7, 279, 3],
["frame", 28, 10, 2, 279, 3],
["setarg", 28, 0, 11, 279, 3],
["stone_text", 12],
["setarg", 28, 1, 12, 279, 3],
["setarg", 28, 2, 14, 279, 3],
["invoke", 28, 11, 279, 3],
["jump", "call_done_379", 279, 3],
"record_path_378",
["load_field", 12, 10, "print", 279, 3],
["frame", 14, 12, 1, 279, 3],
["setarg", 14, 0, 10, 279, 3],
["stone_text", 7],
["setarg", 14, 1, 7, 279, 3],
["invoke", 14, 11, 279, 3],
"call_done_379",
["setarg", 7, 2, 12, 275, 5],
["invoke", 7, 11, 275, 5],
["access", 7, 1, 276, 17],
["add", 29, 29, 7, 276, 17],
["jump", "while_start_368", 276, 17],
"while_end_369",
"if_end_350",
["null", 7, 279, 3],
["return", 7, 279, 3]
["null", 7, 276, 17],
["return", 7, 276, 17]
],
"_write_types": [null, null, null, "bool", null, null, null, null, "function", "function", "function", null, "function", null, null, null, null, null, "function", null, null, null, "function", "function", null, null, "int", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "function", null, null, "text", null, null, "text", null, null, null, null, null, null, null, null, null, "null", "text", "array", null, null, null, "text", null, "text", null, null, null, "null", "text", "array", null, null, null, "text", null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", "text", null, null, null, "null", "text", "array", null, null, null, "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", "text", null, null, null, "null", "text", "array", null, null, null, "null"],
"_write_types": [null, null, null, "bool", null, null, null, null, "function", "function", "function", null, "function", null, null, null, null, null, "function", null, null, null, "function", "function", null, null, "int", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", "function", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "function", null, null, "text", null, null, "text", null, null, null, null, null, null, null, null, null, "null", "text", "array", null, null, null, "text", null, "text", null, null, null, "null", "text", "array", null, null, null, "text", null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", "null"],
"nr_args": 0,
"closure_written": {
"7": true,

File diff suppressed because one or more lines are too long

View File

@@ -3348,7 +3348,7 @@
{
"_closure_slot_types": {},
"disruption_pc": 0,
"nr_slots": 7,
"nr_slots": 8,
"nr_close_slots": 0,
"instructions": [
["get", 2, 14, 2, 1167, 15],
@@ -3356,23 +3356,35 @@
["invoke", 3, 2, 1167, 15],
["move", 3, 2, 1167, 15],
["access", 2, 8, 1, 13],
"_nop_tc_1",
"_nop_tc_2",
["is_num", 4, 1, 1, 13],
["jump_false", 4, "num_err_160", 1, 13],
["multiply", 4, 1, 2, 1, 13],
["jump", "num_done_161", 1, 13],
"num_err_160",
"_nop_ucfg_1",
"_nop_ucfg_2",
"_nop_ucfg_3",
"_nop_ucfg_4",
"_nop_ucfg_5",
"_nop_ucfg_6",
"_nop_ucfg_7",
"_nop_ucfg_8",
"_nop_ucfg_9",
"_nop_ucfg_10",
"_nop_ucfg_11",
"_nop_ucfg_12",
[
"access",
2,
{
"name": "log",
"kind": "name",
"make": "intrinsic"
},
1,
13
],
["access", 5, "error", 1, 13],
["access", 6, "operands must be numbers", 1, 13],
["array", 7, 0, 1, 13],
["stone_text", 6],
["push", 7, 6, 1, 13],
["frame", 6, 2, 2, 1, 13],
["null", 2, 1, 13],
["setarg", 6, 0, 2, 1, 13],
["stone_text", 5],
["setarg", 6, 1, 5, 1, 13],
["setarg", 6, 2, 7, 1, 13],
["invoke", 6, 2, 1, 13],
["disrupt", 1, 13],
"num_done_161",
[
"access",
@@ -3459,7 +3471,7 @@
"_nop_ur_1",
"_nop_ur_2"
],
"_write_types": [null, null, null, null, null, null, "int", "num", null, null, null, null, null, null, null, null, null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null],
"_write_types": [null, null, null, null, null, null, "int", "num", "bool", null, "text", "text", "array", null, null, "null", null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null],
"name": "<anonymous>",
"filename": ".cell/packages/core/qbe_emit.cm",
"nr_args": 1
@@ -3467,7 +3479,7 @@
{
"_closure_slot_types": {},
"disruption_pc": 0,
"nr_slots": 9,
"nr_slots": 10,
"nr_close_slots": 0,
"instructions": [
["get", 3, 14, 2, 1174, 15],
@@ -3541,23 +3553,35 @@
"if_else_162",
"if_end_163",
["access", 5, 8, 1, 13],
"_nop_tc_1",
"_nop_tc_2",
["is_num", 6, 1, 1, 13],
["jump_false", 6, "num_err_164", 1, 13],
["multiply", 6, 1, 5, 1, 13],
["jump", "num_done_165", 1, 13],
"num_err_164",
"_nop_ucfg_1",
"_nop_ucfg_2",
"_nop_ucfg_3",
"_nop_ucfg_4",
"_nop_ucfg_5",
"_nop_ucfg_6",
"_nop_ucfg_7",
"_nop_ucfg_8",
"_nop_ucfg_9",
"_nop_ucfg_10",
"_nop_ucfg_11",
"_nop_ucfg_12",
[
"access",
5,
{
"name": "log",
"kind": "name",
"make": "intrinsic"
},
1,
13
],
["access", 7, "error", 1, 13],
["access", 8, "operands must be numbers", 1, 13],
["array", 9, 0, 1, 13],
["stone_text", 8],
["push", 9, 8, 1, 13],
["frame", 8, 5, 2, 1, 13],
["null", 5, 1, 13],
["setarg", 8, 0, 5, 1, 13],
["stone_text", 7],
["setarg", 8, 1, 7, 1, 13],
["setarg", 8, 2, 9, 1, 13],
["invoke", 8, 5, 1, 13],
["disrupt", 1, 13],
"num_done_165",
[
"access",
@@ -3624,7 +3648,7 @@
["null", 3, 1181, 7],
["return", 3, 1181, 7]
],
"_write_types": [null, null, null, null, null, null, null, null, "text", "bool", null, null, null, "array", null, "text", null, "array", null, "text", null, null, null, null, null, "int", "num", null, null, null, null, null, null, null, null, null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null, null, null, "null"],
"_write_types": [null, null, null, null, null, null, null, null, "text", "bool", null, null, null, "array", null, "text", null, "array", null, "text", null, null, null, null, null, "int", "num", "bool", null, "text", "text", "array", null, null, "null", null, null, null, "array", null, "text", null, null, null, null, null, "array", null, "text", null, null, null, null, null, "null"],
"name": "<anonymous>",
"filename": ".cell/packages/core/qbe_emit.cm",
"nr_args": 2

File diff suppressed because one or more lines are too long

140
build.cm
View File

@@ -65,7 +65,7 @@ function replace_sigils(str, pkg_dir) {
function replace_sigils_array(flags, pkg_dir) {
var result = []
arrfor(flags, function(flag) {
push(result, replace_sigils(flag, pkg_dir))
result[] = replace_sigils(flag, pkg_dir)
})
return result
}
@@ -179,7 +179,7 @@ function bmfst_save(cmd_str, src_path, deps, obj_path) {
arrfor(deps, function(dep_path) {
var st = memo_stat(dep_path)
if (st)
push(entries, {p: dep_path, m: st.m, s: st.s})
entries[] = {p: dep_path, m: st.m, s: st.s}
})
var mf = {o: obj_path, d: entries}
var mf_path = bmfst_path(cmd_str, src_path)
@@ -191,16 +191,16 @@ function bmfst_save(cmd_str, src_path, deps, obj_path) {
function bmfst_dl_key(setup, link_info) {
var parts = [setup.cmd_str, setup.src_path]
push(parts, 'target:' + text(link_info.target))
push(parts, 'cc:' + text(link_info.cc))
parts[] = 'target:' + text(link_info.target)
parts[] = 'cc:' + text(link_info.cc)
arrfor(link_info.extra_objects, function(obj) {
if (obj != null) push(parts, 'extra:' + text(obj))
if (obj != null) parts[] = 'extra:' + text(obj)
})
arrfor(link_info.ldflags, function(flag) {
push(parts, 'ldflag:' + text(flag))
parts[] = 'ldflag:' + text(flag)
})
arrfor(link_info.target_ldflags, function(flag) {
push(parts, 'target_ldflag:' + text(flag))
parts[] = 'target_ldflag:' + text(flag)
})
return text(parts, '\n')
}
@@ -227,7 +227,7 @@ function bmfst_dl_save(setup, link_info, deps, dylib_path) {
arrfor(deps, function(dep_path) {
var st = memo_stat(dep_path)
if (st)
push(entries, {p: dep_path, m: st.m, s: st.s})
entries[] = {p: dep_path, m: st.m, s: st.s}
})
var mf = {dylib: dylib_path, d: entries}
var mf_path = cache_path(bmfst_dl_key(setup, link_info), SALT_BMFST_DL)
@@ -259,7 +259,7 @@ function get_c_deps(cc, flags, src_path) {
var dep_file = '/tmp/cell_deps_' + content_hash(src_path) + '.d'
var dep_cmd = [cc, '-MM', '-MG', '-MF', '"' + dep_file + '"']
dep_cmd = array(dep_cmd, flags)
push(dep_cmd, '"' + src_path + '"')
dep_cmd[] = '"' + src_path + '"'
var ret = os.system(text(dep_cmd, ' ') + ' 2>/dev/null')
if (ret != 0) return [src_path]
if (!fd.is_file(dep_file)) return [src_path]
@@ -274,9 +274,9 @@ function hash_all_deps(cmd_str, deps) {
arrfor(deps, function(dep_path) {
var content = memo_read(dep_path)
if (content != null)
push(parts, dep_path + '\n' + content)
parts[] = dep_path + '\n' + content
else
push(parts, dep_path + '\n<missing>')
parts[] = dep_path + '\n<missing>'
})
return text(parts, '\n')
}
@@ -310,16 +310,16 @@ function compile_setup(pkg, file, target, opts) {
common_flags = array(common_flags, ['-Os', '-DNDEBUG'])
}
push(common_flags, '-DCELL_USE_NAME=' + sym_name)
push(common_flags, '-I"' + pkg_dir + '"')
common_flags[] = '-DCELL_USE_NAME=' + sym_name
common_flags[] = '-I"' + pkg_dir + '"'
if (fd.is_dir(pkg_dir + '/include')) {
push(common_flags, '-I"' + pkg_dir + '/include"')
common_flags[] = '-I"' + pkg_dir + '/include"'
}
if (pkg != 'core') {
core_dir = shop.get_package_dir('core')
push(common_flags, '-I"' + core_dir + '/source"')
common_flags[] = '-I"' + core_dir + '/source"'
}
arrfor(cflags, function(flag) {
@@ -331,16 +331,16 @@ function compile_setup(pkg, file, target, opts) {
f = '-I"' + pkg_dir + '/' + ipath + '"'
}
}
push(common_flags, f)
common_flags[] = f
})
arrfor(target_cflags, function(flag) {
push(common_flags, flag)
common_flags[] = flag
})
var cmd_parts = [cc, '-c', '-fPIC']
cmd_parts = array(cmd_parts, common_flags)
push(cmd_parts, '"' + src_path + '"')
cmd_parts[] = '"' + src_path + '"'
return {
cmd_str: text(cmd_parts, ' '),
@@ -513,7 +513,7 @@ Build.build_package = function(pkg, target, exclude_main, buildtype) {
arrfor(c_files, function(file) {
var obj = Build.compile_file(pkg, file, _target, {buildtype: _buildtype, cflags: cached_cflags})
push(objects, obj)
objects[] = obj
})
return objects
@@ -527,16 +527,16 @@ Build.build_package = function(pkg, target, exclude_main, buildtype) {
// link_opts: {extra_objects, ldflags, target_ldflags, target, cc}
function compute_dylib_content(full_content, link_opts) {
var parts = [full_content]
push(parts, 'target:' + text(link_opts.target))
push(parts, 'cc:' + text(link_opts.cc))
parts[] = 'target:' + text(link_opts.target)
parts[] = 'cc:' + text(link_opts.cc)
arrfor(link_opts.extra_objects, function(obj) {
if (obj != null) push(parts, 'extra:' + text(obj))
if (obj != null) parts[] = 'extra:' + text(obj)
})
arrfor(link_opts.ldflags, function(flag) {
push(parts, 'ldflag:' + text(flag))
parts[] = 'ldflag:' + text(flag)
})
arrfor(link_opts.target_ldflags, function(flag) {
push(parts, 'target_ldflag:' + text(flag))
parts[] = 'target_ldflag:' + text(flag)
})
return text(parts, '\n')
}
@@ -570,7 +570,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
f = '-L"' + setup.pkg_dir + '/' + lpath + '"'
}
}
push(resolved_ldflags, f)
resolved_ldflags[] = f
})
var build_dir = get_build_dir()
@@ -683,18 +683,18 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
'-Wl,-rpath,' + local_dir
])
} else if (tc.system == 'windows') {
push(cmd_parts, '-Wl,--allow-shlib-undefined')
cmd_parts[] = '-Wl,--allow-shlib-undefined'
}
push(cmd_parts, '-L"' + local_dir + '"')
push(cmd_parts, '"' + text(obj) + '"')
cmd_parts[] = '-L"' + local_dir + '"'
cmd_parts[] = '"' + text(obj) + '"'
arrfor(_extra, function(extra_obj) {
if (extra_obj != null) push(cmd_parts, '"' + text(extra_obj) + '"')
if (extra_obj != null) cmd_parts[] = '"' + text(extra_obj) + '"'
})
cmd_parts = array(cmd_parts, resolved_ldflags)
cmd_parts = array(cmd_parts, target_ldflags)
push(cmd_parts, '-o')
push(cmd_parts, '"' + dylib_path + '"')
cmd_parts[] = '-o'
cmd_parts[] = '"' + dylib_path + '"'
cmd_str = text(cmd_parts, ' ')
if (_opts.verbose) log.build('[verbose] link: ' + cmd_str)
@@ -737,7 +737,7 @@ Build.compile_c_module = function(pkg, file, target, opts) {
if (pkg != 'core') {
arrfor(sources, function(src_file) {
var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags})
if (obj != null) push(support_objects, obj)
if (obj != null) support_objects[] = obj
})
}
@@ -767,27 +767,23 @@ Build.build_dynamic = function(pkg, target, buildtype, opts) {
if (pkg != 'core') {
arrfor(sources, function(src_file) {
var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags, verbose: _opts.verbose, force: _opts.force})
if (obj != null) push(support_objects, obj)
if (obj != null) support_objects[] = obj
})
}
if (total > 0)
os.print(' Building C modules ')
arrfor(c_files, function(file) {
var sym_name = shop.c_symbol_for_file(pkg, file)
var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects, cflags: cached_cflags, verbose: _opts.verbose, force: _opts.force})
if (dylib) {
push(results, {file: file, symbol: sym_name, dylib: dylib})
results[] = {file: file, symbol: sym_name, dylib: dylib}
} else {
failed = failed + 1
}
done = done + 1
os.print('.')
})
if (total > 0)
os.print(` ${text(done)}/${text(total)}${failed > 0 ? `, ${text(failed)} failed` : ''}\n`)
log.build(` Building C modules (${text(done)} ok${failed > 0 ? `, ${text(failed)} failed` : ''})`)
// Write manifest so runtime can find dylibs without the build module
var mpath = manifest_path(pkg)
@@ -818,7 +814,7 @@ Build.build_static = function(packages, target, output, buildtype) {
var objects = Build.build_package(pkg, _target, !is_core, _buildtype)
arrfor(objects, function(obj) {
push(all_objects, obj)
all_objects[] = obj
})
// Collect LDFLAGS (with sigil replacement)
@@ -838,7 +834,7 @@ Build.build_static = function(packages, target, output, buildtype) {
f = '-L"' + pkg_dir + '/' + lpath + '"'
}
}
push(all_ldflags, f)
all_ldflags[] = f
})
}
})
@@ -860,18 +856,18 @@ Build.build_static = function(packages, target, output, buildtype) {
var cmd_parts = [cc]
arrfor(all_objects, function(obj) {
push(cmd_parts, '"' + obj + '"')
cmd_parts[] = '"' + obj + '"'
})
arrfor(all_ldflags, function(flag) {
push(cmd_parts, flag)
cmd_parts[] = flag
})
arrfor(target_ldflags, function(flag) {
push(cmd_parts, flag)
cmd_parts[] = flag
})
push(cmd_parts, '-o', '"' + out_path + '"')
cmd_parts[] = '-o', '"' + out_path + '"'
var cmd_str = text(cmd_parts, ' ')
@@ -925,7 +921,7 @@ function qbe_insert_dead_labels(il_text) {
line = lines[i]
trimmed = trim(line)
if (need_label && !starts_with(trimmed, '@') && !starts_with(trimmed, '}') && length(trimmed) > 0) {
push(result, "@_dead_" + text(dead_id))
result[] = "@_dead_" + text(dead_id)
dead_id = dead_id + 1
need_label = false
}
@@ -935,7 +931,7 @@ function qbe_insert_dead_labels(il_text) {
if (starts_with(trimmed, 'ret ') || starts_with(trimmed, 'jmp ')) {
need_label = true
}
push(result, line)
result[] = line
i = i + 1
}
return text(result, "\n")
@@ -1126,16 +1122,16 @@ Build.compile_cm_to_mach = function(src_path) {
// output: path to write the generated .c file
Build.generate_module_table = function(modules, output) {
var lines = []
push(lines, '/* Generated module table — do not edit */')
push(lines, '#include <stddef.h>')
push(lines, '#include <string.h>')
push(lines, '')
push(lines, 'struct cell_embedded_entry {')
push(lines, ' const char *name;')
push(lines, ' const unsigned char *data;')
push(lines, ' size_t size;')
push(lines, '};')
push(lines, '')
lines[] = '/* Generated module table — do not edit */'
lines[] = '#include <stddef.h>'
lines[] = '#include <string.h>'
lines[] = ''
lines[] = 'struct cell_embedded_entry {'
lines[] = ' const char *name;'
lines[] = ' const unsigned char *data;'
lines[] = ' size_t size;'
lines[] = '};'
lines[] = ''
var entries = []
arrfor(modules, function(mod) {
@@ -1144,27 +1140,27 @@ Build.generate_module_table = function(modules, output) {
var bytes = array(mach)
var hex = []
arrfor(bytes, function(b) {
push(hex, '0x' + text(b, 'h2'))
hex[] = '0x' + text(b, 'h2')
})
push(lines, 'static const unsigned char mod_' + safe + '_data[] = {')
push(lines, ' ' + text(hex, ', '))
push(lines, '};')
push(lines, '')
push(entries, safe)
lines[] = 'static const unsigned char mod_' + safe + '_data[] = {'
lines[] = ' ' + text(hex, ', ')
lines[] = '};'
lines[] = ''
entries[] = safe
log.console('Embedded: ' + mod.name + ' (' + text(length(bytes)) + ' bytes)')
})
// Lookup function
push(lines, 'const struct cell_embedded_entry *cell_embedded_module_lookup(const char *name) {')
lines[] = 'const struct cell_embedded_entry *cell_embedded_module_lookup(const char *name) {'
arrfor(modules, function(mod, i) {
var safe = entries[i]
push(lines, ' if (strcmp(name, "' + mod.name + '") == 0) {')
push(lines, ' static const struct cell_embedded_entry e = {"' + mod.name + '", mod_' + safe + '_data, sizeof(mod_' + safe + '_data)};')
push(lines, ' return &e;')
push(lines, ' }')
lines[] = ' if (strcmp(name, "' + mod.name + '") == 0) {'
lines[] = ' static const struct cell_embedded_entry e = {"' + mod.name + '", mod_' + safe + '_data, sizeof(mod_' + safe + '_data)};'
lines[] = ' return &e;'
lines[] = ' }'
})
push(lines, ' return (void *)0;')
push(lines, '}')
lines[] = ' return (void *)0;'
lines[] = '}'
var c_text = text(lines, '\n')
fd.slurpwrite(output, stone(blob(c_text)))
@@ -1192,14 +1188,14 @@ Build.build_all_dynamic = function(target, buildtype, opts) {
// Build core first
if (find(packages, function(p) { return p == 'core' }) != null) {
core_mods = Build.build_dynamic('core', _target, _buildtype, _opts)
push(results, {package: 'core', modules: core_mods})
results[] = {package: 'core', modules: core_mods}
}
// Build other packages
arrfor(packages, function(pkg) {
if (pkg == 'core') return
var pkg_mods = Build.build_dynamic(pkg, _target, _buildtype, _opts)
push(results, {package: pkg, modules: pkg_mods})
results[] = {package: pkg, modules: pkg_mods}
})
// Print build report

View File

@@ -152,7 +152,7 @@ function mount(source, name) {
})
}
}
push(mounts, mount_info)
mounts[] = mount_info
return
}
@@ -187,7 +187,7 @@ function mount(source, name) {
log.error("Unsupported mount source type: " + source); disrupt
}
push(mounts, mount_info)
mounts[] = mount_info
}
function unmount(name_or_source) {
@@ -356,7 +356,7 @@ function enumerate(_path, recurse) {
arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item
var child_st = null
push(results, item_rel)
results[] = item_rel
if (recurse) {
child_st = fd.stat(fd.join_paths(curr_full, item))
@@ -396,7 +396,7 @@ function enumerate(_path, recurse) {
if (!seen[rel]) {
seen[rel] = true
push(results, rel)
results[] = rel
}
}
})
@@ -455,7 +455,7 @@ function globfs(globs, _dir) {
}
} else {
if (!check_neg(item_rel) && check_pos(item_rel)) {
push(results, item_rel)
results[] = item_rel
}
}
})
@@ -479,7 +479,7 @@ function globfs(globs, _dir) {
if (length(rel) == 0) return
if (!check_neg(rel) && check_pos(rel)) {
push(results, rel)
results[] = rel
}
}
})

18
cfg.ce
View File

@@ -168,7 +168,7 @@ var run = function() {
if (is_array(instr)) {
if (block_start_pcs[text(pc)]) {
if (current_block != null) {
push(blocks, current_block)
blocks[] = current_block
}
current_block = {
id: length(blocks),
@@ -184,7 +184,7 @@ var run = function() {
}
if (current_block != null) {
push(current_block.instrs, {pc: pc, instr: instr})
current_block.instrs[] = {pc: pc, instr: instr}
current_block.end_pc = pc
n = length(instr)
line_num = instr[n - 2]
@@ -200,7 +200,7 @@ var run = function() {
ii = ii + 1
}
if (current_block != null) {
push(blocks, current_block)
blocks[] = current_block
}
// Build block index
@@ -235,19 +235,19 @@ var run = function() {
if (target_bi <= bi) {
edge_type = "loop back-edge"
}
push(blk.edges, {target: target_bi, kind: edge_type})
blk.edges[] = {target: target_bi, kind: edge_type}
}
if (is_conditional_jump(last_op)) {
if (bi + 1 < length(blocks)) {
push(blk.edges, {target: bi + 1, kind: "fallthrough"})
blk.edges[] = {target: bi + 1, kind: "fallthrough"}
}
}
} else if (is_terminator(last_op)) {
push(blk.edges, {target: -1, kind: "EXIT (" + last_op + ")"})
blk.edges[] = {target: -1, kind: "EXIT (" + last_op + ")"}
} else {
if (bi + 1 < length(blocks)) {
push(blk.edges, {target: bi + 1, kind: "fallthrough"})
blk.edges[] = {target: bi + 1, kind: "fallthrough"}
}
}
}
@@ -308,7 +308,7 @@ var run = function() {
parts = []
j = 1
while (j < n - 2) {
push(parts, fmt_val(instr[j]))
parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(parts, ", ")
@@ -381,7 +381,7 @@ var run = function() {
parts = []
j = 1
while (j < n - 2) {
push(parts, fmt_val(instr[j]))
parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(parts, ", ")

View File

@@ -93,13 +93,13 @@ if (is_shop_scope) {
packages_to_clean = shop.list_packages()
} else {
// Single package
push(packages_to_clean, scope)
packages_to_clean[] = scope
if (deep) {
_gather = function() {
deps = pkg.gather_dependencies(scope)
arrfor(deps, function(dep) {
push(packages_to_clean, dep)
packages_to_clean[] = dep
})
} disruption {
// Skip if can't read dependencies
@@ -116,11 +116,11 @@ var packages_dir = replace(shop.get_package_dir(''), /\/$/, '') // Get base pack
if (clean_build) {
// Nuke entire build cache (content-addressed, per-package clean impractical)
if (fd.is_dir(build_dir)) {
push(dirs_to_delete, build_dir)
dirs_to_delete[] = build_dir
}
// Clean orphaned lib/ directory if it exists (legacy)
if (fd.is_dir(lib_dir)) {
push(dirs_to_delete, lib_dir)
dirs_to_delete[] = lib_dir
}
}
@@ -128,7 +128,7 @@ if (clean_fetch) {
if (is_shop_scope) {
// Clean entire packages directory (dangerous!)
if (fd.is_dir(packages_dir)) {
push(dirs_to_delete, packages_dir)
dirs_to_delete[] = packages_dir
}
} else {
// Clean specific package directories
@@ -137,7 +137,7 @@ if (clean_fetch) {
var pkg_dir = shop.get_package_dir(p)
if (fd.is_dir(pkg_dir) || fd.is_link(pkg_dir)) {
push(dirs_to_delete, pkg_dir)
dirs_to_delete[] = pkg_dir
}
})
}

24
diff.ce
View File

@@ -55,7 +55,7 @@ function collect_tests(specific_test) {
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (test_name != match_base) continue
}
push(test_files, f)
test_files[] = f
}
}
return test_files
@@ -100,7 +100,7 @@ function diff_test_file(file_path) {
src = text(fd.slurp(src_path))
ast = analyze(src, src_path)
} disruption {
push(results.errors, `failed to parse ${file_path}`)
results.errors[] = `failed to parse ${file_path}`
return results
}
_read()
@@ -124,14 +124,14 @@ function diff_test_file(file_path) {
// Compare module-level behavior
if (opt_error != noopt_error) {
push(results.errors, `module load mismatch: opt=${opt_error != null ? opt_error : "ok"} noopt=${noopt_error != null ? noopt_error : "ok"}`)
results.errors[] = `module load mismatch: opt=${opt_error != null ? opt_error : "ok"} noopt=${noopt_error != null ? noopt_error : "ok"}`
results.failed = results.failed + 1
return results
}
if (opt_error != null) {
// Both disrupted during load — that's consistent
results.passed = results.passed + 1
push(results.tests, {name: "<module>", status: "passed"})
results.tests[] = {name: "<module>", status: "passed"}
return results
}
@@ -161,15 +161,15 @@ function diff_test_file(file_path) {
_run_one_noopt()
if (opt_err != noopt_err) {
push(results.tests, {name: k, status: "failed"})
push(results.errors, `${k}: disruption mismatch opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`)
results.tests[] = {name: k, status: "failed"}
results.errors[] = `${k}: disruption mismatch opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`
results.failed = results.failed + 1
} else if (!values_equal(opt_result, noopt_result)) {
push(results.tests, {name: k, status: "failed"})
push(results.errors, `${k}: result mismatch opt=${describe(opt_result)} noopt=${describe(noopt_result)}`)
results.tests[] = {name: k, status: "failed"}
results.errors[] = `${k}: result mismatch opt=${describe(opt_result)} noopt=${describe(noopt_result)}`
results.failed = results.failed + 1
} else {
push(results.tests, {name: k, status: "passed"})
results.tests[] = {name: k, status: "passed"}
results.passed = results.passed + 1
}
}
@@ -178,11 +178,11 @@ function diff_test_file(file_path) {
} else {
// Compare direct return values
if (!values_equal(mod_opt, mod_noopt)) {
push(results.tests, {name: "<return>", status: "failed"})
push(results.errors, `return value mismatch: opt=${describe(mod_opt)} noopt=${describe(mod_noopt)}`)
results.tests[] = {name: "<return>", status: "failed"}
results.errors[] = `return value mismatch: opt=${describe(mod_opt)} noopt=${describe(mod_noopt)}`
results.failed = results.failed + 1
} else {
push(results.tests, {name: "<return>", status: "passed"})
results.tests[] = {name: "<return>", status: "passed"}
results.passed = results.passed + 1
}
}

View File

@@ -93,7 +93,7 @@ var run = function() {
var operands = null
var line_str = null
while (j < n - 2) {
push(parts, fmt_val(instr[j]))
parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(parts, ", ")

View File

@@ -206,7 +206,7 @@ var run = function() {
parts = []
j = 1
while (j < n - 2) {
push(parts, fmt_val(instr[j]))
parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(parts, ", ")

2
fd.cm
View File

@@ -83,7 +83,7 @@ fd.globfs = function(globs, dir) {
}
} else {
if (!check_neg(item_rel) && check_pos(item_rel)) {
push(results, item_rel)
results[] = item_rel
}
}
});

26
fold.cm
View File

@@ -709,26 +709,26 @@ var fold = function(ast) {
if (sv != null && sv.nr_uses == 0) {
if (is_pure(stmt.right)) stmt.dead = true
if (stmt.right != null && stmt.right.kind == "(" && stmt.right.expression != null && stmt.right.expression.name == "use") {
push(ast._diagnostics, {
ast._diagnostics[] = {
severity: "warning",
line: stmt.left.from_row + 1,
col: stmt.left.from_column + 1,
message: `unused import '${name}'`
})
}
} else if (stmt.kind == "def") {
push(ast._diagnostics, {
ast._diagnostics[] = {
severity: "warning",
line: stmt.left.from_row + 1,
col: stmt.left.from_column + 1,
message: `unused constant '${name}'`
})
}
} else {
push(ast._diagnostics, {
ast._diagnostics[] = {
severity: "warning",
line: stmt.left.from_row + 1,
col: stmt.left.from_column + 1,
message: `unused variable '${name}'`
})
}
}
}
}
@@ -742,15 +742,15 @@ var fold = function(ast) {
sv = scope_var(fn_nr, stmt.name)
if (sv != null && sv.nr_uses == 0) {
stmt.dead = true
push(ast._diagnostics, {
ast._diagnostics[] = {
severity: "warning",
line: stmt.from_row + 1,
col: stmt.from_column + 1,
message: `unused function '${stmt.name}'`
})
}
}
if (stmt.dead != true) push(out, stmt)
}
if (stmt.dead != true) out[] = stmt
i = i + 1
}
return out
@@ -1039,7 +1039,7 @@ var fold = function(ast) {
i = 0
while (i < length(ast.intrinsics)) {
if (used_intrinsics[ast.intrinsics[i]] == true) {
push(new_intrinsics, ast.intrinsics[i])
new_intrinsics[] = ast.intrinsics[i]
}
i = i + 1
}
@@ -1071,16 +1071,16 @@ var fold = function(ast) {
fn_sv = scope_var(0, fn.name)
if (fn_sv != null && fn_sv.nr_uses == 0) {
fn.dead = true
push(ast._diagnostics, {
ast._diagnostics[] = {
severity: "warning",
line: fn.from_row + 1,
col: fn.from_column + 1,
message: `unused function '${fn.name}'`
})
}
}
}
if (fn.dead != true) {
push(live_fns, fn)
live_fns[] = fn
}
fi = fi + 1
}

12
fuzz.ce
View File

@@ -89,7 +89,7 @@ function run_fuzz(seed_val) {
var _parse = function() {
ast = analyze(src, name + ".cm")
} disruption {
push(errors, "parse error")
errors[] = "parse error"
}
_parse()
if (length(errors) > 0) return {seed: seed_val, errors: errors, src: src}
@@ -112,7 +112,7 @@ function run_fuzz(seed_val) {
// Check module-level behavior
if (opt_err != noopt_err) {
push(errors, `module load: opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`)
errors[] = `module load: opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`
return {seed: seed_val, errors: errors, src: src}
}
if (opt_err != null) {
@@ -137,10 +137,10 @@ function run_fuzz(seed_val) {
_run()
if (is_text(ret)) {
push(errors, `self-check ${key}: ${ret}`)
errors[] = `self-check ${key}: ${ret}`
}
if (run_err != null) {
push(errors, `self-check ${key}: unexpected disruption`)
errors[] = `self-check ${key}: unexpected disruption`
}
}
k = k + 1
@@ -174,9 +174,9 @@ function run_fuzz(seed_val) {
_run_noopt()
if (opt_fn_err != noopt_fn_err) {
push(errors, `diff ${key2}: opt=${opt_fn_err != null ? opt_fn_err : "ok"} noopt=${noopt_fn_err != null ? noopt_fn_err : "ok"}`)
errors[] = `diff ${key2}: opt=${opt_fn_err != null ? opt_fn_err : "ok"} noopt=${noopt_fn_err != null ? noopt_fn_err : "ok"}`
} else if (!values_equal(opt_result, noopt_result)) {
push(errors, `diff ${key2}: opt=${describe(opt_result)} noopt=${describe(noopt_result)}`)
errors[] = `diff ${key2}: opt=${describe(opt_result)} noopt=${describe(noopt_result)}`
}
}
k2 = k2 + 1

View File

@@ -241,7 +241,7 @@ function gen_array_test() {
var v = 0
while (i < n) {
v = rand_int(-100, 100)
push(vals, v)
vals[] = v
sum = sum + v
i = i + 1
}
@@ -249,7 +249,7 @@ function gen_array_test() {
var val_strs = []
i = 0
while (i < n) {
push(val_strs, text(vals[i]))
val_strs[] = text(vals[i])
i = i + 1
}

View File

@@ -98,7 +98,7 @@ function gather_graph(locator, visited) {
arrfor(array(deps), function(alias) {
var dep_locator = deps[alias]
add_node(dep_locator)
push(edges, { from: locator, to: dep_locator, alias: alias })
edges[] = { from: locator, to: dep_locator, alias: alias }
gather_graph(dep_locator, visited)
})
}
@@ -117,7 +117,7 @@ if (show_world) {
packages = shop.list_packages()
arrfor(packages, function(p) {
if (p != 'core') {
push(roots, p)
roots[] = p
}
})
} else {
@@ -128,7 +128,7 @@ if (show_world) {
target_locator = shop.resolve_locator(target_locator)
push(roots, target_locator)
roots[] = target_locator
}
arrfor(roots, function(root) {
@@ -164,7 +164,7 @@ if (format == 'tree') {
children = []
arrfor(edges, function(e) {
if (e.from == locator) {
push(children, e)
children[] = e
}
})
@@ -180,7 +180,7 @@ if (format == 'tree') {
children = []
arrfor(edges, function(e) {
if (e.from == roots[i]) {
push(children, e)
children[] = e
}
})
@@ -230,7 +230,7 @@ if (format == 'tree') {
}
arrfor(array(nodes), function(id) {
push(output.nodes, nodes[id])
output.nodes[] = nodes[id]
})
output.edges = edges

47
http.cm
View File

@@ -457,7 +457,7 @@ function parse_headers(raw) {
}
}
// decode chunked transfer encoding
// decode chunked transfer encoding (text version, for async responses)
function decode_chunked(body_text) {
var result = ""
var pos = 0
@@ -475,6 +475,37 @@ function decode_chunked(body_text) {
return result
}
// decode chunked transfer encoding (blob version, preserves binary data)
function decode_chunked_blob(buf, body_start_bytes) {
var result = Blob()
var pos = body_start_bytes
var total_bytes = length(buf) / 8
var header_end = null
var header_blob = null
var header_text = null
var crlf_pos = null
var chunk_size = null
var chunk_data = null
while (pos < total_bytes) {
header_end = pos + 20
if (header_end > total_bytes) header_end = total_bytes
header_blob = buf.read_blob(pos * 8, header_end * 8)
stone(header_blob)
header_text = text(header_blob)
crlf_pos = search(header_text, CRLF)
if (crlf_pos == null) break
chunk_size = number(text(header_text, 0, crlf_pos), 16)
if (chunk_size == null || chunk_size == 0) break
pos = pos + crlf_pos + 2
chunk_data = buf.read_blob(pos * 8, (pos + chunk_size) * 8)
stone(chunk_data)
result.write_blob(chunk_data)
pos = pos + chunk_size + 2
}
stone(result)
return result
}
// receive_response requestor — async incremental receive
var receive_response = function(callback, state) {
var cancelled = false
@@ -650,6 +681,8 @@ var fetch = function(url) {
var addrs = null
var address = null
var ok = true
var status_line = null
var status_code = null
if (scheme_end != null) {
scheme = lower(text(url, 0, scheme_end))
@@ -705,8 +738,16 @@ var fetch = function(url) {
hdr_end = search(raw_text, CRLF + CRLF)
if (hdr_end == null) return null
header_text = text(raw_text, 0, hdr_end)
if (search(lower(header_text), "transfer-encoding: chunked") != null)
return decode_chunked(text(raw_text, hdr_end + 4))
status_line = text(header_text, 0, search(header_text, CRLF) || length(header_text))
status_code = number(text(status_line, 9, 12))
if (status_code == null || status_code < 200 || status_code >= 300) {
log.error("fetch: " + status_line)
disrupt
}
if (search(lower(header_text), "transfer-encoding: chunked") != null) {
body = decode_chunked_blob(buf, hdr_end + 4)
return body
}
// Headers are ASCII so char offset = byte offset
body_start_bits = (hdr_end + 4) * 8
body = buf.read_blob(body_start_bits, length(buf))

View File

@@ -109,7 +109,7 @@ function trace_imports(file_path, depth) {
all_packages[imp_pkg] = true
push(all_imports, {
all_imports[] = {
from: file_path,
from_pkg: file_pkg,
module_path: mod_path,
@@ -117,7 +117,7 @@ function trace_imports(file_path, depth) {
package: imp_pkg,
type: imp_type,
depth: depth
})
}
// Recurse into resolved scripts
if (resolved && (ends_with(resolved, '.cm') || ends_with(resolved, '.ce'))) {

View File

@@ -14,31 +14,28 @@ static void js_enet_host_finalizer(JSRuntime *rt, JSValue val)
if (host) enet_host_destroy(host);
}
static void js_enet_peer_finalizer(JSRuntime *rt, JSValue val)
static JSClassDef enet_host_def = {
"ENetHost",
.finalizer = js_enet_host_finalizer,
};
static JSClassDef enet_peer_def = {
"ENetPeer",
};
/* Helper: create a JS peer wrapper for an ENetPeer pointer.
Fresh wrapper each time — no caching in peer->data. */
static JSValue peer_wrap(JSContext *ctx, ENetPeer *peer)
{
ENetPeer *peer = JS_GetOpaque(val, enet_peer_class_id);
if (peer && peer->data) {
free(peer->data);
}
JSValue obj = JS_NewObjectClass(ctx, enet_peer_class_id);
if (JS_IsException(obj)) return obj;
JS_SetOpaque(obj, peer);
return obj;
}
// Initialize the ENet library. Must be called before using any ENet functionality.
static JSValue js_enet_initialize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
if (enet_initialize() != 0) return JS_RaiseDisrupt(ctx, "Error initializing ENet");
return JS_NULL;
}
/* ── Host functions ─────────────────────────────────────────── */
// Deinitialize the ENet library, cleaning up all resources.
static JSValue js_enet_deinitialize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
enet_deinitialize();
return JS_NULL;
}
// Create an ENet host for either a client-like unbound host or a server bound to a specific
// address and port.
static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
static JSValue js_enet_create_host(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host;
ENetAddress address;
@@ -74,7 +71,7 @@ static JSValue js_enet_host_create(JSContext *ctx, JSValueConst this_val, int ar
int err = enet_address_set_host_ip(&address, addr_str);
if (err != 0) {
JS_FreeCString(ctx, addr_str);
return JS_RaiseDisrupt(ctx, "Failed to set host IP from '%s'. Error: %d", addr_str, err);
return JS_RaiseDisrupt(ctx, "Failed to set host IP. Error: %d", err);
}
}
address.port = (enet_uint16)port32;
@@ -103,97 +100,76 @@ wrap:
return obj;
}
// Helper function to get a JSValue for an ENetPeer.
static JSValue peer_get_value(JSContext *ctx, ENetPeer *peer)
/* service(host, callback [, timeout]) */
static JSValue js_enet_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
if (!peer->data) {
peer->data = malloc(sizeof(JSValue));
*(JSValue*)peer->data = JS_NewObjectClass(ctx, enet_peer_class_id);
JS_SetOpaque(*(JSValue*)peer->data, peer);
}
return *(JSValue*)peer->data;
}
if (argc < 2) return JS_RaiseDisrupt(ctx, "service: expected (host, callback)");
// Poll for and process any available network events from this host,
// calling the provided callback for each event.
static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
if (!host) return JS_EXCEPTION;
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "service: invalid host");
if (argc < 1 || !JS_IsFunction(argv[0]))
return JS_RaiseDisrupt(ctx, "Expected a callback function as first argument");
if (!JS_IsFunction(argv[1]))
return JS_RaiseDisrupt(ctx, "service: expected callback function");
enet_uint32 timeout_ms = 0;
if (argc >= 2 && !JS_IsNull(argv[1])) {
if (argc >= 3 && !JS_IsNull(argv[2])) {
double secs = 0;
JS_ToFloat64(ctx, &secs, argv[1]);
JS_ToFloat64(ctx, &secs, argv[2]);
if (secs > 0) timeout_ms = (enet_uint32)(secs * 1000.0);
}
JS_FRAME(ctx);
JSGCRef event_ref = { .val = JS_NULL, .prev = NULL };
JS_PushGCRef(ctx, &event_ref);
JS_ROOT(event_obj, JS_NULL);
ENetEvent event;
while (enet_host_service(host, &event, timeout_ms) > 0) {
event_ref.val = JS_NewObject(ctx);
event_obj.val = JS_NewObject(ctx);
JSValue peer_val = peer_get_value(ctx, event.peer);
JS_SetPropertyStr(ctx, event_ref.val, "peer", peer_val);
JSValue peer_val = peer_wrap(ctx, event.peer);
JS_SetPropertyStr(ctx, event_obj.val, "peer", peer_val);
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: {
JSValue type_str = JS_NewString(ctx, "connect");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
case ENET_EVENT_TYPE_CONNECT:
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "connect"));
break;
}
case ENET_EVENT_TYPE_RECEIVE: {
JSValue type_str = JS_NewString(ctx, "receive");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
JS_SetPropertyStr(ctx, event_ref.val, "channelID", JS_NewInt32(ctx, event.channelID));
case ENET_EVENT_TYPE_RECEIVE:
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "receive"));
JS_SetPropertyStr(ctx, event_obj.val, "channelID", JS_NewInt32(ctx, event.channelID));
if (event.packet->dataLength > 0) {
JSValue data_val = js_new_blob_stoned_copy(ctx, event.packet->data, event.packet->dataLength);
JS_SetPropertyStr(ctx, event_ref.val, "data", data_val);
JS_SetPropertyStr(ctx, event_obj.val, "data", data_val);
}
enet_packet_destroy(event.packet);
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
JSValue type_str = JS_NewString(ctx, "disconnect");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
case ENET_EVENT_TYPE_DISCONNECT:
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect"));
break;
}
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {
JSValue type_str = JS_NewString(ctx, "disconnect_timeout");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect_timeout"));
break;
}
case ENET_EVENT_TYPE_NONE: {
JSValue type_str = JS_NewString(ctx, "none");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
case ENET_EVENT_TYPE_NONE:
JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "none"));
break;
}
}
JS_Call(ctx, argv[0], JS_NULL, 1, &event_ref.val);
JS_Call(ctx, argv[1], JS_NULL, 1, &event_obj.val);
}
JS_RETURN_NULL();
}
// Initiate a connection from this host to a remote server.
static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* connect(host, address, port) → peer */
static JSValue js_enet_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
if (!host) return JS_EXCEPTION;
if (argc < 3) return JS_RaiseDisrupt(ctx, "connect: expected (host, address, port)");
if (argc < 2) return JS_RaiseDisrupt(ctx, "Expected 2 arguments: hostname, port");
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "connect: invalid host");
const char *hostname = JS_ToCString(ctx, argv[0]);
const char *hostname = JS_ToCString(ctx, argv[1]);
if (!hostname) return JS_EXCEPTION;
int port;
JS_ToInt32(ctx, &port, argv[1]);
JS_ToInt32(ctx, &port, argv[2]);
ENetAddress address;
enet_address_set_host(&address, hostname);
@@ -201,40 +177,40 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int a
address.port = port;
ENetPeer *peer = enet_host_connect(host, &address, 2, 0);
if (!peer) return JS_RaiseDisrupt(ctx, "No available peers for initiating an ENet connection");
if (!peer) return JS_RaiseDisrupt(ctx, "No available peers for connection");
return peer_get_value(ctx, peer);
return peer_wrap(ctx, peer);
}
// Flush all pending outgoing packets for this host immediately.
static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* flush(host) */
static JSValue js_enet_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
if (!host) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "flush: expected (host)");
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "flush: invalid host");
enet_host_flush(host);
return JS_NULL;
}
// Broadcast a string or blob to all connected peers on channel 0.
static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* broadcast(host, data) */
static JSValue js_enet_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host = JS_GetOpaque(this_val, enet_host_id);
if (!host) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to broadcast");
if (argc < 2) return JS_RaiseDisrupt(ctx, "broadcast: expected (host, data)");
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "broadcast: invalid host");
const char *data_str = NULL;
size_t data_len = 0;
uint8_t *buf = NULL;
if (JS_IsText(argv[0])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
if (JS_IsText(argv[1])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
if (!data_str) return JS_EXCEPTION;
} else if (js_is_blob(ctx, argv[0])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]);
} else if (js_is_blob(ctx, argv[1])) {
buf = js_get_blob_data(ctx, &data_len, argv[1]);
if (!buf) return JS_EXCEPTION;
} else {
return JS_RaiseDisrupt(ctx, "broadcast() only accepts a string or blob");
return JS_RaiseDisrupt(ctx, "broadcast: data must be string or blob");
}
ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
@@ -245,52 +221,48 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int
return JS_NULL;
}
// Host property getters
static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self)
/* host_port(host) → number */
static JSValue js_enet_host_port(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *host = JS_GetOpaque(self, enet_host_id);
if (!host) return JS_EXCEPTION;
return JS_NewInt32(js, host->address.port);
if (argc < 1) return JS_RaiseDisrupt(ctx, "host_port: expected (host)");
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "host_port: invalid host");
return JS_NewInt32(ctx, host->address.port);
}
static JSValue js_enet_host_get_address(JSContext *js, JSValueConst self)
/* host_address(host) → string */
static JSValue js_enet_host_address(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetHost *me = JS_GetOpaque(self, enet_host_id);
if (!me) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "host_address: expected (host)");
ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "host_address: invalid host");
char ip_str[128];
if (enet_address_get_host_ip(&me->address, ip_str, sizeof(ip_str)) != 0)
if (enet_address_get_host_ip(&host->address, ip_str, sizeof(ip_str)) != 0)
return JS_NULL;
return JS_NewString(js, ip_str);
return JS_NewString(ctx, ip_str);
}
// Peer-level operations
static JSValue js_enet_peer_disconnect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
enet_peer_disconnect(peer, 0);
return JS_NULL;
}
/* ── Peer functions ─────────────────────────────────────────── */
static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* send(peer, data) */
static JSValue js_enet_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to send");
if (argc < 2) return JS_RaiseDisrupt(ctx, "send: expected (peer, data)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "send: invalid peer");
const char *data_str = NULL;
size_t data_len = 0;
uint8_t *buf = NULL;
if (JS_IsText(argv[0])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
if (JS_IsText(argv[1])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
if (!data_str) return JS_EXCEPTION;
} else if (js_is_blob(ctx, argv[0])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]);
} else if (js_is_blob(ctx, argv[1])) {
buf = js_get_blob_data(ctx, &data_len, argv[1]);
if (!buf) return JS_EXCEPTION;
} else {
return JS_RaiseDisrupt(ctx, "send() only accepts a string or blob");
return JS_RaiseDisrupt(ctx, "send: data must be string or blob");
}
ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
@@ -301,225 +273,185 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc
return JS_NULL;
}
static JSValue js_enet_peer_disconnect_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* disconnect(peer) */
static JSValue js_enet_disconnect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect: invalid peer");
enet_peer_disconnect(peer, 0);
return JS_NULL;
}
/* disconnect_now(peer) */
static JSValue js_enet_disconnect_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect_now: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect_now: invalid peer");
enet_peer_disconnect_now(peer, 0);
return JS_NULL;
}
static JSValue js_enet_peer_disconnect_later(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* disconnect_later(peer) */
static JSValue js_enet_disconnect_later(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect_later: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "disconnect_later: invalid peer");
enet_peer_disconnect_later(peer, 0);
return JS_NULL;
}
static JSValue js_enet_peer_reset(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* reset(peer) */
static JSValue js_enet_reset(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "reset: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "reset: invalid peer");
enet_peer_reset(peer);
return JS_NULL;
}
static JSValue js_enet_peer_ping(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* ping(peer) */
static JSValue js_enet_ping(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "ping: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "ping: invalid peer");
enet_peer_ping(peer);
return JS_NULL;
}
static JSValue js_enet_peer_throttle_configure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
/* throttle_configure(peer, interval, acceleration, deceleration) */
static JSValue js_enet_throttle_configure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 4) return JS_RaiseDisrupt(ctx, "throttle_configure: expected (peer, interval, accel, decel)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "throttle_configure: invalid peer");
int interval, acceleration, deceleration;
if (argc < 3 || JS_ToInt32(ctx, &interval, argv[0]) || JS_ToInt32(ctx, &acceleration, argv[1]) || JS_ToInt32(ctx, &deceleration, argv[2]))
return JS_RaiseDisrupt(ctx, "Expected 3 int arguments: interval, acceleration, deceleration");
if (JS_ToInt32(ctx, &interval, argv[1]) || JS_ToInt32(ctx, &acceleration, argv[2]) || JS_ToInt32(ctx, &deceleration, argv[3]))
return JS_RaiseDisrupt(ctx, "throttle_configure: expected integer arguments");
enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
return JS_NULL;
}
/* peer_timeout(peer, limit, min, max) */
static JSValue js_enet_peer_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 4) return JS_RaiseDisrupt(ctx, "peer_timeout: expected (peer, limit, min, max)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "peer_timeout: invalid peer");
int timeout_limit, timeout_min, timeout_max;
if (argc < 3 || JS_ToInt32(ctx, &timeout_limit, argv[0]) || JS_ToInt32(ctx, &timeout_min, argv[1]) || JS_ToInt32(ctx, &timeout_max, argv[2]))
return JS_RaiseDisrupt(ctx, "Expected 3 integer arguments: timeout_limit, timeout_min, timeout_max");
if (JS_ToInt32(ctx, &timeout_limit, argv[1]) || JS_ToInt32(ctx, &timeout_min, argv[2]) || JS_ToInt32(ctx, &timeout_max, argv[3]))
return JS_RaiseDisrupt(ctx, "peer_timeout: expected integer arguments");
enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max);
return JS_NULL;
}
// Class definitions
static JSClassDef enet_host = {
"ENetHost",
.finalizer = js_enet_host_finalizer,
};
/* ── Peer property getters ──────────────────────────────────── */
static JSClassDef enet_peer_class = {
"ENetPeer",
.finalizer = js_enet_peer_finalizer,
};
static JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue *argv)
{
const char *hostname = JS_ToCString(js, argv[0]);
JS_FreeCString(js, hostname);
return JS_NULL;
#define PEER_GETTER(name, field, convert) \
static JSValue js_enet_##name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \
if (argc < 1) return JS_RaiseDisrupt(ctx, #name ": expected (peer)"); \
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id); \
if (!peer) return JS_RaiseDisrupt(ctx, #name ": invalid peer"); \
return convert(ctx, peer->field); \
}
static const JSCFunctionListEntry js_enet_funcs[] = {
JS_CFUNC_DEF("initialize", 0, js_enet_initialize),
JS_CFUNC_DEF("deinitialize", 0, js_enet_deinitialize),
JS_CFUNC_DEF("create_host", 1, js_enet_host_create),
JS_CFUNC_DEF("resolve_hostname", 1, js_enet_resolve_hostname),
};
static inline JSValue _int32(JSContext *ctx, int v) { return JS_NewInt32(ctx, v); }
static inline JSValue _uint32(JSContext *ctx, unsigned int v) { return JS_NewUint32(ctx, v); }
static const JSCFunctionListEntry js_enet_host_funcs[] = {
JS_CFUNC_DEF("service", 2, js_enet_host_service),
JS_CFUNC_DEF("connect", 2, js_enet_host_connect),
JS_CFUNC_DEF("flush", 0, js_enet_host_flush),
JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast),
JS_CFUNC0_DEF("port", js_enet_host_get_port),
JS_CFUNC0_DEF("address", js_enet_host_get_address),
};
PEER_GETTER(peer_rtt, roundTripTime, _int32)
PEER_GETTER(peer_rtt_variance, roundTripTimeVariance, _int32)
PEER_GETTER(peer_last_send_time, lastSendTime, _int32)
PEER_GETTER(peer_last_receive_time, lastReceiveTime, _int32)
PEER_GETTER(peer_mtu, mtu, _int32)
PEER_GETTER(peer_outgoing_data_total, outgoingDataTotal, _int32)
PEER_GETTER(peer_incoming_data_total, incomingDataTotal, _int32)
PEER_GETTER(peer_packet_loss, packetLoss, _int32)
PEER_GETTER(peer_state, state, _int32)
PEER_GETTER(peer_reliable_data_in_transit, reliableDataInTransit, _int32)
// Peer property getters (zero-arg methods)
static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val)
static JSValue js_enet_peer_incoming_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
return JS_NewInt32(ctx, peer->roundTripTime);
}
static JSValue js_enet_peer_get_incoming_bandwidth(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: invalid peer");
if (peer->incomingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->incomingBandwidth);
}
static JSValue js_enet_peer_get_outgoing_bandwidth(JSContext *ctx, JSValueConst this_val)
static JSValue js_enet_peer_outgoing_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_outgoing_bandwidth: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "peer_outgoing_bandwidth: invalid peer");
if (peer->outgoingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->outgoingBandwidth);
}
static JSValue js_enet_peer_get_last_send_time(JSContext *ctx, JSValueConst this_val)
static JSValue js_enet_peer_port(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
return JS_NewInt32(ctx, peer->lastSendTime);
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_port: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "peer_port: invalid peer");
return JS_NewUint32(ctx, peer->address.port);
}
static JSValue js_enet_peer_get_last_receive_time(JSContext *ctx, JSValueConst this_val)
static JSValue js_enet_peer_address(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
return JS_NewInt32(ctx, peer->lastReceiveTime);
}
static JSValue js_enet_peer_get_mtu(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->mtu);
}
static JSValue js_enet_peer_get_outgoing_data_total(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->outgoingDataTotal);
}
static JSValue js_enet_peer_get_incoming_data_total(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->incomingDataTotal);
}
static JSValue js_enet_peer_get_rtt_variance(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->roundTripTimeVariance);
}
static JSValue js_enet_peer_get_packet_loss(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->packetLoss);
}
static JSValue js_enet_peer_get_state(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewInt32(ctx, -1);
return JS_NewInt32(ctx, peer->state);
}
static JSValue js_enet_peer_get_reliable_data_in_transit(JSContext *ctx, JSValueConst this_val)
{
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id);
if (!peer) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->reliableDataInTransit);
}
static JSValue js_enet_peer_get_port(JSContext *js, JSValueConst self)
{
ENetPeer *peer = JS_GetOpaque(self, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
return JS_NewUint32(js, peer->address.port);
}
static JSValue js_enet_peer_get_address(JSContext *js, JSValueConst self)
{
ENetPeer *peer = JS_GetOpaque(self, enet_peer_class_id);
if (!peer) return JS_EXCEPTION;
if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_address: expected (peer)");
ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "peer_address: invalid peer");
char ip_str[128];
if (enet_address_get_host_ip(&peer->address, ip_str, sizeof(ip_str)) != 0)
return JS_NULL;
return JS_NewString(js, ip_str);
return JS_NewString(ctx, ip_str);
}
static const JSCFunctionListEntry js_enet_peer_funcs[] = {
JS_CFUNC_DEF("send", 1, js_enet_peer_send),
JS_CFUNC_DEF("disconnect", 0, js_enet_peer_disconnect),
JS_CFUNC_DEF("disconnect_now", 0, js_enet_peer_disconnect_now),
JS_CFUNC_DEF("disconnect_later", 0, js_enet_peer_disconnect_later),
JS_CFUNC_DEF("reset", 0, js_enet_peer_reset),
JS_CFUNC_DEF("ping", 0, js_enet_peer_ping),
JS_CFUNC_DEF("throttle_configure", 3, js_enet_peer_throttle_configure),
JS_CFUNC_DEF("timeout", 3, js_enet_peer_timeout),
JS_CFUNC0_DEF("rtt", js_enet_peer_get_rtt),
JS_CFUNC0_DEF("incoming_bandwidth", js_enet_peer_get_incoming_bandwidth),
JS_CFUNC0_DEF("outgoing_bandwidth", js_enet_peer_get_outgoing_bandwidth),
JS_CFUNC0_DEF("last_send_time", js_enet_peer_get_last_send_time),
JS_CFUNC0_DEF("last_receive_time", js_enet_peer_get_last_receive_time),
JS_CFUNC0_DEF("mtu", js_enet_peer_get_mtu),
JS_CFUNC0_DEF("outgoing_data_total", js_enet_peer_get_outgoing_data_total),
JS_CFUNC0_DEF("incoming_data_total", js_enet_peer_get_incoming_data_total),
JS_CFUNC0_DEF("rtt_variance", js_enet_peer_get_rtt_variance),
JS_CFUNC0_DEF("packet_loss", js_enet_peer_get_packet_loss),
JS_CFUNC0_DEF("state", js_enet_peer_get_state),
JS_CFUNC0_DEF("reliable_data_in_transit", js_enet_peer_get_reliable_data_in_transit),
JS_CFUNC0_DEF("port", js_enet_peer_get_port),
JS_CFUNC0_DEF("address", js_enet_peer_get_address),
static JSValue js_enet_resolve_hostname(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
const char *hostname = JS_ToCString(ctx, argv[0]);
JS_FreeCString(ctx, hostname);
return JS_NULL;
}
/* ── Module export ──────────────────────────────────────────── */
static const JSCFunctionListEntry js_enet_funcs[] = {
/* host */
JS_CFUNC_DEF("create_host", 1, js_enet_create_host),
JS_CFUNC_DEF("service", 2, js_enet_service),
JS_CFUNC_DEF("connect", 3, js_enet_connect),
JS_CFUNC_DEF("flush", 1, js_enet_flush),
JS_CFUNC_DEF("broadcast", 2, js_enet_broadcast),
JS_CFUNC_DEF("host_port", 1, js_enet_host_port),
JS_CFUNC_DEF("host_address", 1, js_enet_host_address),
/* peer */
JS_CFUNC_DEF("send", 2, js_enet_send),
JS_CFUNC_DEF("disconnect", 1, js_enet_disconnect),
JS_CFUNC_DEF("disconnect_now", 1, js_enet_disconnect_now),
JS_CFUNC_DEF("disconnect_later", 1, js_enet_disconnect_later),
JS_CFUNC_DEF("reset", 1, js_enet_reset),
JS_CFUNC_DEF("ping", 1, js_enet_ping),
JS_CFUNC_DEF("throttle_configure", 4, js_enet_throttle_configure),
JS_CFUNC_DEF("peer_timeout", 4, js_enet_peer_timeout),
JS_CFUNC_DEF("peer_address", 1, js_enet_peer_address),
JS_CFUNC_DEF("peer_port", 1, js_enet_peer_port),
JS_CFUNC_DEF("peer_rtt", 1, js_enet_peer_rtt),
JS_CFUNC_DEF("peer_rtt_variance", 1, js_enet_peer_rtt_variance),
JS_CFUNC_DEF("peer_incoming_bandwidth", 1, js_enet_peer_incoming_bandwidth),
JS_CFUNC_DEF("peer_outgoing_bandwidth", 1, js_enet_peer_outgoing_bandwidth),
JS_CFUNC_DEF("peer_last_send_time", 1, js_enet_peer_last_send_time),
JS_CFUNC_DEF("peer_last_receive_time", 1, js_enet_peer_last_receive_time),
JS_CFUNC_DEF("peer_mtu", 1, js_enet_peer_mtu),
JS_CFUNC_DEF("peer_outgoing_data_total", 1, js_enet_peer_outgoing_data_total),
JS_CFUNC_DEF("peer_incoming_data_total", 1, js_enet_peer_incoming_data_total),
JS_CFUNC_DEF("peer_packet_loss", 1, js_enet_peer_packet_loss),
JS_CFUNC_DEF("peer_state", 1, js_enet_peer_state),
JS_CFUNC_DEF("peer_reliable_data_in_transit", 1, js_enet_peer_reliable_data_in_transit),
JS_CFUNC_DEF("resolve_hostname", 1, js_enet_resolve_hostname),
};
JSValue js_core_internal_enet_use(JSContext *ctx)
@@ -529,16 +461,10 @@ JSValue js_core_internal_enet_use(JSContext *ctx)
JS_FRAME(ctx);
JS_NewClassID(&enet_host_id);
JS_NewClass(ctx, enet_host_id, &enet_host);
JS_ROOT(host_proto, JS_NewObject(ctx));
JS_SetPropertyFunctionList(ctx, host_proto.val, js_enet_host_funcs, countof(js_enet_host_funcs));
JS_SetClassProto(ctx, enet_host_id, host_proto.val);
JS_NewClass(ctx, enet_host_id, &enet_host_def);
JS_NewClassID(&enet_peer_class_id);
JS_NewClass(ctx, enet_peer_class_id, &enet_peer_class);
JS_ROOT(peer_proto, JS_NewObject(ctx));
JS_SetPropertyFunctionList(ctx, peer_proto.val, js_enet_peer_funcs, countof(js_enet_peer_funcs));
JS_SetClassProto(ctx, enet_peer_class_id, peer_proto.val);
JS_NewClass(ctx, enet_peer_class_id, &enet_peer_def);
JS_ROOT(export_obj, JS_NewObject(ctx));
JS_SetPropertyFunctionList(ctx, export_obj.val, js_enet_funcs, countof(js_enet_funcs));

View File

@@ -5,6 +5,10 @@ var native_mode = false
var _no_warn = (init != null && init.no_warn) ? true : false
var SYSYM = '__SYSTEM__'
var log = function(name, args) {
}
var _cell = {}
var need_stop = false
@@ -539,7 +543,7 @@ if (_init != null && _init.native_mode)
if (args != null && (_init == null || !_init.program)) {
_program = args[0]
while (_j < length(args)) {
push(_user_args, args[_j])
_user_args[] = args[_j]
_j = _j + 1
}
if (_init == null) {
@@ -908,6 +912,7 @@ $_.delay = function delay(fn, seconds) {
send_messages()
}
var id = actor_mod.delay(delay_turn, _seconds)
log.connection(`$delay: registered timer id=${text(id)} seconds=${text(_seconds)}`)
return function() { actor_mod.removetimer(id) }
}
@@ -940,7 +945,7 @@ $_.start = function start(cb, program) {
no_warn: _no_warn,
}
greeters[id] = cb
push(message_queue, { startup })
message_queue[] = { startup }
}
$_.receiver = function receiver(fn) {
@@ -959,20 +964,34 @@ $_.couple = function couple(actor) {
}
$_.contact = function(callback, record) {
send(create_actor(record), record, callback)
log.connection(`contact: creating actor for ${record.address}:${text(record.port)}`)
var a = create_actor(record)
log.connection(`contact: actor created, sending contact`)
send(a, record, function(reply) {
var server = null
if (reply && reply.actor_id) {
server = create_actor({id: reply.actor_id, address: record.address, port: record.port})
log.connection(`contact: connected, server id=${reply.actor_id}`)
callback(server)
} else {
log.connection(`contact: connection failed or no reply`)
callback(null)
}
})
}
$_.portal = function(fn, port) {
if (portal) {
log.error(`Already started a portal listening on ${portal.port()}`)
log.error(`Already started a portal listening on ${enet.host_port(portal)}`)
disrupt
}
if (!port) {
log.error("Requires a valid port.")
disrupt
}
log.system(`starting a portal on port ${port}`)
log.connection(`portal: starting on port ${text(port)}`)
portal = enet.create_host({address: "any", port})
log.connection(`portal: created host=${portal}`)
portal_fn = fn
enet_check()
}
@@ -1362,59 +1381,74 @@ function guid(bits)
}
enet = use_core('internal/enet')
enet = use_core('enet')
function peer_connection(peer) {
return {
latency: peer.rtt(),
latency: enet.peer_rtt(peer),
bandwidth: {
incoming: peer.incoming_bandwidth(),
outgoing: peer.outgoing_bandwidth()
incoming: enet.peer_incoming_bandwidth(peer),
outgoing: enet.peer_outgoing_bandwidth(peer)
},
activity: {
last_sent: peer.last_send_time(),
last_received: peer.last_receive_time()
last_sent: enet.peer_last_send_time(peer),
last_received: enet.peer_last_receive_time(peer)
},
mtu: peer.mtu(),
mtu: enet.peer_mtu(peer),
data: {
incoming_total: peer.incoming_data_total(),
outgoing_total: peer.outgoing_data_total(),
reliable_in_transit: peer.reliable_data_in_transit()
incoming_total: enet.peer_incoming_data_total(peer),
outgoing_total: enet.peer_outgoing_data_total(peer),
reliable_in_transit: enet.peer_reliable_data_in_transit(peer)
},
latency_variance: peer.rtt_variance(),
packet_loss: peer.packet_loss(),
state: peer.state()
latency_variance: enet.peer_rtt_variance(peer),
packet_loss: enet.peer_packet_loss(peer),
state: enet.peer_state(peer)
}
}
// Strip ::ffff: prefix from IPv6-mapped IPv4 addresses
function normalize_addr(addr) {
if (starts_with(addr, "::ffff:"))
return text(addr, 7)
return addr
}
function handle_host(e) {
var queue = null
var data = null
var addr = null
var port = null
var pkey = null
log.connection(`handle_host: event type=${e.type}`)
if (e.type == "connect") {
addr = e.peer.address()
port = e.peer.port()
log.system(`connected a new peer: ${addr}:${port}`)
peers[`${addr}:${port}`] = e.peer
queue = peer_queue[e.peer]
addr = normalize_addr(enet.peer_address(e.peer))
port = enet.peer_port(e.peer)
pkey = addr + ":" + text(port)
log.connection(`handle_host: peer connected ${pkey}`)
peers[pkey] = e.peer
queue = peer_queue[pkey]
if (queue) {
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
log.system(`sent queue out of queue`)
delete peer_queue[e.peer]
log.connection(`handle_host: flushing ${text(length(queue))} queued messages to ${pkey}`)
arrfor(queue, (msg, index) => enet.send(e.peer, nota.encode(msg)))
delete peer_queue[pkey]
} else {
log.connection(`handle_host: no queued messages for ${pkey}`)
}
} else if (e.type == "disconnect") {
delete peer_queue[e.peer]
arrfor(array(peers), function(id, index) {
if (peers[id] == e.peer) delete peers[id]
})
log.system('portal got disconnect from ' + e.peer.address() + ":" + e.peer.port())
addr = normalize_addr(enet.peer_address(e.peer))
port = enet.peer_port(e.peer)
pkey = addr + ":" + text(port)
log.connection(`handle_host: peer disconnected ${pkey}`)
delete peer_queue[pkey]
delete peers[pkey]
} else if (e.type == "receive") {
data = nota.decode(e.data)
if (data.replycc && !data.replycc.address) {
data.replycc[ACTORDATA].address = e.peer.address()
data.replycc[ACTORDATA].port = e.peer.port()
log.connection(`handle_host: received data type=${data.type}`)
if (data.replycc_id && !data.replycc) {
data.replycc = create_actor({id: data.replycc_id, address: normalize_addr(enet.peer_address(e.peer)), port: enet.peer_port(e.peer)})
} else if (data.replycc && !data.replycc.address) {
data.replycc[ACTORDATA].address = normalize_addr(enet.peer_address(e.peer))
data.replycc[ACTORDATA].port = enet.peer_port(e.peer)
}
if (data.data) populate_actor_addresses(data.data, e)
handle_message(data)
@@ -1425,8 +1459,8 @@ function handle_host(e) {
function populate_actor_addresses(obj, e) {
if (!is_object(obj)) return
if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
obj[ACTORDATA].address = e.peer.address()
obj[ACTORDATA].port = e.peer.port()
obj[ACTORDATA].address = normalize_addr(enet.peer_address(e.peer))
obj[ACTORDATA].port = enet.peer_port(e.peer)
}
arrfor(array(obj), function(key, index) {
if (key in obj)
@@ -1436,7 +1470,7 @@ function populate_actor_addresses(obj, e) {
function actor_prep(actor, send) {
push(message_queue, {actor,send});
message_queue[] = {actor,send};
}
// Send a message immediately without queuing
@@ -1447,6 +1481,7 @@ function actor_send_immediate(actor, send) {
function actor_send(actor, message) {
var wota_blob = null
var peer = null
var pkey = null
if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
return
@@ -1463,12 +1498,14 @@ function actor_send(actor, message) {
// message to self
if (actor[ACTORDATA].id == _cell.id) {
log.connection(`actor_send: message to self, type=${message.type}`)
if (receive_fn) receive_fn(message.data)
return
}
// message to actor in same flock
if (actor[ACTORDATA].id && actor_mod.mailbox_exist(actor[ACTORDATA].id)) {
log.connection(`actor_send: local mailbox for ${text(actor[ACTORDATA].id, 0, 8)}`)
wota_blob = wota.encode(message)
actor_mod.mailbox_push(actor[ACTORDATA].id, wota_blob)
return
@@ -1480,23 +1517,27 @@ function actor_send(actor, message) {
else
message.type = "contact"
peer = peers[actor[ACTORDATA].address + ":" + actor[ACTORDATA].port]
pkey = actor[ACTORDATA].address + ":" + text(actor[ACTORDATA].port)
log.connection(`actor_send: remote ${pkey} msg.type=${message.type}`)
peer = peers[pkey]
if (!peer) {
if (!portal) {
log.system(`creating a contactor ...`)
log.connection(`actor_send: no portal, creating contactor`)
portal = enet.create_host({address:"any"})
log.system(`allowing contact to port ${portal.port()}`)
log.connection(`actor_send: contactor on port ${text(enet.host_port(portal))}`)
enet_check()
}
log.system(`no peer! connecting to ${actor[ACTORDATA].address}:${actor[ACTORDATA].port}`)
peer = portal.connect(actor[ACTORDATA].address, actor[ACTORDATA].port)
peer_queue.set(peer, [message])
log.connection(`actor_send: no peer for ${pkey}, connecting...`)
peer = enet.connect(portal, actor[ACTORDATA].address, actor[ACTORDATA].port)
log.connection(`actor_send: connect initiated, peer=${peer}, queuing message`)
peer_queue[pkey] = [message]
} else {
peer.send(nota.encode(message))
log.connection(`actor_send: have peer for ${pkey}, sending directly`)
enet.send(peer, nota.encode(message))
}
return
}
log.system(`Unable to send message to actor ${actor[ACTORDATA].id}`)
log.connection(`actor_send: no route for actor id=${actor[ACTORDATA].id} (no address, not local)`)
}
function send_messages() {
@@ -1509,6 +1550,8 @@ function send_messages() {
var _qi = 0
var _qm = null
if (length(message_queue) > 0)
log.connection(`send_messages: processing ${text(length(message_queue))} queued messages`)
while (_qi < length(message_queue)) {
_qm = message_queue[_qi]
if (_qm.startup) {
@@ -1667,13 +1710,40 @@ function handle_sysym(msg)
function handle_message(msg) {
var letter = null
var fn = null
var conn = null
var pkey = null
var peer = null
var reply_msg = null
log.connection(`handle_message: type=${msg.type}`)
if (msg[SYSYM]) {
handle_sysym(msg[SYSYM])
return
}
if (msg.type == "user") {
if (msg.type == "contact") {
// Remote $contact arrived — create a connection actor for the caller.
// msg.replycc was constructed by handle_host with id + address + port.
conn = msg.replycc
log.connection(`handle_message: contact from ${conn ? conn[ACTORDATA].id : "unknown"}`)
// Reply directly over enet so the client's $contact callback fires
if (conn && msg.reply) {
pkey = conn[ACTORDATA].address + ":" + text(conn[ACTORDATA].port)
peer = peers[pkey]
if (peer) {
reply_msg = {type: "user", data: {type: "connected", actor_id: _cell.id}, return: msg.reply}
log.connection(`handle_message: sending contact reply to ${pkey}`)
enet.send(peer, nota.encode(reply_msg))
}
}
if (portal_fn) {
log.connection(`handle_message: calling portal_fn`)
portal_fn(conn)
}
} else if (msg.type == "user") {
letter = msg.data // what the sender really sent
if (msg.replycc_id) {
msg.replycc = create_actor({id: msg.replycc_id})
@@ -1683,11 +1753,13 @@ function handle_message(msg) {
if (msg.return) {
fn = replies[msg.return]
log.connection(`handle_message: reply callback ${msg.return} fn=${fn ? "yes" : "no"}`)
if (fn) fn(letter)
delete replies[msg.return]
return
}
log.connection(`handle_message: dispatching to receive_fn=${receive_fn ? "yes" : "no"}`)
if (receive_fn) receive_fn(letter)
} else if (msg.type == "stopped") {
handle_actor_disconnect(msg.id)
@@ -1696,8 +1768,12 @@ function handle_message(msg) {
function enet_check()
{
if (portal) portal.service(handle_host)
if (portal) {
log.connection(`enet_check: servicing portal`)
enet.service(portal, handle_host)
} else {
log.connection(`enet_check: no portal`)
}
$_.delay(enet_check, ENETSERVICE);
}

View File

@@ -117,10 +117,10 @@ JSC_CCALL(fd_read,
JSC_SCALL(fd_slurp,
struct stat st;
if (stat(str, &st) != 0)
return JS_RaiseDisrupt(js, "stat failed: %s", strerror(errno));
return JS_RaiseDisrupt(js, "stat failed for %s: %s", str, strerror(errno));
if (!S_ISREG(st.st_mode))
return JS_RaiseDisrupt(js, "path is not a regular file");
return JS_RaiseDisrupt(js, "path %s is not a regular file", str);
size_t size = st.st_size;
if (size == 0)

View File

@@ -1021,8 +1021,29 @@ function ensure_package_dylibs(pkg) {
var build_mod = use_cache['core/build']
var target = null
var c_files = null
var _all_ok = true
var _ri = 0
if (build_mod) {
// Fast path: if manifest exists and all dylibs are present, skip build_dynamic
results = read_dylib_manifest(_pkg)
if (results != null) {
_all_ok = true
_ri = 0
while (_ri < length(results)) {
if (results[_ri].dylib && !fd.is_file(results[_ri].dylib)) {
_all_ok = false
break
}
_ri = _ri + 1
}
if (_all_ok) {
log.shop('manifest ok for ' + _pkg + ' (' + text(length(results)) + ' modules)')
} else {
results = null
}
}
if (results == null) {
target = detect_host_target()
if (!target) return null
@@ -1034,6 +1055,7 @@ function ensure_package_dylibs(pkg) {
log.shop('ensuring C modules for ' + _pkg)
results = build_mod.build_dynamic(_pkg, target, 'release', {})
}
} else {
// No build module at runtime — read manifest from cell build
results = read_dylib_manifest(_pkg)
@@ -1477,18 +1499,18 @@ Shop.use = function use(path, _pkg_ctx) {
if (use_cache[info.cache_key])
return use_cache[info.cache_key]
push(use_stack, _use_entry)
use_stack[] = _use_entry
var _use_result = null
var _use_ok = false
var _load = function() {
_use_result = execute_module(info)
_use_ok = true
} disruption {
pop(use_stack)
use_stack[]
disrupt
}
_load()
pop(use_stack)
use_stack[]
use_cache[info.cache_key] = _use_result
return _use_result
}
@@ -1622,12 +1644,16 @@ function download_zip(pkg, commit_hash) {
return _download()
}
// Get zip from cache, returns null if not cached
// Get zip from cache, returns null if not cached or empty
function get_cached_zip(pkg, commit_hash) {
var cache_path = get_cache_path(pkg, commit_hash)
if (fd.is_file(cache_path))
return fd.slurp(cache_path)
var data = null
if (fd.is_file(cache_path)) {
data = fd.slurp(cache_path)
stone(data)
if (length(data) > 0) return data
fd.remove(cache_path)
}
return null
}
@@ -1883,7 +1909,7 @@ Shop.sync_with_deps = function(pkg, opts) {
if (visited[current]) continue
visited[current] = true
log.console(' Fetching ' + current + '...')
log.build(' Fetching ' + current + '...')
Shop.sync(current, opts)
_read_deps = function() {
@@ -1897,7 +1923,7 @@ Shop.sync_with_deps = function(pkg, opts) {
arrfor(array(deps), function(alias) {
dep_locator = deps[alias]
if (!visited[dep_locator])
push(queue, dep_locator)
queue[] = dep_locator
})
}
}
@@ -2036,7 +2062,7 @@ function get_package_scripts(package)
for (i = 0; i < length(files); i++) {
file = files[i]
if (ends_with(file, '.cm') || ends_with(file, '.ce')) {
push(scripts, file)
scripts[] = file
}
}
@@ -2058,7 +2084,7 @@ function extract_use_calls(source) {
if (end == null) end = search(text(source, start), '"')
if (end != null) {
arg = text(source, start, start + end)
push(uses, arg)
uses[] = arg
}
idx = search(text(source, idx + 4), "use(")
if (idx != null) idx = idx + (source.length - (source.length - idx))
@@ -2081,16 +2107,16 @@ Shop.build_package_scripts = function(package)
resolve_mod_fn(pkg_dir + '/' + script, package)
ok = ok + 1
} disruption {
push(errors, script)
log.console(" compile error: " + package + '/' + script)
errors[] = script
log.build(" compile error: " + package + '/' + script)
}
_try()
})
if (length(errors) > 0) {
log.console(' Compiling scripts (' + text(ok) + ' ok, ' + text(length(errors)) + ' errors)')
log.build(' Compiling scripts (' + text(ok) + ' ok, ' + text(length(errors)) + ' errors)')
} else if (ok > 0) {
log.console(' Compiling scripts (' + text(ok) + ' ok)')
log.build(' Compiling scripts (' + text(ok) + ' ok)')
}
return {ok: ok, errors: errors, total: length(scripts)}
@@ -2134,14 +2160,14 @@ Shop.audit_use_resolution = function(package) {
end = search(rest, quote)
if (end == null) continue
arg = text(rest, 0, end)
if (length(arg) > 0) push(uses, arg)
if (length(arg) > 0) uses[] = arg
rest = text(rest, end + 1)
}
arrfor(uses, function(mod) {
var _resolve = function() {
info = resolve_module_info(mod, package)
if (!info) push(unresolved, {script: script, module: mod})
if (!info) unresolved[] = {script: script, module: mod}
} disruption {}
_resolve()
})
@@ -2392,7 +2418,7 @@ Shop.audit_packages = function() {
if (package == 'core') return
if (fd.is_dir(package)) return
if (fetch_remote_hash(package)) return
push(bad, package)
bad[] = package
})
return bad

View File

@@ -208,11 +208,11 @@ Link.sync_all = function(shop) {
// Validate target exists
var link_target = resolve_link_target(target)
if (!fd.is_dir(link_target)) {
push(errors, canonical + ': target ' + link_target + ' does not exist')
errors[] = canonical + ': target ' + link_target + ' does not exist'
return
}
if (!fd.is_file(link_target + '/cell.toml')) {
push(errors, canonical + ': target ' + link_target + ' is not a valid package')
errors[] = canonical + ': target ' + link_target + ' is not a valid package'
return
}
@@ -246,7 +246,7 @@ Link.sync_all = function(shop) {
count = count + 1
} disruption {
push(errors, canonical + ': sync failed')
errors[] = canonical + ': sync failed'
}
_sync()
})

14
list.ce
View File

@@ -89,16 +89,16 @@ var run = function() {
// Add status indicators
status = []
if (link_target) {
push(status, "linked -> " + link_target)
status[] = "linked -> " + link_target
}
if (lock_entry && lock_entry.commit) {
push(status, "@" + text(lock_entry.commit, 0, 8))
status[] = "@" + text(lock_entry.commit, 0, 8)
}
if (lock_entry && lock_entry.type == 'local') {
push(status, "local")
status[] = "local"
}
if (!lock_entry) {
push(status, "not installed")
status[] = "not installed"
}
if (length(status) > 0) {
@@ -136,11 +136,11 @@ if (mode == 'local') {
var link_target = links[p]
if (link_target) {
push(linked_pkgs, p)
linked_pkgs[] = p
} else if (lock_entry && lock_entry.type == 'local') {
push(local_pkgs, p)
local_pkgs[] = p
} else {
push(remote_pkgs, p)
remote_pkgs[] = p
}
})

10
log.ce
View File

@@ -371,6 +371,7 @@ function do_enable() {
var sink = null
var i = 0
var already = false
var new_exclude = []
if (length(args) < 2) {
log.error("Usage: cell log enable <channel>")
return
@@ -388,9 +389,9 @@ function do_enable() {
}
if (is_array(sink.channels) && length(sink.channels) == 1 && sink.channels[0] == "*") {
if (is_array(sink.exclude)) {
var new_exclude = []
new_exclude = []
arrfor(sink.exclude, function(ex) {
if (ex != channel) push(new_exclude, ex)
if (ex != channel) new_exclude[] = ex
})
sink.exclude = new_exclude
}
@@ -411,6 +412,7 @@ function do_disable() {
var sink = null
var i = 0
var new_channels = []
var already_excluded = false
if (length(args) < 2) {
log.error("Usage: cell log disable <channel>")
return
@@ -428,7 +430,7 @@ function do_disable() {
}
if (is_array(sink.channels) && length(sink.channels) == 1 && sink.channels[0] == "*") {
if (!is_array(sink.exclude)) sink.exclude = []
var already_excluded = false
already_excluded = false
arrfor(sink.exclude, function(ex) {
if (ex == channel) already_excluded = true
})
@@ -436,7 +438,7 @@ function do_disable() {
} else {
if (is_array(sink.channels)) {
arrfor(sink.channels, function(ch) {
if (ch != channel) push(new_channels, ch)
if (ch != channel) new_channels[] = ch
})
sink.channels = new_channels
}

View File

@@ -85,7 +85,7 @@ var dump_function = function(func, name) {
parts = []
j = 1
while (j < n - 2) {
push(parts, fmt_val(instr[j]))
parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(parts, ", ")

View File

@@ -166,7 +166,7 @@ var mcode = function(ast) {
// Variable tracking
var add_var = function(name, slot, is_const) {
push(s_vars, {name: name, slot: slot, is_const: is_const, is_closure: false})
s_vars[] = {name: name, slot: slot, is_const: is_const, is_closure: false}
}
var find_var = function(name) {
@@ -228,13 +228,13 @@ var mcode = function(ast) {
// Instruction emission
var add_instr = function(instr) {
push(instr, s_cur_line)
push(instr, s_cur_col)
push(s_instructions, instr)
instr[] = s_cur_line
instr[] = s_cur_col
s_instructions[] = instr
}
var emit_label = function(label) {
push(s_instructions, label)
s_instructions[] = label
}
var emit_0 = function(op) {
@@ -743,7 +743,7 @@ var mcode = function(ast) {
slot = alloc_slot()
lit = {kind: "name", name: name, make: "intrinsic"}
add_instr(["access", slot, lit])
push(s_intrinsic_cache, {name: name, slot: slot})
s_intrinsic_cache[] = {name: name, slot: slot}
_i = _i + 1
}
}
@@ -1974,7 +1974,7 @@ var mcode = function(ast) {
expr_slots = []
_i = 0
while (_i < nexpr) {
push(expr_slots, gen_expr(list[_i], -1))
expr_slots[] = gen_expr(list[_i], -1)
_i = _i + 1
}
// Create array from expression results
@@ -2083,6 +2083,23 @@ var mcode = function(ast) {
if (kind == "[") {
obj = expr.left
idx = expr.right
if (idx == null) {
// arr[] pop expression
obj_slot = gen_expr(obj, -1)
guard_t = alloc_slot()
guard_err = gen_label("pop_err")
guard_done = gen_label("pop_done")
emit_2("is_array", guard_t, obj_slot)
emit_jump_cond("jump_false", guard_t, guard_err)
slot = target >= 0 ? target : alloc_slot()
emit_2("pop", slot, obj_slot)
emit_jump(guard_done)
emit_label(guard_err)
emit_log_error("cannot pop: target must be an array")
emit_0("disrupt")
emit_label(guard_done)
return slot
}
obj_slot = gen_expr(obj, -1)
idx_slot = gen_expr(idx, -1)
slot = alloc_slot()
@@ -2264,7 +2281,7 @@ var mcode = function(ast) {
_i = 0
nargs = args_list != null ? length(args_list) : 0
while (_i < nargs) {
push(arg_slots, gen_expr(args_list[_i], -1))
arg_slots[] = gen_expr(args_list[_i], -1)
_i = _i + 1
}
dest = alloc_slot()
@@ -2432,7 +2449,7 @@ var mcode = function(ast) {
elem_slots = []
_i = 0
while (_i < count) {
push(elem_slots, gen_expr(list[_i], -1))
elem_slots[] = gen_expr(list[_i], -1)
_i = _i + 1
}
dest = alloc_slot()
@@ -2449,7 +2466,7 @@ var mcode = function(ast) {
if (kind == "record") {
list = expr.list
dest = alloc_slot()
push(s_instructions, ["record", dest, length(list)])
s_instructions[] = ["record", dest, length(list)]
_i = 0
while (_i < length(list)) {
pair = list[_i]
@@ -2479,7 +2496,7 @@ var mcode = function(ast) {
func = gen_function(expr)
func_id = s_func_counter
s_func_counter = s_func_counter + 1
push(s_functions, func)
s_functions[] = func
dest = alloc_slot()
emit_2("function", dest, func_id)
return dest
@@ -2797,7 +2814,7 @@ var mcode = function(ast) {
_i = 0
nargs = args_list != null ? length(args_list) : 0
while (_i < nargs) {
push(arg_slots, gen_expr(args_list[_i], -1))
arg_slots[] = gen_expr(args_list[_i], -1)
_i = _i + 1
}
callee_kind = callee.kind
@@ -2852,7 +2869,7 @@ var mcode = function(ast) {
case_kind = case_node.kind
if (case_kind == "default") {
default_label = gen_label("switch_default")
push(case_labels, default_label)
case_labels[] = default_label
} else {
case_label = gen_label("switch_case")
case_expr = case_node.expression
@@ -2862,7 +2879,7 @@ var mcode = function(ast) {
_bp_rn = case_expr
emit_binop("eq", cmp_slot, switch_val, case_val)
emit_jump_cond("jump_true", cmp_slot, case_label)
push(case_labels, case_label)
case_labels[] = case_label
}
_i = _i + 1
}
@@ -2894,7 +2911,7 @@ var mcode = function(ast) {
func = gen_function(stmt)
func_id = s_func_counter
s_func_counter = s_func_counter + 1
push(s_functions, func)
s_functions[] = func
local_slot = find_var(name)
dest = alloc_slot()
emit_2("function", dest, func_id)
@@ -2948,7 +2965,7 @@ var mcode = function(ast) {
var saved_func = 0
var captured_this = 0
push(parent_states, saved)
parent_states[] = saved
s_instructions = []
s_vars = []
@@ -3039,7 +3056,7 @@ var mcode = function(ast) {
compiled = gen_function(fn)
func_id = s_func_counter
s_func_counter = s_func_counter + 1
push(s_functions, compiled)
s_functions[] = compiled
local_slot = find_var(fname)
dest = alloc_slot()
emit_2("function", dest, func_id)
@@ -3112,7 +3129,7 @@ var mcode = function(ast) {
saved_func = s_func_counter
// Pop parent state
pop(parent_states)
parent_states[]
restore_state(saved)
s_label_counter = saved_label
s_func_counter = saved_func
@@ -3179,7 +3196,7 @@ var mcode = function(ast) {
compiled = gen_function(fn)
func_id = s_func_counter
s_func_counter = s_func_counter + 1
push(s_functions, compiled)
s_functions[] = compiled
local_slot = find_var(name)
dest = alloc_slot()
emit_2("function", dest, func_id)

View File

@@ -88,9 +88,9 @@ var packages = ['core']
var deps = pkg_tools.gather_dependencies(target_package)
for (i = 0; i < length(deps); i++) {
push(packages, deps[i])
packages[] = deps[i]
}
push(packages, target_package)
packages[] = target_package
// Remove duplicates
var unique_packages = []
@@ -98,7 +98,7 @@ var seen = {}
for (i = 0; i < length(packages); i++) {
if (!seen[packages[i]]) {
seen[packages[i]] = true
push(unique_packages, packages[i])
unique_packages[] = packages[i]
}
}
packages = unique_packages

View File

@@ -198,7 +198,7 @@ package.find_packages = function(dir) {
var list = fd.readdir(dir)
if (!list) return found
if (fd.is_file(dir + '/cell.toml'))
push(found, dir)
found[] = dir
arrfor(list, function(item) {
if (item == '.' || item == '..' || item == '.cell' || item == '.git') return
var full = dir + '/' + item
@@ -207,7 +207,7 @@ package.find_packages = function(dir) {
if (st && st.isDirectory) {
sub = package.find_packages(full)
arrfor(sub, function(p) {
push(found, p)
found[] = p
})
}
})
@@ -227,14 +227,14 @@ package.list_modules = function(name) {
var stem = null
for (i = 0; i < length(files); i++) {
if (ends_with(files[i], '.cm')) {
push(modules, text(files[i], 0, -3))
modules[] = text(files[i], 0, -3)
}
}
var c_files = package.get_c_files(name, null, true)
for (i = 0; i < length(c_files); i++) {
stem = ends_with(c_files[i], '.cpp') ? text(c_files[i], 0, -4) : text(c_files[i], 0, -2)
if (find(modules, function(m) { return m == stem }) == null)
push(modules, stem)
modules[] = stem
}
return modules
}
@@ -245,7 +245,7 @@ package.list_programs = function(name) {
var i = 0
for (i = 0; i < length(files); i++) {
if (ends_with(files[i], '.ce')) {
push(programs, text(files[i], 0, -3))
programs[] = text(files[i], 0, -3)
}
}
return programs
@@ -360,7 +360,7 @@ package.get_c_files = function(name, target, exclude_main) {
basename = fd.basename(selected)
if (basename == 'main.c' || starts_with(basename, 'main_')) return
}
push(result, selected)
result[] = selected
}
})

View File

@@ -90,12 +90,12 @@ var parse = function(tokens, src, filename, tokenizer) {
var parse_error = function(token, msg) {
if (error_count >= 5) return null
error_count = error_count + 1
push(errors, {
errors[] = {
message: msg,
line: token.from_row + 1,
column: token.from_column + 1,
offset: token.at
})
}
}
var _keywords = {
@@ -230,8 +230,8 @@ var parse = function(tokens, src, filename, tokenizer) {
if (tv[tvi] == "\\" && tvi + 1 < tvlen) {
esc_ch = tv[tvi + 1]
esc_val = template_escape_map[esc_ch]
if (esc_val != null) { push(fmt_parts, esc_val) }
else { push(fmt_parts, esc_ch) }
if (esc_val != null) { fmt_parts[] = esc_val }
else { fmt_parts[] = esc_ch }
tvi = tvi + 2
} else if (tv[tvi] == "$" && tvi + 1 < tvlen && tv[tvi + 1] == "{") {
tvi = tvi + 2
@@ -239,27 +239,27 @@ var parse = function(tokens, src, filename, tokenizer) {
expr_parts = []
while (tvi < tvlen && depth > 0) {
tc = tv[tvi]
if (tc == "{") { depth = depth + 1; push(expr_parts, tc); tvi = tvi + 1 }
if (tc == "{") { depth = depth + 1; expr_parts[] = tc; tvi = tvi + 1 }
else if (tc == "}") {
depth = depth - 1
if (depth > 0) { push(expr_parts, tc) }
if (depth > 0) { expr_parts[] = tc }
tvi = tvi + 1
}
else if (tc == "'" || tc == "\"" || tc == "`") {
tq = tc
push(expr_parts, tc)
expr_parts[] = tc
tvi = tvi + 1
while (tvi < tvlen && tv[tvi] != tq) {
if (tv[tvi] == "\\" && tvi + 1 < tvlen) {
push(expr_parts, tv[tvi])
expr_parts[] = tv[tvi]
tvi = tvi + 1
}
push(expr_parts, tv[tvi])
expr_parts[] = tv[tvi]
tvi = tvi + 1
}
if (tvi < tvlen) { push(expr_parts, tv[tvi]); tvi = tvi + 1 }
if (tvi < tvlen) { expr_parts[] = tv[tvi]; tvi = tvi + 1 }
} else {
push(expr_parts, tc)
expr_parts[] = tc
tvi = tvi + 1
}
}
@@ -274,14 +274,14 @@ var parse = function(tokens, src, filename, tokenizer) {
} else {
sub_expr = sub_stmt
}
push(tpl_list, sub_expr)
tpl_list[] = sub_expr
}
push(fmt_parts, "{")
push(fmt_parts, text(idx))
push(fmt_parts, "}")
fmt_parts[] = "{"
fmt_parts[] = text(idx)
fmt_parts[] = "}"
idx = idx + 1
} else {
push(fmt_parts, tv[tvi])
fmt_parts[] = tv[tvi]
tvi = tvi + 1
}
}
@@ -332,7 +332,7 @@ var parse = function(tokens, src, filename, tokenizer) {
advance()
while (tok.kind != "]" && tok.kind != "eof") {
elem = parse_assign_expr()
if (elem != null) push(list, elem)
if (elem != null) list[] = elem
if (tok.kind == ",") advance()
else break
}
@@ -395,7 +395,7 @@ var parse = function(tokens, src, filename, tokenizer) {
advance()
param.expression = parse_assign_expr()
}
push(params, param)
params[] = param
} else {
parse_error(tok, "expected parameter name")
break
@@ -436,7 +436,7 @@ var parse = function(tokens, src, filename, tokenizer) {
} else {
parse_error(tok, "expected ':' after property name")
}
push(list, pair)
list[] = pair
if (tok.kind == ",") advance()
else if (tok.kind == "{") {
if (right && right.kind == "(") {
@@ -473,17 +473,17 @@ var parse = function(tokens, src, filename, tokenizer) {
flags_parts = []
while (rpos < _src_len && src[rpos] != "/") {
if (src[rpos] == "\\" && rpos + 1 < _src_len) {
push(pattern_parts, src[rpos])
push(pattern_parts, src[rpos + 1])
pattern_parts[] = src[rpos]
pattern_parts[] = src[rpos + 1]
rpos = rpos + 2
} else {
push(pattern_parts, src[rpos])
pattern_parts[] = src[rpos]
rpos = rpos + 1
}
}
if (rpos < _src_len) rpos = rpos + 1
while (rpos < _src_len && is_letter(src[rpos])) {
push(flags_parts, src[rpos])
flags_parts[] = src[rpos]
rpos = rpos + 1
}
node.pattern = text(pattern_parts)
@@ -557,7 +557,7 @@ var parse = function(tokens, src, filename, tokenizer) {
new_node.list = args_list
while (tok.kind != ")" && tok.kind != "eof") {
arg = parse_assign_expr()
if (arg != null) push(args_list, arg)
if (arg != null) args_list[] = arg
if (tok.kind == ",") advance()
else break
}
@@ -830,7 +830,7 @@ var parse = function(tokens, src, filename, tokenizer) {
before = cursor
stmt = parse_statement()
if (stmt != null) {
push(stmts, stmt)
stmts[] = stmt
} else if (cursor == before) {
sync_to_statement()
}
@@ -872,14 +872,14 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value
pname = tok.value
if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'")
push(prev_names, pname)
prev_names[] = pname
advance()
ast_node_end(param)
if (tok.kind == "=" || tok.kind == "|") {
advance()
param.expression = parse_assign_expr()
}
push(params, param)
params[] = param
} else {
parse_error(tok, "expected parameter name")
break
@@ -959,7 +959,7 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value
advance()
ast_node_end(param)
push(params, param)
params[] = param
} else if (tok.kind == "(") {
advance()
prev_names = []
@@ -969,14 +969,14 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value
pname = tok.value
if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'")
push(prev_names, pname)
prev_names[] = pname
advance()
ast_node_end(param)
if (tok.kind == "=" || tok.kind == "|") {
advance()
param.expression = parse_assign_expr()
}
push(params, param)
params[] = param
} else {
parse_error(tok, "expected parameter name")
break
@@ -1010,7 +1010,7 @@ var parse = function(tokens, src, filename, tokenizer) {
expr = parse_assign_expr()
ret.expression = expr
ast_node_end(ret)
push(stmts, ret)
stmts[] = ret
node.statements = stmts
}
@@ -1110,7 +1110,7 @@ var parse = function(tokens, src, filename, tokenizer) {
parse_error(start, "'var' declarations must be initialized; use 'var " + var_name + " = null' if no value is needed")
}
ast_node_end(node)
push(decls, node)
decls[] = node
decl_count = decl_count + 1
if (tok.kind == ",") advance()
else break
@@ -1142,7 +1142,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1
_expecting_body = true
body = parse_statement()
if (body != null) push(then_stmts, body)
if (body != null) then_stmts[] = body
else_ifs = []
node.list = else_ifs
if (tok.kind == "else") {
@@ -1151,7 +1151,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = saved_cd
_control_type = saved_ct
elif = parse_statement()
if (elif != null) push(else_ifs, elif)
if (elif != null) else_ifs[] = elif
ast_node_end(node)
return node
} else {
@@ -1159,7 +1159,7 @@ var parse = function(tokens, src, filename, tokenizer) {
node.else = else_stmts
_expecting_body = true
body = parse_statement()
if (body != null) push(else_stmts, body)
if (body != null) else_stmts[] = body
}
}
_control_depth = saved_cd
@@ -1185,7 +1185,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1
_expecting_body = true
body = parse_statement()
if (body != null) push(stmts, body)
if (body != null) stmts[] = body
_control_depth = saved_cd
_control_type = saved_ct
ast_node_end(node)
@@ -1203,7 +1203,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1
_expecting_body = true
body = parse_statement()
if (body != null) push(stmts, body)
if (body != null) stmts[] = body
_control_depth = saved_cd
_control_type = saved_ct
if (tok.kind == "while") advance()
@@ -1256,7 +1256,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1
_expecting_body = true
body = parse_statement()
if (body != null) push(stmts, body)
if (body != null) stmts[] = body
_control_depth = saved_cd
_control_type = saved_ct
ast_node_end(node)
@@ -1402,9 +1402,9 @@ var parse = function(tokens, src, filename, tokenizer) {
stmt = parse_statement()
if (stmt != null) {
if (stmt.kind == "function") {
push(functions, stmt)
functions[] = stmt
} else {
push(statements, stmt)
statements[] = stmt
}
} else if (cursor == before) {
sync_to_statement()
@@ -1426,7 +1426,7 @@ var parse = function(tokens, src, filename, tokenizer) {
var err = {message: msg}
if (node.from_row != null) err.line = node.from_row + 1
if (node.from_column != null) err.column = node.from_column + 1
push(sem_errors, err)
sem_errors[] = err
}
var make_scope = function(parent, fn_nr, opts) {
@@ -1452,7 +1452,7 @@ var parse = function(tokens, src, filename, tokenizer) {
}
if (make_opts.reached == false) entry.reached = false
if (make_opts.decl_line != null) entry.decl_line = make_opts.decl_line
push(scope.vars, entry)
scope.vars[] = entry
}
var sem_lookup_var = function(scope, name) {
@@ -1503,7 +1503,7 @@ var parse = function(tokens, src, filename, tokenizer) {
}
var sem_add_intrinsic = function(name) {
if (find(intrinsics, name) == null) push(intrinsics, name)
if (find(intrinsics, name) == null) intrinsics[] = name
}
var functino_names = {
@@ -1828,7 +1828,7 @@ var parse = function(tokens, src, filename, tokenizer) {
}
}
sr = sem_build_scope_record(fn_scope)
push(scopes_array, sr.rec)
scopes_array[] = sr.rec
expr.nr_slots = sr.nr_slots
expr.nr_close_slots = sr.nr_close
return null
@@ -1858,9 +1858,9 @@ var parse = function(tokens, src, filename, tokenizer) {
r.v.nr_uses = r.v.nr_uses + 1
if (r.level > 0) r.v.closure = 1
if (r.v.reached == false && r.v.decl_line != null && expr.from_row != null && expr.from_row + 1 < r.v.decl_line) {
push(hoisted_fn_refs, {name: name, line: expr.from_row + 1,
hoisted_fn_refs[] = {name: name, line: expr.from_row + 1,
col: expr.from_column != null ? expr.from_column + 1 : null,
decl_line: r.v.decl_line})
decl_line: r.v.decl_line}
}
} else {
expr.level = -1
@@ -2110,7 +2110,7 @@ var parse = function(tokens, src, filename, tokenizer) {
}
}
sr = sem_build_scope_record(fn_scope)
push(scopes_array, sr.rec)
scopes_array[] = sr.rec
stmt.nr_slots = sr.nr_slots
stmt.nr_close_slots = sr.nr_close
return null
@@ -2153,7 +2153,7 @@ var parse = function(tokens, src, filename, tokenizer) {
new_scopes = [sr.rec]
i = 0
while (i < length(scopes_array)) {
push(new_scopes, scopes_array[i])
new_scopes[] = scopes_array[i]
i = i + 1
}
scopes_array = new_scopes
@@ -2183,7 +2183,7 @@ var parse = function(tokens, src, filename, tokenizer) {
if (ast.errors != null) {
_mi = 0
while (_mi < length(errors)) {
push(ast.errors, errors[_mi])
ast.errors[] = errors[_mi]
_mi = _mi + 1
}
} else {

View File

@@ -948,7 +948,7 @@ var qbe_emit = function(ir, qbe, export_name) {
// ============================================================
var emit = function(s) {
push(out, s)
out[] = s
}
var fresh = function() {
@@ -982,9 +982,9 @@ var qbe_emit = function(ir, qbe, export_name) {
escaped = replace(escaped, "\r", "\\r")
escaped = replace(escaped, "\t", "\\t")
var line = "data " + label + ' = ' + '{ b "' + escaped + '", b 0 }'
push(data_out, line)
data_out[] = line
var entry = { label: label, idx: length(str_entries) }
push(str_entries, entry)
str_entries[] = entry
str_table[val] = entry
return entry
}
@@ -2909,16 +2909,16 @@ var qbe_emit = function(ir, qbe, export_name) {
// Export nr_slots for main function so the module loader can use right-sized frames
var main_name = export_name ? sanitize(export_name) : "cell_main"
push(data_out, "export data $" + main_name + "_nr_slots = { w " + text(ir.main.nr_slots) + " }")
push(data_out, "export data $cell_lit_count = { w " + text(length(str_entries)) + " }")
data_out[] = "export data $" + main_name + "_nr_slots = { w " + text(ir.main.nr_slots) + " }"
data_out[] = "export data $cell_lit_count = { w " + text(length(str_entries)) + " }"
if (length(str_entries) > 0) {
lit_data = []
si = 0
while (si < length(str_entries)) {
push(lit_data, `l ${str_entries[si].label}`)
lit_data[] = `l ${str_entries[si].label}`
si = si + 1
}
push(data_out, "export data $cell_lit_table = { " + text(lit_data, ", ") + " }")
data_out[] = "export data $cell_lit_table = { " + text(lit_data, ", ") + " }"
}
return {

View File

@@ -149,7 +149,7 @@ if (!is_array(args) || length(args) < 1) {
}
for (; i < length(args) - 1; i++) {
push(sources, args[i])
sources[] = args[i]
}
archive = args[length(args) - 1]

View File

@@ -78,7 +78,7 @@ var run = function() {
arrfor(all_packages, function(p) {
if (p == 'core') return
if (!needed[p] && find(packages_to_remove, p) == null) {
push(packages_to_remove, p)
packages_to_remove[] = p
}
})
}

View File

@@ -165,11 +165,11 @@ for (i = 0; i < length(sorted); i++) {
// Format output
status_parts = []
if (is_linked) push(status_parts, "linked")
if (is_local) push(status_parts, "local")
if (!is_in_lock) push(status_parts, "not in lock")
if (!is_fetched) push(status_parts, "not fetched")
if (has_c_files) push(status_parts, "has C modules")
if (is_linked) status_parts[] = "linked"
if (is_local) status_parts[] = "local"
if (!is_in_lock) status_parts[] = "not in lock"
if (!is_fetched) status_parts[] = "not fetched"
if (has_c_files) status_parts[] = "has C modules"
commit_str = ""
if (lock_entry && lock_entry.commit) {

View File

@@ -21,7 +21,7 @@ var packages = shop.list_packages()
arrfor(packages, function(package_name) {
// Check if package name matches
if (search(package_name, query) != null) {
push(found_packages, package_name)
found_packages[] = package_name
}
// Search modules and actors within the package
@@ -29,14 +29,14 @@ arrfor(packages, function(package_name) {
var modules = pkg.list_modules(package_name)
arrfor(modules, function(mod) {
if (search(mod, query) != null) {
push(found_modules, package_name + ':' + mod)
found_modules[] = package_name + ':' + mod
}
})
var actors = pkg.list_programs(package_name)
arrfor(actors, function(actor) {
if (search(actor, query) != null) {
push(found_actors, package_name + ':' + actor)
found_actors[] = package_name + ':' + actor
}
})
} disruption {

View File

@@ -179,7 +179,7 @@ var run = function() {
first_def[slot_num] = pc
first_def_op[slot_num] = op
}
push(events, {kind: "DEF", slot: operand_val, pc: pc, instr: instr})
events[] = {kind: "DEF", slot: operand_val, pc: pc, instr: instr}
}
di = di + 1
}
@@ -191,7 +191,7 @@ var run = function() {
slot_num = text(operand_val)
if (!uses[slot_num]) uses[slot_num] = 0
uses[slot_num] = uses[slot_num] + 1
push(events, {kind: "USE", slot: operand_val, pc: pc, instr: instr})
events[] = {kind: "USE", slot: operand_val, pc: pc, instr: instr}
}
ui = ui + 1
}
@@ -219,7 +219,7 @@ var run = function() {
parts = []
j = 1
while (j < n - 2) {
push(parts, fmt_val(evt.instr[j]))
parts[] = fmt_val(evt.instr[j])
j = j + 1
}
operands = text(parts, ", ")

View File

@@ -313,6 +313,26 @@ void actor_disrupt(JSContext *ctx)
JSValue js_core_internal_os_use(JSContext *js);
JSValue js_core_json_use(JSContext *js);
/* Engine-env log proxy: routes log("channel", [msg]) through JS_Log.
Before set_log is called, JS_Log falls back to stderr.
After set_log, JS_Log forwards to the engine's JS log function.
This exists so mcode-generated type-check error paths (which always
access 'log' as an intrinsic) work inside engine.cm itself. */
static JSValue js_engine_log(JSContext *js, JSValue self,
int argc, JSValue *argv) {
if (argc < 2) return JS_NULL;
const char *channel = JS_ToCString(js, argv[0]);
if (!channel) return JS_NULL;
JSValue msg_val = JS_GetPropertyNumber(js, argv[1], 0);
const char *msg = JS_ToCString(js, msg_val);
if (msg) {
JS_Log(js, channel, "%s", msg);
JS_FreeCString(js, msg);
}
JS_FreeCString(js, channel);
return JS_NULL;
}
void script_startup(JSContext *js)
{
if (!g_runtime) {
@@ -414,6 +434,8 @@ void script_startup(JSContext *js)
}
tmp = shop_path ? JS_NewString(js, shop_path) : JS_NULL;
JS_SetPropertyStr(js, env_ref.val, "shop_path", tmp);
tmp = JS_NewCFunction(js, js_engine_log, "log", 2);
JS_SetPropertyStr(js, env_ref.val, "log", tmp);
// Stone the environment
JSValue hidden_env = JS_Stone(js, env_ref.val);
@@ -761,6 +783,8 @@ int cell_init(int argc, char **argv)
}
JS_SetPropertyStr(ctx, env_ref.val, "args", args_ref.val);
JS_DeleteGCRef(ctx, &args_ref);
tmp = JS_NewCFunction(ctx, js_engine_log, "log", 2);
JS_SetPropertyStr(ctx, env_ref.val, "log", tmp);
JSValue hidden_env = JS_Stone(ctx, env_ref.val);
g_crash_ctx = ctx;

View File

@@ -876,7 +876,7 @@ typedef struct {
#define ACTOR_SLOW 5
#define ACTOR_REFRESHED 6
#define ACTOR_FAST_TIMER_NS (10ULL * 1000000)
#define ACTOR_FAST_TIMER_NS (1000ULL * 1000000)
#define ACTOR_SLOW_TIMER_NS (60000ULL * 1000000)
#define ACTOR_SLOW_STRIKES_MAX 3
#define ACTOR_MEMORY_LIMIT (1024ULL * 1024 * 1024)

View File

@@ -1915,12 +1915,13 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
if (ctx->trace_hook && (ctx->trace_type & JS_HOOK_GC))
ctx->trace_hook(ctx, JS_HOOK_GC, NULL, ctx->trace_data);
/* Check memory limit — kill actor if heap exceeds cap */
/* Check memory limit — kill actor if heap exceeds cap.
Use JS_Log "memory" channel which always fprintf's (safe during GC). */
if (ctx->heap_memory_limit > 0 && ctx->current_block_size > ctx->heap_memory_limit) {
#ifdef ACTOR_TRACE
fprintf(stderr, "[ACTOR_TRACE] heap %zu > limit %zu, OOM\n",
ctx->current_block_size, ctx->heap_memory_limit);
#endif
JS_Log(ctx, "memory", "%s: heap %zuKB exceeds limit %zuMB, killing",
ctx->name ? ctx->name : ctx->id,
ctx->current_block_size / 1024,
ctx->heap_memory_limit / (1024 * 1024));
return -1;
}
@@ -3283,19 +3284,18 @@ JS_RaiseDisrupt (JSContext *ctx, const char *fmt, ...) {
return JS_EXCEPTION;
}
/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate). */
/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate).
Uses fprintf directly — safe even during OOM. */
JSValue JS_RaiseOOM (JSContext *ctx) {
size_t used = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base);
size_t block = ctx->current_block_size;
size_t limit = ctx->heap_memory_limit;
const char *name = ctx->name ? ctx->name : ctx->id;
const char *label = ctx->actor_label;
if (limit > 0) {
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, limit %zuMB",
used / 1024, block / 1024, limit / (1024 * 1024));
} else {
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, no limit",
used / 1024, block / 1024);
}
fprintf(stderr, "[memory] %s: out of memory — heap %zuKB / %zuKB block",
name ? name : "?", used / 1024, block / 1024);
if (limit > 0)
fprintf(stderr, ", limit %zuMB", limit / (1024 * 1024));
if (label)
fprintf(stderr, " [%s]", label);
fprintf(stderr, "\n");
@@ -12009,7 +12009,7 @@ void JS_CrashPrintStack(JSContext *ctx) {
if (!ctx) return;
if (JS_IsNull(ctx->reg_current_frame)) return;
static const char hdr[] = "\n--- JS Stack at crash ---\n";
static const char hdr[] = "\n--- JS Stack ---\n";
write(STDERR_FILENO, hdr, sizeof(hdr) - 1);
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(ctx->reg_current_frame);

View File

@@ -293,9 +293,15 @@ void *timer_thread_func(void *arg) {
/* Only fire if turn_gen still matches (stale timers are ignored) */
uint32_t cur = atomic_load_explicit(&t.actor->turn_gen, memory_order_relaxed);
if (cur == t.turn_gen) {
/* Can't call JS_Log from timer thread — use fprintf */
const char *name = t.actor->name ? t.actor->name : t.actor->id;
if (t.type == TIMER_PAUSE) {
fprintf(stderr, "[slow] %s: pausing (turn exceeded %llums)\n",
name, (unsigned long long)(ACTOR_FAST_TIMER_NS / 1000000));
JS_SetPauseFlag(t.actor, 1);
} else {
fprintf(stderr, "[slow] %s: kill timer fired (turn exceeded %llus)\n",
name, (unsigned long long)(ACTOR_SLOW_TIMER_NS / 1000000000));
t.actor->disrupt = 1;
JS_SetPauseFlag(t.actor, 2);
}
@@ -577,17 +583,11 @@ int actor_exists(const char *id)
void set_actor_state(JSContext *actor)
{
if (actor->disrupt) {
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "set_actor_state: %s disrupted, freeing\n", actor->name ? actor->name : actor->id);
#endif
actor_free(actor);
return;
}
pthread_mutex_lock(actor->msg_mutex);
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "set_actor_state: %s state=%d letters=%ld\n", actor->name ? actor->name : actor->id, actor->state, (long)arrlen(actor->letters));
#endif
switch(actor->state) {
case ACTOR_RUNNING:
case ACTOR_READY:
@@ -601,9 +601,6 @@ void set_actor_state(JSContext *actor)
actor->is_quiescent = 0;
atomic_fetch_sub(&engine.quiescent_count, 1);
}
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "set_actor_state: %s IDLE->READY, enqueueing (main=%d)\n", actor->name ? actor->name : actor->id, actor->main_thread_only);
#endif
actor->state = ACTOR_READY;
actor->ar = 0;
enqueue_actor_priority(actor);
@@ -846,6 +843,8 @@ void actor_turn(JSContext *actor)
if (JS_IsSuspended(result)) {
/* Still suspended after kill timer — shouldn't happen, kill it */
fprintf(stderr, "[slow] %s: still suspended after resume, killing\n",
actor->name ? actor->name : actor->id);
actor->disrupt = 1;
goto ENDTURN;
}
@@ -854,16 +853,12 @@ void actor_turn(JSContext *actor)
actor->disrupt = 1;
}
actor->slow_strikes++;
#ifdef ACTOR_TRACE
fprintf(stderr, "[ACTOR_TRACE] %s: slow strike %d/%d\n",
JS_Log(actor, "slow", "%s: slow strike %d/%d",
actor->name ? actor->name : actor->id,
actor->slow_strikes, ACTOR_SLOW_STRIKES_MAX);
#endif
if (actor->slow_strikes >= ACTOR_SLOW_STRIKES_MAX) {
#ifdef ACTOR_TRACE
fprintf(stderr, "[ACTOR_TRACE] %s: %d slow strikes, killing\n",
JS_Log(actor, "slow", "%s: killed after %d consecutive slow turns",
actor->name ? actor->name : actor->id, actor->slow_strikes);
#endif
actor->disrupt = 1;
}
goto ENDTURN;
@@ -876,10 +871,6 @@ void actor_turn(JSContext *actor)
pthread_mutex_unlock(actor->msg_mutex);
goto ENDTURN;
}
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "actor_turn: %s has %d letters, type=%d\n",
actor->name ? actor->name : actor->id, pending, actor->letters[0].type);
#endif
letter l = actor->letters[0];
arrdel(actor->letters, 0);
pthread_mutex_unlock(actor->msg_mutex);
@@ -937,29 +928,22 @@ ENDTURN:
actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
if (actor->disrupt) {
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "actor_turn ENDTURN: %s disrupted, freeing\n",
actor->name ? actor->name : actor->id);
#endif
pthread_mutex_unlock(actor->mutex);
actor_free(actor);
return;
}
#ifdef SCHEDULER_DEBUG
fprintf(stderr, "actor_turn ENDTURN: %s has %ld letters, calling set_actor_state\n",
actor->name ? actor->name : actor->id, (long)arrlen(actor->letters));
#endif
set_actor_state(actor);
pthread_mutex_unlock(actor->mutex);
return;
ENDTURN_SLOW:
g_crash_ctx = NULL;
#ifdef ACTOR_TRACE
fprintf(stderr, "[ACTOR_TRACE] %s: suspended mid-turn -> SLOW\n",
actor->name ? actor->name : actor->id);
#endif
/* VM suspended mid-turn — can't call JS_Log, use fprintf.
Print stack trace while frames are still intact. */
fprintf(stderr, "[slow] %s: suspended mid-turn, entering slow queue (strike %d/%d)\n",
actor->name ? actor->name : actor->id,
actor->slow_strikes + 1, ACTOR_SLOW_STRIKES_MAX);
if (actor->actor_trace_hook)
actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
enqueue_actor_priority(actor);

View File

@@ -243,7 +243,7 @@ var type_annotation = function(slot_types, instr) {
if (is_number(v)) {
t = slot_types[text(v)]
if (t != null && t != T_UNKNOWN) {
push(parts, `s${text(v)}:${t}`)
parts[] = `s${text(v)}:${t}`
}
}
j = j + 1
@@ -290,7 +290,7 @@ var dump_function_typed = function(func, name) {
operand_parts = []
j = 1
while (j < n - 2) {
push(operand_parts, fmt_val(instr[j]))
operand_parts[] = fmt_val(instr[j])
j = j + 1
}
operands = text(operand_parts, ", ")

40
test.ce
View File

@@ -62,7 +62,7 @@ function parse_args() {
} else if (_args[i] == '--diff') {
diff_mode = true
} else {
push(cleaned_args, _args[i])
cleaned_args[] = _args[i]
}
}
_args = cleaned_args
@@ -247,11 +247,11 @@ function collect_actor_tests(package_name, specific_test) {
if (test_base != match_base) continue
}
push(actor_tests, {
actor_tests[] = {
package: package_name || "local",
file: f,
path: prefix + '/' + f
})
}
}
}
return actor_tests
@@ -296,16 +296,16 @@ function spawn_actor_test(test_info) {
entry.error = { message: event.reason || "Actor disrupted" }
log.console(` FAIL ${test_name}: ${entry.error.message}`)
}
push(actor_test_results, entry)
actor_test_results[] = entry
if (gc_after_each_test) dbg.gc()
check_completion()
}, actor_path)
push(pending_actor_tests, entry)
pending_actor_tests[] = entry
} disruption {
entry.status = "failed"
entry.error = { message: "Failed to spawn actor" }
entry.duration_ns = 0
push(actor_test_results, entry)
actor_test_results[] = entry
log.console(` FAIL ${test_name}: Failed to spawn`)
}
_spawn()
@@ -347,7 +347,7 @@ function run_tests(package_name, specific_test) {
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (test_name != match_base) continue
}
push(test_files, f)
test_files[] = f
}
}
@@ -408,14 +408,14 @@ function run_tests(package_name, specific_test) {
var first_null_key = null
var first_other_key = null
if (is_function(test_mod)) {
push(tests, {name: 'main', fn: test_mod})
tests[] = {name: 'main', fn: test_mod}
} else if (is_object(test_mod)) {
all_keys = array(test_mod)
log.console(` Found ${length(all_keys)} test entries`)
arrfor(all_keys, function(k) {
if (is_function(test_mod[k])) {
fn_count = fn_count + 1
push(tests, {name: k, fn: test_mod[k]})
tests[] = {name: k, fn: test_mod[k]}
} else if (is_null(test_mod[k])) {
null_count = null_count + 1
if (!first_null_key) first_null_key = k
@@ -494,7 +494,7 @@ function run_tests(package_name, specific_test) {
file_result.failed = file_result.failed + 1
}
push(file_result.tests, test_entry)
file_result.tests[] = test_entry
pkg_result.total = pkg_result.total + 1
if (gc_after_each_test) {
dbg.gc()
@@ -512,7 +512,7 @@ function run_tests(package_name, specific_test) {
file_result.failed = file_result.failed + 1
pkg_result.total = pkg_result.total + 1
}
push(pkg_result.files, file_result)
pkg_result.files[] = file_result
}
return pkg_result
}
@@ -525,18 +525,18 @@ var i = 0
if (all_pkgs) {
// Run local first if we're in a valid package
if (is_valid_package('.')) {
push(all_results, run_tests(null, null))
all_results[] = run_tests(null, null)
all_actor_tests = array(all_actor_tests, collect_actor_tests(null, null))
}
// Then all packages in lock
packages = shop.list_packages()
for (i = 0; i < length(packages); i++) {
push(all_results, run_tests(packages[i], null))
all_results[] = run_tests(packages[i], null)
all_actor_tests = array(all_actor_tests, collect_actor_tests(packages[i], null))
}
} else {
push(all_results, run_tests(target_pkg, target_test))
all_results[] = run_tests(target_pkg, target_test)
all_actor_tests = array(all_actor_tests, collect_actor_tests(target_pkg, target_test))
}
@@ -561,7 +561,7 @@ function check_timeouts() {
entry = pending_actor_tests[i]
elapsed_ms = (now - entry.start_time) * 1000
if (elapsed_ms > ACTOR_TEST_TIMEOUT) {
push(timed_out, i)
timed_out[] = i
}
}
@@ -573,7 +573,7 @@ function check_timeouts() {
entry.status = "failed"
entry.error = { message: "Test timed out" }
entry.duration_ns = ACTOR_TEST_TIMEOUT * 1000000
push(actor_test_results, entry)
actor_test_results[] = entry
log.console(` TIMEOUT ${entry.test}`)
}
@@ -612,7 +612,7 @@ function finalize_results() {
}
if (!pkg_result) {
pkg_result = { package: r.package, files: [], total: 0, passed: 0, failed: 0 }
push(all_results, pkg_result)
all_results[] = pkg_result
}
file_result = null
@@ -624,10 +624,10 @@ function finalize_results() {
}
if (!file_result) {
file_result = { name: r.file, tests: [], passed: 0, failed: 0 }
push(pkg_result.files, file_result)
pkg_result.files[] = file_result
}
push(file_result.tests, r)
file_result.tests[] = r
pkg_result.total = pkg_result.total + 1
if (r.status == "passed") {
pkg_result.passed = pkg_result.passed + 1
@@ -760,7 +760,7 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
for (j = 0; j < length(pkg_res.files); j++) {
f = pkg_res.files[j]
for (k = 0; k < length(f.tests); k++) {
push(pkg_tests, f.tests[k])
pkg_tests[] = f.tests[k]
}
}

View File

@@ -123,7 +123,7 @@ var testarr = []
var i = 0
var t = null
for (i = 0; i < 500; i++) {
push(testarr, 1)
testarr[] = 1
}
var testCases = [

View File

@@ -2918,7 +2918,7 @@ return {
test_arrfor_with_index: function() {
var arr = ["a", "b", "c"]
var indices = []
arrfor(arr, (x, i) => { push(indices, i) })
arrfor(arr, (x, i) => { indices[] = i })
if (indices[0] != 0 || indices[2] != 2) return "arrfor with index failed"
},
@@ -2931,7 +2931,7 @@ return {
test_arrfor_mutation: function() {
var arr = [1, 2, 3]
var results = []
arrfor(arr, x => { push(results, x * 2) })
arrfor(arr, x => { results[] = x * 2 })
if (results[0] != 2 || results[1] != 4 || results[2] != 6) return "arrfor mutation failed"
},

View File

@@ -65,7 +65,7 @@ var testarr = []
var i = 0
var t = null
var name = null
for (i = 0; i < 500; i++) { push(testarr, 1) }
for (i = 0; i < 500; i++) { testarr[] = 1 }
var testCases = [
{ name: 'zero', input: 0 },

View File

@@ -103,26 +103,26 @@ var tokenize = function(src, filename) {
run_start = pos
while (pos < len && pk() != quote) {
if (pk() == "\\") {
if (pos > run_start) push(parts, text(src, run_start, pos))
if (pos > run_start) parts[] = text(src, run_start, pos)
adv()
esc = adv()
esc_val = escape_map[esc]
if (esc_val != null) { push(parts, esc_val) }
else if (esc == "u") { push(parts, read_unicode_escape()) }
else { push(parts, esc) }
if (esc_val != null) { parts[] = esc_val }
else if (esc == "u") { parts[] = read_unicode_escape() }
else { parts[] = esc }
run_start = pos
} else {
adv()
}
}
if (pos > run_start) push(parts, text(src, run_start, pos))
if (pos > run_start) parts[] = text(src, run_start, pos)
if (pos < len) adv() // skip closing quote
push(tokens, {
tokens[] = {
kind: "text", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: text(parts)
})
}
}
var read_template = function() {
@@ -139,12 +139,12 @@ var tokenize = function(src, filename) {
run_start = pos
while (pos < len && pk() != "`") {
if (pk() == "\\" && pos + 1 < len) {
if (pos > run_start) push(parts, text(src, run_start, pos))
push(parts, text(src, pos, pos + 2))
if (pos > run_start) parts[] = text(src, run_start, pos)
parts[] = text(src, pos, pos + 2)
adv(); adv()
run_start = pos
} else if (pk() == "$" && pos + 1 < len && pk_at(1) == "{") {
if (pos > run_start) push(parts, text(src, run_start, pos))
if (pos > run_start) parts[] = text(src, run_start, pos)
interp_start = pos
adv(); adv() // $ {
depth = 1
@@ -164,20 +164,20 @@ var tokenize = function(src, filename) {
if (pos < len) adv()
} else { adv() }
}
push(parts, text(src, interp_start, pos))
parts[] = text(src, interp_start, pos)
run_start = pos
} else {
adv()
}
}
if (pos > run_start) push(parts, text(src, run_start, pos))
if (pos > run_start) parts[] = text(src, run_start, pos)
if (pos < len) adv() // skip closing backtick
push(tokens, {
tokens[] = {
kind: "text", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: text(parts)
})
}
}
var read_number = function() {
@@ -207,12 +207,12 @@ var tokenize = function(src, filename) {
}
}
raw = substr(start, pos)
push(tokens, {
tokens[] = {
kind: "number", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: raw, number: number(raw)
})
}
}
var read_name = function() {
@@ -225,18 +225,18 @@ var tokenize = function(src, filename) {
name = substr(start, pos)
kw = keywords[name]
if (kw != null) {
push(tokens, {
tokens[] = {
kind: kw, at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col
})
}
} else {
push(tokens, {
tokens[] = {
kind: "name", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: name
})
}
}
}
@@ -258,12 +258,12 @@ var tokenize = function(src, filename) {
}
}
raw = substr(start, pos)
push(tokens, {
tokens[] = {
kind: "comment", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: raw
})
}
}
var emit_op = function(kind, count) {
@@ -272,11 +272,11 @@ var tokenize = function(src, filename) {
var start_col = col
var i = 0
while (i < count) { adv(); i = i + 1 }
push(tokens, {
tokens[] = {
kind: kind, at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col
})
}
}
var emit_ident = function(count) {
@@ -285,12 +285,12 @@ var tokenize = function(src, filename) {
var start_col = col
var i = 0
while (i < count) { adv(); i = i + 1 }
push(tokens, {
tokens[] = {
kind: "name", at: start,
from_row: start_row, from_column: start_col,
to_row: row, to_column: col,
value: text(src, start, pos)
})
}
}
var tokenize_one = function() {
@@ -304,21 +304,21 @@ var tokenize = function(src, filename) {
if (c == "\n") {
start = pos; start_row = row; start_col = col
adv()
push(tokens, { kind: "newline", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: "\n" })
tokens[] = { kind: "newline", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: "\n" }
return true
}
if (c == "\r") {
start = pos; start_row = row; start_col = col
adv()
if (pos < len && pk() == "\n") adv()
push(tokens, { kind: "newline", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: "\n" })
tokens[] = { kind: "newline", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: "\n" }
return true
}
if (c == " " || c == "\t") {
start = pos; start_row = row; start_col = col
while (pos < len && (pk() == " " || pk() == "\t")) adv()
raw = substr(start, pos)
push(tokens, { kind: "space", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: raw })
tokens[] = { kind: "space", at: start, from_row: start_row, from_column: start_col, to_row: row, to_column: col, value: raw }
return true
}
if (c == "'" || c == "\"") { read_string(c); return true }
@@ -446,7 +446,7 @@ var tokenize = function(src, filename) {
}
// EOF token
push(tokens, { kind: "eof", at: pos, from_row: row, from_column: col, to_row: row, to_column: col })
tokens[] = { kind: "eof", at: pos, from_row: row, from_column: col, to_row: row, to_column: col }
return {filename: filename, tokens: tokens}
}

16
toml.cm
View File

@@ -127,7 +127,7 @@ function parse_key_path(str) {
} else if (c == '.' && !in_quote) {
piece = trim(current)
if (piece == null) piece = trim(current)
push(parts, parse_key(piece))
parts[] = parse_key(piece)
current = ''
continue
}
@@ -136,7 +136,7 @@ function parse_key_path(str) {
var tail = trim(current)
if (tail == null) tail = trim(current)
if (length(tail) > 0) push(parts, parse_key(tail))
if (length(tail) > 0) parts[] = parse_key(tail)
return parts
}
@@ -165,7 +165,7 @@ function parse_array(str) {
} else if (ch == ',' && !in_quotes) {
piece = trim(current)
if (piece == null) piece = trim(current)
push(items, parse_value(piece))
items[] = parse_value(piece)
current = ''
} else {
current = current + ch
@@ -174,7 +174,7 @@ function parse_array(str) {
var last = trim(current)
if (last == null) last = trim(current)
if (last) push(items, parse_value(last))
if (last) items[] = parse_value(last)
return items
}
@@ -204,7 +204,7 @@ function encode_toml(obj) {
if (is_number(value)) return text(value)
if (is_array(value)) {
items = []
for (i = 0; i < length(value); i++) push(items, encode_value(value[i]))
for (i = 0; i < length(value); i++) items[] = encode_value(value[i])
return '[' + text(items, ', ') + ']'
}
return text(value)
@@ -230,7 +230,7 @@ function encode_toml(obj) {
for (i = 0; i < length(keys); i++) {
key = keys[i]
value = obj[key]
if (!is_object(value)) push(result, quote_key(key) + ' = ' + encode_value(value))
if (!is_object(value)) result[] = quote_key(key) + ' = ' + encode_value(value)
}
// Second pass: encode nested objects
@@ -252,14 +252,14 @@ function encode_toml(obj) {
if (is_object(value)) {
quoted = quote_key(key)
section_path = path ? path + '.' + quoted : quoted
push(result, '[' + section_path + ']')
result[] = '[' + section_path + ']'
// Direct properties
section_keys = array(value)
for (j = 0; j < length(section_keys); j++) {
sk = section_keys[j]
sv = value[sk]
if (!is_object(sv)) push(result, quote_key(sk) + ' = ' + encode_value(sv))
if (!is_object(sv)) result[] = quote_key(sk) + ' = ' + encode_value(sv)
}
// Nested sections

View File

@@ -20,7 +20,6 @@ var target_triple = null
var follow_links = false
var git_pull = false
var i = 0
var updated = 0
var packages = null
var run = function() {
@@ -54,7 +53,14 @@ var run = function() {
if (target_pkg)
target_pkg = shop.resolve_locator(target_pkg)
function update_one(pkg) {
if (target_pkg) {
update_single(target_pkg)
} else {
update_all()
}
}
function check_one(pkg) {
var effective_pkg = pkg
var link_target = null
var lock = shop.load_lock()
@@ -62,59 +68,84 @@ function update_one(pkg) {
var old_commit = old_entry ? old_entry.commit : null
var info = shop.resolve_package_info(pkg)
var new_entry = null
var old_str = null
if (follow_links) {
link_target = link.get_target(pkg)
if (link_target) {
effective_pkg = link_target
log.console(" Following link: " + pkg + " -> " + effective_pkg)
}
}
// For local packages with --git, pull first
if (git_pull && info == 'local' && fd.is_dir(effective_pkg + '/.git')) {
log.console(" " + effective_pkg + " (git pull)")
log.build(" " + effective_pkg + " (git pull)")
os.system('git -C "' + effective_pkg + '" pull')
}
// Check for update (sets lock entry if changed)
new_entry = shop.update(effective_pkg)
if (new_entry && new_entry.commit) {
old_str = old_commit ? text(old_commit, 0, 8) : "(new)"
log.console(" " + effective_pkg + " " + old_str + " -> " + text(new_entry.commit, 0, 8))
return {
pkg: pkg,
effective: effective_pkg,
old_commit: old_commit,
new_entry: new_entry,
changed: new_entry != null && new_entry.commit != null
}
}
// Sync: fetch, extract, build
function sync_one(effective_pkg) {
shop.sync(effective_pkg, {target: target_triple})
return new_entry
}
if (target_pkg) {
if (update_one(target_pkg)) {
log.console("Updated " + target_pkg + ".")
function update_single(pkg) {
var result = check_one(pkg)
var old_str = null
if (result.changed) {
old_str = result.old_commit ? text(result.old_commit, 0, 8) : "(new)"
log.console("==> Upgrading " + result.effective)
log.console(" " + old_str + " -> " + text(result.new_entry.commit, 0, 8))
log.console("==> Syncing " + result.effective)
sync_one(result.effective)
log.console("Updated " + result.effective + ".")
} else {
log.console(target_pkg + " is up to date.")
log.console(pkg + " is up to date.")
}
} else {
}
function update_all() {
var results = []
var changed = []
var result = null
packages = shop.list_packages()
log.console("Checking for updates (" + text(length(packages)) + " packages)...")
log.console("Checking for updates...")
arrfor(packages, function(pkg) {
if (pkg == 'core') return
if (update_one(pkg))
updated = updated + 1
result = check_one(pkg)
results[] = result
if (result.changed)
changed[] = result
})
if (updated > 0) {
log.console("Updated " + text(updated) + " package(s).")
} else {
if (length(changed) == 0) {
log.console("All packages are up to date.")
return
}
log.console("==> Upgrading " + text(length(changed)) + " outdated package" + (length(changed) != 1 ? "s" : "") + ":")
arrfor(changed, function(r) {
var old_str = r.old_commit ? text(r.old_commit, 0, 8) : "(new)"
log.console(" " + r.effective + " " + old_str + " -> " + text(r.new_entry.commit, 0, 8))
})
arrfor(changed, function(r) {
log.console("==> Syncing " + r.effective)
sync_one(r.effective)
})
log.console("Updated " + text(length(changed)) + " package(s).")
}
}
run()
$stop()

View File

@@ -67,11 +67,11 @@ var warnings = []
var checked = 0
function add_error(msg) {
push(errors, msg)
errors[] = msg
}
function add_warning(msg) {
push(warnings, msg)
warnings[] = msg
}
// Verify a single package
@@ -211,12 +211,12 @@ if (scope == 'shop') {
if (deep) {
// Gather all dependencies
all_deps = pkg.gather_dependencies(locator)
push(packages_to_verify, locator)
packages_to_verify[] = locator
arrfor(all_deps, function(dep) {
push(packages_to_verify, dep)
packages_to_verify[] = dep
})
} else {
push(packages_to_verify, locator)
packages_to_verify[] = locator
}
}

View File

@@ -172,7 +172,7 @@ var check_slot_bounds = function(func) {
if (pos < length(instr) - 2) {
val = instr[pos]
if (is_number(val) && (val < 0 || val >= nr_slots)) {
push(errors, `slot_bounds: instr ${text(i)} op=${op} slot[${text(positions[j])}]=${text(val)} out of range 0..${text(nr_slots - 1)}`)
errors[] = `slot_bounds: instr ${text(i)} op=${op} slot[${text(positions[j])}]=${text(val)} out of range 0..${text(nr_slots - 1)}`
}
}
j = j + 1
@@ -217,7 +217,7 @@ var check_jump_targets = function(func) {
if (label_pos != null) {
target = instr[label_pos + 1]
if (is_text(target) && labels[target] != true) {
push(errors, `jump_targets: instr ${text(i)} op=${op} target label "${target}" not found`)
errors[] = `jump_targets: instr ${text(i)} op=${op} target label "${target}" not found`
}
}
}
@@ -301,46 +301,46 @@ var check_type_consistency = function(func) {
s2 = text(instr[2])
t2 = slot_types[s2]
if (t2 != null && t2 != T_INT && t2 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected int`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected int`
}
if (length(instr) >= 6) {
s3 = text(instr[3])
t3 = slot_types[s3]
if (t3 != null && t3 != T_INT && t3 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected int`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected int`
}
}
} else if (float_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2])
t2 = slot_types[s2]
if (t2 != null && t2 != T_FLOAT && t2 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected float`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected float`
}
if (length(instr) >= 6) {
s3 = text(instr[3])
t3 = slot_types[s3]
if (t3 != null && t3 != T_FLOAT && t3 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected float`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected float`
}
}
} else if (text_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2])
t2 = slot_types[s2]
if (t2 != null && t2 != T_TEXT && t2 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected text`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected text`
}
if (length(instr) >= 6) {
s3 = text(instr[3])
t3 = slot_types[s3]
if (t3 != null && t3 != T_TEXT && t3 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected text`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src2 slot ${s3} has type ${t3}, expected text`
}
}
} else if (bool_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2])
t2 = slot_types[s2]
if (t2 != null && t2 != T_BOOL && t2 != "unknown") {
push(errors, `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected bool`)
errors[] = `type_consistency: instr ${text(i)} op=${op} src1 slot ${s2} has type ${t2}, expected bool`
}
}
@@ -394,7 +394,7 @@ var check_nop_consistency = function(func) {
if (label_pos != null) {
target = instr[label_pos + 1]
if (is_text(target) && nops[target] == true) {
push(errors, `nop_consistency: instr ${text(i)} op=${op} jumps to nop marker "${target}"`)
errors[] = `nop_consistency: instr ${text(i)} op=${op} jumps to nop marker "${target}"`
}
}
}
@@ -415,28 +415,28 @@ var verify_all = function(func, pass_name) {
check_errors = check_slot_bounds(func)
i = 0
while (i < length(check_errors)) {
push(all_errors, `${prefix}${fn_name}: ${check_errors[i]}`)
all_errors[] = `${prefix}${fn_name}: ${check_errors[i]}`
i = i + 1
}
check_errors = check_jump_targets(func)
i = 0
while (i < length(check_errors)) {
push(all_errors, `${prefix}${fn_name}: ${check_errors[i]}`)
all_errors[] = `${prefix}${fn_name}: ${check_errors[i]}`
i = i + 1
}
check_errors = check_type_consistency(func)
i = 0
while (i < length(check_errors)) {
push(all_errors, `${prefix}${fn_name}: ${check_errors[i]}`)
all_errors[] = `${prefix}${fn_name}: ${check_errors[i]}`
i = i + 1
}
check_errors = check_nop_consistency(func)
i = 0
while (i < length(check_errors)) {
push(all_errors, `${prefix}${fn_name}: ${check_errors[i]}`)
all_errors[] = `${prefix}${fn_name}: ${check_errors[i]}`
i = i + 1
}

View File

@@ -93,11 +93,11 @@ var run = function() {
if (!creates[text(parent_idx)]) {
creates[text(parent_idx)] = []
}
push(creates[text(parent_idx)], {child: child_idx, line: instr_line})
creates[text(parent_idx)][] = {child: child_idx, line: instr_line}
if (!created_by[text(child_idx)]) {
created_by[text(child_idx)] = []
}
push(created_by[text(child_idx)], {parent: parent_idx, line: instr_line})
created_by[text(child_idx)][] = {parent: parent_idx, line: instr_line}
}
j = j + 1
}