Merge branch 'core_integration' into fix_imports

This commit is contained in:
2026-02-17 12:34:47 -06:00
33 changed files with 947 additions and 996 deletions

View File

@@ -1,14 +1,16 @@
function mainThread() { function mainThread() {
var maxDepth = max(6, Number(arg[0] || 16)); var maxDepth = max(6, Number(arg[0] || 16));
var stretchDepth = maxDepth + 1; var stretchDepth = maxDepth + 1;
var check = itemCheck(bottomUpTree(stretchDepth)); var check = itemCheck(bottomUpTree(stretchDepth));
var longLivedTree = null
var depth = null
var iterations = null
log.console(`stretch tree of depth ${stretchDepth}\t check: ${check}`); log.console(`stretch tree of depth ${stretchDepth}\t check: ${check}`);
var longLivedTree = bottomUpTree(maxDepth); longLivedTree = bottomUpTree(maxDepth);
for (var depth = 4; depth <= maxDepth; depth += 2) { for (depth = 4; depth <= maxDepth; depth += 2) {
var iterations = 1 << maxDepth - depth + 4; iterations = 1 << maxDepth - depth + 4;
work(iterations, depth); work(iterations, depth);
} }
@@ -17,7 +19,8 @@ function mainThread() {
function work(iterations, depth) { function work(iterations, depth) {
var check = 0; var check = 0;
for (var i = 0; i < iterations; i++) var i = 0
for (i = 0; i < iterations; i++)
check += itemCheck(bottomUpTree(depth)); check += itemCheck(bottomUpTree(depth));
log.console(`${iterations}\t trees of depth ${depth}\t check: ${check}`); log.console(`${iterations}\t trees of depth ${depth}\t check: ${check}`);
} }

View File

@@ -1,6 +1,9 @@
var blob = use('blob') var blob = use('blob')
var math = use('math/radians') var math = use('math/radians')
var i = 0
var j = 0
function eratosthenes (n) { function eratosthenes (n) {
var sieve = blob(n, true) var sieve = blob(n, true)
var sqrtN = whole(math.sqrt(n)); var sqrtN = whole(math.sqrt(n));
@@ -9,7 +12,7 @@ function eratosthenes (n) {
if (sieve.read_logical(i)) if (sieve.read_logical(i))
for (j = i * i; j <= n; j += i) for (j = i * i; j <= n; j += i)
sieve.write_bit(j, false); sieve.write_bit(j, false);
return sieve; return sieve;
} }
@@ -17,9 +20,9 @@ var sieve = eratosthenes(10000000);
stone(sieve) stone(sieve)
var c = 0 var c = 0
for (var i = 0; i < length(sieve); i++) for (i = 0; i < length(sieve); i++)
if (sieve.read_logical(i)) c++ if (sieve.read_logical(i)) c++
log.console(c) log.console(c)
$stop() $stop()

View File

@@ -1,58 +1,65 @@
function fannkuch(n) { function fannkuch(n) {
var perm1 = [n] var perm1 = [n]
for (var i = 0; i < n; i++) perm1[i] = i var i = 0
var k = null
var r = null
var t = null
var p0 = null
var j = null
var more = null
for (i = 0; i < n; i++) perm1[i] = i
var perm = [n] var perm = [n]
var count = [n] var count = [n]
var f = 0, flips = 0, nperm = 0, checksum = 0 var f = 0
var i, k, r var flips = 0
var nperm = 0
var checksum = 0
r = n r = n
while (r > 0) { while (r > 0) {
i = 0 i = 0
while (r != 1) { count[r-1] = r; r -= 1 } while (r != 1) { count[r-1] = r; r -= 1 }
while (i < n) { perm[i] = perm1[i]; i += 1 } while (i < n) { perm[i] = perm1[i]; i += 1 }
// Count flips and update max and checksum
f = 0 f = 0
k = perm[0] k = perm[0]
while (k != 0) { while (k != 0) {
i = 0 i = 0
while (2*i < k) { while (2*i < k) {
var t = perm[i]; perm[i] = perm[k-i]; perm[k-i] = t t = perm[i]; perm[i] = perm[k-i]; perm[k-i] = t
i += 1 i += 1
} }
k = perm[0] k = perm[0]
f += 1 f += 1
} }
if (f > flips) flips = f if (f > flips) flips = f
if ((nperm & 0x1) == 0) checksum += f; else checksum -= f if ((nperm & 0x1) == 0) checksum += f; else checksum -= f
// Use incremental change to generate another permutation more = true
var more = true while (more) {
while (more) {
if (r == n) { if (r == n) {
log.console( checksum ) log.console( checksum )
return flips return flips
} }
var p0 = perm1[0] p0 = perm1[0]
i = 0 i = 0
while (i < r) { while (i < r) {
var j = i + 1 j = i + 1
perm1[i] = perm1[j] perm1[i] = perm1[j]
i = j i = j
} }
perm1[r] = p0 perm1[r] = p0
count[r] -= 1 count[r] -= 1
if (count[r] > 0) more = false; else r += 1 if (count[r] > 0) more = false; else r += 1
} }
nperm += 1 nperm += 1
} }
return flips; return flips;
} }
var n = arg[0] || 10 var n = arg[0] || 10
log.console(`Pfannkuchen(${n}) = ${fannkuch(n)}`) log.console(`Pfannkuchen(${n}) = ${fannkuch(n)}`)
$stop() $stop()

View File

@@ -1,22 +1,12 @@
var time = use('time') var time = use('time')
var math = use('math/radians') var math = use('math/radians')
////////////////////////////////////////////////////////////////////////////////
// JavaScript Performance Benchmark Suite
// Tests core JS operations: property access, function calls, arithmetic, etc.
////////////////////////////////////////////////////////////////////////////////
// Test configurations
def iterations = { def iterations = {
simple: 10000000, simple: 10000000,
medium: 1000000, medium: 1000000,
complex: 100000 complex: 100000
}; };
////////////////////////////////////////////////////////////////////////////////
// Utility: measureTime(fn) => how long fn() takes in seconds
////////////////////////////////////////////////////////////////////////////////
function measureTime(fn) { function measureTime(fn) {
var start = time.number(); var start = time.number();
fn(); fn();
@@ -24,26 +14,24 @@ function measureTime(fn) {
return (end - start); return (end - start);
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Property Access
////////////////////////////////////////////////////////////////////////////////
function benchPropertyAccess() { function benchPropertyAccess() {
var obj = { var obj = {
a: 1, b: 2, c: 3, d: 4, e: 5, a: 1, b: 2, c: 3, d: 4, e: 5,
nested: { x: 10, y: 20, z: 30 } nested: { x: 10, y: 20, z: 30 }
}; };
var readTime = measureTime(function() { var readTime = measureTime(function() {
var sum = 0; var sum = 0;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
sum += obj.a + obj.b + obj.c + obj.d + obj.e; sum += obj.a + obj.b + obj.c + obj.d + obj.e;
sum += obj.nested.x + obj.nested.y + obj.nested.z; sum += obj.nested.x + obj.nested.y + obj.nested.z;
} }
}); });
var writeTime = measureTime(function() { var writeTime = measureTime(function() {
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
obj.a = i; obj.a = i;
obj.b = i + 1; obj.b = i + 1;
obj.c = i + 2; obj.c = i + 2;
@@ -51,49 +39,48 @@ function benchPropertyAccess() {
obj.nested.y = i * 3; obj.nested.y = i * 3;
} }
}); });
return { readTime: readTime, writeTime: writeTime }; return { readTime: readTime, writeTime: writeTime };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Function Calls
////////////////////////////////////////////////////////////////////////////////
function benchFunctionCalls() { function benchFunctionCalls() {
function add(a, b) { return a + b; } function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; } function multiply(a, b) { return a * b; }
function complexCalc(a, b, c) { return (a + b) * c / 2; } function complexCalc(a, b, c) { return (a + b) * c / 2; }
var obj = { var obj = {
method: function(x) { return x * 2; }, method: function(x) { return x * 2; },
nested: { nested: {
deepMethod: function(x, y) { return x + y; } deepMethod: function(x, y) { return x + y; }
} }
}; };
var simpleCallTime = measureTime(function() { var simpleCallTime = measureTime(function() {
var result = 0; var result = 0;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
result = add(i, 1); result = add(i, 1);
result = multiply(result, 2); result = multiply(result, 2);
} }
}); });
var methodCallTime = measureTime(function() { var methodCallTime = measureTime(function() {
var result = 0; var result = 0;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
result = obj.method(i); result = obj.method(i);
result = obj.nested.deepMethod(result, i); result = obj.nested.deepMethod(result, i);
} }
}); });
var complexCallTime = measureTime(function() { var complexCallTime = measureTime(function() {
var result = 0; var result = 0;
for (var i = 0; i < iterations.medium; i++) { var i = 0
for (i = 0; i < iterations.medium; i++) {
result = complexCalc(i, i + 1, i + 2); result = complexCalc(i, i + 1, i + 2);
} }
}); });
return { return {
simpleCallTime: simpleCallTime, simpleCallTime: simpleCallTime,
methodCallTime: methodCallTime, methodCallTime: methodCallTime,
@@ -101,37 +88,39 @@ function benchFunctionCalls() {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Array Operations
////////////////////////////////////////////////////////////////////////////////
function benchArrayOps() { function benchArrayOps() {
var i = 0
var pushTime = measureTime(function() { var pushTime = measureTime(function() {
var arr = []; var arr = [];
for (var i = 0; i < iterations.medium; i++) { var j = 0
push(arr, i); for (j = 0; j < iterations.medium; j++) {
push(arr, j);
} }
}); });
var arr = []; var arr = [];
for (var i = 0; i < 10000; i++) push(arr, i); for (i = 0; i < 10000; i++) push(arr, i);
var accessTime = measureTime(function() { var accessTime = measureTime(function() {
var sum = 0; var sum = 0;
for (var i = 0; i < iterations.medium; i++) { var j = 0
sum += arr[i % 10000]; for (j = 0; j < iterations.medium; j++) {
sum += arr[j % 10000];
} }
}); });
var iterateTime = measureTime(function() { var iterateTime = measureTime(function() {
var sum = 0; var sum = 0;
for (var j = 0; j < 1000; j++) { var j = 0
for (var i = 0; i < length(arr); i++) { var k = 0
sum += arr[i]; for (j = 0; j < 1000; j++) {
for (k = 0; k < length(arr); k++) {
sum += arr[k];
} }
} }
}); });
return { return {
pushTime: pushTime, pushTime: pushTime,
accessTime: accessTime, accessTime: accessTime,
@@ -139,27 +128,27 @@ function benchArrayOps() {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Object Creation
////////////////////////////////////////////////////////////////////////////////
function benchObjectCreation() { function benchObjectCreation() {
var literalTime = measureTime(function() { var literalTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) { var i = 0
var obj = { x: i, y: i * 2, z: i * 3 }; var obj = null
for (i = 0; i < iterations.medium; i++) {
obj = { x: i, y: i * 2, z: i * 3 };
} }
}); });
function Point(x, y) { function Point(x, y) {
return {x,y} return {x,y}
} }
var defructorTime = measureTime(function() { var defructorTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) { var i = 0
var p = Point(i, i * 2); var p = null
for (i = 0; i < iterations.medium; i++) {
p = Point(i, i * 2);
} }
}); });
var protoObj = { var protoObj = {
x: 0, x: 0,
y: 0, y: 0,
@@ -168,15 +157,17 @@ function benchObjectCreation() {
this.y += dy; this.y += dy;
} }
}; };
var prototypeTime = measureTime(function() { var prototypeTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) { var i = 0
var obj = meme(protoObj); var obj = null
for (i = 0; i < iterations.medium; i++) {
obj = meme(protoObj);
obj.x = i; obj.x = i;
obj.y = i * 2; obj.y = i * 2;
} }
}); });
return { return {
literalTime: literalTime, literalTime: literalTime,
defructorTime: defructorTime, defructorTime: defructorTime,
@@ -184,36 +175,39 @@ function benchObjectCreation() {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: String Operations
////////////////////////////////////////////////////////////////////////////////
function benchStringOps() { function benchStringOps() {
var i = 0
var strings = [];
var concatTime = measureTime(function() { var concatTime = measureTime(function() {
var str = ""; var str = "";
for (var i = 0; i < iterations.complex; i++) { var j = 0
str = "test" + i + "value"; for (j = 0; j < iterations.complex; j++) {
str = "test" + j + "value";
} }
}); });
var strings = []; for (i = 0; i < 1000; i++) {
for (var i = 0; i < 1000; i++) {
push(strings, "string" + i); push(strings, "string" + i);
} }
var joinTime = measureTime(function() { var joinTime = measureTime(function() {
for (var i = 0; i < iterations.complex; i++) { var j = 0
var result = text(strings, ","); var result = null
for (j = 0; j < iterations.complex; j++) {
result = text(strings, ",");
} }
}); });
var splitTime = measureTime(function() { var splitTime = measureTime(function() {
var str = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p"; var str = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p";
for (var i = 0; i < iterations.medium; i++) { var j = 0
var parts = array(str, ","); var parts = null
for (j = 0; j < iterations.medium; j++) {
parts = array(str, ",");
} }
}); });
return { return {
concatTime: concatTime, concatTime: concatTime,
joinTime: joinTime, joinTime: joinTime,
@@ -221,35 +215,34 @@ function benchStringOps() {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Arithmetic Operations
////////////////////////////////////////////////////////////////////////////////
function benchArithmetic() { function benchArithmetic() {
var intMathTime = measureTime(function() { var intMathTime = measureTime(function() {
var result = 1; var result = 1;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
result = ((result + i) * 2 - 1) / 3; result = ((result + i) * 2 - 1) / 3;
result = result % 1000 + 1; result = result % 1000 + 1;
} }
}); });
var floatMathTime = measureTime(function() { var floatMathTime = measureTime(function() {
var result = 1.5; var result = 1.5;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
result = math.sine(result) + math.cosine(i * 0.01); result = math.sine(result) + math.cosine(i * 0.01);
result = math.sqrt(abs(result)) + 0.1; result = math.sqrt(abs(result)) + 0.1;
} }
}); });
var bitwiseTime = measureTime(function() { var bitwiseTime = measureTime(function() {
var result = 0; var result = 0;
for (var i = 0; i < iterations.simple; i++) { var i = 0
for (i = 0; i < iterations.simple; i++) {
result = (result ^ i) & 0xFFFF; result = (result ^ i) & 0xFFFF;
result = (result << 1) | (result >> 15); result = (result << 1) | (result >> 15);
} }
}); });
return { return {
intMathTime: intMathTime, intMathTime: intMathTime,
floatMathTime: floatMathTime, floatMathTime: floatMathTime,
@@ -257,134 +250,123 @@ function benchArithmetic() {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Closure Operations
////////////////////////////////////////////////////////////////////////////////
function benchClosures() { function benchClosures() {
var i = 0
function makeAdder(x) { function makeAdder(x) {
return function(y) { return x + y; }; return function(y) { return x + y; };
} }
var closureCreateTime = measureTime(function() { var closureCreateTime = measureTime(function() {
var funcs = []; var funcs = [];
for (var i = 0; i < iterations.medium; i++) { var j = 0
push(funcs, makeAdder(i)); for (j = 0; j < iterations.medium; j++) {
push(funcs, makeAdder(j));
} }
}); });
var adders = []; var adders = [];
for (var i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
push(adders, makeAdder(i)); push(adders, makeAdder(i));
} }
var closureCallTime = measureTime(function() { var closureCallTime = measureTime(function() {
var sum = 0; var sum = 0;
for (var i = 0; i < iterations.medium; i++) { var j = 0
sum += adders[i % 1000](i); for (j = 0; j < iterations.medium; j++) {
sum += adders[j % 1000](j);
} }
}); });
return { return {
closureCreateTime: closureCreateTime, closureCreateTime: closureCreateTime,
closureCallTime: closureCallTime closureCallTime: closureCallTime
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Main benchmark runner
////////////////////////////////////////////////////////////////////////////////
log.console("JavaScript Performance Benchmark"); log.console("JavaScript Performance Benchmark");
log.console("======================\n"); log.console("======================\n");
// Property Access
log.console("BENCHMARK: Property Access"); log.console("BENCHMARK: Property Access");
var propResults = benchPropertyAccess(); var propResults = benchPropertyAccess();
log.console(" Read time: " + propResults.readTime.toFixed(3) + "s => " + log.console(" Read time: " + propResults.readTime.toFixed(3) + "s => " +
(iterations.simple / propResults.readTime).toFixed(1) + " reads/sec [" + (iterations.simple / propResults.readTime).toFixed(1) + " reads/sec [" +
(propResults.readTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (propResults.readTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Write time: " + propResults.writeTime.toFixed(3) + "s => " + log.console(" Write time: " + propResults.writeTime.toFixed(3) + "s => " +
(iterations.simple / propResults.writeTime).toFixed(1) + " writes/sec [" + (iterations.simple / propResults.writeTime).toFixed(1) + " writes/sec [" +
(propResults.writeTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (propResults.writeTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");
// Function Calls
log.console("BENCHMARK: Function Calls"); log.console("BENCHMARK: Function Calls");
var funcResults = benchFunctionCalls(); var funcResults = benchFunctionCalls();
log.console(" Simple calls: " + funcResults.simpleCallTime.toFixed(3) + "s => " + log.console(" Simple calls: " + funcResults.simpleCallTime.toFixed(3) + "s => " +
(iterations.simple / funcResults.simpleCallTime).toFixed(1) + " calls/sec [" + (iterations.simple / funcResults.simpleCallTime).toFixed(1) + " calls/sec [" +
(funcResults.simpleCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (funcResults.simpleCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Method calls: " + funcResults.methodCallTime.toFixed(3) + "s => " + log.console(" Method calls: " + funcResults.methodCallTime.toFixed(3) + "s => " +
(iterations.simple / funcResults.methodCallTime).toFixed(1) + " calls/sec [" + (iterations.simple / funcResults.methodCallTime).toFixed(1) + " calls/sec [" +
(funcResults.methodCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (funcResults.methodCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Complex calls: " + funcResults.complexCallTime.toFixed(3) + "s => " + log.console(" Complex calls: " + funcResults.complexCallTime.toFixed(3) + "s => " +
(iterations.medium / funcResults.complexCallTime).toFixed(1) + " calls/sec [" + (iterations.medium / funcResults.complexCallTime).toFixed(1) + " calls/sec [" +
(funcResults.complexCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (funcResults.complexCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");
// Array Operations
log.console("BENCHMARK: Array Operations"); log.console("BENCHMARK: Array Operations");
var arrayResults = benchArrayOps(); var arrayResults = benchArrayOps();
log.console(" Push: " + arrayResults.pushTime.toFixed(3) + "s => " + log.console(" Push: " + arrayResults.pushTime.toFixed(3) + "s => " +
(iterations.medium / arrayResults.pushTime).toFixed(1) + " pushes/sec [" + (iterations.medium / arrayResults.pushTime).toFixed(1) + " pushes/sec [" +
(arrayResults.pushTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (arrayResults.pushTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Access: " + arrayResults.accessTime.toFixed(3) + "s => " + log.console(" Access: " + arrayResults.accessTime.toFixed(3) + "s => " +
(iterations.medium / arrayResults.accessTime).toFixed(1) + " accesses/sec [" + (iterations.medium / arrayResults.accessTime).toFixed(1) + " accesses/sec [" +
(arrayResults.accessTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (arrayResults.accessTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Iterate: " + arrayResults.iterateTime.toFixed(3) + "s => " + log.console(" Iterate: " + arrayResults.iterateTime.toFixed(3) + "s => " +
(1000 / arrayResults.iterateTime).toFixed(1) + " full iterations/sec"); (1000 / arrayResults.iterateTime).toFixed(1) + " full iterations/sec");
log.console(""); log.console("");
// Object Creation
log.console("BENCHMARK: Object Creation"); log.console("BENCHMARK: Object Creation");
var objResults = benchObjectCreation(); var objResults = benchObjectCreation();
log.console(" Literal: " + objResults.literalTime.toFixed(3) + "s => " + log.console(" Literal: " + objResults.literalTime.toFixed(3) + "s => " +
(iterations.medium / objResults.literalTime).toFixed(1) + " creates/sec [" + (iterations.medium / objResults.literalTime).toFixed(1) + " creates/sec [" +
(objResults.literalTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (objResults.literalTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Constructor: " + objResults.defructorTime.toFixed(3) + "s => " + log.console(" Constructor: " + objResults.defructorTime.toFixed(3) + "s => " +
(iterations.medium / objResults.defructorTime).toFixed(1) + " creates/sec [" + (iterations.medium / objResults.defructorTime).toFixed(1) + " creates/sec [" +
(objResults.defructorTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (objResults.defructorTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Prototype: " + objResults.prototypeTime.toFixed(3) + "s => " + log.console(" Prototype: " + objResults.prototypeTime.toFixed(3) + "s => " +
(iterations.medium / objResults.prototypeTime).toFixed(1) + " creates/sec [" + (iterations.medium / objResults.prototypeTime).toFixed(1) + " creates/sec [" +
(objResults.prototypeTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (objResults.prototypeTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");
// String Operations
log.console("BENCHMARK: String Operations"); log.console("BENCHMARK: String Operations");
var strResults = benchStringOps(); var strResults = benchStringOps();
log.console(" Concat: " + strResults.concatTime.toFixed(3) + "s => " + log.console(" Concat: " + strResults.concatTime.toFixed(3) + "s => " +
(iterations.complex / strResults.concatTime).toFixed(1) + " concats/sec [" + (iterations.complex / strResults.concatTime).toFixed(1) + " concats/sec [" +
(strResults.concatTime / iterations.complex * 1e9).toFixed(1) + " ns/op]"); (strResults.concatTime / iterations.complex * 1e9).toFixed(1) + " ns/op]");
log.console(" Join: " + strResults.joinTime.toFixed(3) + "s => " + log.console(" Join: " + strResults.joinTime.toFixed(3) + "s => " +
(iterations.complex / strResults.joinTime).toFixed(1) + " joins/sec [" + (iterations.complex / strResults.joinTime).toFixed(1) + " joins/sec [" +
(strResults.joinTime / iterations.complex * 1e9).toFixed(1) + " ns/op]"); (strResults.joinTime / iterations.complex * 1e9).toFixed(1) + " ns/op]");
log.console(" Split: " + strResults.splitTime.toFixed(3) + "s => " + log.console(" Split: " + strResults.splitTime.toFixed(3) + "s => " +
(iterations.medium / strResults.splitTime).toFixed(1) + " splits/sec [" + (iterations.medium / strResults.splitTime).toFixed(1) + " splits/sec [" +
(strResults.splitTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (strResults.splitTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");
// Arithmetic Operations
log.console("BENCHMARK: Arithmetic Operations"); log.console("BENCHMARK: Arithmetic Operations");
var mathResults = benchArithmetic(); var mathResults = benchArithmetic();
log.console(" Integer math: " + mathResults.intMathTime.toFixed(3) + "s => " + log.console(" Integer math: " + mathResults.intMathTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.intMathTime).toFixed(1) + " ops/sec [" + (iterations.simple / mathResults.intMathTime).toFixed(1) + " ops/sec [" +
(mathResults.intMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (mathResults.intMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Float math: " + mathResults.floatMathTime.toFixed(3) + "s => " + log.console(" Float math: " + mathResults.floatMathTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.floatMathTime).toFixed(1) + " ops/sec [" + (iterations.simple / mathResults.floatMathTime).toFixed(1) + " ops/sec [" +
(mathResults.floatMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (mathResults.floatMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Bitwise: " + mathResults.bitwiseTime.toFixed(3) + "s => " + log.console(" Bitwise: " + mathResults.bitwiseTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.bitwiseTime).toFixed(1) + " ops/sec [" + (iterations.simple / mathResults.bitwiseTime).toFixed(1) + " ops/sec [" +
(mathResults.bitwiseTime / iterations.simple * 1e9).toFixed(1) + " ns/op]"); (mathResults.bitwiseTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");
// Closures
log.console("BENCHMARK: Closures"); log.console("BENCHMARK: Closures");
var closureResults = benchClosures(); var closureResults = benchClosures();
log.console(" Create: " + closureResults.closureCreateTime.toFixed(3) + "s => " + log.console(" Create: " + closureResults.closureCreateTime.toFixed(3) + "s => " +
(iterations.medium / closureResults.closureCreateTime).toFixed(1) + " creates/sec [" + (iterations.medium / closureResults.closureCreateTime).toFixed(1) + " creates/sec [" +
(closureResults.closureCreateTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (closureResults.closureCreateTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Call: " + closureResults.closureCallTime.toFixed(3) + "s => " + log.console(" Call: " + closureResults.closureCallTime.toFixed(3) + "s => " +
(iterations.medium / closureResults.closureCallTime).toFixed(1) + " calls/sec [" + (iterations.medium / closureResults.closureCallTime).toFixed(1) + " calls/sec [" +
(closureResults.closureCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]"); (closureResults.closureCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(""); log.console("");

View File

@@ -1,40 +1,46 @@
var blob = use('blob') var blob = use('blob')
var iter = 50, limit = 2.0; var iter = 50
var zr, zi, cr, ci, tr, ti; var limit = 2.0
var zr = null
var zi = null
var cr = null
var ci = null
var tr = null
var ti = null
var y = 0
var x = 0
var i = 0
var row = null
var h = Number(arg[0]) || 500 var h = Number(arg[0]) || 500
var w = h var w = h
log.console(`P4\n${w} ${h}`); log.console(`P4\n${w} ${h}`);
for (var y = 0; y < h; ++y) { for (y = 0; y < h; ++y) {
// Create a blob for the row - we need w bits row = blob(w);
var row = blob(w);
for (var x = 0; x < w; ++x) { for (x = 0; x < w; ++x) {
zr = zi = tr = ti = 0; zr = 0; zi = 0; tr = 0; ti = 0;
cr = 2 * x / w - 1.5; cr = 2 * x / w - 1.5;
ci = 2 * y / h - 1; ci = 2 * y / h - 1;
for (var i = 0; i < iter && (tr + ti <= limit * limit); ++i) { for (i = 0; i < iter && (tr + ti <= limit * limit); ++i) {
zi = 2 * zr * zi + ci; zi = 2 * zr * zi + ci;
zr = tr - ti + cr; zr = tr - ti + cr;
tr = zr * zr; tr = zr * zr;
ti = zi * zi; ti = zi * zi;
} }
// Write a 1 bit if inside the set, 0 if outside
if (tr + ti <= limit * limit) if (tr + ti <= limit * limit)
row.write_bit(1); row.write_bit(1);
else else
row.write_bit(0); row.write_bit(0);
} }
// Convert the blob to stone (immutable) to prepare for output
stone(row) stone(row)
// Output the blob data as raw bytes log.console(text(row, 'b'));
log.console(text(row, 'b'));
} }
$stop() $stop()

View File

@@ -1,9 +1,12 @@
var math = use('math/radians') var math = use('math/radians')
var N = 1000000; var N = 1000000;
var num = 0; var num = 0;
for (var i = 0; i < N; i ++) { var i = 0
var x = 2 * $random(); var x = null
var y = $random(); var y = null
for (i = 0; i < N; i++) {
x = 2 * $random();
y = $random();
if (y < math.sine(x * x)) if (y < math.sine(x * x))
num++; num++;
} }

View File

@@ -2,60 +2,60 @@ var math = use('math/radians')
var SOLAR_MASS = 4 * pi * pi; var SOLAR_MASS = 4 * pi * pi;
var DAYS_PER_YEAR = 365.24; var DAYS_PER_YEAR = 365.24;
function Body(x, y, z, vx, vy, vz, mass) { function Body(p) {
return {x, y, z, vx, vy, vz, mass}; return {x: p.x, y: p.y, z: p.z, vx: p.vx, vy: p.vy, vz: p.vz, mass: p.mass};
} }
function Jupiter() { function Jupiter() {
return Body( return Body({
4.84143144246472090e+00, x: 4.84143144246472090e+00,
-1.16032004402742839e+00, y: -1.16032004402742839e+00,
-1.03622044471123109e-01, z: -1.03622044471123109e-01,
1.66007664274403694e-03 * DAYS_PER_YEAR, vx: 1.66007664274403694e-03 * DAYS_PER_YEAR,
7.69901118419740425e-03 * DAYS_PER_YEAR, vy: 7.69901118419740425e-03 * DAYS_PER_YEAR,
-6.90460016972063023e-05 * DAYS_PER_YEAR, vz: -6.90460016972063023e-05 * DAYS_PER_YEAR,
9.54791938424326609e-04 * SOLAR_MASS mass: 9.54791938424326609e-04 * SOLAR_MASS
); });
} }
function Saturn() { function Saturn() {
return Body( return Body({
8.34336671824457987e+00, x: 8.34336671824457987e+00,
4.12479856412430479e+00, y: 4.12479856412430479e+00,
-4.03523417114321381e-01, z: -4.03523417114321381e-01,
-2.76742510726862411e-03 * DAYS_PER_YEAR, vx: -2.76742510726862411e-03 * DAYS_PER_YEAR,
4.99852801234917238e-03 * DAYS_PER_YEAR, vy: 4.99852801234917238e-03 * DAYS_PER_YEAR,
2.30417297573763929e-05 * DAYS_PER_YEAR, vz: 2.30417297573763929e-05 * DAYS_PER_YEAR,
2.85885980666130812e-04 * SOLAR_MASS mass: 2.85885980666130812e-04 * SOLAR_MASS
); });
} }
function Uranus() { function Uranus() {
return Body( return Body({
1.28943695621391310e+01, x: 1.28943695621391310e+01,
-1.51111514016986312e+01, y: -1.51111514016986312e+01,
-2.23307578892655734e-01, z: -2.23307578892655734e-01,
2.96460137564761618e-03 * DAYS_PER_YEAR, vx: 2.96460137564761618e-03 * DAYS_PER_YEAR,
2.37847173959480950e-03 * DAYS_PER_YEAR, vy: 2.37847173959480950e-03 * DAYS_PER_YEAR,
-2.96589568540237556e-05 * DAYS_PER_YEAR, vz: -2.96589568540237556e-05 * DAYS_PER_YEAR,
4.36624404335156298e-05 * SOLAR_MASS mass: 4.36624404335156298e-05 * SOLAR_MASS
); });
} }
function Neptune() { function Neptune() {
return Body( return Body({
1.53796971148509165e+01, x: 1.53796971148509165e+01,
-2.59193146099879641e+01, y: -2.59193146099879641e+01,
1.79258772950371181e-01, z: 1.79258772950371181e-01,
2.68067772490389322e-03 * DAYS_PER_YEAR, vx: 2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR, vy: 1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR, vz: -9.51592254519715870e-05 * DAYS_PER_YEAR,
5.15138902046611451e-05 * SOLAR_MASS mass: 5.15138902046611451e-05 * SOLAR_MASS
); });
} }
function Sun() { function Sun() {
return Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS); return Body({x: 0.0, y: 0.0, z: 0.0, vx: 0.0, vy: 0.0, vz: 0.0, mass: SOLAR_MASS});
} }
var bodies = Array(Sun(), Jupiter(), Saturn(), Uranus(), Neptune()); var bodies = Array(Sun(), Jupiter(), Saturn(), Uranus(), Neptune());
@@ -65,15 +65,18 @@ function offsetMomentum() {
var py = 0; var py = 0;
var pz = 0; var pz = 0;
var size = length(bodies); var size = length(bodies);
for (var i = 0; i < size; i++) { var i = 0
var body = bodies[i]; var body = null
var mass = body.mass; var mass = null
for (i = 0; i < size; i++) {
body = bodies[i];
mass = body.mass;
px += body.vx * mass; px += body.vx * mass;
py += body.vy * mass; py += body.vy * mass;
pz += body.vz * mass; pz += body.vz * mass;
} }
var body = bodies[0]; body = bodies[0];
body.vx = -px / SOLAR_MASS; body.vx = -px / SOLAR_MASS;
body.vy = -py / SOLAR_MASS; body.vy = -py / SOLAR_MASS;
body.vz = -pz / SOLAR_MASS; body.vz = -pz / SOLAR_MASS;
@@ -81,27 +84,42 @@ function offsetMomentum() {
function advance(dt) { function advance(dt) {
var size = length(bodies); var size = length(bodies);
var i = 0
var j = 0
var bodyi = null
var bodyj = null
var vxi = null
var vyi = null
var vzi = null
var dx = null
var dy = null
var dz = null
var d2 = null
var mag = null
var massj = null
var massi = null
var body = null
for (var i = 0; i < size; i++) { for (i = 0; i < size; i++) {
var bodyi = bodies[i]; bodyi = bodies[i];
var vxi = bodyi.vx; vxi = bodyi.vx;
var vyi = bodyi.vy; vyi = bodyi.vy;
var vzi = bodyi.vz; vzi = bodyi.vz;
for (var j = i + 1; j < size; j++) { for (j = i + 1; j < size; j++) {
var bodyj = bodies[j]; bodyj = bodies[j];
var dx = bodyi.x - bodyj.x; dx = bodyi.x - bodyj.x;
var dy = bodyi.y - bodyj.y; dy = bodyi.y - bodyj.y;
var dz = bodyi.z - bodyj.z; dz = bodyi.z - bodyj.z;
var d2 = dx * dx + dy * dy + dz * dz; d2 = dx * dx + dy * dy + dz * dz;
var mag = dt / (d2 * math.sqrt(d2)); mag = dt / (d2 * math.sqrt(d2));
var massj = bodyj.mass; massj = bodyj.mass;
vxi -= dx * massj * mag; vxi -= dx * massj * mag;
vyi -= dy * massj * mag; vyi -= dy * massj * mag;
vzi -= dz * massj * mag; vzi -= dz * massj * mag;
var massi = bodyi.mass; massi = bodyi.mass;
bodyj.vx += dx * massi * mag; bodyj.vx += dx * massi * mag;
bodyj.vy += dy * massi * mag; bodyj.vy += dy * massi * mag;
bodyj.vz += dz * massi * mag; bodyj.vz += dz * massi * mag;
@@ -111,8 +129,8 @@ function advance(dt) {
bodyi.vz = vzi; bodyi.vz = vzi;
} }
for (var i = 0; i < size; i++) { for (i = 0; i < size; i++) {
var body = bodies[i]; body = bodies[i];
body.x += dt * body.vx; body.x += dt * body.vx;
body.y += dt * body.vy; body.y += dt * body.vy;
body.z += dt * body.vz; body.z += dt * body.vz;
@@ -122,20 +140,28 @@ function advance(dt) {
function energy() { function energy() {
var e = 0; var e = 0;
var size = length(bodies); var size = length(bodies);
var i = 0
var j = 0
var bodyi = null
var bodyj = null
var dx = null
var dy = null
var dz = null
var distance = null
for (var i = 0; i < size; i++) { for (i = 0; i < size; i++) {
var bodyi = bodies[i]; bodyi = bodies[i];
e += 0.5 * bodyi.mass * ( bodyi.vx * bodyi.vx + e += 0.5 * bodyi.mass * ( bodyi.vx * bodyi.vx +
bodyi.vy * bodyi.vy + bodyi.vz * bodyi.vz ); bodyi.vy * bodyi.vy + bodyi.vz * bodyi.vz );
for (var j = i + 1; j < size; j++) { for (j = i + 1; j < size; j++) {
var bodyj = bodies[j]; bodyj = bodies[j];
var dx = bodyi.x - bodyj.x; dx = bodyi.x - bodyj.x;
var dy = bodyi.y - bodyj.y; dy = bodyi.y - bodyj.y;
var dz = bodyi.z - bodyj.z; dz = bodyi.z - bodyj.z;
var distance = math.sqrt(dx * dx + dy * dy + dz * dz); distance = math.sqrt(dx * dx + dy * dy + dz * dz);
e -= (bodyi.mass * bodyj.mass) / distance; e -= (bodyi.mass * bodyj.mass) / distance;
} }
} }
@@ -143,12 +169,13 @@ function energy() {
} }
var n = arg[0] || 100000 var n = arg[0] || 100000
var i = 0
offsetMomentum(); offsetMomentum();
log.console(`n = ${n}`) log.console(`n = ${n}`)
log.console(energy().toFixed(9)) log.console(energy().toFixed(9))
for (var i = 0; i < n; i++) for (i = 0; i < n; i++)
advance(0.01); advance(0.01);
log.console(energy().toFixed(9)) log.console(energy().toFixed(9))

View File

@@ -7,41 +7,40 @@ var ll = io.slurp('benchmarks/nota.json')
var newarr = [] var newarr = []
var accstr = "" var accstr = ""
for (var i = 0; i < 10000; i++) { var i = 0
var start = null
var jll = null
var jsonStr = null
var nll = null
var oll = null
for (i = 0; i < 10000; i++) {
accstr += i; accstr += i;
newarrpush(i.toString()) push(newarr, text(i))
} }
// Arrays to store timing results
var jsonDecodeTimes = []; var jsonDecodeTimes = [];
var jsonEncodeTimes = []; var jsonEncodeTimes = [];
var notaEncodeTimes = []; var notaEncodeTimes = [];
var notaDecodeTimes = []; var notaDecodeTimes = [];
var notaSizes = []; var notaSizes = [];
// Run 100 tests for (i = 0; i < 100; i++) {
for (var i = 0; i < 100; i++) {
// JSON Decode test
var start = os.now();
var jll = json.decode(ll);
jsonDecodeTimespush((os.now() - start) * 1000);
// JSON Encode test
start = os.now(); start = os.now();
var jsonStr = JSON.stringify(jll); jll = json.decode(ll);
jsonEncodeTimespush((os.now() - start) * 1000); push(jsonDecodeTimes, (os.now() - start) * 1000);
// NOTA Encode test
start = os.now(); start = os.now();
var nll = nota.encode(jll); jsonStr = JSON.stringify(jll);
notaEncodeTimespush((os.now() - start) * 1000); push(jsonEncodeTimes, (os.now() - start) * 1000);
// NOTA Decode test
start = os.now(); start = os.now();
var oll = nota.decode(nll); nll = nota.encode(jll);
notaDecodeTimespush((os.now() - start) * 1000); push(notaEncodeTimes, (os.now() - start) * 1000);
start = os.now();
oll = nota.decode(nll);
push(notaDecodeTimes, (os.now() - start) * 1000);
} }
// Calculate statistics
function getStats(arr) { function getStats(arr) {
return { return {
avg: reduce(arr, (a,b) => a+b, 0) / length(arr), avg: reduce(arr, (a,b) => a+b, 0) / length(arr),
@@ -50,7 +49,6 @@ function getStats(arr) {
}; };
} }
// Pretty print results
log.console("\n== Performance Test Results (100 iterations) =="); log.console("\n== Performance Test Results (100 iterations) ==");
log.console("\nJSON Decoding (ms):"); log.console("\nJSON Decoding (ms):");
def jsonDecStats = getStats(jsonDecodeTimes); def jsonDecStats = getStats(jsonDecodeTimes);
@@ -75,4 +73,3 @@ def notaDecStats = getStats(notaDecodeTimes);
log.console(`Average: ${notaDecStats.avg.toFixed(2)} ms`); log.console(`Average: ${notaDecStats.avg.toFixed(2)} ms`);
log.console(`Min: ${notaDecStats.min.toFixed(2)} ms`); log.console(`Min: ${notaDecStats.min.toFixed(2)} ms`);
log.console(`Max: ${notaDecStats.max.toFixed(2)} ms`); log.console(`Max: ${notaDecStats.max.toFixed(2)} ms`);

View File

@@ -5,21 +5,27 @@ function A(i,j) {
} }
function Au(u,v) { function Au(u,v) {
for (var i=0; i<length(u); ++i) { var i = 0
var t = 0; var j = 0
for (var j=0; j<length(u); ++j) var t = null
for (i = 0; i < length(u); ++i) {
t = 0;
for (j = 0; j < length(u); ++j)
t += A(i,j) * u[j]; t += A(i,j) * u[j];
v[i] = t; v[i] = t;
} }
} }
function Atu(u,v) { function Atu(u,v) {
for (var i=0; i<length(u); ++i) { var i = 0
var t = 0; var j = 0
for (var j=0; j<length(u); ++j) var t = null
for (i = 0; i < length(u); ++i) {
t = 0;
for (j = 0; j < length(u); ++j)
t += A(j,i) * u[j]; t += A(j,i) * u[j];
v[i] = t; v[i] = t;
} }
} }
@@ -30,20 +36,26 @@ function AtAu(u,v,w) {
} }
function spectralnorm(n) { function spectralnorm(n) {
var i, u=[], v=[], w=[], vv=0, vBv=0; var i = 0
for (i=0; i<n; ++i) var u = []
u[i] = 1; v[i] = w[i] = 0; var v = []
var w = []
var vv = 0
var vBv = 0
for (i = 0; i < n; ++i) {
u[i] = 1; v[i] = 0; w[i] = 0;
}
for (i=0; i<10; ++i) { for (i = 0; i < 10; ++i) {
AtAu(u,v,w); AtAu(u,v,w);
AtAu(v,u,w); AtAu(v,u,w);
} }
for (i=0; i<n; ++i) { for (i = 0; i < n; ++i) {
vBv += u[i]*v[i]; vBv += u[i]*v[i];
vv += v[i]*v[i]; vv += v[i]*v[i];
} }
return math.sqrt(vBv/vv); return math.sqrt(vBv/vv);
} }

View File

@@ -1,41 +1,22 @@
// var wota = use('wota');
// wota_benchmark.js var os = use('os');
//
// Usage in QuickJS: var i = 0
// qjs wota_benchmark.js
//
// Prerequisite:
var wota = use('wota');
var os = use('os');
// or otherwise ensure `wota` and `os` are available.
// Make sure wota_benchmark.js is loaded after wota.js or combined with it.
//
// Helper to run a function repeatedly and measure total time in seconds.
// Returns elapsed time in seconds.
function measureTime(fn, iterations) { function measureTime(fn, iterations) {
var t1 = os.now(); var t1 = os.now();
for (var i = 0; i < iterations; i++) { for (i = 0; i < iterations; i++) {
fn(); fn();
} }
var t2 = os.now(); var t2 = os.now();
return t2 - t1; return t2 - t1;
} }
// We'll define a function that does `encode -> decode` for a given value:
function roundTripWota(value) { function roundTripWota(value) {
var encoded = wota.encode(value); var encoded = wota.encode(value);
var decoded = wota.decode(encoded); var decoded = wota.decode(encoded);
// Not doing a deep compare here, just measuring performance.
// (We trust the test suite to verify correctness.)
} }
// A small suite of data we want to benchmark. Each entry includes:
// name: label for printing
// data: the test value(s) to encode/decode
// iterations: how many times to loop
//
// You can tweak these as you like for heavier or lighter tests.
def benchmarks = [ def benchmarks = [
{ {
name: "Small Integers", name: "Small Integers",
@@ -62,22 +43,17 @@ def benchmarks = [
}, },
{ {
name: "Large Array (1k numbers)", name: "Large Array (1k numbers)",
// A thousand random numbers
data: [ array(1000, i => i *0.5) ], data: [ array(1000, i => i *0.5) ],
iterations: 1000 iterations: 1000
}, },
]; ];
// Print a header
log.console("Wota Encode/Decode Benchmark"); log.console("Wota Encode/Decode Benchmark");
log.console("===================\n"); log.console("===================\n");
// We'll run each benchmark scenario in turn.
arrfor(benchmarks, function(bench) { arrfor(benchmarks, function(bench) {
var totalIterations = bench.iterations * length(bench.data); var totalIterations = bench.iterations * length(bench.data);
// We'll define a function that does a roundTrip for *each* data item in bench.data
// to measure in one loop iteration. Then we multiply by bench.iterations.
function runAllData() { function runAllData() {
arrfor(bench.data, roundTripWota) arrfor(bench.data, roundTripWota)
} }
@@ -91,5 +67,4 @@ arrfor(benchmarks, function(bench) {
log.console(` Throughput: ${opsPerSec} encode+decode ops/sec\n`); log.console(` Throughput: ${opsPerSec} encode+decode ops/sec\n`);
}) })
// All done
log.console("Benchmark completed.\n"); log.console("Benchmark completed.\n");

View File

@@ -1,18 +1,9 @@
// var wota = use('wota');
// benchmark_wota_nota_json.js var nota = use('nota');
// var json = use('json');
// Usage in QuickJS: var jswota = use('jswota')
// qjs benchmark_wota_nota_json.js <LibraryName> <ScenarioName> var os = use('os');
//
// Ensure wota, nota, json, and os are all available, e.g.:
var wota = use('wota');
var nota = use('nota');
var json = use('json');
var jswota = use('jswota')
var os = use('os');
//
// Parse command line arguments
if (length(arg) != 2) { if (length(arg) != 2) {
log.console('Usage: cell benchmark_wota_nota_json.ce <LibraryName> <ScenarioName>'); log.console('Usage: cell benchmark_wota_nota_json.ce <LibraryName> <ScenarioName>');
$stop() $stop()
@@ -21,16 +12,11 @@ if (length(arg) != 2) {
var lib_name = arg[0]; var lib_name = arg[0];
var scenario_name = arg[1]; var scenario_name = arg[1];
////////////////////////////////////////////////////////////////////////////////
// 1. Setup "libraries" array to easily switch among wota, nota, and json
////////////////////////////////////////////////////////////////////////////////
def libraries = [ def libraries = [
{ {
name: "wota", name: "wota",
encode: wota.encode, encode: wota.encode,
decode: wota.decode, decode: wota.decode,
// wota produces an ArrayBuffer. We'll count `buffer.byteLength` as size.
getSize(encoded) { getSize(encoded) {
return length(encoded); return length(encoded);
} }
@@ -39,7 +25,6 @@ def libraries = [
name: "nota", name: "nota",
encode: nota.encode, encode: nota.encode,
decode: nota.decode, decode: nota.decode,
// nota also produces an ArrayBuffer:
getSize(encoded) { getSize(encoded) {
return length(encoded); return length(encoded);
} }
@@ -48,19 +33,12 @@ def libraries = [
name: "json", name: "json",
encode: json.encode, encode: json.encode,
decode: json.decode, decode: json.decode,
// json produces a JS string. We'll measure its UTF-16 code unit length
// as a rough "size". Alternatively, you could convert to UTF-8 for
getSize(encodedStr) { getSize(encodedStr) {
return length(encodedStr); return length(encodedStr);
} }
} }
]; ];
////////////////////////////////////////////////////////////////////////////////
// 2. Test data sets (similar to wota benchmarks).
// Each scenario has { name, data, iterations }
////////////////////////////////////////////////////////////////////////////////
def benchmarks = [ def benchmarks = [
{ {
name: "empty", name: "empty",
@@ -102,42 +80,24 @@ def benchmarks = [
}, },
]; ];
////////////////////////////////////////////////////////////////////////////////
// 3. Utility: measureTime(fn) => how long fn() takes in seconds.
////////////////////////////////////////////////////////////////////////////////
function measureTime(fn) { function measureTime(fn) {
var start = os.now(); var start = os.now();
fn(); fn();
var end = os.now(); var end = os.now();
return (end - start); // in seconds return (end - start);
} }
////////////////////////////////////////////////////////////////////////////////
// 4. For each library, we run each benchmark scenario and measure:
// - Encoding time (seconds)
// - Decoding time (seconds)
// - Total encoded size (bytes or code units for json)
//
////////////////////////////////////////////////////////////////////////////////
function runBenchmarkForLibrary(lib, bench) { function runBenchmarkForLibrary(lib, bench) {
// We'll encode and decode each item in `bench.data`.
// We do 'bench.iterations' times. Then sum up total time.
// Pre-store the encoded results for all items so we can measure decode time
// in a separate pass. Also measure total size once.
var encodedList = []; var encodedList = [];
var totalSize = 0; var totalSize = 0;
var i = 0
var j = 0
var e = null
// 1) Measure ENCODING
var encodeTime = measureTime(() => { var encodeTime = measureTime(() => {
for (var i = 0; i < bench.iterations; i++) { for (i = 0; i < bench.iterations; i++) {
// For each data item, encode it for (j = 0; j < length(bench.data); j++) {
for (var j = 0; j < length(bench.data); j++) { e = lib.encode(bench.data[j]);
var e = lib.encode(bench.data[j]);
// store only in the very first iteration, so we can decode them later
// but do not store them every iteration or we blow up memory.
if (i == 0) { if (i == 0) {
push(encodedList, e); push(encodedList, e);
totalSize += lib.getSize(e); totalSize += lib.getSize(e);
@@ -146,9 +106,8 @@ function runBenchmarkForLibrary(lib, bench) {
} }
}); });
// 2) Measure DECODING
var decodeTime = measureTime(() => { var decodeTime = measureTime(() => {
for (var i = 0; i < bench.iterations; i++) { for (i = 0; i < bench.iterations; i++) {
arrfor(encodedList, lib.decode) arrfor(encodedList, lib.decode)
} }
}); });
@@ -156,11 +115,6 @@ function runBenchmarkForLibrary(lib, bench) {
return { encodeTime, decodeTime, totalSize }; return { encodeTime, decodeTime, totalSize };
} }
////////////////////////////////////////////////////////////////////////////////
// 5. Main driver: run only the specified library and scenario
////////////////////////////////////////////////////////////////////////////////
// Find the requested library and scenario
var lib = libraries[find(libraries, l => l.name == lib_name)]; var lib = libraries[find(libraries, l => l.name == lib_name)];
var bench = benchmarks[find(benchmarks, b => b.name == scenario_name)]; var bench = benchmarks[find(benchmarks, b => b.name == scenario_name)];
@@ -176,10 +130,11 @@ if (!bench) {
$stop() $stop()
} }
// Run the benchmark for this library/scenario combination var bench_result = runBenchmarkForLibrary(lib, bench);
var { encodeTime, decodeTime, totalSize } = runBenchmarkForLibrary(lib, bench); var encodeTime = bench_result.encodeTime;
var decodeTime = bench_result.decodeTime;
var totalSize = bench_result.totalSize;
// Output json for easy parsing by hyperfine or other tools
var totalOps = bench.iterations * length(bench.data); var totalOps = bench.iterations * length(bench.data);
var result = { var result = {
lib: lib_name, lib: lib_name,

242
cellfs.cm
View File

@@ -1,28 +1,23 @@
var cellfs = {} var cellfs = {}
// CellFS: A filesystem implementation using miniz and raw OS filesystem
// Supports mounting multiple sources (fs, zip) and named mounts (@name)
var fd = use('fd') var fd = use('fd')
var miniz = use('miniz') var miniz = use('miniz')
var qop = use('qop') var qop = use('qop')
var wildstar = use('wildstar') var wildstar = use('wildstar')
// Internal state var mounts = []
var mounts = [] // Array of {source, type, handle, name}
var writepath = "." var writepath = "."
// Helper to normalize paths
function normalize_path(path) { function normalize_path(path) {
if (!path) return "" if (!path) return ""
// Remove leading/trailing slashes and normalize
return replace(path, /^\/+|\/+$/, "") return replace(path, /^\/+|\/+$/, "")
} }
// Check if a file exists in a specific mount
function mount_exists(mount, path) { function mount_exists(mount, path) {
var result = false var result = false
var full_path = null
var st = null
var _check = null var _check = null
if (mount.type == 'zip') { if (mount.type == 'zip') {
_check = function() { _check = function() {
@@ -36,9 +31,9 @@ function mount_exists(mount, path) {
} disruption {} } disruption {}
_check() _check()
} else { } else {
var full_path = fd.join_paths(mount.source, path) full_path = fd.join_paths(mount.source, path)
_check = function() { _check = function() {
var st = fd.stat(full_path) st = fd.stat(full_path)
result = st.isFile || st.isDirectory result = st.isFile || st.isDirectory
} disruption {} } disruption {}
_check() _check()
@@ -46,11 +41,12 @@ function mount_exists(mount, path) {
return result return result
} }
// Check if a path refers to a directory in a specific mount
function is_directory(path) { function is_directory(path) {
var res = resolve(path) var res = resolve(path)
var mount = res.mount var mount = res.mount
var result = false var result = false
var full_path = null
var st = null
var _check = null var _check = null
if (mount.type == 'zip') { if (mount.type == 'zip') {
_check = function() { _check = function() {
@@ -63,9 +59,9 @@ function is_directory(path) {
} disruption {} } disruption {}
_check() _check()
} else { } else {
var full_path = fd.join_paths(mount.source, path) full_path = fd.join_paths(mount.source, path)
_check = function() { _check = function() {
var st = fd.stat(full_path) st = fd.stat(full_path)
result = st.isDirectory result = st.isDirectory
} disruption {} } disruption {}
_check() _check()
@@ -73,64 +69,63 @@ function is_directory(path) {
return result return result
} }
// Resolve a path to a specific mount and relative path
// Returns { mount, path } or throws/returns null
function resolve(path, must_exist) { function resolve(path, must_exist) {
path = normalize_path(path) var idx = null
var mount_name = ""
// Check for named mount var rel_path = ""
if (starts_with(path, "@")) { var mount = null
var idx = search(path, "/") var found_mount = null
var mount_name = "" var npath = normalize_path(path)
var rel_path = ""
if (starts_with(npath, "@")) {
idx = search(npath, "/")
if (idx == null) { if (idx == null) {
mount_name = text(path, 1) mount_name = text(npath, 1)
rel_path = "" rel_path = ""
} else { } else {
mount_name = text(path, 1, idx) mount_name = text(npath, 1, idx)
rel_path = text(path, idx + 1) rel_path = text(npath, idx + 1)
} }
// Find named mount
var mount = null
arrfor(mounts, function(m) { arrfor(mounts, function(m) {
if (m.name == mount_name) { if (m.name == mount_name) {
mount = m mount = m
return true return true
} }
}, false, true) }, false, true)
if (!mount) { if (!mount) {
print("Unknown mount point: @" + mount_name); disrupt print("Unknown mount point: @" + mount_name); disrupt
} }
return { mount: mount, path: rel_path } return { mount: mount, path: rel_path }
} }
// Search path arrfor(mounts, function(m) {
var found_mount = null if (mount_exists(m, npath)) {
arrfor(mounts, function(mount) { found_mount = { mount: m, path: npath }
if (mount_exists(mount, path)) {
found_mount = { mount: mount, path: path }
return true return true
} }
}, false, true) }, false, true)
if (found_mount) { if (found_mount) {
return found_mount return found_mount
} }
if (must_exist) { if (must_exist) {
print("File not found in any mount: " + path); disrupt print("File not found in any mount: " + npath); disrupt
} }
} }
// Mount a source
function mount(source, name) { function mount(source, name) {
// Check if source exists
var st = fd.stat(source) var st = fd.stat(source)
var blob = null
var qop_archive = null
var zip = null
var _try_qop = null
var mount_info = { var mount_info = {
source: source, source: source,
name: name || null, name: name || null,
@@ -138,14 +133,14 @@ function mount(source, name) {
handle: null, handle: null,
zip_blob: null zip_blob: null
} }
if (st.isDirectory) { if (st.isDirectory) {
mount_info.type = 'fs' mount_info.type = 'fs'
} else if (st.isFile) { } else if (st.isFile) {
var blob = fd.slurp(source) blob = fd.slurp(source)
var qop_archive = null qop_archive = null
var _try_qop = function() { _try_qop = function() {
qop_archive = qop.open(blob) qop_archive = qop.open(blob)
} disruption {} } disruption {}
_try_qop() _try_qop()
@@ -153,58 +148,56 @@ function mount(source, name) {
if (qop_archive) { if (qop_archive) {
mount_info.type = 'qop' mount_info.type = 'qop'
mount_info.handle = qop_archive mount_info.handle = qop_archive
mount_info.zip_blob = blob // keep blob alive mount_info.zip_blob = blob
} else { } else {
var zip = miniz.read(blob) zip = miniz.read(blob)
if (!is_object(zip) || !is_function(zip.count)) { if (!is_object(zip) || !is_function(zip.count)) {
print("Invalid archive file (not zip or qop): " + source); disrupt print("Invalid archive file (not zip or qop): " + source); disrupt
} }
mount_info.type = 'zip' mount_info.type = 'zip'
mount_info.handle = zip mount_info.handle = zip
mount_info.zip_blob = blob // keep blob alive mount_info.zip_blob = blob
} }
} else { } else {
print("Unsupported mount source type: " + source); disrupt print("Unsupported mount source type: " + source); disrupt
} }
push(mounts, mount_info) push(mounts, mount_info)
} }
// Unmount
function unmount(name_or_source) { function unmount(name_or_source) {
mounts = filter(mounts, function(mount) { mounts = filter(mounts, function(m) {
return mount.name != name_or_source && mount.source != name_or_source return m.name != name_or_source && m.source != name_or_source
}) })
} }
// Read file
function slurp(path) { function slurp(path) {
var res = resolve(path, true) var res = resolve(path, true)
var data = null
var full_path = null
if (!res) { print("File not found: " + path); disrupt } if (!res) { print("File not found: " + path); disrupt }
if (res.mount.type == 'zip') { if (res.mount.type == 'zip') {
return res.mount.handle.slurp(res.path) return res.mount.handle.slurp(res.path)
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var data = res.mount.handle.read(res.path) data = res.mount.handle.read(res.path)
if (!data) { print("File not found in qop: " + path); disrupt } if (!data) { print("File not found in qop: " + path); disrupt }
return data return data
} else { } else {
var full_path = fd.join_paths(res.mount.source, res.path) full_path = fd.join_paths(res.mount.source, res.path)
return fd.slurp(full_path) return fd.slurp(full_path)
} }
} }
// Write file
function slurpwrite(path, data) { function slurpwrite(path, data) {
var full_path = writepath + "/" + path var full_path = writepath + "/" + path
var f = fd.open(full_path, 'w') var f = fd.open(full_path, 'w')
fd.write(f, data) fd.write(f, data)
fd.close(f) fd.close(f)
} }
// Check existence
function exists(path) { function exists(path) {
var res = resolve(path, false) var res = resolve(path, false)
if (starts_with(path, "@")) { if (starts_with(path, "@")) {
@@ -213,20 +206,22 @@ function exists(path) {
return res != null return res != null
} }
// Stat
function stat(path) { function stat(path) {
var res = resolve(path, true) var res = resolve(path, true)
var mod = null
var s = null
var full_path = null
if (!res) { print("File not found: " + path); disrupt } if (!res) { print("File not found: " + path); disrupt }
if (res.mount.type == 'zip') { if (res.mount.type == 'zip') {
var mod = res.mount.handle.mod(res.path) mod = res.mount.handle.mod(res.path)
return { return {
filesize: 0, filesize: 0,
modtime: mod * 1000, modtime: mod * 1000,
isDirectory: false isDirectory: false
} }
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var s = res.mount.handle.stat(res.path) s = res.mount.handle.stat(res.path)
if (!s) { print("File not found in qop: " + path); disrupt } if (!s) { print("File not found in qop: " + path); disrupt }
return { return {
filesize: s.size, filesize: s.size,
@@ -234,8 +229,8 @@ function stat(path) {
isDirectory: s.isDirectory isDirectory: s.isDirectory
} }
} else { } else {
var full_path = fd.join_paths(res.mount.source, res.path) full_path = fd.join_paths(res.mount.source, res.path)
var s = fd.stat(full_path) s = fd.stat(full_path)
return { return {
filesize: s.size, filesize: s.size,
modtime: s.mtime, modtime: s.mtime,
@@ -244,18 +239,16 @@ function stat(path) {
} }
} }
// Get search paths
function searchpath() { function searchpath() {
return array(mounts) return array(mounts)
} }
// Mount a package using the shop system
function mount_package(name) { function mount_package(name) {
if (name == null) { if (name == null) {
mount('.', null) mount('.', null)
return return
} }
var shop = use('internal/shop') var shop = use('internal/shop')
var dir = shop.get_package_dir(name) var dir = shop.get_package_dir(name)
@@ -266,18 +259,18 @@ function mount_package(name) {
mount(dir, name) mount(dir, name)
} }
// New functions for qjs_io compatibility
function match(str, pattern) { function match(str, pattern) {
return wildstar.match(pattern, str, wildstar.WM_PATHNAME | wildstar.WM_PERIOD | wildstar.WM_WILDSTAR) return wildstar.match(pattern, str, wildstar.WM_PATHNAME | wildstar.WM_PERIOD | wildstar.WM_WILDSTAR)
} }
function rm(path) { function rm(path) {
var res = resolve(path, true) var res = resolve(path, true)
var full_path = null
var st = null
if (res.mount.type != 'fs') { print("Cannot delete from non-fs mount"); disrupt } if (res.mount.type != 'fs') { print("Cannot delete from non-fs mount"); disrupt }
var full_path = fd.join_paths(res.mount.source, res.path) full_path = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full_path) st = fd.stat(full_path)
if (st.isDirectory) fd.rmdir(full_path) if (st.isDirectory) fd.rmdir(full_path)
else fd.unlink(full_path) else fd.unlink(full_path)
} }
@@ -305,55 +298,63 @@ function realdir(path) {
return fd.join_paths(res.mount.source, res.path) return fd.join_paths(res.mount.source, res.path)
} }
function enumerate(path, recurse) { function enumerate(_path, recurse) {
if (path == null) path = "" var path = _path == null ? "" : _path
var res = resolve(path, true) var res = resolve(path, true)
var results = [] var results = []
var full = null
var st = null
var all = null
var prefix = null
var prefix_len = null
var seen = null
function visit(curr_full, rel_prefix) { function visit(curr_full, rel_prefix) {
var list = fd.readdir(curr_full) var list = fd.readdir(curr_full)
if (!list) return if (!list) return
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
push(results, item_rel) push(results, item_rel)
if (recurse) { if (recurse) {
var st = fd.stat(fd.join_paths(curr_full, item)) child_st = fd.stat(fd.join_paths(curr_full, item))
if (st.isDirectory) { if (child_st.isDirectory) {
visit(fd.join_paths(curr_full, item), item_rel) visit(fd.join_paths(curr_full, item), item_rel)
} }
} }
}) })
} }
if (res.mount.type == 'fs') { if (res.mount.type == 'fs') {
var full = fd.join_paths(res.mount.source, res.path) full = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full) st = fd.stat(full)
if (st && st.isDirectory) { if (st && st.isDirectory) {
visit(full, "") visit(full, "")
} }
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var all = res.mount.handle.list() all = res.mount.handle.list()
var prefix = res.path ? res.path + "/" : "" prefix = res.path ? res.path + "/" : ""
var prefix_len = length(prefix) prefix_len = length(prefix)
// Use a set to avoid duplicates if we are simulating directories seen = {}
var seen = {}
arrfor(all, function(p) { arrfor(all, function(p) {
var rel = null
var slash = null
if (starts_with(p, prefix)) { if (starts_with(p, prefix)) {
var rel = text(p, prefix_len) rel = text(p, prefix_len)
if (length(rel) == 0) return if (length(rel) == 0) return
if (!recurse) { if (!recurse) {
var slash = search(rel, '/') slash = search(rel, '/')
if (slash != null) { if (slash != null) {
rel = text(rel, 0, slash) rel = text(rel, 0, slash)
} }
} }
if (!seen[rel]) { if (!seen[rel]) {
seen[rel] = true seen[rel] = true
push(results, rel) push(results, rel)
@@ -361,15 +362,20 @@ function enumerate(path, recurse) {
} }
}) })
} }
return results return results
} }
function globfs(globs, dir) { function globfs(globs, _dir) {
if (dir == null) dir = "" var dir = _dir == null ? "" : _dir
var res = resolve(dir, true) var res = resolve(dir, true)
var results = [] var results = []
var full = null
var st = null
var all = null
var prefix = null
var prefix_len = null
function check_neg(path) { function check_neg(path) {
var result = false var result = false
arrfor(globs, function(g) { arrfor(globs, function(g) {
@@ -380,7 +386,7 @@ function globfs(globs, dir) {
}, false, true) }, false, true)
return result return result
} }
function check_pos(path) { function check_pos(path) {
var result = false var result = false
arrfor(globs, function(g) { arrfor(globs, function(g) {
@@ -397,14 +403,14 @@ function globfs(globs, dir) {
var list = fd.readdir(curr_full) var list = fd.readdir(curr_full)
if (!list) return if (!list) return
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_full = fd.join_paths(curr_full, item) var child_full = fd.join_paths(curr_full, item)
var st = fd.stat(child_full) var child_st = fd.stat(child_full)
if (st.isDirectory) { if (child_st.isDirectory) {
if (!check_neg(item_rel)) { if (!check_neg(item_rel)) {
visit(child_full, item_rel) visit(child_full, item_rel)
} }
@@ -415,21 +421,22 @@ function globfs(globs, dir) {
} }
}) })
} }
if (res.mount.type == 'fs') { if (res.mount.type == 'fs') {
var full = fd.join_paths(res.mount.source, res.path) full = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full) st = fd.stat(full)
if (st && st.isDirectory) { if (st && st.isDirectory) {
visit(full, "") visit(full, "")
} }
} else if (res.mount.type == 'qop') { } else if (res.mount.type == 'qop') {
var all = res.mount.handle.list() all = res.mount.handle.list()
var prefix = res.path ? res.path + "/" : "" prefix = res.path ? res.path + "/" : ""
var prefix_len = length(prefix) prefix_len = length(prefix)
arrfor(all, function(p) { arrfor(all, function(p) {
var rel = null
if (starts_with(p, prefix)) { if (starts_with(p, prefix)) {
var rel = text(p, prefix_len) rel = text(p, prefix_len)
if (length(rel) == 0) return if (length(rel) == 0) return
if (!check_neg(rel) && check_pos(rel)) { if (!check_neg(rel) && check_pos(rel)) {
@@ -438,11 +445,10 @@ function globfs(globs, dir) {
} }
}) })
} }
return results return results
} }
// Exports
cellfs.mount = mount cellfs.mount = mount
cellfs.mount_package = mount_package cellfs.mount_package = mount_package
cellfs.unmount = unmount cellfs.unmount = unmount

View File

@@ -8,15 +8,17 @@ $contact((actor, reason) => {
log.console(reason) log.console(reason)
} }
}, { }, {
address: "108.210.60.32", // NAT server's public IP address: "108.210.60.32",
port: 4000, port: 4000,
actor: $self actor: $self
}) })
$receiver(e => { var handlers = {
switch(e.type) { greet: function() {
case 'greet': log.console(`hello!`)
log.console(`hello!`)
break
} }
}
$receiver(e => {
if (handlers[e.type]) handlers[e.type]()
}) })

View File

@@ -1436,7 +1436,7 @@ Shop.build_package_scripts = function(package)
// compiles all .ce and .cm files in a package // compiles all .ce and .cm files in a package
// continues past failures and returns results // continues past failures and returns results
var scripts = get_package_scripts(package) var scripts = get_package_scripts(package)
var pkg_dir = get_package_abs_dir(package) var pkg_dir = starts_with(package, '/') ? package : get_package_abs_dir(package)
var errors = [] var errors = []
var ok = 0 var ok = 0

View File

@@ -41,64 +41,6 @@ function get_path(name)
} }
var config_cache = {} var config_cache = {}
var compilation_cache = {}
// Fallback parser for [compilation] sections when toml.decode() is unreliable.
// Stores results as flat keys in compilation_cache: "key|CFLAGS", "key|target|CFLAGS"
function parse_compilation_into_cache(content, cache_key) {
var lines = array(content, "\n")
var current_section = null
var i = 0
var line = null
var trimmed = null
var eq_pos = null
var key = null
var val_part = null
var val = null
var sub = null
var flat_key = null
for (i = 0; i < length(lines); i++) {
line = lines[i]
trimmed = trim(line)
if (length(trimmed) == 0 || starts_with(trimmed, '#')) continue
// Detect section headers
if (starts_with(trimmed, '[compilation.') && ends_with(trimmed, ']')) {
sub = text(trimmed, 13, -1)
current_section = sub
continue
}
if (trimmed == '[compilation]') {
current_section = '_base_'
continue
}
if (starts_with(trimmed, '[')) {
current_section = null
continue
}
// Parse KEY = "VALUE" in a compilation section
if (current_section == null) continue
eq_pos = search(trimmed, '=')
if (eq_pos == null) continue
key = trim(text(trimmed, 0, eq_pos))
val_part = trim(text(trimmed, eq_pos + 1))
// Strip surrounding quotes
if (starts_with(val_part, '"') && ends_with(val_part, '"')) {
val = text(val_part, 1, -1)
} else {
val = val_part
}
if (current_section == '_base_') {
flat_key = cache_key + '|' + key
} else {
flat_key = cache_key + '|' + current_section + '|' + key
}
compilation_cache[flat_key] = val
}
// Mark that we parsed this package
compilation_cache[cache_key] = true
}
package.load_config = function(name) package.load_config = function(name)
{ {
@@ -121,16 +63,6 @@ package.load_config = function(name)
return {} return {}
} }
// If the raw TOML text has [compilation] sections, always use
// the fallback line parser (the TOML decoder is unreliable for
// nested [compilation.target] sub-tables).
// We store it alongside the result in a separate cache since
// toml.decode returns frozen objects.
var has_compilation = search(content, /\[compilation/) != null
if (has_compilation) {
parse_compilation_into_cache(content, cache_key)
}
config_cache[cache_key] = result config_cache[cache_key] = result
return result return result
} }
@@ -339,33 +271,23 @@ package.list_programs = function(name) {
// Returns an array of flag strings // Returns an array of flag strings
package.get_flags = function(name, flag_type, target) { package.get_flags = function(name, flag_type, target) {
var config = package.load_config(name) var config = package.load_config(name)
var cache_key = name || '_project_' var comp = config.compilation
var flags = [] var flags = []
var base = null var base = null
var target_flags = null var target_flags = null
if (compilation_cache[cache_key]) { if (!comp) return flags
// Use flat cache: keys are "cache_key|FLAG_TYPE" and "cache_key|target|FLAG_TYPE"
base = compilation_cache[cache_key + '|' + flag_type] // Base flags
if (base) { if (comp[flag_type]) {
flags = array(flags, filter(array(base, /\s+/), function(f) { return length(f) > 0 })) base = comp[flag_type]
} flags = array(flags, filter(array(base, /\s+/), function(f) { return length(f) > 0 }))
if (target) { }
target_flags = compilation_cache[cache_key + '|' + target + '|' + flag_type]
if (target_flags) { // Target-specific flags
flags = array(flags, filter(array(target_flags, /\s+/), function(f) { return length(f) > 0 })) if (target && comp[target] && comp[target][flag_type]) {
} target_flags = comp[target][flag_type]
} flags = array(flags, filter(array(target_flags, /\s+/), function(f) { return length(f) > 0 }))
} else if (config.compilation) {
// Fall back to toml.decode() result
if (config.compilation[flag_type]) {
base = config.compilation[flag_type]
flags = array(flags, filter(array(base, /\s+/), function(f) { return length(f) > 0 }))
}
if (target && config.compilation[target] && config.compilation[target][flag_type]) {
target_flags = config.compilation[target][flag_type]
flags = array(flags, filter(array(target_flags, /\s+/), function(f) { return length(f) > 0 }))
}
} }
return flags return flags

View File

@@ -526,7 +526,7 @@ JS_BOOL js_key_equal_str (JSValue a, const char *str) {
} }
if (!JS_IsPtr (a)) return FALSE; if (!JS_IsPtr (a)) return FALSE;
JSText *ta = (JSText *)JS_VALUE_GET_PTR (a); JSText *ta = (JSText *)chase (a);
if (objhdr_type (ta->hdr) != OBJ_TEXT) return FALSE; if (objhdr_type (ta->hdr) != OBJ_TEXT) return FALSE;
uint64_t txt_len = objhdr_cap56 (ta->hdr); uint64_t txt_len = objhdr_cap56 (ta->hdr);
if (txt_len != len) return FALSE; if (txt_len != len) return FALSE;
@@ -704,6 +704,16 @@ int rec_set_own (JSContext *ctx, JSValue *pobj, JSValue k, JSValue val) {
rec->slots[insert_slot].val = val; rec->slots[insert_slot].val = val;
rec->len++; rec->len++;
#ifdef VALIDATE_GC
/* Verify the just-inserted key is findable */
int verify = rec_find_slot (rec, k);
if (verify <= 0) {
fprintf (stderr, "rec_set_own: INSERTED KEY NOT FINDABLE! slot=%d insert_slot=%d len=%u\n",
verify, insert_slot, (uint32_t)rec->len);
abort ();
}
#endif
return 0; return 0;
} }
@@ -1873,6 +1883,12 @@ JSText *js_alloc_string (JSContext *ctx, int max_len) {
/* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */ /* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */
str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false); str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false);
str->length = 0; /* length starts at 0, capacity is in hdr */ str->length = 0; /* length starts at 0, capacity is in hdr */
/* Zero packed data so odd-length strings have deterministic padding.
js_malloc is a bump allocator and does not zero memory; without this,
the last word's unused low 32 bits contain garbage, causing
fash64_hash_words and JSText_equal (memcmp) to produce inconsistent
results for different allocations of the same text content. */
memset (str->packed, 0, data_words * sizeof (uint64_t));
return str; return str;
} }
@@ -3514,9 +3530,9 @@ JSValue JS_GetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key) {
return JS_GetProperty (ctx, this_obj, key); return JS_GetProperty (ctx, this_obj, key);
} }
/* CAUTION: rec_set_own is NOT GC-safe if rec_resize is implemented. /* rec_set_own calls rec_resize which can move the record.
Currently safe because rec_resize always fails. JS_SetProperty uses a local copy so the caller's JSValue is NOT updated;
When resize is implemented, rec pointer may become stale. */ the VM must call mach_resolve_forward after store operations. */
int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key, JSValue val) { int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key, JSValue val) {
if (JS_IsRecord (key)) { if (JS_IsRecord (key)) {
if (!JS_IsRecord (this_obj)) { if (!JS_IsRecord (this_obj)) {

View File

@@ -1,17 +1,12 @@
// blob_test.cm
var Blob = use('blob'); var Blob = use('blob');
var os = use('os'); var os = use('os');
function assert(condition, message) { function assert(condition, message) {
if (!condition) { if (!condition) disrupt
throw Error(message || "Assertion failed");
}
} }
function assertEqual(actual, expected, message) { function assertEqual(actual, expected, message) {
if (actual != expected) { if (actual != expected) disrupt
throw Error(message || "Expected " + expected + ", got " + actual);
}
} }
return { return {
@@ -19,12 +14,12 @@ return {
var b = Blob(); var b = Blob();
assertEqual(length(b), 0, "Empty blob should have length 0"); assertEqual(length(b), 0, "Empty blob should have length 0");
}, },
test_create_blob_with_capacity: function() { test_create_blob_with_capacity: function() {
var b = Blob(100); var b = Blob(100);
assertEqual(length(b), 0, "New blob with capacity should still have length 0"); assertEqual(length(b), 0, "New blob with capacity should still have length 0");
}, },
test_write_and_read_single_bit: function() { test_write_and_read_single_bit: function() {
var b = Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
@@ -32,36 +27,39 @@ return {
b.write_bit(1); b.write_bit(1);
b.write_bit(0); b.write_bit(0);
assertEqual(length(b), 4, "Should have 4 bits after writing"); assertEqual(length(b), 4, "Should have 4 bits after writing");
stone(b); stone(b);
assertEqual(b.read_logical(0), true, "First bit should be true"); assertEqual(b.read_logical(0), true, "First bit should be true");
assertEqual(b.read_logical(1), false, "Second bit should be false"); assertEqual(b.read_logical(1), false, "Second bit should be false");
assertEqual(b.read_logical(2), true, "Third bit should be true (1)"); assertEqual(b.read_logical(2), true, "Third bit should be true (1)");
assertEqual(b.read_logical(3), false, "Fourth bit should be false (0)"); assertEqual(b.read_logical(3), false, "Fourth bit should be false (0)");
}, },
test_out_of_range_read_throws_error: function() { test_out_of_range_read_throws_error: function() {
var b = Blob(); var b = Blob();
var threw = false;
b.write_bit(true); b.write_bit(true);
stone(b); stone(b);
var threw = false;
try {
b.read_logical(100);
} catch (e) {
threw = true;
}
assert(threw, "Out of range read should throw");
threw = false; threw = false;
try { var _try1 = function() {
b.read_logical(-1); b.read_logical(100);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "Negative index read should throw"); _try1();
assert(threw, "Out of range read should disrupt");
threw = false;
var _try2 = function() {
b.read_logical(-1);
} disruption {
threw = true;
}
_try2();
assert(threw, "Negative index read should disrupt");
}, },
test_write_and_read_numbers: function() { test_write_and_read_numbers: function() {
var b = Blob(); var b = Blob();
b.write_number(3.14159); b.write_number(3.14159);
@@ -69,41 +67,41 @@ return {
b.write_number(0); b.write_number(0);
b.write_number(1e20); b.write_number(1e20);
stone(b); stone(b);
assertEqual(b.read_number(0), 3.14159, "First number should match"); assertEqual(b.read_number(0), 3.14159, "First number should match");
assertEqual(b.read_number(64), -42, "Second number should match"); assertEqual(b.read_number(64), -42, "Second number should match");
assertEqual(b.read_number(128), 0, "Third number should match"); assertEqual(b.read_number(128), 0, "Third number should match");
assertEqual(b.read_number(192), 1e20, "Fourth number should match"); assertEqual(b.read_number(192), 1e20, "Fourth number should match");
}, },
test_write_and_read_text: function() { test_write_and_read_text: function() {
var b = Blob(); var b = Blob();
b.write_text("Hello"); b.write_text("Hello");
b.write_text("World"); b.write_text("World");
b.write_text("🎉"); b.write_text("🎉");
stone(b); stone(b);
assertEqual(b.read_text(0), "Hello", "First text should match"); assertEqual(b.read_text(0), "Hello", "First text should match");
}, },
test_write_and_read_blobs: function() { test_write_and_read_blobs: function() {
var b1 = Blob(); var b1 = Blob();
b1.write_bit(true); b1.write_bit(true);
b1.write_bit(false); b1.write_bit(false);
b1.write_bit(true); b1.write_bit(true);
var b2 = Blob(10); var b2 = Blob(10);
b2.write_blob(b1); b2.write_blob(b1);
b2.write_bit(false); b2.write_bit(false);
assertEqual(length(b2), 4, "Combined blob should have 4 bits"); assertEqual(length(b2), 4, "Combined blob should have 4 bits");
stone(b2); stone(b2);
assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(1), false); assertEqual(b2.read_logical(1), false);
assertEqual(b2.read_logical(2), true); assertEqual(b2.read_logical(2), true);
assertEqual(b2.read_logical(3), false); assertEqual(b2.read_logical(3), false);
}, },
test_blob_copy_constructor: function() { test_blob_copy_constructor: function() {
var b1 = Blob(); var b1 = Blob();
b1.write_bit(true); b1.write_bit(true);
@@ -111,98 +109,103 @@ return {
b1.write_bit(true); b1.write_bit(true);
b1.write_bit(true); b1.write_bit(true);
stone(b1); stone(b1);
var b2 = Blob(b1); var b2 = Blob(b1);
stone(b2); stone(b2);
assertEqual(length(b2), 4, "Copied blob should have same length"); assertEqual(length(b2), 4, "Copied blob should have same length");
assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(3), true); assertEqual(b2.read_logical(3), true);
}, },
test_blob_partial_copy_constructor: function() { test_blob_partial_copy_constructor: function() {
var b1 = Blob(); var b1 = Blob();
for (var i = 0; i < 10; i++) { var i = 0;
for (i = 0; i < 10; i++) {
b1.write_bit(i % 2 == 0); b1.write_bit(i % 2 == 0);
} }
stone(b1); stone(b1);
var b2 = Blob(b1, 2, 7); var b2 = Blob(b1, 2, 7);
stone(b2); stone(b2);
assertEqual(length(b2), 5, "Partial copy should have 5 bits"); assertEqual(length(b2), 5, "Partial copy should have 5 bits");
assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(2), true); assertEqual(b2.read_logical(2), true);
}, },
test_create_blob_with_fill: function() { test_create_blob_with_fill: function() {
var b1 = Blob(8, true); var b1 = Blob(8, true);
var b2 = Blob(8, false); var b2 = Blob(8, false);
var i = 0;
stone(b1); stone(b1);
stone(b2); stone(b2);
for (var i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true"); assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true");
assertEqual(b2.read_logical(i), false, "Bit " + i + " should be false"); assertEqual(b2.read_logical(i), false, "Bit " + i + " should be false");
} }
}, },
test_create_blob_with_random_function: function() { test_create_blob_with_random_function: function() {
var sequence = [true, false, true, true, false]; var sequence = [true, false, true, true, false];
var index = 0; var index = 0;
var i = 0;
var b = Blob(5, function() { var b = Blob(5, function() {
return sequence[index++] ? 1 : 0; return sequence[index++] ? 1 : 0;
}); });
stone(b); stone(b);
for (var i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence"); assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence");
} }
}, },
test_write_pad_and_check_padding: function() { test_write_pad_and_check_padding: function() {
var b = Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
b.write_bit(false); b.write_bit(false);
b.write_bit(true); b.write_bit(true);
b.write_pad(8); b.write_pad(8);
assertEqual(length(b), 8, "Should be padded to 8 bits"); assertEqual(length(b), 8, "Should be padded to 8 bits");
stone(b); stone(b);
assert(b['pad?'](3, 8), "Should detect valid padding at position 3"); assert(b['pad?'](3, 8), "Should detect valid padding at position 3");
assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2"); assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2");
}, },
test_read_blob_from_stone_blob: function() { test_read_blob_from_stone_blob: function() {
var b1 = Blob(); var b1 = Blob();
for (var i = 0; i < 16; i++) { var i = 0;
for (i = 0; i < 16; i++) {
b1.write_bit(i % 3 == 0); b1.write_bit(i % 3 == 0);
} }
stone(b1); stone(b1);
var b2 = b1.read_blob(4, 12); var b2 = b1.read_blob(4, 12);
stone(b2); stone(b2);
assertEqual(length(b2), 8, "Read blob should have 8 bits"); assertEqual(length(b2), 8, "Read blob should have 8 bits");
assertEqual(b2.read_logical(2), true); assertEqual(b2.read_logical(2), true);
assertEqual(b2.read_logical(5), true); assertEqual(b2.read_logical(5), true);
}, },
test_stone_blob_is_immutable: function() { test_stone_blob_is_immutable: function() {
var b = Blob(); var b = Blob();
var threw = false;
b.write_bit(true); b.write_bit(true);
stone(b); stone(b);
var threw = false; var _try = function() {
try {
b.write_bit(false); b.write_bit(false);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "Writing to stone blob should throw error"); _try();
assert(threw, "Writing to stone blob should disrupt");
}, },
test_multiple_stone_calls_are_safe: function() { test_multiple_stone_calls_are_safe: function() {
var b = Blob(); var b = Blob();
b.write_bit(true); b.write_bit(true);
@@ -211,149 +214,161 @@ return {
assert(stone.p(b), "Blob should be a stone after stone() call"); assert(stone.p(b), "Blob should be a stone after stone() call");
stone(b); stone(b);
assertEqual(b.read_logical(0), true, "Blob data should remain intact"); assertEqual(b.read_logical(0), true, "Blob data should remain intact");
assert(b.stone == null, "blob.stone should not be available as a method"); assert(b.stone == null, "blob.stone should not be available as a method");
}, },
test_invalid_constructor_arguments: function() { test_invalid_constructor_arguments: function() {
var threw = false; var threw = false;
try { var _try = function() {
var b = Blob("invalid"); var b = Blob("invalid");
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "Invalid constructor arguments should throw"); _try();
assert(threw, "Invalid constructor arguments should disrupt");
}, },
test_write_bit_validation: function() { test_write_bit_validation: function() {
var b = Blob(); var b = Blob();
var threw = false;
b.write_bit(0); b.write_bit(0);
b.write_bit(1); b.write_bit(1);
var threw = false; var _try = function() {
try {
b.write_bit(2); b.write_bit(2);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "write_bit with value 2 should throw"); _try();
assert(threw, "write_bit with value 2 should disrupt");
}, },
test_complex_data_round_trip: function() { test_complex_data_round_trip: function() {
var b = Blob(); var b = Blob();
b.write_text("Test"); b.write_text("Test");
b.write_number(123.456); b.write_number(123.456);
b.write_bit(true); b.write_bit(true);
b.write_bit(false); b.write_bit(false);
b.write_number(-999.999); b.write_number(-999.999);
var originalLength = length(b); var originalLength = length(b);
stone(b); stone(b);
var b2 = Blob(b); var b2 = Blob(b);
stone(b2); stone(b2);
assertEqual(length(b2), originalLength, "Copy should have same length"); assertEqual(length(b2), originalLength, "Copy should have same length");
assertEqual(b2.read_text(0), "Test", "First text should match"); assertEqual(b2.read_text(0), "Test", "First text should match");
}, },
test_zero_capacity_blob: function() { test_zero_capacity_blob: function() {
var b = Blob(0); var b = Blob(0);
assertEqual(length(b), 0, "Zero capacity blob should have length 0"); assertEqual(length(b), 0, "Zero capacity blob should have length 0");
b.write_bit(true); b.write_bit(true);
assertEqual(length(b), 1, "Should expand when writing"); assertEqual(length(b), 1, "Should expand when writing");
}, },
test_large_blob_handling: function() { test_large_blob_handling: function() {
var b = Blob(); var b = Blob();
var testSize = 1000; var testSize = 1000;
var i = 0;
for (var i = 0; i < testSize; i++) {
for (i = 0; i < testSize; i++) {
b.write_bit(i % 7 == 0); b.write_bit(i % 7 == 0);
} }
assertEqual(length(b), testSize, "Should have " + testSize + " bits"); assertEqual(length(b), testSize, "Should have " + testSize + " bits");
stone(b); stone(b);
assertEqual(b.read_logical(0), true, "Bit 0 should be true"); assertEqual(b.read_logical(0), true, "Bit 0 should be true");
assertEqual(b.read_logical(7), true, "Bit 7 should be true"); assertEqual(b.read_logical(7), true, "Bit 7 should be true");
assertEqual(b.read_logical(14), true, "Bit 14 should be true"); assertEqual(b.read_logical(14), true, "Bit 14 should be true");
assertEqual(b.read_logical(15), false, "Bit 15 should be false"); assertEqual(b.read_logical(15), false, "Bit 15 should be false");
}, },
test_non_stone_blob_read_methods_should_throw: function() { test_non_stone_blob_read_methods_should_throw: function() {
var b = Blob(); var b = Blob();
var threw = false;
b.write_bit(true); b.write_bit(true);
b.write_number(42); b.write_number(42);
b.write_text("test"); b.write_text("test");
var threw = false; threw = false;
try { var _try1 = function() {
b.read_logical(0); b.read_logical(0);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "read_logical on non-stone blob should throw"); _try1();
assert(threw, "read_logical on non-stone blob should disrupt");
threw = false; threw = false;
try { var _try2 = function() {
b.read_number(0); b.read_number(0);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "read_number on non-stone blob should throw"); _try2();
assert(threw, "read_number on non-stone blob should disrupt");
threw = false; threw = false;
try { var _try3 = function() {
b.read_text(0); b.read_text(0);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "read_text on non-stone blob should throw"); _try3();
assert(threw, "read_text on non-stone blob should disrupt");
threw = false; threw = false;
try { var _try4 = function() {
b.read_blob(0, 10); b.read_blob(0, 10);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "read_blob on non-stone blob should throw"); _try4();
assert(threw, "read_blob on non-stone blob should disrupt");
threw = false; threw = false;
try { var _try5 = function() {
b['pad?'](0, 8); b['pad?'](0, 8);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "pad? on non-stone blob should throw"); _try5();
assert(threw, "pad? on non-stone blob should disrupt");
}, },
test_empty_text_write_and_read: function() { test_empty_text_write_and_read: function() {
var b = Blob(); var b = Blob();
b.write_text(""); b.write_text("");
stone(b); stone(b);
assertEqual(b.read_text(0), "", "Empty string should round-trip"); assertEqual(b.read_text(0), "", "Empty string should round-trip");
}, },
test_invalid_read_positions: function() { test_invalid_read_positions: function() {
var b = Blob(); var b = Blob();
var threw = false;
b.write_number(42); b.write_number(42);
stone(b); stone(b);
var threw = false;
try {
b.read_number(-10);
} catch (e) {
threw = true;
}
assert(threw, "Negative position should throw");
threw = false; threw = false;
try { var _try1 = function() {
b.read_number(1000); b.read_number(-10);
} catch (e) { } disruption {
threw = true; threw = true;
} }
assert(threw, "Position beyond length should throw"); _try1();
assert(threw, "Negative position should disrupt");
threw = false;
var _try2 = function() {
b.read_number(1000);
} disruption {
threw = true;
}
_try2();
assert(threw, "Position beyond length should disrupt");
} }
} }

View File

@@ -3,23 +3,21 @@ var time = use('time')
return { return {
test_cat: function() { test_cat: function() {
// Create temp file
var tmp = "cat_test.tmp" var tmp = "cat_test.tmp"
var f = fd.open(tmp, 'w') var f = fd.open(tmp, 'w')
fd.write(f, "Hello world") fd.write(f, "Hello world")
fd.close(f) fd.close(f)
var st = time.number() var st = time.number()
var f2 = fd.open(tmp, 'r') var f2 = fd.open(tmp, 'r')
var stat = fd.fstat(f2) var stat = fd.fstat(f2)
var data = fd.read(f2, stat.size); var data = fd.read(f2, stat.size);
fd.close(f2) fd.close(f2)
log.console(`cat took ${time.number()-st}`) log.console(`cat took ${time.number()-st}`)
// fd.read returns a blob, read it as text
stone(data) stone(data)
if (data.read_text(0) != "Hello world") throw "Data mismatch" if (data.read_text(0) != "Hello world") disrupt
fd.unlink(tmp) fd.unlink(tmp)
} }
} }

View File

@@ -4,27 +4,28 @@ var blob = use('blob')
return { return {
test_chunkread: function() { test_chunkread: function() {
// Create temp file
var tmp = "chunk_test.tmp" var tmp = "chunk_test.tmp"
var f = fd.open(tmp, 'w') var f = fd.open(tmp, 'w')
var bigdata = "" var bigdata = ""
for(var i=0; i<100; i++) bigdata += "HelloWorld" // 1000 bytes var i = 0
var chunk = null
for (i = 0; i < 100; i++) bigdata += "HelloWorld"
fd.write(f, bigdata) fd.write(f, bigdata)
fd.close(f) fd.close(f)
var data = blob() var data = blob()
var st = time.number() var st = time.number()
var f2 = fd.open(tmp, 'r') var f2 = fd.open(tmp, 'r')
var chunksize = 1024 // reduced for test var chunksize = 1024
while(true) { while (true) {
var chunk = fd.read(f2, chunksize); chunk = fd.read(f2, chunksize);
data.write_blob(chunk); data.write_blob(chunk);
if (length(chunk) < chunksize * 8) break; if (length(chunk) < chunksize * 8) break;
} }
fd.close(f2) fd.close(f2)
log.console(`read took ${time.number()-st}`) log.console(`read took ${time.number()-st}`)
fd.unlink(tmp) fd.unlink(tmp)
} }
} }

View File

@@ -1,5 +1,5 @@
return { return {
test_disrupt: function() { test_disrupt: function() {
throw 1 disrupt
} }
} }

View File

@@ -2,186 +2,186 @@ var fit = use("fit");
return { return {
and_12_10: function() { and_12_10: function() {
if (fit.and(12, 10) != 8) throw "fit.and(12, 10) expected 8"; if (fit.and(12, 10) != 8) disrupt
}, },
and_16_2: function() { and_16_2: function() {
if (fit.and(16, 2) != 0) throw "fit.and(16, 2) expected 0"; if (fit.and(16, 2) != 0) disrupt
}, },
and_15_3: function() { and_15_3: function() {
if (fit.and(15, 3) != 3) throw "fit.and(15, 3) expected 3"; if (fit.and(15, 3) != 3) disrupt
}, },
and_13_3: function() { and_13_3: function() {
if (fit.and(13, 3) != 1) throw "fit.and(13, 3) expected 1"; if (fit.and(13, 3) != 1) disrupt
}, },
and_string_input: function() { and_string_input: function() {
if (fit.and("10", 3) != null) throw "fit.and('10', 3) expected null"; if (fit.and("10", 3) != null) disrupt
}, },
or_12_10: function() { or_12_10: function() {
if (fit.or(12, 10) != 14) throw "fit.or(12, 10) expected 14"; if (fit.or(12, 10) != 14) disrupt
}, },
or_16_2: function() { or_16_2: function() {
if (fit.or(16, 2) != 18) throw "fit.or(16, 2) expected 18"; if (fit.or(16, 2) != 18) disrupt
}, },
or_15_3: function() { or_15_3: function() {
if (fit.or(15, 3) != 15) throw "fit.or(15, 3) expected 15"; if (fit.or(15, 3) != 15) disrupt
}, },
or_13_3: function() { or_13_3: function() {
if (fit.or(13, 3) != 15) throw "fit.or(13, 3) expected 15"; if (fit.or(13, 3) != 15) disrupt
}, },
xor_12_10: function() { xor_12_10: function() {
if (fit.xor(12, 10) != 6) throw "fit.xor(12, 10) expected 6"; if (fit.xor(12, 10) != 6) disrupt
}, },
xor_16_2: function() { xor_16_2: function() {
if (fit.xor(16, 2) != 18) throw "fit.xor(16, 2) expected 18"; if (fit.xor(16, 2) != 18) disrupt
}, },
xor_15_3: function() { xor_15_3: function() {
if (fit.xor(15, 3) != 12) throw "fit.xor(15, 3) expected 12"; if (fit.xor(15, 3) != 12) disrupt
}, },
xor_13_3: function() { xor_13_3: function() {
if (fit.xor(13, 3) != 14) throw "fit.xor(13, 3) expected 14"; if (fit.xor(13, 3) != 14) disrupt
}, },
xor_float_input: function() { xor_float_input: function() {
if (fit.xor(13.01, 3) != null) throw "fit.xor(13.01, 3) expected null"; if (fit.xor(13.01, 3) != null) disrupt
}, },
left_12_10: function() { left_12_10: function() {
if (fit.left(12, 10) != 12288) throw "fit.left(12, 10) expected 12288"; if (fit.left(12, 10) != 12288) disrupt
}, },
left_16_2: function() { left_16_2: function() {
if (fit.left(16, 2) != 64) throw "fit.left(16, 2) expected 64"; if (fit.left(16, 2) != 64) disrupt
}, },
left_15_53: function() { left_15_53: function() {
if (fit.left(15, 53) != -9007199254740992) throw "fit.left(15, 53) expected -9007199254740992"; if (fit.left(15, 53) != -9007199254740992) disrupt
}, },
right_12_10: function() { right_12_10: function() {
if (fit.right(12, 10) != 0) throw "fit.right(12, 10) expected 0"; if (fit.right(12, 10) != 0) disrupt
}, },
right_19_2: function() { right_19_2: function() {
if (fit.right(19, 2) != 4) throw "fit.right(19, 2) expected 4"; if (fit.right(19, 2) != 4) disrupt
}, },
right_large: function() { right_large: function() {
if (fit.right(-9007199254740992, 53) != 7) throw "fit.right(-9007199254740992, 53) expected 7"; if (fit.right(-9007199254740992, 53) != 7) disrupt
}, },
right_signed: function() { right_signed: function() {
if (fit.right_signed(-2, 1) != -1) throw "fit.right_signed(-2, 1) expected -1"; if (fit.right_signed(-2, 1) != -1) disrupt
}, },
mask_0: function() { mask_0: function() {
if (fit.mask(0) != 0) throw "fit.mask(0) expected 0"; if (fit.mask(0) != 0) disrupt
}, },
mask_1: function() { mask_1: function() {
if (fit.mask(1) != 1) throw "fit.mask(1) expected 1"; if (fit.mask(1) != 1) disrupt
}, },
mask_3: function() { mask_3: function() {
if (fit.mask(3) != 7) throw "fit.mask(3) expected 7"; if (fit.mask(3) != 7) disrupt
}, },
mask_8: function() { mask_8: function() {
if (fit.mask(8) != 255) throw "fit.mask(8) expected 255"; if (fit.mask(8) != 255) disrupt
}, },
mask_16: function() { mask_16: function() {
if (fit.mask(16) != 65535) throw "fit.mask(16) expected 65535"; if (fit.mask(16) != 65535) disrupt
}, },
mask_32: function() { mask_32: function() {
if (fit.mask(32) != 4294967295) throw "fit.mask(32) expected 4294967295"; if (fit.mask(32) != 4294967295) disrupt
}, },
mask_55: function() { mask_55: function() {
if (fit.mask(55) != 36028797018963967) throw "fit.mask(55) expected 36028797018963967"; if (fit.mask(55) != 36028797018963967) disrupt
}, },
mask_56: function() { mask_56: function() {
if (fit.mask(56) != -1) throw "fit.mask(56) expected -1"; if (fit.mask(56) != -1) disrupt
}, },
mask_57: function() { mask_57: function() {
if (fit.mask(57) != null) throw "fit.mask(57) expected null"; if (fit.mask(57) != null) disrupt
}, },
mask_neg1: function() { mask_neg1: function() {
if (fit.mask(-1) != -2) throw "fit.mask(-1) expected -2"; if (fit.mask(-1) != -2) disrupt
}, },
mask_neg3: function() { mask_neg3: function() {
if (fit.mask(-3) != -8) throw "fit.mask(-3) expected -8"; if (fit.mask(-3) != -8) disrupt
}, },
mask_neg8: function() { mask_neg8: function() {
if (fit.mask(-8) != -256) throw "fit.mask(-8) expected -256"; if (fit.mask(-8) != -256) disrupt
}, },
mask_neg16: function() { mask_neg16: function() {
if (fit.mask(-16) != -65536) throw "fit.mask(-16) expected -65536"; if (fit.mask(-16) != -65536) disrupt
}, },
mask_neg32: function() { mask_neg32: function() {
if (fit.mask(-32) != -4294967296) throw "fit.mask(-32) expected -4294967296"; if (fit.mask(-32) != -4294967296) disrupt
}, },
mask_neg55: function() { mask_neg55: function() {
if (fit.mask(-55) != -36028797018963968) throw "fit.mask(-55) expected -36028797018963968"; if (fit.mask(-55) != -36028797018963968) disrupt
}, },
mask_neg56: function() { mask_neg56: function() {
if (fit.mask(-56) != 0) throw "fit.mask(-56) expected 0"; if (fit.mask(-56) != 0) disrupt
}, },
not_0: function() { not_0: function() {
if (fit.not(0) != -1) throw "fit.not(0) expected -1"; if (fit.not(0) != -1) disrupt
}, },
not_1: function() { not_1: function() {
if (fit.not(1) != -2) throw "fit.not(1) expected -2"; if (fit.not(1) != -2) disrupt
}, },
not_neg1: function() { not_neg1: function() {
if (fit.not(-1) != 0) throw "fit.not(-1) expected 0"; if (fit.not(-1) != 0) disrupt
}, },
ones_neg1: function() { ones_neg1: function() {
if (fit.ones(-1) != 56) throw "fit.ones(-1) expected 56"; if (fit.ones(-1) != 56) disrupt
}, },
ones_0: function() { ones_0: function() {
if (fit.ones(0) != 0) throw "fit.ones(0) expected 0"; if (fit.ones(0) != 0) disrupt
}, },
ones_8: function() { ones_8: function() {
if (fit.ones(8) != 1) throw "fit.ones(8) expected 1"; if (fit.ones(8) != 1) disrupt
}, },
ones_18: function() { ones_18: function() {
if (fit.ones(18) != 2) throw "fit.ones(18) expected 2"; if (fit.ones(18) != 2) disrupt
}, },
ones_255: function() { ones_255: function() {
if (fit.ones(255) != 8) throw "fit.ones(255) expected 8"; if (fit.ones(255) != 8) disrupt
}, },
zeros_neg1: function() { zeros_neg1: function() {
if (fit.zeros(-1) != 0) throw "fit.zeros(-1) expected 0"; if (fit.zeros(-1) != 0) disrupt
}, },
zeros_0: function() { zeros_0: function() {
if (fit.zeros(0) != 56) throw "fit.zeros(0) expected 56"; if (fit.zeros(0) != 56) disrupt
}, },
zeros_1: function() { zeros_1: function() {
if (fit.zeros(1) != 55) throw "fit.zeros(1) expected 55"; if (fit.zeros(1) != 55) disrupt
}, },
zeros_2: function() { zeros_2: function() {
if (fit.zeros(2) != 54) throw "fit.zeros(2) expected 54"; if (fit.zeros(2) != 54) disrupt
}, },
zeros_1024: function() { zeros_1024: function() {
if (fit.zeros(1024) != 45) throw "fit.zeros(1024) expected 45"; if (fit.zeros(1024) != 45) disrupt
}, },
rotate_1_1: function() { rotate_1_1: function() {
if (fit.rotate(1, 1) != 2) throw "fit.rotate(1, 1) expected 2"; if (fit.rotate(1, 1) != 2) disrupt
}, },
rotate_neg2_1: function() { rotate_neg2_1: function() {
if (fit.rotate(-2, 1) != -3) throw "fit.rotate(-2, 1) expected -3"; if (fit.rotate(-2, 1) != -3) disrupt
}, },
rotate_full: function() { rotate_full: function() {
if (fit.rotate(1, 56) != 1) throw "fit.rotate(1, 56) expected 1"; if (fit.rotate(1, 56) != 1) disrupt
}, },
rotate_right: function() { rotate_right: function() {
if (fit.rotate(1, -1) != 1 << 55) throw "fit.rotate(1, -1) expected 1 << 55"; if (fit.rotate(1, -1) != 1 << 55) disrupt
}, },
reverse_neg: function() { reverse_neg: function() {
if (fit.reverse(-36028797018963968) != 1) throw "fit.reverse(-36028797018963968) expected 1"; if (fit.reverse(-36028797018963968) != 1) disrupt
}, },
reverse_pi: function() { reverse_pi: function() {
if (fit.reverse(3141592653589793) != 2334719610726733) throw "fit.reverse(3141592653589793) expected 2334719610726733"; if (fit.reverse(3141592653589793) != 2334719610726733) disrupt
}, },
and_out_of_range: function() { and_out_of_range: function() {
if (fit.and(1 << 56, 1) != null) throw "fit.and with out-of-range expected null"; if (fit.and(1 << 56, 1) != null) disrupt
}, },
left_negative_shift: function() { left_negative_shift: function() {
if (fit.left(1, -1) != null) throw "fit.left with negative shift expected null"; if (fit.left(1, -1) != null) disrupt
}, },
left_large_shift: function() { left_large_shift: function() {
if (fit.left(1, 100) != null) throw "fit.left with large shift expected null"; if (fit.left(1, 100) != null) disrupt
}, },
right_negative_shift: function() { right_negative_shift: function() {
if (fit.right(1, -1) != null) throw "fit.right with negative shift expected null"; if (fit.right(1, -1) != null) disrupt
}, },
mask_float: function() { mask_float: function() {
if (fit.mask(3.5) != null) throw "fit.mask with float expected null"; if (fit.mask(3.5) != null) disrupt
} }
} }

View File

@@ -3,5 +3,5 @@ var http = use('http')
return function() { return function() {
var url = "http://example.com" var url = "http://example.com"
var b2 = http.fetch(url) var b2 = http.fetch(url)
if (length(b2) == 0) throw "Empty response" if (length(b2) == 0) disrupt
} }

View File

@@ -6,34 +6,34 @@ return {
var input = "Hello, World!"; var input = "Hello, World!";
var encoded = kim.encode(input); var encoded = kim.encode(input);
var decoded = kim.decode(encoded); var decoded = kim.decode(encoded);
if (input != decoded) throw "ASCII encoding/decoding failed" if (input != decoded) disrupt
}, },
unicode_multilingual: function() { unicode_multilingual: function() {
var input = "Hello, 世界! 🌍 Привет мир"; var input = "Hello, 世界! 🌍 Привет мир";
var encoded = kim.encode(input); var encoded = kim.encode(input);
var decoded = kim.decode(encoded); var decoded = kim.decode(encoded);
if (input != decoded) throw "Unicode multilingual encoding/decoding failed" if (input != decoded) disrupt
}, },
empty_string: function() { empty_string: function() {
var input = " "; var input = " ";
var encoded = kim.encode(input); var encoded = kim.encode(input);
var decoded = kim.decode(encoded); var decoded = kim.decode(encoded);
if (input != decoded) throw "Empty string encoding/decoding failed" if (input != decoded) disrupt
}, },
mixed_unicode_ranges: function() { mixed_unicode_ranges: function() {
var input = "αβγδε АБВГД 你好 😀😎🎉 ∑∏∫"; var input = "αβγδε АБВГД 你好 😀😎🎉 ∑∏∫";
var encoded = kim.encode(input); var encoded = kim.encode(input);
var decoded = kim.decode(encoded); var decoded = kim.decode(encoded);
if (input != decoded) throw "Mixed Unicode ranges encoding/decoding failed" if (input != decoded) disrupt
}, },
high_codepoints: function() { high_codepoints: function() {
var input = "🌍🌎🌏🗺️🧭"; var input = "🌍🌎🌏🗺️🧭";
var encoded = kim.encode(input); var encoded = kim.encode(input);
var decoded = kim.decode(encoded); var decoded = kim.decode(encoded);
if (input != decoded) throw "High codepoints encoding/decoding failed" if (input != decoded) disrupt
} }
} }

View File

@@ -8,79 +8,99 @@ return {
var SOURCE_PATH = "miniz_source.txt" var SOURCE_PATH = "miniz_source.txt"
var ENTRY_PATH = "sample/hello.txt" var ENTRY_PATH = "sample/hello.txt"
var PAYLOAD = "Miniz integration test payload." var PAYLOAD = "Miniz integration test payload."
var source_blob = null
function write_text_file(path, text) { var writer = null
var zip_blob = null
var reader = null
var extracted_blob = null
var extracted_text = null
function write_text_file(path, txt) {
var handle = fd.open(path, "w") var handle = fd.open(path, "w")
fd.write(handle, text) fd.write(handle, txt)
fd.close(handle) fd.close(handle)
} }
try { var _run = function() {
write_text_file(SOURCE_PATH, PAYLOAD) write_text_file(SOURCE_PATH, PAYLOAD)
var source_blob = fd.slurp(SOURCE_PATH) source_blob = fd.slurp(SOURCE_PATH)
var writer = miniz.write(ZIP_PATH) writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY_PATH, source_blob) writer.add_file(ENTRY_PATH, source_blob)
writer = null writer = null
var zip_blob = fd.slurp(ZIP_PATH) zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob) reader = miniz.read(zip_blob)
if (!reader.exists(ENTRY_PATH)) if (!reader.exists(ENTRY_PATH))
throw "entry missing in archive" disrupt
var extracted_blob = reader.slurp(ENTRY_PATH) extracted_blob = reader.slurp(ENTRY_PATH)
var extracted_text = utf8.decode(extracted_blob) extracted_text = utf8.decode(extracted_blob)
if (extracted_text != PAYLOAD) if (extracted_text != PAYLOAD)
throw "extracted text mismatch" disrupt
} finally { } disruption {}
try { fd.unlink(ZIP_PATH) } catch(e) {} _run()
try { fd.unlink(SOURCE_PATH) } catch(e) {}
} var _clean1 = function() { fd.unlink(ZIP_PATH) } disruption {}
_clean1()
var _clean2 = function() { fd.unlink(SOURCE_PATH) } disruption {}
_clean2()
}, },
list_and_count: function() { list_and_count: function() {
var ZIP_PATH = "miniz_list_test.zip" var ZIP_PATH = "miniz_list_test.zip"
var ENTRY1 = "file1.txt" var ENTRY1 = "file1.txt"
var ENTRY2 = "dir/file2.txt" var ENTRY2 = "dir/file2.txt"
var writer = null
try { var zip_blob = null
var writer = miniz.write(ZIP_PATH) var reader = null
var listed = null
var _run = function() {
writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY1, utf8.encode("content1")) writer.add_file(ENTRY1, utf8.encode("content1"))
writer.add_file(ENTRY2, utf8.encode("content2")) writer.add_file(ENTRY2, utf8.encode("content2"))
writer = null writer = null
var zip_blob = fd.slurp(ZIP_PATH) zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob) reader = miniz.read(zip_blob)
var listed = reader.list() listed = reader.list()
if (length(listed) != reader.count()) if (length(listed) != reader.count())
throw "list/count mismatch" disrupt
if (length(listed) != 2) if (length(listed) != 2)
throw "unexpected entry count" disrupt
} finally { } disruption {}
try { fd.unlink(ZIP_PATH) } catch(e) {} _run()
}
var _clean = function() { fd.unlink(ZIP_PATH) } disruption {}
_clean()
}, },
exists_check: function() { exists_check: function() {
var ZIP_PATH = "miniz_exists_test.zip" var ZIP_PATH = "miniz_exists_test.zip"
var ENTRY_PATH = "existing.txt" var ENTRY_PATH = "existing.txt"
var writer = null
try { var zip_blob = null
var writer = miniz.write(ZIP_PATH) var reader = null
var _run = function() {
writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY_PATH, utf8.encode("data")) writer.add_file(ENTRY_PATH, utf8.encode("data"))
writer = null writer = null
var zip_blob = fd.slurp(ZIP_PATH) zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob) reader = miniz.read(zip_blob)
if (!reader.exists(ENTRY_PATH)) if (!reader.exists(ENTRY_PATH))
throw "existing entry not found" disrupt
if (reader.exists("nonexistent.txt")) if (reader.exists("nonexistent.txt"))
throw "nonexistent entry reported as existing" disrupt
} finally { } disruption {}
try { fd.unlink(ZIP_PATH) } catch(e) {} _run()
}
var _clean = function() { fd.unlink(ZIP_PATH) } disruption {}
_clean()
} }
} }

View File

@@ -8,26 +8,34 @@ function stone_if_needed(b) { if (!stone.p(b)) stone(b) }
function bytes_to_blob(bytes) { function bytes_to_blob(bytes) {
var b = blob() var b = blob()
for (var i = 0; i < length(bytes); i++) { var i = 0
var byte = bytes[i] var byte = null
for (var bit = 7; bit >= 0; bit--) b.write_bit((byte >> bit) & 1) var bit = null
for (i = 0; i < length(bytes); i++) {
byte = bytes[i]
for (bit = 7; bit >= 0; bit--) b.write_bit((byte >> bit) & 1)
} }
stone(b) stone(b)
return b return b
} }
function deepCompare(expected, actual, path) { function deepCompare(expected, actual, _path) {
path = path || '' var diff = null
var messages = null
var expKeys = null
var actKeys = null
var i = 0
var path = _path || ''
if (expected == actual) return { passed: true, messages: [] }; if (expected == actual) return { passed: true, messages: [] };
if (is_number(expected) && is_number(actual)) { if (is_number(expected) && is_number(actual)) {
if (isNaN(expected) && isNaN(actual)) if (isNaN(expected) && isNaN(actual))
return { passed: true, messages: [] }; return { passed: true, messages: [] };
var diff = abs(expected - actual); diff = abs(expected - actual);
if (diff <= EPSILON) if (diff <= EPSILON)
return { passed: true, messages: [] }; return { passed: true, messages: [] };
return { return {
passed: false, passed: false,
messages: [ messages: [
@@ -41,7 +49,7 @@ function deepCompare(expected, actual, path) {
stone_if_needed(expected); stone_if_needed(actual) stone_if_needed(expected); stone_if_needed(actual)
if (length(expected) != length(actual)) if (length(expected) != length(actual))
return { passed: false, messages: [`blob length mismatch at ${path}: ${length(expected)} vs ${length(actual)}`] } return { passed: false, messages: [`blob length mismatch at ${path}: ${length(expected)} vs ${length(actual)}`] }
for (var i = 0; i < length(expected); i++) { for (i = 0; i < length(expected); i++) {
if (expected.read_logical(i) != actual.read_logical(i)) if (expected.read_logical(i) != actual.read_logical(i))
return { passed: false, messages: [`blob bit mismatch at ${path}[${i}]`] } return { passed: false, messages: [`blob bit mismatch at ${path}[${i}]`] }
} }
@@ -54,7 +62,7 @@ function deepCompare(expected, actual, path) {
passed: false, passed: false,
messages: [`Array length mismatch at ${path}: expected ${length(expected)}, got ${length(actual)}`] messages: [`Array length mismatch at ${path}: expected ${length(expected)}, got ${length(actual)}`]
}; };
var messages = []; messages = [];
arrfor(expected, function(val, i) { arrfor(expected, function(val, i) {
var result = deepCompare(val, actual[i], `${path}[${i}]`); var result = deepCompare(val, actual[i], `${path}[${i}]`);
if (!result.passed) if (!result.passed)
@@ -64,17 +72,17 @@ function deepCompare(expected, actual, path) {
} }
if (is_object(expected) && is_object(actual)) { if (is_object(expected) && is_object(actual)) {
var expKeys = sort(array(expected)) expKeys = sort(array(expected))
var actKeys = sort(array(actual)) actKeys = sort(array(actual))
if (JSON.stringify(expKeys) != JSON.stringify(actKeys)) if (JSON.stringify(expKeys) != JSON.stringify(actKeys))
return { return {
passed: false, passed: false,
messages: [`Object keys mismatch at ${path}: expected ${expKeys}, got ${actKeys}`] messages: [`Object keys mismatch at ${path}: expected ${expKeys}, got ${actKeys}`]
}; };
var messages = []; messages = [];
arrfor(expKeys, function(key) { arrfor(expKeys, function(key) {
var result = deepCompare(expected[key], actual[key], `${path}.${key}`); var result = deepCompare(expected[key], actual[key], `${path}.${key}`);
if (!result.passed) if (!result.passed)
messages = array(messages, result.messages) messages = array(messages, result.messages)
}) })
return { passed: length(messages) == 0, messages: messages }; return { passed: length(messages) == 0, messages: messages };
@@ -89,26 +97,32 @@ function deepCompare(expected, actual, path) {
function makeTest(test) { function makeTest(test) {
return function() { return function() {
var encoded = test.replacer ? nota.encode(test.input, test.replacer) : nota.encode(test.input); var encoded = test.replacer ? nota.encode(test.input, test.replacer) : nota.encode(test.input);
if (!is_blob(encoded)){ var decoded = null
throw "encode() should return blob"; var expected = null
var key = null
var compareResult = null
if (!is_blob(encoded)) {
disrupt
} }
var decoded = test.reviver ? nota.decode(encoded, test.reviver) : nota.decode(encoded); decoded = test.reviver ? nota.decode(encoded, test.reviver) : nota.decode(encoded);
var expected = test.expected || test.input; expected = test.expected || test.input;
if (expected && (expected.private || expected.system)) { if (expected && (expected.private || expected.system)) {
var key = expected.private ? 'private' : 'system'; key = expected.private ? 'private' : 'system';
expected = { [key]: expected[key] }; expected = { [key]: expected[key] };
} }
var compareResult = deepCompare(expected, decoded); compareResult = deepCompare(expected, decoded);
if (!compareResult.passed) { if (!compareResult.passed) {
throw text(compareResult.messages, '; '); disrupt
} }
}; };
} }
var testarr = [] var testarr = []
for (var i = 0; i < 500; i++) { var i = 0
var t = null
for (i = 0; i < 500; i++) {
push(testarr, 1) push(testarr, 1)
} }
@@ -172,8 +186,8 @@ var testCases = [
]; ];
var tests = {}; var tests = {};
for (var i = 0; i < length(testCases); i++) { for (i = 0; i < length(testCases); i++) {
var t = testCases[i]; t = testCases[i];
tests[t.name] = makeTest(t); tests[t.name] = makeTest(t);
} }

View File

@@ -2,28 +2,17 @@ var time = use('time');
return { return {
test_overling: function() { test_overling: function() {
// Ported from overling.ce
// Note: This test spawns actors and waits for them.
// In a sync function test, we can't easily wait for async actor events unless we block/poll.
// However, the new test runner might expect sync return or a promise (not available yet?).
// For now, we'll just spawn them to ensure no immediate crashes.
// Full async testing might require a different approach or `dmon.poll` style loop if events are exposed.
// Assuming for now that we just verify strict logical errors.
var underlingCount = 0; var underlingCount = 0;
var targetCount = 3; var targetCount = 3;
var i = 0;
// Spawn several underlings
for (var i = 0; i < targetCount; i++) { for (i = 0; i < targetCount; i++) {
$start(function(greet) { $start(function(greet) {
underlingCount++; underlingCount++;
log.console("Underling spawned: " + underlingCount); log.console("Underling spawned: " + underlingCount);
}, "tests/underling_actor", ["test" + i]); }, "tests/underling_actor", ["test" + i]);
} }
// We can't easily wait here without a loop that yields, but this is a single threaded JS env usually.
// If $delay is async, we return immediately.
log.console("Spawned " + targetCount + " underlings (async)"); log.console("Spawned " + targetCount + " underlings (async)");
} }
} }

View File

@@ -20,17 +20,10 @@ return {
} }
] ]
} }
var st = time.number() var st = time.number()
var actor var actor = null
// This test depends on 'tests/comments' which we created as 'comments.cm'
// but 'comments.cm' wraps the actor logic in a function.
// The original 'comments.ce' was an actor script.
// We should probably restore 'comments.ce' as 'comments_actor.ce' for this test to work if it relies on spawning it.
// But 'comments.cm' (the new test file) also has the logic.
// We need an actor file for $start to work with.
$start(e => { $start(e => {
if (actor) return if (actor) return
actor = e.actor actor = e.actor
@@ -39,9 +32,9 @@ return {
log.console(reason) log.console(reason)
else else
log.console(result) log.console(result)
log.console(`took ${time.number()-st} secs`) log.console(`took ${time.number()-st} secs`)
}); });
}, "tests/comments_actor") // We will create this next }, "tests/comments_actor")
} }
} }

View File

@@ -1,247 +1,241 @@
return { return {
// Array conversion tests
test_array_basic: function() { test_array_basic: function() {
var arr1 = ["Hello", " ", "World"] var arr1 = ["Hello", " ", "World"]
var result1 = text(arr1) var result1 = text(arr1)
if (result1 != "Hello World") throw "Basic array concat failed" if (result1 != "Hello World") disrupt
}, },
test_array_separator: function() { test_array_separator: function() {
var arr2 = ["one", "two", "three"] var arr2 = ["one", "two", "three"]
var result2 = text(arr2, ", ") var result2 = text(arr2, ", ")
if (result2 != "one, two, three") throw "Array with separator failed" if (result2 != "one, two, three") disrupt
}, },
test_array_codepoints: function() { test_array_codepoints: function() {
var arr3 = [72, 101, 108, 108, 111] var arr3 = [72, 101, 108, 108, 111]
var result3 = text(arr3) var result3 = text(arr3)
if (result3 != "Hello") throw "Codepoints failed" if (result3 != "Hello") disrupt
}, },
test_array_mixed: function() { test_array_mixed: function() {
var arr4 = ["Hi", 32, "there", 33] var arr4 = ["Hi", 32, "there", 33]
var result4 = text(arr4) var result4 = text(arr4)
if (result4 != "Hi there!") throw "Mixed array failed" if (result4 != "Hi there!") disrupt
}, },
// Radix tests
test_radix_10: function() { test_radix_10: function() {
var result = text(12, 10) var result = text(12, 10)
if (result != "12") throw "Radix 10 failed" if (result != "12") disrupt
}, },
test_radix_8: function() { test_radix_8: function() {
var result = text(12, 8) var result = text(12, 8)
if (result != "14") throw "Radix 8 failed" if (result != "14") disrupt
}, },
test_radix_16: function() { test_radix_16: function() {
var result = text(12, 16) var result = text(12, 16)
if (result != "c") throw "Radix 16 failed" if (result != "c") disrupt
}, },
test_radix_2: function() { test_radix_2: function() {
var result = text(12, 2) var result = text(12, 2)
if (result != "1100") throw "Radix 2 failed" if (result != "1100") disrupt
}, },
test_radix_32: function() { test_radix_32: function() {
var result = text(12, 32) var result = text(12, 32)
if (result != "c") throw "Radix 32 failed" if (result != "c") disrupt
}, },
test_radix_hex_large: function() { test_radix_hex_large: function() {
var result = text(255, 16) var result = text(255, 16)
if (result != "ff") throw "Radix 16 large failed" if (result != "ff") disrupt
}, },
test_radix_negative: function() { test_radix_negative: function() {
var result = text(-42, 10) var result = text(-42, 10)
if (result != "-42") throw "Radix negative failed" if (result != "-42") disrupt
}, },
test_radix_36: function() { test_radix_36: function() {
var result = text(100, 36) var result = text(100, 36)
if (result != "2s") throw "Radix 36 failed" if (result != "2s") disrupt
}, },
// Formatted number tests
test_format_n: function() { test_format_n: function() {
var result = text(123456789.1, "n") var result = text(123456789.1, "n")
if (result != "123456789.1") throw "Format n failed" if (result != "123456789.1") disrupt
}, },
test_format_spaced_decimal: function() { test_format_spaced_decimal: function() {
var result = text(123456789.1, "3s4") var result = text(123456789.1, "3s4")
if (result != "123 456 789.1000") throw "Format 3s4 failed" if (result != "123 456 789.1000") disrupt
}, },
test_format_s: function() { test_format_s: function() {
var result = text(123456789.1, "s") var result = text(123456789.1, "s")
if (result != "123 456 789.1") throw "Format s failed" if (result != "123 456 789.1") disrupt
}, },
test_format_d2: function() { test_format_d2: function() {
var result = text(123456789.1, "d2") var result = text(123456789.1, "d2")
if (result != "123,456,789.10") throw "Format d2 failed" if (result != "123,456,789.10") disrupt
}, },
test_format_4d0: function() { test_format_4d0: function() {
var result = text(123456789.1, "4d0") var result = text(123456789.1, "4d0")
if (result != "1,2345,6789.1") throw "Format 4d0 failed" if (result != "1,2345,6789.1") disrupt
}, },
test_format_e: function() { test_format_e: function() {
var result = text(123456789.1, "e") var result = text(123456789.1, "e")
if (result != "1.234567891e+8") throw "Format e failed" if (result != "1.234567891e+8") disrupt
}, },
test_format_e4: function() { test_format_e4: function() {
var result = text(123456789.1, "e4") var result = text(123456789.1, "e4")
if (result != "1.2346e+8") throw "Format e4 failed" if (result != "1.2346e+8") disrupt
}, },
test_format_i: function() { test_format_i: function() {
var result = text(123456789.1, "i") var result = text(123456789.1, "i")
if (result != "123456789") throw "Format i failed" if (result != "123456789") disrupt
}, },
test_format_8b: function() { test_format_8b: function() {
var result = text(123456789.1, "8b") var result = text(123456789.1, "8b")
if (result != "111_01011011_11001101_00010101") throw "Format 8b failed" if (result != "111_01011011_11001101_00010101") disrupt
}, },
test_format_o: function() { test_format_o: function() {
var result = text(123456789.1, "o") var result = text(123456789.1, "o")
if (result != "726746425") throw "Format o failed" if (result != "726746425") disrupt
}, },
test_format_h: function() { test_format_h: function() {
var result = text(123456789.1, "h") var result = text(123456789.1, "h")
if (result != "75BCD15") throw "Format h failed" if (result != "75BCD15") disrupt
}, },
test_format_t: function() { test_format_t: function() {
var result = text(123456789.1, "t") var result = text(123456789.1, "t")
if (result != "3NQK8N") throw "Format t failed" if (result != "3NQK8N") disrupt
}, },
// Integer formatting tests
test_int_4b8: function() { test_int_4b8: function() {
var result = text(12, "4b8") var result = text(12, "4b8")
if (result != "0000_1100") throw "Int format 4b8 failed" if (result != "0000_1100") disrupt
}, },
test_int_o3: function() { test_int_o3: function() {
var result = text(12, "o3") var result = text(12, "o3")
if (result != "014") throw "Int format o3 failed" if (result != "014") disrupt
}, },
test_int_h4: function() { test_int_h4: function() {
var result = text(12, "h4") var result = text(12, "h4")
if (result != "000C") throw "Int format h4 failed" if (result != "000C") disrupt
}, },
test_int_t2: function() { test_int_t2: function() {
var result = text(12, "t2") var result = text(12, "t2")
if (result != "0C") throw "Int format t2 failed" if (result != "0C") disrupt
}, },
test_int_h_negative: function() { test_int_h_negative: function() {
var result = text(-15, "h") var result = text(-15, "h")
if (result != "-F") throw "Int format negative h failed" if (result != "-F") disrupt
}, },
test_int_b_zero: function() { test_int_b_zero: function() {
var result = text(0, "b") var result = text(0, "b")
if (result != "0") throw "Int format zero b failed" if (result != "0") disrupt
}, },
// Substring tests
test_substr_start: function() { test_substr_start: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 0, 3) var result = text(str, 0, 3)
if (result != "mis") throw "Substr start failed" if (result != "mis") disrupt
}, },
test_substr_middle: function() { test_substr_middle: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 3, 6) var result = text(str, 3, 6)
if (result != "kat") throw "Substr middle failed" if (result != "kat") disrupt
}, },
test_substr_to_end: function() { test_substr_to_end: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 5, null) var result = text(str, 5, null)
if (result != "tonic") throw "Substr to end failed" if (result != "tonic") disrupt
}, },
test_substr_negative_to: function() { test_substr_negative_to: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 0, -4) var result = text(str, 0, -4)
if (result != "miskat") throw "Substr negative to failed" if (result != "miskat") disrupt
}, },
test_substr_negative_from: function() { test_substr_negative_from: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, -3, null) var result = text(str, -3, null)
if (result != "nic") throw "Substr negative from failed" if (result != "nic") disrupt
}, },
test_substr_empty_range: function() { test_substr_empty_range: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 0, 0) var result = text(str, 0, 0)
if (result != "") throw "Substr empty range failed" if (result != "") disrupt
}, },
test_substr_past_end: function() { test_substr_past_end: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 10, null) var result = text(str, 10, null)
if (result != "") throw "Substr past end failed" if (result != "") disrupt
}, },
test_substr_out_of_bounds: function() { test_substr_out_of_bounds: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 11, null) var result = text(str, 11, null)
if (result != null) throw "Substr out of bounds failed" if (result != null) disrupt
}, },
test_substr_invalid_range: function() { test_substr_invalid_range: function() {
var str = "miskatonic" var str = "miskatonic"
var result = text(str, 2, 1) var result = text(str, 2, 1)
if (result != null) throw "Substr invalid range failed" if (result != null) disrupt
}, },
// Edge cases
test_empty_array: function() { test_empty_array: function() {
var result = text([]) var result = text([])
if (result != "") throw "Empty array test failed" if (result != "") disrupt
}, },
test_single_element: function() { test_single_element: function() {
var result = text([42]) var result = text([42])
if (result != "42") throw "Single element array test failed" if (result != "42") disrupt
}, },
test_identity: function() { test_identity: function() {
var result = text("hello") var result = text("hello")
if (result != "hello") throw "Text identity test failed" if (result != "hello") disrupt
}, },
test_invalid_format: function() { test_invalid_format: function() {
var result = text(123, "xyz") var result = text(123, "xyz")
if (result != null) throw "Invalid format test failed" if (result != null) disrupt
}, },
test_tiny_number: function() { test_tiny_number: function() {
var tiny = 0.0000001 var tiny = 0.0000001
var result = text(tiny, "n") var result = text(tiny, "n")
if (search(result, 'e', 0) == null) throw "Tiny number format failed" if (search(result, 'e', 0) == null) disrupt
}, },
test_huge_number: function() { test_huge_number: function() {
var huge = 1e22 var huge = 1e22
var result = text(huge, "n") var result = text(huge, "n")
if (search(result, 'e', 0) == null) throw "Huge number format failed" if (search(result, 'e', 0) == null) disrupt
} }
} }

View File

@@ -1,21 +1,24 @@
var toml = use('toml') var toml = use('toml')
function deep_equal(a, b) { function deep_equal(a, b) {
var keys_a = null
var keys_b = null
var i = 0
if (a == b) return true if (a == b) return true
if (is_null(a) || is_null(b)) return false if (is_null(a) || is_null(b)) return false
if ((is_number(a) && !is_number(b)) || (is_text(a) && !is_text(b)) || (is_object(a) && !is_object(b)) || (is_array(a) && !is_array(b)) || (is_blob(a) && !is_blob(b)) || (is_function(a) && !is_function(b)) || (is_logical(a) && !is_logical(b))) return false if ((is_number(a) && !is_number(b)) || (is_text(a) && !is_text(b)) || (is_object(a) && !is_object(b)) || (is_array(a) && !is_array(b)) || (is_blob(a) && !is_blob(b)) || (is_function(a) && !is_function(b)) || (is_logical(a) && !is_logical(b))) return false
if (is_object(a)) { if (is_object(a)) {
var keys_a = array(a) keys_a = array(a)
var keys_b = array(b) keys_b = array(b)
if (length(keys_a) != length(keys_b)) return false if (length(keys_a) != length(keys_b)) return false
for (var i = 0; i < length(keys_a); i++) { for (i = 0; i < length(keys_a); i++) {
if (!deep_equal(a[keys_a[i]], b[keys_a[i]])) return false if (!deep_equal(a[keys_a[i]], b[keys_a[i]])) return false
} }
return true return true
} }
return false return false
} }
@@ -25,7 +28,7 @@ function test_roundtrip(obj, name) {
if (!deep_equal(obj, decoded)) { if (!deep_equal(obj, decoded)) {
log.console(name + " - Original:", obj) log.console(name + " - Original:", obj)
log.console(name + " - Round-trip:", decoded) log.console(name + " - Round-trip:", decoded)
throw name + " round-trip failed" disrupt
} }
} }
@@ -79,7 +82,7 @@ return {
port: 8080 port: 8080
}, },
beta: { beta: {
ip: "192.168.1.2", ip: "192.168.1.2",
port: 8081 port: 8081
} }
}, },

View File

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

View File

@@ -1,5 +1,6 @@
try { var _try = function() {
var u = use('tests/use') var u = use('tests/use')
} catch(e) { } disruption {
log.console(e) log.console("disruption caught")
} }
_try()

View File

@@ -7,14 +7,18 @@ var EPSILON = 1e-12
function stone_if_needed(b) { if (!stone.p(b)) stone(b) } function stone_if_needed(b) { if (!stone.p(b)) stone(b) }
/* Deep comparison capable of blobs + tolerance for floating diff */ function deep_compare(expected, actual, _path) {
function deep_compare(expected, actual, path) { var diff = null
path = path || '' var msgs = null
var expKeys = null
var actKeys = null
var i = 0
var path = _path || ''
if (expected == actual) return { passed: true, messages: [] } if (expected == actual) return { passed: true, messages: [] }
if (is_number(expected) && is_number(actual)) { if (is_number(expected) && is_number(actual)) {
if (isNaN(expected) && isNaN(actual)) return { passed: true, messages: [] } if (isNaN(expected) && isNaN(actual)) return { passed: true, messages: [] }
var diff = abs(expected - actual) diff = abs(expected - actual)
if (diff <= EPSILON) return { passed: true, messages: [] } if (diff <= EPSILON) return { passed: true, messages: [] }
return { passed: false, messages: [`Value mismatch at ${path}: ${expected} vs ${actual} (diff ${diff})`] } return { passed: false, messages: [`Value mismatch at ${path}: ${expected} vs ${actual} (diff ${diff})`] }
} }
@@ -33,7 +37,7 @@ function deep_compare(expected, actual, path) {
if (is_array(expected) && is_array(actual)) { if (is_array(expected) && is_array(actual)) {
if (length(expected) != length(actual)) if (length(expected) != length(actual))
return { passed: false, messages: [`Array length mismatch at ${path}: ${length(expected)} vs ${length(actual)}`] } return { passed: false, messages: [`Array length mismatch at ${path}: ${length(expected)} vs ${length(actual)}`] }
var msgs = [] msgs = []
arrfor(array(expected), function(i) { arrfor(array(expected), function(i) {
var res = deep_compare(expected[i], actual[i], `${path}[${i}]`) var res = deep_compare(expected[i], actual[i], `${path}[${i}]`)
if (!res.passed) array(msgs, res.messages) if (!res.passed) array(msgs, res.messages)
@@ -42,11 +46,11 @@ function deep_compare(expected, actual, path) {
} }
if (is_object(expected) && is_object(actual)) { if (is_object(expected) && is_object(actual)) {
var expKeys = sort(array(expected)) expKeys = sort(array(expected))
var actKeys = sort(array(actual)) actKeys = sort(array(actual))
if (JSON.stringify(expKeys) != JSON.stringify(actKeys)) if (JSON.stringify(expKeys) != JSON.stringify(actKeys))
return { passed: false, messages: [`Object keys mismatch at ${path}: ${expKeys} vs ${actKeys}`] } return { passed: false, messages: [`Object keys mismatch at ${path}: ${expKeys} vs ${actKeys}`] }
var msgs = [] msgs = []
arrfor(expKeys, function(k) { arrfor(expKeys, function(k) {
var res = deep_compare(expected[k], actual[k], `${path}.${k}`) var res = deep_compare(expected[k], actual[k], `${path}.${k}`)
if (!res.passed) array(msgs, res.messages) if (!res.passed) array(msgs, res.messages)
@@ -58,7 +62,10 @@ function deep_compare(expected, actual, path) {
} }
var testarr = [] var testarr = []
for (var i = 0; i < 500; i++) { push(testarr, 1) } var i = 0
var t = null
var name = null
for (i = 0; i < 500; i++) { push(testarr, 1) }
var testCases = [ var testCases = [
{ name: 'zero', input: 0 }, { name: 'zero', input: 0 },
@@ -84,7 +91,7 @@ var testCases = [
{ name: 'empty_string', input: '' }, { name: 'empty_string', input: '' },
{ name: 'string_cat', input: 'cat' }, { name: 'string_cat', input: 'cat' },
{ name: 'string_unicode', input: 'U+1F4A9 πÇîπüåπéôπüíτ╡╡µûçσ¡ùπÇì ┬½≡ƒÆ⌐┬╗' }, { name: 'string_unicode', input: 'U+1F4A9 「うんち絵文字」 «💩»' },
{ name: 'large_array', input: testarr }, { name: 'large_array', input: testarr },
@@ -106,19 +113,19 @@ var testCases = [
function make_test(t) { function make_test(t) {
return function() { return function() {
var enc = wota.encode(t.input) var enc = wota.encode(t.input)
if (!is_blob(enc)) throw 'encode() should return a blob' if (!is_blob(enc)) disrupt
var dec = wota.decode(enc) var dec = wota.decode(enc)
var cmp = deep_compare(t.input, dec) var cmp = deep_compare(t.input, dec)
if (!cmp.passed) throw text(cmp.messages, '; ') if (!cmp.passed) disrupt
} }
} }
var tests = {} var tests = {}
for (var i = 0; i < length(testCases); i++) { for (i = 0; i < length(testCases); i++) {
var t = testCases[i] t = testCases[i]
var name = t.name || ('case_' + i) name = t.name || ('case_' + i)
tests[name] = make_test(t) tests[name] = make_test(t)
} }

View File

@@ -87,8 +87,8 @@ function parse_toml(toml_text) {
if (current_section[key] == null) return null if (current_section[key] == null) return null
} else if (value == 'true' || value == 'false') { } else if (value == 'true' || value == 'false') {
current_section[key] = value == 'true' current_section[key] = value == 'true'
} else if (is_number(value)) { } else if (number(value) != null) {
current_section[key] = Number(value) current_section[key] = number(value)
} else { } else {
// Unquoted string // Unquoted string
current_section[key] = value current_section[key] = value
@@ -187,8 +187,8 @@ function parse_value(str) {
} }
if (str == 'true' || str == 'false') return str == 'true' if (str == 'true' || str == 'false') return str == 'true'
// Use your existing numeric test; TOML numeric formats are richer, but this keeps your "module TOML" scope. var n = number(str)
if (!isNaN(Number(str))) return Number(str) if (n != null) return n
return str return str
} }