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 total_scripts = total_scripts + result.total
arrfor(result.errors, function(e) { arrfor(result.errors, function(e) {
push(all_failures, p + ": " + e) all_failures[] = p + ": " + e
}) })
// Check use() resolution // Check use() resolution
resolution = shop.audit_use_resolution(p) resolution = shop.audit_use_resolution(p)
arrfor(resolution.unresolved, function(u) { 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') { } else if (a == '--compare') {
bench_mode = "compare" bench_mode = "compare"
} else { } else {
push(filtered, a) filtered[] = a
} }
}) })
_args = filtered _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 match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (bench_name != match_base) return if (bench_name != match_base) return
} }
push(bench_files, f) bench_files[] = f
} }
}) })
return bench_files return bench_files
@@ -355,7 +355,7 @@ function run_single_bench(bench_fn, bench_name) {
if (teardown_fn) teardown_fn(state) if (teardown_fn) teardown_fn(state)
ns_per_op = is_batch ? duration / batch_size : duration ns_per_op = is_batch ? duration / batch_size : duration
push(timings_per_op, ns_per_op) timings_per_op[] = ns_per_op
} else { } else {
start = os.now() start = os.now()
if (is_batch) { if (is_batch) {
@@ -366,7 +366,7 @@ function run_single_bench(bench_fn, bench_name) {
duration = os.now() - start duration = os.now() - start
ns_per_op = is_batch ? duration / batch_size : duration 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) { function collect_bench_fns(bench_mod) {
var benches = [] var benches = []
if (is_function(bench_mod)) { if (is_function(bench_mod)) {
push(benches, {name: 'main', fn: bench_mod}) benches[] = {name: 'main', fn: bench_mod}
} else if (is_object(bench_mod)) { } else if (is_object(bench_mod)) {
arrfor(array(bench_mod), function(k) { arrfor(array(bench_mod), function(k) {
if (is_function(bench_mod[k])) if (is_function(bench_mod[k]))
push(benches, {name: k, fn: bench_mod[k]}) benches[] = {name: k, fn: bench_mod[k]}
}) })
} }
return benches return benches
@@ -524,7 +524,7 @@ function run_benchmarks(package_name, specific_bench) {
result = run_single_bench(b.fn, b.name) result = run_single_bench(b.fn, b.name)
result.package = pkg_result.package result.package = pkg_result.package
result.mode = bench_mode == "compare" ? "bytecode" : bench_mode result.mode = bench_mode == "compare" ? "bytecode" : bench_mode
push(file_result.benchmarks, result) file_result.benchmarks[] = result
pkg_result.total++ pkg_result.total++
log.console(` ${result.name}`) 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 = run_single_bench(native_benches[nat_b].fn, b.name)
nat_result.package = pkg_result.package nat_result.package = pkg_result.package
nat_result.mode = "native" nat_result.mode = "native"
push(file_result.benchmarks, nat_result) file_result.benchmarks[] = nat_result
pkg_result.total++ pkg_result.total++
print_bench_result(nat_result, "native ") print_bench_result(nat_result, "native ")
@@ -570,7 +570,7 @@ function run_benchmarks(package_name, specific_bench) {
name: b.name, name: b.name,
error: "benchmark disrupted" error: "benchmark disrupted"
} }
push(file_result.benchmarks, error_result) file_result.benchmarks[] = error_result
pkg_result.total++ pkg_result.total++
} }
}) })
@@ -586,12 +586,12 @@ function run_benchmarks(package_name, specific_bench) {
name: "load_module", name: "load_module",
error: "error loading module" error: "error loading module"
} }
push(file_result.benchmarks, error_result) file_result.benchmarks[] = error_result
pkg_result.total++ pkg_result.total++
} }
if (length(file_result.benchmarks) > 0) { 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 (all_pkgs) {
if (testlib.is_valid_package('.')) { if (testlib.is_valid_package('.')) {
push(all_results, run_benchmarks(null, null)) all_results[] = run_benchmarks(null, null)
} }
packages = shop.list_packages() packages = shop.list_packages()
arrfor(packages, function(p) { arrfor(packages, function(p) {
push(all_results, run_benchmarks(p, null)) all_results[] = run_benchmarks(p, null)
}) })
} else { } else {
push(all_results, run_benchmarks(target_pkg, target_bench)) all_results[] = run_benchmarks(target_pkg, target_bench)
} }
// Calculate totals // Calculate totals
@@ -688,7 +688,7 @@ Total benchmarks: ${total_benches}
var pkg_benches = [] var pkg_benches = []
arrfor(pkg_res.files, function(f) { arrfor(pkg_res.files, function(f) {
arrfor(f.benchmarks, function(benchmark) { 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) { function receive(mailbox) {
if (length(mailbox.queue) == 0) return null if (length(mailbox.queue) == 0) return null
mailbox.delivered++ mailbox.delivered++
return pop(mailbox.queue) return mailbox.queue[]
} }
function drain(mailbox) { function drain(mailbox) {
var count = 0 var count = 0
while (length(mailbox.queue) > 0) { while (length(mailbox.queue) > 0) {
pop(mailbox.queue) mailbox.queue[]
count++ count++
} }
return count return count

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,21 +16,21 @@ function tokenize(src) {
ch = chars[i] ch = chars[i]
if (ch == " " || ch == "\n" || ch == "\t") { if (ch == " " || ch == "\n" || ch == "\t") {
if (length(buf) > 0) { if (length(buf) > 0) {
push(tokens, buf) tokens[] = buf
buf = "" buf = ""
} }
} else if (ch == "(" || ch == ")" || ch == "+" || ch == "-" } else if (ch == "(" || ch == ")" || ch == "+" || ch == "-"
|| ch == "*" || ch == "=" || ch == ";" || ch == ",") { || ch == "*" || ch == "=" || ch == ";" || ch == ",") {
if (length(buf) > 0) { if (length(buf) > 0) {
push(tokens, buf) tokens[] = buf
buf = "" buf = ""
} }
push(tokens, ch) tokens[] = ch
} else { } else {
buf = buf + ch buf = buf + ch
} }
} }
if (length(buf) > 0) push(tokens, buf) if (length(buf) > 0) tokens[] = buf
return tokens return tokens
} }
@@ -49,21 +49,21 @@ function parse_tokens(tokens) {
i++ // skip = i++ // skip =
i++ i++
if (i < length(tokens)) node.value = tokens[i] if (i < length(tokens)) node.value = tokens[i]
push(ast, node) ast[] = node
} else if (tok == "return") { } else if (tok == "return") {
node = {type: "return", value: null} node = {type: "return", value: null}
i++ i++
if (i < length(tokens)) node.value = tokens[i] if (i < length(tokens)) node.value = tokens[i]
push(ast, node) ast[] = node
} else if (tok == "function") { } else if (tok == "function") {
node = {type: "func", name: null, body: []} node = {type: "func", name: null, body: []}
i++ i++
if (i < length(tokens)) node.name = tokens[i] if (i < length(tokens)) node.name = tokens[i]
// Skip to matching ) // Skip to matching )
while (i < length(tokens) && tokens[i] != ")") i++ while (i < length(tokens) && tokens[i] != ")") i++
push(ast, node) ast[] = node
} else { } else {
push(ast, {type: "expr", value: tok}) ast[] = {type: "expr", value: tok}
} }
} }
return ast return ast
@@ -121,7 +121,7 @@ function simulate_build(n_modules, deps_per_module) {
// Generate all module sources // Generate all module sources
for (i = 0; i < n_modules; i++) { for (i = 0; i < n_modules; i++) {
src = generate_module(i, deps_per_module) src = generate_module(i, deps_per_module)
push(modules, src) modules[] = src
} }
// "Load" each module: tokenize → parse → evaluate // "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++) { for (j = 0; j < deps_per_module; j++) {
if (j < i) { if (j < i) {
dep = "mod_" + text(j) dep = "mod_" + text(j)
push(adj[dep], name) adj[dep][] = name
in_degree[name] = in_degree[name] + 1 in_degree[name] = in_degree[name] + 1
} }
} }
@@ -183,7 +183,7 @@ function topo_sort(n_modules, deps_per_module) {
var queue = [] var queue = []
var keys = array(in_degree) var keys = array(in_degree)
for (i = 0; i < length(keys); i++) { 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 = [] var order = []
@@ -193,12 +193,12 @@ function topo_sort(n_modules, deps_per_module) {
while (qi < length(queue)) { while (qi < length(queue)) {
current = queue[qi] current = queue[qi]
qi++ qi++
push(order, current) order[] = current
neighbors = adj[current] neighbors = adj[current]
if (neighbors) { if (neighbors) {
for (i = 0; i < length(neighbors); i++) { for (i = 0; i < length(neighbors); i++) {
in_degree[neighbors[i]] = in_degree[neighbors[i]] - 1 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 var i = 0
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0 x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(a, x % 10000) a[] = x % 10000
} }
return a return a
} }
@@ -15,7 +15,7 @@ function make_random_array(n, seed) {
function make_descending(n) { function make_descending(n) {
var a = [] var a = []
var i = 0 var i = 0
for (i = n - 1; i >= 0; i--) push(a, i) for (i = n - 1; i >= 0; i--) a[] = i
return a return a
} }
@@ -58,19 +58,19 @@ function merge(a, b) {
var j = 0 var j = 0
while (i < length(a) && j < length(b)) { while (i < length(a) && j < length(b)) {
if (a[i] <= b[j]) { if (a[i] <= b[j]) {
push(result, a[i]) result[] = a[i]
i++ i++
} else { } else {
push(result, b[j]) result[] = b[j]
j++ j++
} }
} }
while (i < length(a)) { while (i < length(a)) {
push(result, a[i]) result[] = a[i]
i++ i++
} }
while (j < length(b)) { while (j < length(b)) {
push(result, b[j]) result[] = b[j]
j++ j++
} }
return result return result
@@ -97,7 +97,7 @@ function sort_records(n) {
var i = 0 var i = 0
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0 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") return sort(records, "score")
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -3348,7 +3348,7 @@
{ {
"_closure_slot_types": {}, "_closure_slot_types": {},
"disruption_pc": 0, "disruption_pc": 0,
"nr_slots": 7, "nr_slots": 8,
"nr_close_slots": 0, "nr_close_slots": 0,
"instructions": [ "instructions": [
["get", 2, 14, 2, 1167, 15], ["get", 2, 14, 2, 1167, 15],
@@ -3356,23 +3356,35 @@
["invoke", 3, 2, 1167, 15], ["invoke", 3, 2, 1167, 15],
["move", 3, 2, 1167, 15], ["move", 3, 2, 1167, 15],
["access", 2, 8, 1, 13], ["access", 2, 8, 1, 13],
"_nop_tc_1", ["is_num", 4, 1, 1, 13],
"_nop_tc_2", ["jump_false", 4, "num_err_160", 1, 13],
["multiply", 4, 1, 2, 1, 13], ["multiply", 4, 1, 2, 1, 13],
["jump", "num_done_161", 1, 13], ["jump", "num_done_161", 1, 13],
"num_err_160", "num_err_160",
"_nop_ucfg_1", [
"_nop_ucfg_2", "access",
"_nop_ucfg_3", 2,
"_nop_ucfg_4", {
"_nop_ucfg_5", "name": "log",
"_nop_ucfg_6", "kind": "name",
"_nop_ucfg_7", "make": "intrinsic"
"_nop_ucfg_8", },
"_nop_ucfg_9", 1,
"_nop_ucfg_10", 13
"_nop_ucfg_11", ],
"_nop_ucfg_12", ["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", "num_done_161",
[ [
"access", "access",
@@ -3459,7 +3471,7 @@
"_nop_ur_1", "_nop_ur_1",
"_nop_ur_2" "_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>", "name": "<anonymous>",
"filename": ".cell/packages/core/qbe_emit.cm", "filename": ".cell/packages/core/qbe_emit.cm",
"nr_args": 1 "nr_args": 1
@@ -3467,7 +3479,7 @@
{ {
"_closure_slot_types": {}, "_closure_slot_types": {},
"disruption_pc": 0, "disruption_pc": 0,
"nr_slots": 9, "nr_slots": 10,
"nr_close_slots": 0, "nr_close_slots": 0,
"instructions": [ "instructions": [
["get", 3, 14, 2, 1174, 15], ["get", 3, 14, 2, 1174, 15],
@@ -3541,23 +3553,35 @@
"if_else_162", "if_else_162",
"if_end_163", "if_end_163",
["access", 5, 8, 1, 13], ["access", 5, 8, 1, 13],
"_nop_tc_1", ["is_num", 6, 1, 1, 13],
"_nop_tc_2", ["jump_false", 6, "num_err_164", 1, 13],
["multiply", 6, 1, 5, 1, 13], ["multiply", 6, 1, 5, 1, 13],
["jump", "num_done_165", 1, 13], ["jump", "num_done_165", 1, 13],
"num_err_164", "num_err_164",
"_nop_ucfg_1", [
"_nop_ucfg_2", "access",
"_nop_ucfg_3", 5,
"_nop_ucfg_4", {
"_nop_ucfg_5", "name": "log",
"_nop_ucfg_6", "kind": "name",
"_nop_ucfg_7", "make": "intrinsic"
"_nop_ucfg_8", },
"_nop_ucfg_9", 1,
"_nop_ucfg_10", 13
"_nop_ucfg_11", ],
"_nop_ucfg_12", ["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", "num_done_165",
[ [
"access", "access",
@@ -3624,7 +3648,7 @@
["null", 3, 1181, 7], ["null", 3, 1181, 7],
["return", 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>", "name": "<anonymous>",
"filename": ".cell/packages/core/qbe_emit.cm", "filename": ".cell/packages/core/qbe_emit.cm",
"nr_args": 2 "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) { function replace_sigils_array(flags, pkg_dir) {
var result = [] var result = []
arrfor(flags, function(flag) { arrfor(flags, function(flag) {
push(result, replace_sigils(flag, pkg_dir)) result[] = replace_sigils(flag, pkg_dir)
}) })
return result return result
} }
@@ -179,7 +179,7 @@ function bmfst_save(cmd_str, src_path, deps, obj_path) {
arrfor(deps, function(dep_path) { arrfor(deps, function(dep_path) {
var st = memo_stat(dep_path) var st = memo_stat(dep_path)
if (st) 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 = {o: obj_path, d: entries}
var mf_path = bmfst_path(cmd_str, src_path) 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) { function bmfst_dl_key(setup, link_info) {
var parts = [setup.cmd_str, setup.src_path] var parts = [setup.cmd_str, setup.src_path]
push(parts, 'target:' + text(link_info.target)) parts[] = 'target:' + text(link_info.target)
push(parts, 'cc:' + text(link_info.cc)) parts[] = 'cc:' + text(link_info.cc)
arrfor(link_info.extra_objects, function(obj) { 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) { arrfor(link_info.ldflags, function(flag) {
push(parts, 'ldflag:' + text(flag)) parts[] = 'ldflag:' + text(flag)
}) })
arrfor(link_info.target_ldflags, function(flag) { arrfor(link_info.target_ldflags, function(flag) {
push(parts, 'target_ldflag:' + text(flag)) parts[] = 'target_ldflag:' + text(flag)
}) })
return text(parts, '\n') return text(parts, '\n')
} }
@@ -227,7 +227,7 @@ function bmfst_dl_save(setup, link_info, deps, dylib_path) {
arrfor(deps, function(dep_path) { arrfor(deps, function(dep_path) {
var st = memo_stat(dep_path) var st = memo_stat(dep_path)
if (st) 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 = {dylib: dylib_path, d: entries}
var mf_path = cache_path(bmfst_dl_key(setup, link_info), SALT_BMFST_DL) 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_file = '/tmp/cell_deps_' + content_hash(src_path) + '.d'
var dep_cmd = [cc, '-MM', '-MG', '-MF', '"' + dep_file + '"'] var dep_cmd = [cc, '-MM', '-MG', '-MF', '"' + dep_file + '"']
dep_cmd = array(dep_cmd, flags) 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') var ret = os.system(text(dep_cmd, ' ') + ' 2>/dev/null')
if (ret != 0) return [src_path] if (ret != 0) return [src_path]
if (!fd.is_file(dep_file)) 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) { arrfor(deps, function(dep_path) {
var content = memo_read(dep_path) var content = memo_read(dep_path)
if (content != null) if (content != null)
push(parts, dep_path + '\n' + content) parts[] = dep_path + '\n' + content
else else
push(parts, dep_path + '\n<missing>') parts[] = dep_path + '\n<missing>'
}) })
return text(parts, '\n') return text(parts, '\n')
} }
@@ -310,16 +310,16 @@ function compile_setup(pkg, file, target, opts) {
common_flags = array(common_flags, ['-Os', '-DNDEBUG']) common_flags = array(common_flags, ['-Os', '-DNDEBUG'])
} }
push(common_flags, '-DCELL_USE_NAME=' + sym_name) common_flags[] = '-DCELL_USE_NAME=' + sym_name
push(common_flags, '-I"' + pkg_dir + '"') common_flags[] = '-I"' + pkg_dir + '"'
if (fd.is_dir(pkg_dir + '/include')) { if (fd.is_dir(pkg_dir + '/include')) {
push(common_flags, '-I"' + pkg_dir + '/include"') common_flags[] = '-I"' + pkg_dir + '/include"'
} }
if (pkg != 'core') { if (pkg != 'core') {
core_dir = shop.get_package_dir('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) { arrfor(cflags, function(flag) {
@@ -331,16 +331,16 @@ function compile_setup(pkg, file, target, opts) {
f = '-I"' + pkg_dir + '/' + ipath + '"' f = '-I"' + pkg_dir + '/' + ipath + '"'
} }
} }
push(common_flags, f) common_flags[] = f
}) })
arrfor(target_cflags, function(flag) { arrfor(target_cflags, function(flag) {
push(common_flags, flag) common_flags[] = flag
}) })
var cmd_parts = [cc, '-c', '-fPIC'] var cmd_parts = [cc, '-c', '-fPIC']
cmd_parts = array(cmd_parts, common_flags) cmd_parts = array(cmd_parts, common_flags)
push(cmd_parts, '"' + src_path + '"') cmd_parts[] = '"' + src_path + '"'
return { return {
cmd_str: text(cmd_parts, ' '), cmd_str: text(cmd_parts, ' '),
@@ -513,7 +513,7 @@ Build.build_package = function(pkg, target, exclude_main, buildtype) {
arrfor(c_files, function(file) { arrfor(c_files, function(file) {
var obj = Build.compile_file(pkg, file, _target, {buildtype: _buildtype, cflags: cached_cflags}) var obj = Build.compile_file(pkg, file, _target, {buildtype: _buildtype, cflags: cached_cflags})
push(objects, obj) objects[] = obj
}) })
return objects return objects
@@ -527,16 +527,16 @@ Build.build_package = function(pkg, target, exclude_main, buildtype) {
// link_opts: {extra_objects, ldflags, target_ldflags, target, cc} // link_opts: {extra_objects, ldflags, target_ldflags, target, cc}
function compute_dylib_content(full_content, link_opts) { function compute_dylib_content(full_content, link_opts) {
var parts = [full_content] var parts = [full_content]
push(parts, 'target:' + text(link_opts.target)) parts[] = 'target:' + text(link_opts.target)
push(parts, 'cc:' + text(link_opts.cc)) parts[] = 'cc:' + text(link_opts.cc)
arrfor(link_opts.extra_objects, function(obj) { 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) { arrfor(link_opts.ldflags, function(flag) {
push(parts, 'ldflag:' + text(flag)) parts[] = 'ldflag:' + text(flag)
}) })
arrfor(link_opts.target_ldflags, function(flag) { arrfor(link_opts.target_ldflags, function(flag) {
push(parts, 'target_ldflag:' + text(flag)) parts[] = 'target_ldflag:' + text(flag)
}) })
return text(parts, '\n') return text(parts, '\n')
} }
@@ -570,7 +570,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
f = '-L"' + setup.pkg_dir + '/' + lpath + '"' f = '-L"' + setup.pkg_dir + '/' + lpath + '"'
} }
} }
push(resolved_ldflags, f) resolved_ldflags[] = f
}) })
var build_dir = get_build_dir() var build_dir = get_build_dir()
@@ -683,18 +683,18 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
'-Wl,-rpath,' + local_dir '-Wl,-rpath,' + local_dir
]) ])
} else if (tc.system == 'windows') { } else if (tc.system == 'windows') {
push(cmd_parts, '-Wl,--allow-shlib-undefined') cmd_parts[] = '-Wl,--allow-shlib-undefined'
} }
push(cmd_parts, '-L"' + local_dir + '"') cmd_parts[] = '-L"' + local_dir + '"'
push(cmd_parts, '"' + text(obj) + '"') cmd_parts[] = '"' + text(obj) + '"'
arrfor(_extra, function(extra_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, resolved_ldflags)
cmd_parts = array(cmd_parts, target_ldflags) cmd_parts = array(cmd_parts, target_ldflags)
push(cmd_parts, '-o') cmd_parts[] = '-o'
push(cmd_parts, '"' + dylib_path + '"') cmd_parts[] = '"' + dylib_path + '"'
cmd_str = text(cmd_parts, ' ') cmd_str = text(cmd_parts, ' ')
if (_opts.verbose) log.build('[verbose] link: ' + cmd_str) 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') { if (pkg != 'core') {
arrfor(sources, function(src_file) { arrfor(sources, function(src_file) {
var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags}) 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') { if (pkg != 'core') {
arrfor(sources, function(src_file) { 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}) 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) { arrfor(c_files, function(file) {
var sym_name = shop.c_symbol_for_file(pkg, 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}) 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) { if (dylib) {
push(results, {file: file, symbol: sym_name, dylib: dylib}) results[] = {file: file, symbol: sym_name, dylib: dylib}
} else { } else {
failed = failed + 1 failed = failed + 1
} }
done = done + 1 done = done + 1
os.print('.')
}) })
if (total > 0) 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 // Write manifest so runtime can find dylibs without the build module
var mpath = manifest_path(pkg) 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) var objects = Build.build_package(pkg, _target, !is_core, _buildtype)
arrfor(objects, function(obj) { arrfor(objects, function(obj) {
push(all_objects, obj) all_objects[] = obj
}) })
// Collect LDFLAGS (with sigil replacement) // Collect LDFLAGS (with sigil replacement)
@@ -838,7 +834,7 @@ Build.build_static = function(packages, target, output, buildtype) {
f = '-L"' + pkg_dir + '/' + lpath + '"' 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] var cmd_parts = [cc]
arrfor(all_objects, function(obj) { arrfor(all_objects, function(obj) {
push(cmd_parts, '"' + obj + '"') cmd_parts[] = '"' + obj + '"'
}) })
arrfor(all_ldflags, function(flag) { arrfor(all_ldflags, function(flag) {
push(cmd_parts, flag) cmd_parts[] = flag
}) })
arrfor(target_ldflags, function(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, ' ') var cmd_str = text(cmd_parts, ' ')
@@ -925,7 +921,7 @@ function qbe_insert_dead_labels(il_text) {
line = lines[i] line = lines[i]
trimmed = trim(line) trimmed = trim(line)
if (need_label && !starts_with(trimmed, '@') && !starts_with(trimmed, '}') && length(trimmed) > 0) { 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 dead_id = dead_id + 1
need_label = false need_label = false
} }
@@ -935,7 +931,7 @@ function qbe_insert_dead_labels(il_text) {
if (starts_with(trimmed, 'ret ') || starts_with(trimmed, 'jmp ')) { if (starts_with(trimmed, 'ret ') || starts_with(trimmed, 'jmp ')) {
need_label = true need_label = true
} }
push(result, line) result[] = line
i = i + 1 i = i + 1
} }
return text(result, "\n") return text(result, "\n")
@@ -1126,16 +1122,16 @@ Build.compile_cm_to_mach = function(src_path) {
// output: path to write the generated .c file // output: path to write the generated .c file
Build.generate_module_table = function(modules, output) { Build.generate_module_table = function(modules, output) {
var lines = [] var lines = []
push(lines, '/* Generated module table — do not edit */') lines[] = '/* Generated module table — do not edit */'
push(lines, '#include <stddef.h>') lines[] = '#include <stddef.h>'
push(lines, '#include <string.h>') lines[] = '#include <string.h>'
push(lines, '') lines[] = ''
push(lines, 'struct cell_embedded_entry {') lines[] = 'struct cell_embedded_entry {'
push(lines, ' const char *name;') lines[] = ' const char *name;'
push(lines, ' const unsigned char *data;') lines[] = ' const unsigned char *data;'
push(lines, ' size_t size;') lines[] = ' size_t size;'
push(lines, '};') lines[] = '};'
push(lines, '') lines[] = ''
var entries = [] var entries = []
arrfor(modules, function(mod) { arrfor(modules, function(mod) {
@@ -1144,27 +1140,27 @@ Build.generate_module_table = function(modules, output) {
var bytes = array(mach) var bytes = array(mach)
var hex = [] var hex = []
arrfor(bytes, function(b) { arrfor(bytes, function(b) {
push(hex, '0x' + text(b, 'h2')) hex[] = '0x' + text(b, 'h2')
}) })
push(lines, 'static const unsigned char mod_' + safe + '_data[] = {') lines[] = 'static const unsigned char mod_' + safe + '_data[] = {'
push(lines, ' ' + text(hex, ', ')) lines[] = ' ' + text(hex, ', ')
push(lines, '};') lines[] = '};'
push(lines, '') lines[] = ''
push(entries, safe) entries[] = safe
log.console('Embedded: ' + mod.name + ' (' + text(length(bytes)) + ' bytes)') log.console('Embedded: ' + mod.name + ' (' + text(length(bytes)) + ' bytes)')
}) })
// Lookup function // 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) { arrfor(modules, function(mod, i) {
var safe = entries[i] var safe = entries[i]
push(lines, ' if (strcmp(name, "' + mod.name + '") == 0) {') 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)};') lines[] = ' static const struct cell_embedded_entry e = {"' + mod.name + '", mod_' + safe + '_data, sizeof(mod_' + safe + '_data)};'
push(lines, ' return &e;') lines[] = ' return &e;'
push(lines, ' }') lines[] = ' }'
}) })
push(lines, ' return (void *)0;') lines[] = ' return (void *)0;'
push(lines, '}') lines[] = '}'
var c_text = text(lines, '\n') var c_text = text(lines, '\n')
fd.slurpwrite(output, stone(blob(c_text))) fd.slurpwrite(output, stone(blob(c_text)))
@@ -1192,14 +1188,14 @@ Build.build_all_dynamic = function(target, buildtype, opts) {
// Build core first // Build core first
if (find(packages, function(p) { return p == 'core' }) != null) { if (find(packages, function(p) { return p == 'core' }) != null) {
core_mods = Build.build_dynamic('core', _target, _buildtype, _opts) 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 // Build other packages
arrfor(packages, function(pkg) { arrfor(packages, function(pkg) {
if (pkg == 'core') return if (pkg == 'core') return
var pkg_mods = Build.build_dynamic(pkg, _target, _buildtype, _opts) 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 // Print build report

View File

@@ -152,7 +152,7 @@ function mount(source, name) {
}) })
} }
} }
push(mounts, mount_info) mounts[] = mount_info
return return
} }
@@ -187,7 +187,7 @@ function mount(source, name) {
log.error("Unsupported mount source type: " + source); disrupt log.error("Unsupported mount source type: " + source); disrupt
} }
push(mounts, mount_info) mounts[] = mount_info
} }
function unmount(name_or_source) { function unmount(name_or_source) {
@@ -356,7 +356,7 @@ function enumerate(_path, recurse) {
arrfor(list, function(item) { arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item var item_rel = rel_prefix ? rel_prefix + "/" + item : item
var child_st = null var child_st = null
push(results, item_rel) results[] = item_rel
if (recurse) { if (recurse) {
child_st = fd.stat(fd.join_paths(curr_full, item)) child_st = fd.stat(fd.join_paths(curr_full, item))
@@ -396,7 +396,7 @@ function enumerate(_path, recurse) {
if (!seen[rel]) { if (!seen[rel]) {
seen[rel] = true seen[rel] = true
push(results, rel) results[] = rel
} }
} }
}) })
@@ -455,7 +455,7 @@ function globfs(globs, _dir) {
} }
} else { } else {
if (!check_neg(item_rel) && check_pos(item_rel)) { 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 (length(rel) == 0) return
if (!check_neg(rel) && check_pos(rel)) { 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 (is_array(instr)) {
if (block_start_pcs[text(pc)]) { if (block_start_pcs[text(pc)]) {
if (current_block != null) { if (current_block != null) {
push(blocks, current_block) blocks[] = current_block
} }
current_block = { current_block = {
id: length(blocks), id: length(blocks),
@@ -184,7 +184,7 @@ var run = function() {
} }
if (current_block != null) { if (current_block != null) {
push(current_block.instrs, {pc: pc, instr: instr}) current_block.instrs[] = {pc: pc, instr: instr}
current_block.end_pc = pc current_block.end_pc = pc
n = length(instr) n = length(instr)
line_num = instr[n - 2] line_num = instr[n - 2]
@@ -200,7 +200,7 @@ var run = function() {
ii = ii + 1 ii = ii + 1
} }
if (current_block != null) { if (current_block != null) {
push(blocks, current_block) blocks[] = current_block
} }
// Build block index // Build block index
@@ -235,19 +235,19 @@ var run = function() {
if (target_bi <= bi) { if (target_bi <= bi) {
edge_type = "loop back-edge" 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 (is_conditional_jump(last_op)) {
if (bi + 1 < length(blocks)) { 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)) { } else if (is_terminator(last_op)) {
push(blk.edges, {target: -1, kind: "EXIT (" + last_op + ")"}) blk.edges[] = {target: -1, kind: "EXIT (" + last_op + ")"}
} else { } else {
if (bi + 1 < length(blocks)) { 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 = [] parts = []
j = 1 j = 1
while (j < n - 2) { while (j < n - 2) {
push(parts, fmt_val(instr[j])) parts[] = fmt_val(instr[j])
j = j + 1 j = j + 1
} }
operands = text(parts, ", ") operands = text(parts, ", ")
@@ -381,7 +381,7 @@ var run = function() {
parts = [] parts = []
j = 1 j = 1
while (j < n - 2) { while (j < n - 2) {
push(parts, fmt_val(instr[j])) parts[] = fmt_val(instr[j])
j = j + 1 j = j + 1
} }
operands = text(parts, ", ") operands = text(parts, ", ")

View File

@@ -93,13 +93,13 @@ if (is_shop_scope) {
packages_to_clean = shop.list_packages() packages_to_clean = shop.list_packages()
} else { } else {
// Single package // Single package
push(packages_to_clean, scope) packages_to_clean[] = scope
if (deep) { if (deep) {
_gather = function() { _gather = function() {
deps = pkg.gather_dependencies(scope) deps = pkg.gather_dependencies(scope)
arrfor(deps, function(dep) { arrfor(deps, function(dep) {
push(packages_to_clean, dep) packages_to_clean[] = dep
}) })
} disruption { } disruption {
// Skip if can't read dependencies // Skip if can't read dependencies
@@ -116,11 +116,11 @@ var packages_dir = replace(shop.get_package_dir(''), /\/$/, '') // Get base pack
if (clean_build) { if (clean_build) {
// Nuke entire build cache (content-addressed, per-package clean impractical) // Nuke entire build cache (content-addressed, per-package clean impractical)
if (fd.is_dir(build_dir)) { 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) // Clean orphaned lib/ directory if it exists (legacy)
if (fd.is_dir(lib_dir)) { 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) { if (is_shop_scope) {
// Clean entire packages directory (dangerous!) // Clean entire packages directory (dangerous!)
if (fd.is_dir(packages_dir)) { if (fd.is_dir(packages_dir)) {
push(dirs_to_delete, packages_dir) dirs_to_delete[] = packages_dir
} }
} else { } else {
// Clean specific package directories // Clean specific package directories
@@ -137,7 +137,7 @@ if (clean_fetch) {
var pkg_dir = shop.get_package_dir(p) var pkg_dir = shop.get_package_dir(p)
if (fd.is_dir(pkg_dir) || fd.is_link(pkg_dir)) { 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 match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (test_name != match_base) continue if (test_name != match_base) continue
} }
push(test_files, f) test_files[] = f
} }
} }
return test_files return test_files
@@ -100,7 +100,7 @@ function diff_test_file(file_path) {
src = text(fd.slurp(src_path)) src = text(fd.slurp(src_path))
ast = analyze(src, src_path) ast = analyze(src, src_path)
} disruption { } disruption {
push(results.errors, `failed to parse ${file_path}`) results.errors[] = `failed to parse ${file_path}`
return results return results
} }
_read() _read()
@@ -124,14 +124,14 @@ function diff_test_file(file_path) {
// Compare module-level behavior // Compare module-level behavior
if (opt_error != noopt_error) { 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 results.failed = results.failed + 1
return results return results
} }
if (opt_error != null) { if (opt_error != null) {
// Both disrupted during load — that's consistent // Both disrupted during load — that's consistent
results.passed = results.passed + 1 results.passed = results.passed + 1
push(results.tests, {name: "<module>", status: "passed"}) results.tests[] = {name: "<module>", status: "passed"}
return results return results
} }
@@ -161,15 +161,15 @@ function diff_test_file(file_path) {
_run_one_noopt() _run_one_noopt()
if (opt_err != noopt_err) { if (opt_err != noopt_err) {
push(results.tests, {name: k, status: "failed"}) 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.errors[] = `${k}: disruption mismatch opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`
results.failed = results.failed + 1 results.failed = results.failed + 1
} else if (!values_equal(opt_result, noopt_result)) { } else if (!values_equal(opt_result, noopt_result)) {
push(results.tests, {name: k, status: "failed"}) results.tests[] = {name: k, status: "failed"}
push(results.errors, `${k}: result mismatch opt=${describe(opt_result)} noopt=${describe(noopt_result)}`) results.errors[] = `${k}: result mismatch opt=${describe(opt_result)} noopt=${describe(noopt_result)}`
results.failed = results.failed + 1 results.failed = results.failed + 1
} else { } else {
push(results.tests, {name: k, status: "passed"}) results.tests[] = {name: k, status: "passed"}
results.passed = results.passed + 1 results.passed = results.passed + 1
} }
} }
@@ -178,11 +178,11 @@ function diff_test_file(file_path) {
} else { } else {
// Compare direct return values // Compare direct return values
if (!values_equal(mod_opt, mod_noopt)) { if (!values_equal(mod_opt, mod_noopt)) {
push(results.tests, {name: "<return>", status: "failed"}) results.tests[] = {name: "<return>", status: "failed"}
push(results.errors, `return value mismatch: opt=${describe(mod_opt)} noopt=${describe(mod_noopt)}`) results.errors[] = `return value mismatch: opt=${describe(mod_opt)} noopt=${describe(mod_noopt)}`
results.failed = results.failed + 1 results.failed = results.failed + 1
} else { } else {
push(results.tests, {name: "<return>", status: "passed"}) results.tests[] = {name: "<return>", status: "passed"}
results.passed = results.passed + 1 results.passed = results.passed + 1
} }
} }

View File

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

View File

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

2
fd.cm
View File

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

12
fuzz.ce
View File

@@ -89,7 +89,7 @@ function run_fuzz(seed_val) {
var _parse = function() { var _parse = function() {
ast = analyze(src, name + ".cm") ast = analyze(src, name + ".cm")
} disruption { } disruption {
push(errors, "parse error") errors[] = "parse error"
} }
_parse() _parse()
if (length(errors) > 0) return {seed: seed_val, errors: errors, src: src} 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 // Check module-level behavior
if (opt_err != noopt_err) { 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} return {seed: seed_val, errors: errors, src: src}
} }
if (opt_err != null) { if (opt_err != null) {
@@ -137,10 +137,10 @@ function run_fuzz(seed_val) {
_run() _run()
if (is_text(ret)) { if (is_text(ret)) {
push(errors, `self-check ${key}: ${ret}`) errors[] = `self-check ${key}: ${ret}`
} }
if (run_err != null) { if (run_err != null) {
push(errors, `self-check ${key}: unexpected disruption`) errors[] = `self-check ${key}: unexpected disruption`
} }
} }
k = k + 1 k = k + 1
@@ -174,9 +174,9 @@ function run_fuzz(seed_val) {
_run_noopt() _run_noopt()
if (opt_fn_err != noopt_fn_err) { 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)) { } 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 k2 = k2 + 1

View File

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

View File

@@ -98,7 +98,7 @@ function gather_graph(locator, visited) {
arrfor(array(deps), function(alias) { arrfor(array(deps), function(alias) {
var dep_locator = deps[alias] var dep_locator = deps[alias]
add_node(dep_locator) 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) gather_graph(dep_locator, visited)
}) })
} }
@@ -117,7 +117,7 @@ if (show_world) {
packages = shop.list_packages() packages = shop.list_packages()
arrfor(packages, function(p) { arrfor(packages, function(p) {
if (p != 'core') { if (p != 'core') {
push(roots, p) roots[] = p
} }
}) })
} else { } else {
@@ -128,7 +128,7 @@ if (show_world) {
target_locator = shop.resolve_locator(target_locator) target_locator = shop.resolve_locator(target_locator)
push(roots, target_locator) roots[] = target_locator
} }
arrfor(roots, function(root) { arrfor(roots, function(root) {
@@ -164,7 +164,7 @@ if (format == 'tree') {
children = [] children = []
arrfor(edges, function(e) { arrfor(edges, function(e) {
if (e.from == locator) { if (e.from == locator) {
push(children, e) children[] = e
} }
}) })
@@ -180,7 +180,7 @@ if (format == 'tree') {
children = [] children = []
arrfor(edges, function(e) { arrfor(edges, function(e) {
if (e.from == roots[i]) { if (e.from == roots[i]) {
push(children, e) children[] = e
} }
}) })
@@ -230,7 +230,7 @@ if (format == 'tree') {
} }
arrfor(array(nodes), function(id) { arrfor(array(nodes), function(id) {
push(output.nodes, nodes[id]) output.nodes[] = nodes[id]
}) })
output.edges = edges 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) { function decode_chunked(body_text) {
var result = "" var result = ""
var pos = 0 var pos = 0
@@ -475,6 +475,37 @@ function decode_chunked(body_text) {
return result 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 // receive_response requestor — async incremental receive
var receive_response = function(callback, state) { var receive_response = function(callback, state) {
var cancelled = false var cancelled = false
@@ -650,6 +681,8 @@ var fetch = function(url) {
var addrs = null var addrs = null
var address = null var address = null
var ok = true var ok = true
var status_line = null
var status_code = null
if (scheme_end != null) { if (scheme_end != null) {
scheme = lower(text(url, 0, scheme_end)) scheme = lower(text(url, 0, scheme_end))
@@ -705,8 +738,16 @@ var fetch = function(url) {
hdr_end = search(raw_text, CRLF + CRLF) hdr_end = search(raw_text, CRLF + CRLF)
if (hdr_end == null) return null if (hdr_end == null) return null
header_text = text(raw_text, 0, hdr_end) header_text = text(raw_text, 0, hdr_end)
if (search(lower(header_text), "transfer-encoding: chunked") != null) status_line = text(header_text, 0, search(header_text, CRLF) || length(header_text))
return decode_chunked(text(raw_text, hdr_end + 4)) 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 // Headers are ASCII so char offset = byte offset
body_start_bits = (hdr_end + 4) * 8 body_start_bits = (hdr_end + 4) * 8
body = buf.read_blob(body_start_bits, length(buf)) 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 all_packages[imp_pkg] = true
push(all_imports, { all_imports[] = {
from: file_path, from: file_path,
from_pkg: file_pkg, from_pkg: file_pkg,
module_path: mod_path, module_path: mod_path,
@@ -117,7 +117,7 @@ function trace_imports(file_path, depth) {
package: imp_pkg, package: imp_pkg,
type: imp_type, type: imp_type,
depth: depth depth: depth
}) }
// Recurse into resolved scripts // Recurse into resolved scripts
if (resolved && (ends_with(resolved, '.cm') || ends_with(resolved, '.ce'))) { 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); 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); JSValue obj = JS_NewObjectClass(ctx, enet_peer_class_id);
if (peer && peer->data) { if (JS_IsException(obj)) return obj;
free(peer->data); JS_SetOpaque(obj, peer);
} return obj;
} }
// Initialize the ENet library. Must be called before using any ENet functionality. /* ── Host functions ─────────────────────────────────────────── */
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;
}
// Deinitialize the ENet library, cleaning up all resources. static JSValue js_enet_create_host(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
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)
{ {
ENetHost *host; ENetHost *host;
ENetAddress address; 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); int err = enet_address_set_host_ip(&address, addr_str);
if (err != 0) { if (err != 0) {
JS_FreeCString(ctx, addr_str); 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; address.port = (enet_uint16)port32;
@@ -103,97 +100,76 @@ wrap:
return obj; return obj;
} }
// Helper function to get a JSValue for an ENetPeer. /* service(host, callback [, timeout]) */
static JSValue peer_get_value(JSContext *ctx, ENetPeer *peer) static JSValue js_enet_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{ {
if (!peer->data) { if (argc < 2) return JS_RaiseDisrupt(ctx, "service: expected (host, callback)");
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;
}
// Poll for and process any available network events from this host, ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
// calling the provided callback for each event. if (!host) return JS_RaiseDisrupt(ctx, "service: invalid host");
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;
if (argc < 1 || !JS_IsFunction(argv[0])) if (!JS_IsFunction(argv[1]))
return JS_RaiseDisrupt(ctx, "Expected a callback function as first argument"); return JS_RaiseDisrupt(ctx, "service: expected callback function");
enet_uint32 timeout_ms = 0; enet_uint32 timeout_ms = 0;
if (argc >= 2 && !JS_IsNull(argv[1])) { if (argc >= 3 && !JS_IsNull(argv[2])) {
double secs = 0; 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); if (secs > 0) timeout_ms = (enet_uint32)(secs * 1000.0);
} }
JS_FRAME(ctx); JS_FRAME(ctx);
JSGCRef event_ref = { .val = JS_NULL, .prev = NULL }; JS_ROOT(event_obj, JS_NULL);
JS_PushGCRef(ctx, &event_ref);
ENetEvent event; ENetEvent event;
while (enet_host_service(host, &event, timeout_ms) > 0) { 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); JSValue peer_val = peer_wrap(ctx, event.peer);
JS_SetPropertyStr(ctx, event_ref.val, "peer", peer_val); JS_SetPropertyStr(ctx, event_obj.val, "peer", peer_val);
switch (event.type) { switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: { case ENET_EVENT_TYPE_CONNECT:
JSValue type_str = JS_NewString(ctx, "connect"); JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "connect"));
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
break; break;
} case ENET_EVENT_TYPE_RECEIVE:
case ENET_EVENT_TYPE_RECEIVE: { JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "receive"));
JSValue type_str = JS_NewString(ctx, "receive"); JS_SetPropertyStr(ctx, event_obj.val, "channelID", JS_NewInt32(ctx, event.channelID));
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
JS_SetPropertyStr(ctx, event_ref.val, "channelID", JS_NewInt32(ctx, event.channelID));
if (event.packet->dataLength > 0) { if (event.packet->dataLength > 0) {
JSValue data_val = js_new_blob_stoned_copy(ctx, event.packet->data, event.packet->dataLength); 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); enet_packet_destroy(event.packet);
break; break;
} case ENET_EVENT_TYPE_DISCONNECT:
case ENET_EVENT_TYPE_DISCONNECT: { JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect"));
JSValue type_str = JS_NewString(ctx, "disconnect");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
break; break;
} case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: { JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "disconnect_timeout"));
JSValue type_str = JS_NewString(ctx, "disconnect_timeout");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
break; break;
} case ENET_EVENT_TYPE_NONE:
case ENET_EVENT_TYPE_NONE: { JS_SetPropertyStr(ctx, event_obj.val, "type", JS_NewString(ctx, "none"));
JSValue type_str = JS_NewString(ctx, "none");
JS_SetPropertyStr(ctx, event_ref.val, "type", type_str);
break; 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(); JS_RETURN_NULL();
} }
// Initiate a connection from this host to a remote server. /* connect(host, address, port) → peer */
static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) static JSValue js_enet_connect(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{ {
ENetHost *host = JS_GetOpaque(this_val, enet_host_id); if (argc < 3) return JS_RaiseDisrupt(ctx, "connect: expected (host, address, port)");
if (!host) return JS_EXCEPTION;
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; if (!hostname) return JS_EXCEPTION;
int port; int port;
JS_ToInt32(ctx, &port, argv[1]); JS_ToInt32(ctx, &port, argv[2]);
ENetAddress address; ENetAddress address;
enet_address_set_host(&address, hostname); enet_address_set_host(&address, hostname);
@@ -201,43 +177,43 @@ static JSValue js_enet_host_connect(JSContext *ctx, JSValueConst this_val, int a
address.port = port; address.port = port;
ENetPeer *peer = enet_host_connect(host, &address, 2, 0); 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. /* flush(host) */
static JSValue js_enet_host_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) static JSValue js_enet_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{ {
ENetHost *host = JS_GetOpaque(this_val, enet_host_id); if (argc < 1) return JS_RaiseDisrupt(ctx, "flush: expected (host)");
if (!host) return JS_EXCEPTION; ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "flush: invalid host");
enet_host_flush(host); enet_host_flush(host);
return JS_NULL; return JS_NULL;
} }
// Broadcast a string or blob to all connected peers on channel 0. /* broadcast(host, data) */
static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) static JSValue js_enet_broadcast(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{ {
ENetHost *host = JS_GetOpaque(this_val, enet_host_id); if (argc < 2) return JS_RaiseDisrupt(ctx, "broadcast: expected (host, data)");
if (!host) return JS_EXCEPTION; ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "broadcast: invalid host");
if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to broadcast");
const char *data_str = NULL; const char *data_str = NULL;
size_t data_len = 0; size_t data_len = 0;
uint8_t *buf = NULL; uint8_t *buf = NULL;
if (JS_IsText(argv[0])) { if (JS_IsText(argv[1])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
if (!data_str) return JS_EXCEPTION; if (!data_str) return JS_EXCEPTION;
} else if (js_is_blob(ctx, argv[0])) { } else if (js_is_blob(ctx, argv[1])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]); buf = js_get_blob_data(ctx, &data_len, argv[1]);
if (!buf) return JS_EXCEPTION; if (!buf) return JS_EXCEPTION;
} else { } 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); ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
if (data_str) JS_FreeCString(ctx, data_str); if (data_str) JS_FreeCString(ctx, data_str);
if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet"); if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet");
@@ -245,55 +221,51 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int
return JS_NULL; return JS_NULL;
} }
// Host property getters /* host_port(host) → number */
static JSValue js_enet_host_get_port(JSContext *js, JSValueConst self) static JSValue js_enet_host_port(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{ {
ENetHost *host = JS_GetOpaque(self, enet_host_id); if (argc < 1) return JS_RaiseDisrupt(ctx, "host_port: expected (host)");
if (!host) return JS_EXCEPTION; ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
return JS_NewInt32(js, host->address.port); 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 (argc < 1) return JS_RaiseDisrupt(ctx, "host_address: expected (host)");
if (!me) return JS_EXCEPTION; ENetHost *host = JS_GetOpaque(argv[0], enet_host_id);
if (!host) return JS_RaiseDisrupt(ctx, "host_address: invalid host");
char ip_str[128]; 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_NULL;
return JS_NewString(js, ip_str); return JS_NewString(ctx, ip_str);
} }
// Peer-level operations /* ── Peer functions ─────────────────────────────────────────── */
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;
}
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 (argc < 2) return JS_RaiseDisrupt(ctx, "send: expected (peer, data)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "send: invalid peer");
if (argc < 1) return JS_RaiseDisrupt(ctx, "Expected a string or blob to send");
const char *data_str = NULL; const char *data_str = NULL;
size_t data_len = 0; size_t data_len = 0;
uint8_t *buf = NULL; uint8_t *buf = NULL;
if (JS_IsText(argv[0])) { if (JS_IsText(argv[1])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]); data_str = JS_ToCStringLen(ctx, &data_len, argv[1]);
if (!data_str) return JS_EXCEPTION; if (!data_str) return JS_EXCEPTION;
} else if (js_is_blob(ctx, argv[0])) { } else if (js_is_blob(ctx, argv[1])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]); buf = js_get_blob_data(ctx, &data_len, argv[1]);
if (!buf) return JS_EXCEPTION; if (!buf) return JS_EXCEPTION;
} else { } 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); ENetPacket *packet = enet_packet_create(data_str ? (const void *)data_str : (const void *)buf, data_len, ENET_PACKET_FLAG_RELIABLE);
if (data_str) JS_FreeCString(ctx, data_str); if (data_str) JS_FreeCString(ctx, data_str);
if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet"); if (!packet) return JS_RaiseDisrupt(ctx, "Failed to create ENet packet");
@@ -301,225 +273,185 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc
return JS_NULL; 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 (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect: expected (peer)");
if (!peer) return JS_EXCEPTION; 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); enet_peer_disconnect_now(peer, 0);
return JS_NULL; 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 (argc < 1) return JS_RaiseDisrupt(ctx, "disconnect_later: expected (peer)");
if (!peer) return JS_EXCEPTION; 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); enet_peer_disconnect_later(peer, 0);
return JS_NULL; 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 (argc < 1) return JS_RaiseDisrupt(ctx, "reset: expected (peer)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "reset: invalid peer");
enet_peer_reset(peer); enet_peer_reset(peer);
return JS_NULL; 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 (argc < 1) return JS_RaiseDisrupt(ctx, "ping: expected (peer)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "ping: invalid peer");
enet_peer_ping(peer); enet_peer_ping(peer);
return JS_NULL; 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 (argc < 4) return JS_RaiseDisrupt(ctx, "throttle_configure: expected (peer, interval, accel, decel)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
if (!peer) return JS_RaiseDisrupt(ctx, "throttle_configure: invalid peer");
int interval, acceleration, deceleration; 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])) if (JS_ToInt32(ctx, &interval, argv[1]) || JS_ToInt32(ctx, &acceleration, argv[2]) || JS_ToInt32(ctx, &deceleration, argv[3]))
return JS_RaiseDisrupt(ctx, "Expected 3 int arguments: interval, acceleration, deceleration"); return JS_RaiseDisrupt(ctx, "throttle_configure: expected integer arguments");
enet_peer_throttle_configure(peer, interval, acceleration, deceleration); enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
return JS_NULL; return JS_NULL;
} }
/* peer_timeout(peer, limit, min, max) */
static JSValue js_enet_peer_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) 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 (argc < 4) return JS_RaiseDisrupt(ctx, "peer_timeout: expected (peer, limit, min, max)");
if (!peer) return JS_EXCEPTION; 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; 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])) 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, "Expected 3 integer arguments: timeout_limit, timeout_min, timeout_max"); return JS_RaiseDisrupt(ctx, "peer_timeout: expected integer arguments");
enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max); enet_peer_timeout(peer, timeout_limit, timeout_min, timeout_max);
return JS_NULL; return JS_NULL;
} }
// Class definitions /* ── Peer property getters ──────────────────────────────────── */
static JSClassDef enet_host = {
"ENetHost",
.finalizer = js_enet_host_finalizer,
};
static JSClassDef enet_peer_class = { #define PEER_GETTER(name, field, convert) \
"ENetPeer", static JSValue js_enet_##name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { \
.finalizer = js_enet_peer_finalizer, 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"); \
static JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) return convert(ctx, peer->field); \
{
const char *hostname = JS_ToCString(js, argv[0]);
JS_FreeCString(js, hostname);
return JS_NULL;
} }
static const JSCFunctionListEntry js_enet_funcs[] = { static inline JSValue _int32(JSContext *ctx, int v) { return JS_NewInt32(ctx, v); }
JS_CFUNC_DEF("initialize", 0, js_enet_initialize), static inline JSValue _uint32(JSContext *ctx, unsigned int v) { return JS_NewUint32(ctx, v); }
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 const JSCFunctionListEntry js_enet_host_funcs[] = { PEER_GETTER(peer_rtt, roundTripTime, _int32)
JS_CFUNC_DEF("service", 2, js_enet_host_service), PEER_GETTER(peer_rtt_variance, roundTripTimeVariance, _int32)
JS_CFUNC_DEF("connect", 2, js_enet_host_connect), PEER_GETTER(peer_last_send_time, lastSendTime, _int32)
JS_CFUNC_DEF("flush", 0, js_enet_host_flush), PEER_GETTER(peer_last_receive_time, lastReceiveTime, _int32)
JS_CFUNC_DEF("broadcast", 1, js_enet_host_broadcast), PEER_GETTER(peer_mtu, mtu, _int32)
JS_CFUNC0_DEF("port", js_enet_host_get_port), PEER_GETTER(peer_outgoing_data_total, outgoingDataTotal, _int32)
JS_CFUNC0_DEF("address", js_enet_host_get_address), 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_incoming_bandwidth(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
static JSValue js_enet_peer_get_rtt(JSContext *ctx, JSValueConst this_val)
{ {
ENetPeer *peer = JS_GetOpaque(this_val, enet_peer_class_id); if (argc < 1) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: expected (peer)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
return JS_NewInt32(ctx, peer->roundTripTime); if (!peer) return JS_RaiseDisrupt(ctx, "peer_incoming_bandwidth: invalid peer");
}
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 (peer->incomingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY); if (peer->incomingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->incomingBandwidth); 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 (argc < 1) return JS_RaiseDisrupt(ctx, "peer_outgoing_bandwidth: expected (peer)");
if (!peer) return JS_EXCEPTION; 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); if (peer->outgoingBandwidth == 0) return JS_NewFloat64(ctx, INFINITY);
return JS_NewInt32(ctx, peer->outgoingBandwidth); 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 (argc < 1) return JS_RaiseDisrupt(ctx, "peer_port: expected (peer)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
return JS_NewInt32(ctx, peer->lastSendTime); 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 (argc < 1) return JS_RaiseDisrupt(ctx, "peer_address: expected (peer)");
if (!peer) return JS_EXCEPTION; ENetPeer *peer = JS_GetOpaque(argv[0], enet_peer_class_id);
return JS_NewInt32(ctx, peer->lastReceiveTime); if (!peer) return JS_RaiseDisrupt(ctx, "peer_address: invalid peer");
}
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;
char ip_str[128]; char ip_str[128];
if (enet_address_get_host_ip(&peer->address, ip_str, sizeof(ip_str)) != 0) if (enet_address_get_host_ip(&peer->address, ip_str, sizeof(ip_str)) != 0)
return JS_NULL; return JS_NULL;
return JS_NewString(js, ip_str); return JS_NewString(ctx, ip_str);
} }
static const JSCFunctionListEntry js_enet_peer_funcs[] = { static JSValue js_enet_resolve_hostname(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
JS_CFUNC_DEF("send", 1, js_enet_peer_send), {
JS_CFUNC_DEF("disconnect", 0, js_enet_peer_disconnect), const char *hostname = JS_ToCString(ctx, argv[0]);
JS_CFUNC_DEF("disconnect_now", 0, js_enet_peer_disconnect_now), JS_FreeCString(ctx, hostname);
JS_CFUNC_DEF("disconnect_later", 0, js_enet_peer_disconnect_later), return JS_NULL;
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), /* ── Module export ──────────────────────────────────────────── */
JS_CFUNC_DEF("timeout", 3, js_enet_peer_timeout),
JS_CFUNC0_DEF("rtt", js_enet_peer_get_rtt), static const JSCFunctionListEntry js_enet_funcs[] = {
JS_CFUNC0_DEF("incoming_bandwidth", js_enet_peer_get_incoming_bandwidth), /* host */
JS_CFUNC0_DEF("outgoing_bandwidth", js_enet_peer_get_outgoing_bandwidth), JS_CFUNC_DEF("create_host", 1, js_enet_create_host),
JS_CFUNC0_DEF("last_send_time", js_enet_peer_get_last_send_time), JS_CFUNC_DEF("service", 2, js_enet_service),
JS_CFUNC0_DEF("last_receive_time", js_enet_peer_get_last_receive_time), JS_CFUNC_DEF("connect", 3, js_enet_connect),
JS_CFUNC0_DEF("mtu", js_enet_peer_get_mtu), JS_CFUNC_DEF("flush", 1, js_enet_flush),
JS_CFUNC0_DEF("outgoing_data_total", js_enet_peer_get_outgoing_data_total), JS_CFUNC_DEF("broadcast", 2, js_enet_broadcast),
JS_CFUNC0_DEF("incoming_data_total", js_enet_peer_get_incoming_data_total), JS_CFUNC_DEF("host_port", 1, js_enet_host_port),
JS_CFUNC0_DEF("rtt_variance", js_enet_peer_get_rtt_variance), JS_CFUNC_DEF("host_address", 1, js_enet_host_address),
JS_CFUNC0_DEF("packet_loss", js_enet_peer_get_packet_loss), /* peer */
JS_CFUNC0_DEF("state", js_enet_peer_get_state), JS_CFUNC_DEF("send", 2, js_enet_send),
JS_CFUNC0_DEF("reliable_data_in_transit", js_enet_peer_get_reliable_data_in_transit), JS_CFUNC_DEF("disconnect", 1, js_enet_disconnect),
JS_CFUNC0_DEF("port", js_enet_peer_get_port), JS_CFUNC_DEF("disconnect_now", 1, js_enet_disconnect_now),
JS_CFUNC0_DEF("address", js_enet_peer_get_address), 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) JSValue js_core_internal_enet_use(JSContext *ctx)
@@ -529,16 +461,10 @@ JSValue js_core_internal_enet_use(JSContext *ctx)
JS_FRAME(ctx); JS_FRAME(ctx);
JS_NewClassID(&enet_host_id); JS_NewClassID(&enet_host_id);
JS_NewClass(ctx, enet_host_id, &enet_host); JS_NewClass(ctx, enet_host_id, &enet_host_def);
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_NewClassID(&enet_peer_class_id); JS_NewClassID(&enet_peer_class_id);
JS_NewClass(ctx, enet_peer_class_id, &enet_peer_class); JS_NewClass(ctx, enet_peer_class_id, &enet_peer_def);
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_ROOT(export_obj, JS_NewObject(ctx)); JS_ROOT(export_obj, JS_NewObject(ctx));
JS_SetPropertyFunctionList(ctx, export_obj.val, js_enet_funcs, countof(js_enet_funcs)); 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 _no_warn = (init != null && init.no_warn) ? true : false
var SYSYM = '__SYSTEM__' var SYSYM = '__SYSTEM__'
var log = function(name, args) {
}
var _cell = {} var _cell = {}
var need_stop = false var need_stop = false
@@ -539,7 +543,7 @@ if (_init != null && _init.native_mode)
if (args != null && (_init == null || !_init.program)) { if (args != null && (_init == null || !_init.program)) {
_program = args[0] _program = args[0]
while (_j < length(args)) { while (_j < length(args)) {
push(_user_args, args[_j]) _user_args[] = args[_j]
_j = _j + 1 _j = _j + 1
} }
if (_init == null) { if (_init == null) {
@@ -908,6 +912,7 @@ $_.delay = function delay(fn, seconds) {
send_messages() send_messages()
} }
var id = actor_mod.delay(delay_turn, _seconds) 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) } return function() { actor_mod.removetimer(id) }
} }
@@ -940,7 +945,7 @@ $_.start = function start(cb, program) {
no_warn: _no_warn, no_warn: _no_warn,
} }
greeters[id] = cb greeters[id] = cb
push(message_queue, { startup }) message_queue[] = { startup }
} }
$_.receiver = function receiver(fn) { $_.receiver = function receiver(fn) {
@@ -959,20 +964,34 @@ $_.couple = function couple(actor) {
} }
$_.contact = function(callback, record) { $_.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) { $_.portal = function(fn, port) {
if (portal) { 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 disrupt
} }
if (!port) { if (!port) {
log.error("Requires a valid port.") log.error("Requires a valid port.")
disrupt disrupt
} }
log.system(`starting a portal on port ${port}`) log.connection(`portal: starting on port ${text(port)}`)
portal = enet.create_host({address: "any", port}) portal = enet.create_host({address: "any", port})
log.connection(`portal: created host=${portal}`)
portal_fn = fn portal_fn = fn
enet_check() enet_check()
} }
@@ -1362,59 +1381,74 @@ function guid(bits)
} }
enet = use_core('internal/enet') enet = use_core('internal/enet')
enet = use_core('enet')
function peer_connection(peer) { function peer_connection(peer) {
return { return {
latency: peer.rtt(), latency: enet.peer_rtt(peer),
bandwidth: { bandwidth: {
incoming: peer.incoming_bandwidth(), incoming: enet.peer_incoming_bandwidth(peer),
outgoing: peer.outgoing_bandwidth() outgoing: enet.peer_outgoing_bandwidth(peer)
}, },
activity: { activity: {
last_sent: peer.last_send_time(), last_sent: enet.peer_last_send_time(peer),
last_received: peer.last_receive_time() last_received: enet.peer_last_receive_time(peer)
}, },
mtu: peer.mtu(), mtu: enet.peer_mtu(peer),
data: { data: {
incoming_total: peer.incoming_data_total(), incoming_total: enet.peer_incoming_data_total(peer),
outgoing_total: peer.outgoing_data_total(), outgoing_total: enet.peer_outgoing_data_total(peer),
reliable_in_transit: peer.reliable_data_in_transit() reliable_in_transit: enet.peer_reliable_data_in_transit(peer)
}, },
latency_variance: peer.rtt_variance(), latency_variance: enet.peer_rtt_variance(peer),
packet_loss: peer.packet_loss(), packet_loss: enet.peer_packet_loss(peer),
state: peer.state() 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) { function handle_host(e) {
var queue = null var queue = null
var data = null var data = null
var addr = null var addr = null
var port = null var port = null
var pkey = null
log.connection(`handle_host: event type=${e.type}`)
if (e.type == "connect") { if (e.type == "connect") {
addr = e.peer.address() addr = normalize_addr(enet.peer_address(e.peer))
port = e.peer.port() port = enet.peer_port(e.peer)
log.system(`connected a new peer: ${addr}:${port}`) pkey = addr + ":" + text(port)
peers[`${addr}:${port}`] = e.peer log.connection(`handle_host: peer connected ${pkey}`)
queue = peer_queue[e.peer] peers[pkey] = e.peer
queue = peer_queue[pkey]
if (queue) { if (queue) {
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg))) log.connection(`handle_host: flushing ${text(length(queue))} queued messages to ${pkey}`)
log.system(`sent queue out of queue`) arrfor(queue, (msg, index) => enet.send(e.peer, nota.encode(msg)))
delete peer_queue[e.peer] delete peer_queue[pkey]
} else {
log.connection(`handle_host: no queued messages for ${pkey}`)
} }
} else if (e.type == "disconnect") { } else if (e.type == "disconnect") {
delete peer_queue[e.peer] addr = normalize_addr(enet.peer_address(e.peer))
arrfor(array(peers), function(id, index) { port = enet.peer_port(e.peer)
if (peers[id] == e.peer) delete peers[id] pkey = addr + ":" + text(port)
}) log.connection(`handle_host: peer disconnected ${pkey}`)
log.system('portal got disconnect from ' + e.peer.address() + ":" + e.peer.port()) delete peer_queue[pkey]
delete peers[pkey]
} else if (e.type == "receive") { } else if (e.type == "receive") {
data = nota.decode(e.data) data = nota.decode(e.data)
if (data.replycc && !data.replycc.address) { log.connection(`handle_host: received data type=${data.type}`)
data.replycc[ACTORDATA].address = e.peer.address() if (data.replycc_id && !data.replycc) {
data.replycc[ACTORDATA].port = e.peer.port() 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) if (data.data) populate_actor_addresses(data.data, e)
handle_message(data) handle_message(data)
@@ -1425,8 +1459,8 @@ function handle_host(e) {
function populate_actor_addresses(obj, e) { function populate_actor_addresses(obj, e) {
if (!is_object(obj)) return if (!is_object(obj)) return
if (obj[ACTORDATA] && !obj[ACTORDATA].address) { if (obj[ACTORDATA] && !obj[ACTORDATA].address) {
obj[ACTORDATA].address = e.peer.address() obj[ACTORDATA].address = normalize_addr(enet.peer_address(e.peer))
obj[ACTORDATA].port = e.peer.port() obj[ACTORDATA].port = enet.peer_port(e.peer)
} }
arrfor(array(obj), function(key, index) { arrfor(array(obj), function(key, index) {
if (key in obj) if (key in obj)
@@ -1436,7 +1470,7 @@ function populate_actor_addresses(obj, e) {
function actor_prep(actor, send) { function actor_prep(actor, send) {
push(message_queue, {actor,send}); message_queue[] = {actor,send};
} }
// Send a message immediately without queuing // Send a message immediately without queuing
@@ -1447,6 +1481,7 @@ function actor_send_immediate(actor, send) {
function actor_send(actor, message) { function actor_send(actor, message) {
var wota_blob = null var wota_blob = null
var peer = 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 if (actor[HEADER] && !actor[HEADER].replycc) // attempting to respond to a message but sender is not expecting; silently drop
return return
@@ -1463,12 +1498,14 @@ function actor_send(actor, message) {
// message to self // message to self
if (actor[ACTORDATA].id == _cell.id) { if (actor[ACTORDATA].id == _cell.id) {
log.connection(`actor_send: message to self, type=${message.type}`)
if (receive_fn) receive_fn(message.data) if (receive_fn) receive_fn(message.data)
return return
} }
// message to actor in same flock // message to actor in same flock
if (actor[ACTORDATA].id && actor_mod.mailbox_exist(actor[ACTORDATA].id)) { 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) wota_blob = wota.encode(message)
actor_mod.mailbox_push(actor[ACTORDATA].id, wota_blob) actor_mod.mailbox_push(actor[ACTORDATA].id, wota_blob)
return return
@@ -1480,23 +1517,27 @@ function actor_send(actor, message) {
else else
message.type = "contact" 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 (!peer) {
if (!portal) { if (!portal) {
log.system(`creating a contactor ...`) log.connection(`actor_send: no portal, creating contactor`)
portal = enet.create_host({address:"any"}) 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() enet_check()
} }
log.system(`no peer! connecting to ${actor[ACTORDATA].address}:${actor[ACTORDATA].port}`) log.connection(`actor_send: no peer for ${pkey}, connecting...`)
peer = portal.connect(actor[ACTORDATA].address, actor[ACTORDATA].port) peer = enet.connect(portal, actor[ACTORDATA].address, actor[ACTORDATA].port)
peer_queue.set(peer, [message]) log.connection(`actor_send: connect initiated, peer=${peer}, queuing message`)
peer_queue[pkey] = [message]
} else { } else {
peer.send(nota.encode(message)) log.connection(`actor_send: have peer for ${pkey}, sending directly`)
enet.send(peer, nota.encode(message))
} }
return 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() { function send_messages() {
@@ -1509,6 +1550,8 @@ function send_messages() {
var _qi = 0 var _qi = 0
var _qm = null var _qm = null
if (length(message_queue) > 0)
log.connection(`send_messages: processing ${text(length(message_queue))} queued messages`)
while (_qi < length(message_queue)) { while (_qi < length(message_queue)) {
_qm = message_queue[_qi] _qm = message_queue[_qi]
if (_qm.startup) { if (_qm.startup) {
@@ -1667,13 +1710,40 @@ function handle_sysym(msg)
function handle_message(msg) { function handle_message(msg) {
var letter = null var letter = null
var fn = 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]) { if (msg[SYSYM]) {
handle_sysym(msg[SYSYM]) handle_sysym(msg[SYSYM])
return 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 letter = msg.data // what the sender really sent
if (msg.replycc_id) { if (msg.replycc_id) {
msg.replycc = create_actor({id: msg.replycc_id}) msg.replycc = create_actor({id: msg.replycc_id})
@@ -1683,11 +1753,13 @@ function handle_message(msg) {
if (msg.return) { if (msg.return) {
fn = replies[msg.return] fn = replies[msg.return]
log.connection(`handle_message: reply callback ${msg.return} fn=${fn ? "yes" : "no"}`)
if (fn) fn(letter) if (fn) fn(letter)
delete replies[msg.return] delete replies[msg.return]
return return
} }
log.connection(`handle_message: dispatching to receive_fn=${receive_fn ? "yes" : "no"}`)
if (receive_fn) receive_fn(letter) if (receive_fn) receive_fn(letter)
} else if (msg.type == "stopped") { } else if (msg.type == "stopped") {
handle_actor_disconnect(msg.id) handle_actor_disconnect(msg.id)
@@ -1696,8 +1768,12 @@ function handle_message(msg) {
function enet_check() 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); $_.delay(enet_check, ENETSERVICE);
} }

View File

@@ -117,10 +117,10 @@ JSC_CCALL(fd_read,
JSC_SCALL(fd_slurp, JSC_SCALL(fd_slurp,
struct stat st; struct stat st;
if (stat(str, &st) != 0) 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)) 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; size_t size = st.st_size;
if (size == 0) if (size == 0)

View File

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

View File

@@ -208,11 +208,11 @@ Link.sync_all = function(shop) {
// Validate target exists // Validate target exists
var link_target = resolve_link_target(target) var link_target = resolve_link_target(target)
if (!fd.is_dir(link_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 return
} }
if (!fd.is_file(link_target + '/cell.toml')) { 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 return
} }
@@ -246,7 +246,7 @@ Link.sync_all = function(shop) {
count = count + 1 count = count + 1
} disruption { } disruption {
push(errors, canonical + ': sync failed') errors[] = canonical + ': sync failed'
} }
_sync() _sync()
}) })

14
list.ce
View File

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

10
log.ce
View File

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

View File

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

View File

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

View File

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

View File

@@ -198,7 +198,7 @@ package.find_packages = function(dir) {
var list = fd.readdir(dir) var list = fd.readdir(dir)
if (!list) return found if (!list) return found
if (fd.is_file(dir + '/cell.toml')) if (fd.is_file(dir + '/cell.toml'))
push(found, dir) found[] = dir
arrfor(list, function(item) { arrfor(list, function(item) {
if (item == '.' || item == '..' || item == '.cell' || item == '.git') return if (item == '.' || item == '..' || item == '.cell' || item == '.git') return
var full = dir + '/' + item var full = dir + '/' + item
@@ -207,7 +207,7 @@ package.find_packages = function(dir) {
if (st && st.isDirectory) { if (st && st.isDirectory) {
sub = package.find_packages(full) sub = package.find_packages(full)
arrfor(sub, function(p) { arrfor(sub, function(p) {
push(found, p) found[] = p
}) })
} }
}) })
@@ -227,14 +227,14 @@ package.list_modules = function(name) {
var stem = null var stem = null
for (i = 0; i < length(files); i++) { for (i = 0; i < length(files); i++) {
if (ends_with(files[i], '.cm')) { 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) var c_files = package.get_c_files(name, null, true)
for (i = 0; i < length(c_files); i++) { 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) 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) if (find(modules, function(m) { return m == stem }) == null)
push(modules, stem) modules[] = stem
} }
return modules return modules
} }
@@ -245,7 +245,7 @@ package.list_programs = function(name) {
var i = 0 var i = 0
for (i = 0; i < length(files); i++) { for (i = 0; i < length(files); i++) {
if (ends_with(files[i], '.ce')) { if (ends_with(files[i], '.ce')) {
push(programs, text(files[i], 0, -3)) programs[] = text(files[i], 0, -3)
} }
} }
return programs return programs
@@ -360,7 +360,7 @@ package.get_c_files = function(name, target, exclude_main) {
basename = fd.basename(selected) basename = fd.basename(selected)
if (basename == 'main.c' || starts_with(basename, 'main_')) return 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) { var parse_error = function(token, msg) {
if (error_count >= 5) return null if (error_count >= 5) return null
error_count = error_count + 1 error_count = error_count + 1
push(errors, { errors[] = {
message: msg, message: msg,
line: token.from_row + 1, line: token.from_row + 1,
column: token.from_column + 1, column: token.from_column + 1,
offset: token.at offset: token.at
}) }
} }
var _keywords = { var _keywords = {
@@ -230,8 +230,8 @@ var parse = function(tokens, src, filename, tokenizer) {
if (tv[tvi] == "\\" && tvi + 1 < tvlen) { if (tv[tvi] == "\\" && tvi + 1 < tvlen) {
esc_ch = tv[tvi + 1] esc_ch = tv[tvi + 1]
esc_val = template_escape_map[esc_ch] esc_val = template_escape_map[esc_ch]
if (esc_val != null) { push(fmt_parts, esc_val) } if (esc_val != null) { fmt_parts[] = esc_val }
else { push(fmt_parts, esc_ch) } else { fmt_parts[] = esc_ch }
tvi = tvi + 2 tvi = tvi + 2
} else if (tv[tvi] == "$" && tvi + 1 < tvlen && tv[tvi + 1] == "{") { } else if (tv[tvi] == "$" && tvi + 1 < tvlen && tv[tvi + 1] == "{") {
tvi = tvi + 2 tvi = tvi + 2
@@ -239,27 +239,27 @@ var parse = function(tokens, src, filename, tokenizer) {
expr_parts = [] expr_parts = []
while (tvi < tvlen && depth > 0) { while (tvi < tvlen && depth > 0) {
tc = tv[tvi] 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 == "}") { else if (tc == "}") {
depth = depth - 1 depth = depth - 1
if (depth > 0) { push(expr_parts, tc) } if (depth > 0) { expr_parts[] = tc }
tvi = tvi + 1 tvi = tvi + 1
} }
else if (tc == "'" || tc == "\"" || tc == "`") { else if (tc == "'" || tc == "\"" || tc == "`") {
tq = tc tq = tc
push(expr_parts, tc) expr_parts[] = tc
tvi = tvi + 1 tvi = tvi + 1
while (tvi < tvlen && tv[tvi] != tq) { while (tvi < tvlen && tv[tvi] != tq) {
if (tv[tvi] == "\\" && tvi + 1 < tvlen) { if (tv[tvi] == "\\" && tvi + 1 < tvlen) {
push(expr_parts, tv[tvi]) expr_parts[] = tv[tvi]
tvi = tvi + 1 tvi = tvi + 1
} }
push(expr_parts, tv[tvi]) expr_parts[] = tv[tvi]
tvi = tvi + 1 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 { } else {
push(expr_parts, tc) expr_parts[] = tc
tvi = tvi + 1 tvi = tvi + 1
} }
} }
@@ -274,14 +274,14 @@ var parse = function(tokens, src, filename, tokenizer) {
} else { } else {
sub_expr = sub_stmt sub_expr = sub_stmt
} }
push(tpl_list, sub_expr) tpl_list[] = sub_expr
} }
push(fmt_parts, "{") fmt_parts[] = "{"
push(fmt_parts, text(idx)) fmt_parts[] = text(idx)
push(fmt_parts, "}") fmt_parts[] = "}"
idx = idx + 1 idx = idx + 1
} else { } else {
push(fmt_parts, tv[tvi]) fmt_parts[] = tv[tvi]
tvi = tvi + 1 tvi = tvi + 1
} }
} }
@@ -332,7 +332,7 @@ var parse = function(tokens, src, filename, tokenizer) {
advance() advance()
while (tok.kind != "]" && tok.kind != "eof") { while (tok.kind != "]" && tok.kind != "eof") {
elem = parse_assign_expr() elem = parse_assign_expr()
if (elem != null) push(list, elem) if (elem != null) list[] = elem
if (tok.kind == ",") advance() if (tok.kind == ",") advance()
else break else break
} }
@@ -395,7 +395,7 @@ var parse = function(tokens, src, filename, tokenizer) {
advance() advance()
param.expression = parse_assign_expr() param.expression = parse_assign_expr()
} }
push(params, param) params[] = param
} else { } else {
parse_error(tok, "expected parameter name") parse_error(tok, "expected parameter name")
break break
@@ -436,7 +436,7 @@ var parse = function(tokens, src, filename, tokenizer) {
} else { } else {
parse_error(tok, "expected ':' after property name") parse_error(tok, "expected ':' after property name")
} }
push(list, pair) list[] = pair
if (tok.kind == ",") advance() if (tok.kind == ",") advance()
else if (tok.kind == "{") { else if (tok.kind == "{") {
if (right && right.kind == "(") { if (right && right.kind == "(") {
@@ -473,17 +473,17 @@ var parse = function(tokens, src, filename, tokenizer) {
flags_parts = [] flags_parts = []
while (rpos < _src_len && src[rpos] != "/") { while (rpos < _src_len && src[rpos] != "/") {
if (src[rpos] == "\\" && rpos + 1 < _src_len) { if (src[rpos] == "\\" && rpos + 1 < _src_len) {
push(pattern_parts, src[rpos]) pattern_parts[] = src[rpos]
push(pattern_parts, src[rpos + 1]) pattern_parts[] = src[rpos + 1]
rpos = rpos + 2 rpos = rpos + 2
} else { } else {
push(pattern_parts, src[rpos]) pattern_parts[] = src[rpos]
rpos = rpos + 1 rpos = rpos + 1
} }
} }
if (rpos < _src_len) rpos = rpos + 1 if (rpos < _src_len) rpos = rpos + 1
while (rpos < _src_len && is_letter(src[rpos])) { while (rpos < _src_len && is_letter(src[rpos])) {
push(flags_parts, src[rpos]) flags_parts[] = src[rpos]
rpos = rpos + 1 rpos = rpos + 1
} }
node.pattern = text(pattern_parts) node.pattern = text(pattern_parts)
@@ -557,7 +557,7 @@ var parse = function(tokens, src, filename, tokenizer) {
new_node.list = args_list new_node.list = args_list
while (tok.kind != ")" && tok.kind != "eof") { while (tok.kind != ")" && tok.kind != "eof") {
arg = parse_assign_expr() arg = parse_assign_expr()
if (arg != null) push(args_list, arg) if (arg != null) args_list[] = arg
if (tok.kind == ",") advance() if (tok.kind == ",") advance()
else break else break
} }
@@ -830,7 +830,7 @@ var parse = function(tokens, src, filename, tokenizer) {
before = cursor before = cursor
stmt = parse_statement() stmt = parse_statement()
if (stmt != null) { if (stmt != null) {
push(stmts, stmt) stmts[] = stmt
} else if (cursor == before) { } else if (cursor == before) {
sync_to_statement() sync_to_statement()
} }
@@ -872,14 +872,14 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value param.name = tok.value
pname = tok.value pname = tok.value
if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'") if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'")
push(prev_names, pname) prev_names[] = pname
advance() advance()
ast_node_end(param) ast_node_end(param)
if (tok.kind == "=" || tok.kind == "|") { if (tok.kind == "=" || tok.kind == "|") {
advance() advance()
param.expression = parse_assign_expr() param.expression = parse_assign_expr()
} }
push(params, param) params[] = param
} else { } else {
parse_error(tok, "expected parameter name") parse_error(tok, "expected parameter name")
break break
@@ -959,7 +959,7 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value param.name = tok.value
advance() advance()
ast_node_end(param) ast_node_end(param)
push(params, param) params[] = param
} else if (tok.kind == "(") { } else if (tok.kind == "(") {
advance() advance()
prev_names = [] prev_names = []
@@ -969,14 +969,14 @@ var parse = function(tokens, src, filename, tokenizer) {
param.name = tok.value param.name = tok.value
pname = tok.value pname = tok.value
if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'") if (find(prev_names, pname) != null) parse_error(tok, "duplicate parameter name '" + pname + "'")
push(prev_names, pname) prev_names[] = pname
advance() advance()
ast_node_end(param) ast_node_end(param)
if (tok.kind == "=" || tok.kind == "|") { if (tok.kind == "=" || tok.kind == "|") {
advance() advance()
param.expression = parse_assign_expr() param.expression = parse_assign_expr()
} }
push(params, param) params[] = param
} else { } else {
parse_error(tok, "expected parameter name") parse_error(tok, "expected parameter name")
break break
@@ -1010,7 +1010,7 @@ var parse = function(tokens, src, filename, tokenizer) {
expr = parse_assign_expr() expr = parse_assign_expr()
ret.expression = expr ret.expression = expr
ast_node_end(ret) ast_node_end(ret)
push(stmts, ret) stmts[] = ret
node.statements = stmts 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") parse_error(start, "'var' declarations must be initialized; use 'var " + var_name + " = null' if no value is needed")
} }
ast_node_end(node) ast_node_end(node)
push(decls, node) decls[] = node
decl_count = decl_count + 1 decl_count = decl_count + 1
if (tok.kind == ",") advance() if (tok.kind == ",") advance()
else break else break
@@ -1142,7 +1142,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1 _control_depth = _control_depth + 1
_expecting_body = true _expecting_body = true
body = parse_statement() body = parse_statement()
if (body != null) push(then_stmts, body) if (body != null) then_stmts[] = body
else_ifs = [] else_ifs = []
node.list = else_ifs node.list = else_ifs
if (tok.kind == "else") { if (tok.kind == "else") {
@@ -1151,7 +1151,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = saved_cd _control_depth = saved_cd
_control_type = saved_ct _control_type = saved_ct
elif = parse_statement() elif = parse_statement()
if (elif != null) push(else_ifs, elif) if (elif != null) else_ifs[] = elif
ast_node_end(node) ast_node_end(node)
return node return node
} else { } else {
@@ -1159,7 +1159,7 @@ var parse = function(tokens, src, filename, tokenizer) {
node.else = else_stmts node.else = else_stmts
_expecting_body = true _expecting_body = true
body = parse_statement() body = parse_statement()
if (body != null) push(else_stmts, body) if (body != null) else_stmts[] = body
} }
} }
_control_depth = saved_cd _control_depth = saved_cd
@@ -1185,7 +1185,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1 _control_depth = _control_depth + 1
_expecting_body = true _expecting_body = true
body = parse_statement() body = parse_statement()
if (body != null) push(stmts, body) if (body != null) stmts[] = body
_control_depth = saved_cd _control_depth = saved_cd
_control_type = saved_ct _control_type = saved_ct
ast_node_end(node) ast_node_end(node)
@@ -1203,7 +1203,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1 _control_depth = _control_depth + 1
_expecting_body = true _expecting_body = true
body = parse_statement() body = parse_statement()
if (body != null) push(stmts, body) if (body != null) stmts[] = body
_control_depth = saved_cd _control_depth = saved_cd
_control_type = saved_ct _control_type = saved_ct
if (tok.kind == "while") advance() if (tok.kind == "while") advance()
@@ -1256,7 +1256,7 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = _control_depth + 1 _control_depth = _control_depth + 1
_expecting_body = true _expecting_body = true
body = parse_statement() body = parse_statement()
if (body != null) push(stmts, body) if (body != null) stmts[] = body
_control_depth = saved_cd _control_depth = saved_cd
_control_type = saved_ct _control_type = saved_ct
ast_node_end(node) ast_node_end(node)
@@ -1402,9 +1402,9 @@ var parse = function(tokens, src, filename, tokenizer) {
stmt = parse_statement() stmt = parse_statement()
if (stmt != null) { if (stmt != null) {
if (stmt.kind == "function") { if (stmt.kind == "function") {
push(functions, stmt) functions[] = stmt
} else { } else {
push(statements, stmt) statements[] = stmt
} }
} else if (cursor == before) { } else if (cursor == before) {
sync_to_statement() sync_to_statement()
@@ -1426,7 +1426,7 @@ var parse = function(tokens, src, filename, tokenizer) {
var err = {message: msg} var err = {message: msg}
if (node.from_row != null) err.line = node.from_row + 1 if (node.from_row != null) err.line = node.from_row + 1
if (node.from_column != null) err.column = node.from_column + 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) { 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.reached == false) entry.reached = false
if (make_opts.decl_line != null) entry.decl_line = make_opts.decl_line 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) { var sem_lookup_var = function(scope, name) {
@@ -1503,7 +1503,7 @@ var parse = function(tokens, src, filename, tokenizer) {
} }
var sem_add_intrinsic = function(name) { var sem_add_intrinsic = function(name) {
if (find(intrinsics, name) == null) push(intrinsics, name) if (find(intrinsics, name) == null) intrinsics[] = name
} }
var functino_names = { var functino_names = {
@@ -1828,7 +1828,7 @@ var parse = function(tokens, src, filename, tokenizer) {
} }
} }
sr = sem_build_scope_record(fn_scope) sr = sem_build_scope_record(fn_scope)
push(scopes_array, sr.rec) scopes_array[] = sr.rec
expr.nr_slots = sr.nr_slots expr.nr_slots = sr.nr_slots
expr.nr_close_slots = sr.nr_close expr.nr_close_slots = sr.nr_close
return null return null
@@ -1858,9 +1858,9 @@ var parse = function(tokens, src, filename, tokenizer) {
r.v.nr_uses = r.v.nr_uses + 1 r.v.nr_uses = r.v.nr_uses + 1
if (r.level > 0) r.v.closure = 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) { 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, col: expr.from_column != null ? expr.from_column + 1 : null,
decl_line: r.v.decl_line}) decl_line: r.v.decl_line}
} }
} else { } else {
expr.level = -1 expr.level = -1
@@ -2110,7 +2110,7 @@ var parse = function(tokens, src, filename, tokenizer) {
} }
} }
sr = sem_build_scope_record(fn_scope) sr = sem_build_scope_record(fn_scope)
push(scopes_array, sr.rec) scopes_array[] = sr.rec
stmt.nr_slots = sr.nr_slots stmt.nr_slots = sr.nr_slots
stmt.nr_close_slots = sr.nr_close stmt.nr_close_slots = sr.nr_close
return null return null
@@ -2153,7 +2153,7 @@ var parse = function(tokens, src, filename, tokenizer) {
new_scopes = [sr.rec] new_scopes = [sr.rec]
i = 0 i = 0
while (i < length(scopes_array)) { while (i < length(scopes_array)) {
push(new_scopes, scopes_array[i]) new_scopes[] = scopes_array[i]
i = i + 1 i = i + 1
} }
scopes_array = new_scopes scopes_array = new_scopes
@@ -2183,7 +2183,7 @@ var parse = function(tokens, src, filename, tokenizer) {
if (ast.errors != null) { if (ast.errors != null) {
_mi = 0 _mi = 0
while (_mi < length(errors)) { while (_mi < length(errors)) {
push(ast.errors, errors[_mi]) ast.errors[] = errors[_mi]
_mi = _mi + 1 _mi = _mi + 1
} }
} else { } else {

View File

@@ -948,7 +948,7 @@ var qbe_emit = function(ir, qbe, export_name) {
// ============================================================ // ============================================================
var emit = function(s) { var emit = function(s) {
push(out, s) out[] = s
} }
var fresh = function() { var fresh = function() {
@@ -982,9 +982,9 @@ var qbe_emit = function(ir, qbe, export_name) {
escaped = replace(escaped, "\r", "\\r") escaped = replace(escaped, "\r", "\\r")
escaped = replace(escaped, "\t", "\\t") escaped = replace(escaped, "\t", "\\t")
var line = "data " + label + ' = ' + '{ b "' + escaped + '", b 0 }' var line = "data " + label + ' = ' + '{ b "' + escaped + '", b 0 }'
push(data_out, line) data_out[] = line
var entry = { label: label, idx: length(str_entries) } var entry = { label: label, idx: length(str_entries) }
push(str_entries, entry) str_entries[] = entry
str_table[val] = entry str_table[val] = entry
return 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 // 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" 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) + " }") 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 $cell_lit_count = { w " + text(length(str_entries)) + " }"
if (length(str_entries) > 0) { if (length(str_entries) > 0) {
lit_data = [] lit_data = []
si = 0 si = 0
while (si < length(str_entries)) { while (si < length(str_entries)) {
push(lit_data, `l ${str_entries[si].label}`) lit_data[] = `l ${str_entries[si].label}`
si = si + 1 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 { return {

View File

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

View File

@@ -78,7 +78,7 @@ var run = function() {
arrfor(all_packages, function(p) { arrfor(all_packages, function(p) {
if (p == 'core') return if (p == 'core') return
if (!needed[p] && find(packages_to_remove, p) == null) { 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 // Format output
status_parts = [] status_parts = []
if (is_linked) push(status_parts, "linked") if (is_linked) status_parts[] = "linked"
if (is_local) push(status_parts, "local") if (is_local) status_parts[] = "local"
if (!is_in_lock) push(status_parts, "not in lock") if (!is_in_lock) status_parts[] = "not in lock"
if (!is_fetched) push(status_parts, "not fetched") if (!is_fetched) status_parts[] = "not fetched"
if (has_c_files) push(status_parts, "has C modules") if (has_c_files) status_parts[] = "has C modules"
commit_str = "" commit_str = ""
if (lock_entry && lock_entry.commit) { if (lock_entry && lock_entry.commit) {

View File

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

View File

@@ -179,7 +179,7 @@ var run = function() {
first_def[slot_num] = pc first_def[slot_num] = pc
first_def_op[slot_num] = op 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 di = di + 1
} }
@@ -191,7 +191,7 @@ var run = function() {
slot_num = text(operand_val) slot_num = text(operand_val)
if (!uses[slot_num]) uses[slot_num] = 0 if (!uses[slot_num]) uses[slot_num] = 0
uses[slot_num] = uses[slot_num] + 1 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 ui = ui + 1
} }
@@ -219,7 +219,7 @@ var run = function() {
parts = [] parts = []
j = 1 j = 1
while (j < n - 2) { while (j < n - 2) {
push(parts, fmt_val(evt.instr[j])) parts[] = fmt_val(evt.instr[j])
j = j + 1 j = j + 1
} }
operands = text(parts, ", ") 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_internal_os_use(JSContext *js);
JSValue js_core_json_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) void script_startup(JSContext *js)
{ {
if (!g_runtime) { if (!g_runtime) {
@@ -414,6 +434,8 @@ void script_startup(JSContext *js)
} }
tmp = shop_path ? JS_NewString(js, shop_path) : JS_NULL; tmp = shop_path ? JS_NewString(js, shop_path) : JS_NULL;
JS_SetPropertyStr(js, env_ref.val, "shop_path", tmp); 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 // Stone the environment
JSValue hidden_env = JS_Stone(js, env_ref.val); 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_SetPropertyStr(ctx, env_ref.val, "args", args_ref.val);
JS_DeleteGCRef(ctx, &args_ref); 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); JSValue hidden_env = JS_Stone(ctx, env_ref.val);
g_crash_ctx = ctx; g_crash_ctx = ctx;

View File

@@ -876,7 +876,7 @@ typedef struct {
#define ACTOR_SLOW 5 #define ACTOR_SLOW 5
#define ACTOR_REFRESHED 6 #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_TIMER_NS (60000ULL * 1000000)
#define ACTOR_SLOW_STRIKES_MAX 3 #define ACTOR_SLOW_STRIKES_MAX 3
#define ACTOR_MEMORY_LIMIT (1024ULL * 1024 * 1024) #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)) if (ctx->trace_hook && (ctx->trace_type & JS_HOOK_GC))
ctx->trace_hook(ctx, JS_HOOK_GC, NULL, ctx->trace_data); 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) { if (ctx->heap_memory_limit > 0 && ctx->current_block_size > ctx->heap_memory_limit) {
#ifdef ACTOR_TRACE JS_Log(ctx, "memory", "%s: heap %zuKB exceeds limit %zuMB, killing",
fprintf(stderr, "[ACTOR_TRACE] heap %zu > limit %zu, OOM\n", ctx->name ? ctx->name : ctx->id,
ctx->current_block_size, ctx->heap_memory_limit); ctx->current_block_size / 1024,
#endif ctx->heap_memory_limit / (1024 * 1024));
return -1; return -1;
} }
@@ -3283,19 +3284,18 @@ JS_RaiseDisrupt (JSContext *ctx, const char *fmt, ...) {
return JS_EXCEPTION; 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) { JSValue JS_RaiseOOM (JSContext *ctx) {
size_t used = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base); size_t used = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base);
size_t block = ctx->current_block_size; size_t block = ctx->current_block_size;
size_t limit = ctx->heap_memory_limit; size_t limit = ctx->heap_memory_limit;
const char *name = ctx->name ? ctx->name : ctx->id;
const char *label = ctx->actor_label; const char *label = ctx->actor_label;
if (limit > 0) { fprintf(stderr, "[memory] %s: out of memory — heap %zuKB / %zuKB block",
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, limit %zuMB", name ? name : "?", used / 1024, block / 1024);
used / 1024, block / 1024, limit / (1024 * 1024)); if (limit > 0)
} else { fprintf(stderr, ", limit %zuMB", limit / (1024 * 1024));
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, no limit",
used / 1024, block / 1024);
}
if (label) if (label)
fprintf(stderr, " [%s]", label); fprintf(stderr, " [%s]", label);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@@ -12009,7 +12009,7 @@ void JS_CrashPrintStack(JSContext *ctx) {
if (!ctx) return; if (!ctx) return;
if (JS_IsNull(ctx->reg_current_frame)) 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); write(STDERR_FILENO, hdr, sizeof(hdr) - 1);
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(ctx->reg_current_frame); 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) */ /* Only fire if turn_gen still matches (stale timers are ignored) */
uint32_t cur = atomic_load_explicit(&t.actor->turn_gen, memory_order_relaxed); uint32_t cur = atomic_load_explicit(&t.actor->turn_gen, memory_order_relaxed);
if (cur == t.turn_gen) { 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) { 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); JS_SetPauseFlag(t.actor, 1);
} else { } 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; t.actor->disrupt = 1;
JS_SetPauseFlag(t.actor, 2); JS_SetPauseFlag(t.actor, 2);
} }
@@ -577,17 +583,11 @@ int actor_exists(const char *id)
void set_actor_state(JSContext *actor) void set_actor_state(JSContext *actor)
{ {
if (actor->disrupt) { 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); actor_free(actor);
return; return;
} }
pthread_mutex_lock(actor->msg_mutex); 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) { switch(actor->state) {
case ACTOR_RUNNING: case ACTOR_RUNNING:
case ACTOR_READY: case ACTOR_READY:
@@ -601,9 +601,6 @@ void set_actor_state(JSContext *actor)
actor->is_quiescent = 0; actor->is_quiescent = 0;
atomic_fetch_sub(&engine.quiescent_count, 1); 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->state = ACTOR_READY;
actor->ar = 0; actor->ar = 0;
enqueue_actor_priority(actor); enqueue_actor_priority(actor);
@@ -846,6 +843,8 @@ void actor_turn(JSContext *actor)
if (JS_IsSuspended(result)) { if (JS_IsSuspended(result)) {
/* Still suspended after kill timer — shouldn't happen, kill it */ /* 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; actor->disrupt = 1;
goto ENDTURN; goto ENDTURN;
} }
@@ -854,16 +853,12 @@ void actor_turn(JSContext *actor)
actor->disrupt = 1; actor->disrupt = 1;
} }
actor->slow_strikes++; actor->slow_strikes++;
#ifdef ACTOR_TRACE JS_Log(actor, "slow", "%s: slow strike %d/%d",
fprintf(stderr, "[ACTOR_TRACE] %s: slow strike %d/%d\n", actor->name ? actor->name : actor->id,
actor->name ? actor->name : actor->id, actor->slow_strikes, ACTOR_SLOW_STRIKES_MAX);
actor->slow_strikes, ACTOR_SLOW_STRIKES_MAX);
#endif
if (actor->slow_strikes >= ACTOR_SLOW_STRIKES_MAX) { if (actor->slow_strikes >= ACTOR_SLOW_STRIKES_MAX) {
#ifdef ACTOR_TRACE JS_Log(actor, "slow", "%s: killed after %d consecutive slow turns",
fprintf(stderr, "[ACTOR_TRACE] %s: %d slow strikes, killing\n", actor->name ? actor->name : actor->id, actor->slow_strikes);
actor->name ? actor->name : actor->id, actor->slow_strikes);
#endif
actor->disrupt = 1; actor->disrupt = 1;
} }
goto ENDTURN; goto ENDTURN;
@@ -876,10 +871,6 @@ void actor_turn(JSContext *actor)
pthread_mutex_unlock(actor->msg_mutex); pthread_mutex_unlock(actor->msg_mutex);
goto ENDTURN; 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]; letter l = actor->letters[0];
arrdel(actor->letters, 0); arrdel(actor->letters, 0);
pthread_mutex_unlock(actor->msg_mutex); pthread_mutex_unlock(actor->msg_mutex);
@@ -937,29 +928,22 @@ ENDTURN:
actor->actor_trace_hook(actor, CELL_HOOK_EXIT); actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
if (actor->disrupt) { 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); pthread_mutex_unlock(actor->mutex);
actor_free(actor); actor_free(actor);
return; 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); set_actor_state(actor);
pthread_mutex_unlock(actor->mutex); pthread_mutex_unlock(actor->mutex);
return; return;
ENDTURN_SLOW: ENDTURN_SLOW:
g_crash_ctx = NULL; g_crash_ctx = NULL;
#ifdef ACTOR_TRACE /* VM suspended mid-turn — can't call JS_Log, use fprintf.
fprintf(stderr, "[ACTOR_TRACE] %s: suspended mid-turn -> SLOW\n", Print stack trace while frames are still intact. */
actor->name ? actor->name : actor->id); fprintf(stderr, "[slow] %s: suspended mid-turn, entering slow queue (strike %d/%d)\n",
#endif actor->name ? actor->name : actor->id,
actor->slow_strikes + 1, ACTOR_SLOW_STRIKES_MAX);
if (actor->actor_trace_hook) if (actor->actor_trace_hook)
actor->actor_trace_hook(actor, CELL_HOOK_EXIT); actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
enqueue_actor_priority(actor); enqueue_actor_priority(actor);

View File

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

40
test.ce
View File

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

View File

@@ -2918,7 +2918,7 @@ return {
test_arrfor_with_index: function() { test_arrfor_with_index: function() {
var arr = ["a", "b", "c"] var arr = ["a", "b", "c"]
var indices = [] 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" if (indices[0] != 0 || indices[2] != 2) return "arrfor with index failed"
}, },
@@ -2931,7 +2931,7 @@ return {
test_arrfor_mutation: function() { test_arrfor_mutation: function() {
var arr = [1, 2, 3] var arr = [1, 2, 3]
var results = [] 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" 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 i = 0
var t = null var t = null
var name = null var name = null
for (i = 0; i < 500; i++) { push(testarr, 1) } for (i = 0; i < 500; i++) { testarr[] = 1 }
var testCases = [ var testCases = [
{ name: 'zero', input: 0 }, { name: 'zero', input: 0 },

View File

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

16
toml.cm
View File

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

View File

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

View File

@@ -67,11 +67,11 @@ var warnings = []
var checked = 0 var checked = 0
function add_error(msg) { function add_error(msg) {
push(errors, msg) errors[] = msg
} }
function add_warning(msg) { function add_warning(msg) {
push(warnings, msg) warnings[] = msg
} }
// Verify a single package // Verify a single package
@@ -211,12 +211,12 @@ if (scope == 'shop') {
if (deep) { if (deep) {
// Gather all dependencies // Gather all dependencies
all_deps = pkg.gather_dependencies(locator) all_deps = pkg.gather_dependencies(locator)
push(packages_to_verify, locator) packages_to_verify[] = locator
arrfor(all_deps, function(dep) { arrfor(all_deps, function(dep) {
push(packages_to_verify, dep) packages_to_verify[] = dep
}) })
} else { } 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) { if (pos < length(instr) - 2) {
val = instr[pos] val = instr[pos]
if (is_number(val) && (val < 0 || val >= nr_slots)) { 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 j = j + 1
@@ -217,7 +217,7 @@ var check_jump_targets = function(func) {
if (label_pos != null) { if (label_pos != null) {
target = instr[label_pos + 1] target = instr[label_pos + 1]
if (is_text(target) && labels[target] != true) { 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]) s2 = text(instr[2])
t2 = slot_types[s2] t2 = slot_types[s2]
if (t2 != null && t2 != T_INT && t2 != "unknown") { 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) { if (length(instr) >= 6) {
s3 = text(instr[3]) s3 = text(instr[3])
t3 = slot_types[s3] t3 = slot_types[s3]
if (t3 != null && t3 != T_INT && t3 != "unknown") { 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) { } else if (float_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2]) s2 = text(instr[2])
t2 = slot_types[s2] t2 = slot_types[s2]
if (t2 != null && t2 != T_FLOAT && t2 != "unknown") { 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) { if (length(instr) >= 6) {
s3 = text(instr[3]) s3 = text(instr[3])
t3 = slot_types[s3] t3 = slot_types[s3]
if (t3 != null && t3 != T_FLOAT && t3 != "unknown") { 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) { } else if (text_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2]) s2 = text(instr[2])
t2 = slot_types[s2] t2 = slot_types[s2]
if (t2 != null && t2 != T_TEXT && t2 != "unknown") { 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) { if (length(instr) >= 6) {
s3 = text(instr[3]) s3 = text(instr[3])
t3 = slot_types[s3] t3 = slot_types[s3]
if (t3 != null && t3 != T_TEXT && t3 != "unknown") { 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) { } else if (bool_ops[op] == true && length(instr) >= 5) {
s2 = text(instr[2]) s2 = text(instr[2])
t2 = slot_types[s2] t2 = slot_types[s2]
if (t2 != null && t2 != T_BOOL && t2 != "unknown") { 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) { if (label_pos != null) {
target = instr[label_pos + 1] target = instr[label_pos + 1]
if (is_text(target) && nops[target] == true) { 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) check_errors = check_slot_bounds(func)
i = 0 i = 0
while (i < length(check_errors)) { 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 i = i + 1
} }
check_errors = check_jump_targets(func) check_errors = check_jump_targets(func)
i = 0 i = 0
while (i < length(check_errors)) { 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 i = i + 1
} }
check_errors = check_type_consistency(func) check_errors = check_type_consistency(func)
i = 0 i = 0
while (i < length(check_errors)) { 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 i = i + 1
} }
check_errors = check_nop_consistency(func) check_errors = check_nop_consistency(func)
i = 0 i = 0
while (i < length(check_errors)) { 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 i = i + 1
} }

View File

@@ -93,11 +93,11 @@ var run = function() {
if (!creates[text(parent_idx)]) { if (!creates[text(parent_idx)]) {
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)]) { if (!created_by[text(child_idx)]) {
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 j = j + 1
} }