Meet JSON's functional half-brother.
If your business logic has a single-source-of-truth (SSOT) problem, JSOL may help.
I built JSOL because I didn't want to keep maintaining the same rules twice (once for the server, once again for the browser) on IPAX, a color science framework for accessible design systems. Every change meant updating both, testing both, and hoping they still agreed.
Did you know that something as simple as modulo can give you different results across languages? My LLM didn't. Turns out that 7.5 % 2 is 1.5 in JS… and 1 in PHP. And that's just one bug that slipped through code review.
Since most general-use languages today are somehow C-like, I wondered if there was some lingua franca we could use to declare business logic once, and include afterwards in our code with bit-for-bit parity.
That's how JSOL was born: a strict subset of JavaScript that transpiles to JavaScript, PHP, TypeScript and Python (with more targets planned), guaranteeing deterministic parity. Write the rule once, change it once, test it once.
Think JSON, but for business logic.
Is it worth your time?
The first question we developers ask about a new tool is: "Should I bother learning this?"
JSOL has strict syntax, zero syntactic sugar, and a learning curve. Writing it — even with an AI's help — will take you longer than writing native code you've already mastered. But JSOL's upfront cost can pay off in iterative maintenance.
The honest way to answer that question is with a model. So the first example below is exactly that: an adoption-economics model written in JSOL, running live in the REPL. And compiled to every target for inspection.
Play with the inputs: how many targets you maintain, how often your rules change, how many iterations until the upfront cost pays for itself. Add rows to evaluate different scenarios. And while you're at it, you're watching JSOL do what it was built to do.
(INPUT)
(OUTPUT)
Function: $sTestPrimitive
// @JSOL v0.2.96
/**
@description
# Core Primitives Test Suite - Switch Pattern
A complete validation suite that tests every primitive domain method specified in **JSOL v0.3**.
Designed using a **STRICT SWITCH routing pattern** to specifically stress-test the compiler's
support for `switch` statements without fallthrough. Each method is evaluated in isolation
as a separate row in the **JSOL REPL Interpreter**, preventing a single unimplemented function
from crashing the entire test suite.
## Key Design Decisions
- **Strict Switch Pattern**: Specifically tests compiler support for switch without fallthrough
- **Isolation**: Each method runs independently to prevent cascade failures
- **Complementary Testing**: IF-ELSE version available in `.ifs.jsol.js`
## Parameters
- **@param {string} $sMethod** - The name of the method to evaluate.
## Returns
- **@returns {string}** - The stringified result of the evaluation.
## Test Cases
The following methods are tested across all primitive domains:
### String Methods
- `Str.len`
- `Str.sub`
- `Str.indexOf`
- `Str.replace`
- `Str.char`
- `Str.fromChar`
- `Str.upper`
- `Str.lower`
- `Str.trim`
- `Str.split`
### Array Methods
- `Arr.count`
- `Arr.push`
- `Arr.pop`
- `Arr.shift`
- `Arr.slice`
- `Arr.indexOf`
- `Arr.join`
### Map Methods
- `Map.create`
- `Map.has`
- `Map.keys`
### Math Methods
- `Math.floor`
- `Math.abs`
- `Math.pow`
- `Math.min`
- `Math.max`
- `Math.round`
### Bitwise Methods
- `Bit.and`
- `Bit.or`
- `Bit.xor`
- `Bit.not`
- `Bit.shiftL`
- `Bit.shiftR`
### Casting Methods
- `Cast.toStr`
- `Cast.toInt`
- `Cast.toFloat`
### Regex Methods
- `Regex.match`
- `Regex.replace`
- `Regex.test`
*/
/**
@contract
{
"cases": [
{ "$sMethod": "Str.len" },
{ "$sMethod": "Str.sub" },
{ "$sMethod": "Str.indexOf" },
{ "$sMethod": "Str.replace" },
{ "$sMethod": "Str.char" },
{ "$sMethod": "Str.fromChar" },
{ "$sMethod": "Str.upper" },
{ "$sMethod": "Str.lower" },
{ "$sMethod": "Str.trim" },
{ "$sMethod": "Str.split" },
{ "$sMethod": "Arr.count" },
{ "$sMethod": "Arr.push" },
{ "$sMethod": "Arr.pop" },
{ "$sMethod": "Arr.shift" },
{ "$sMethod": "Arr.slice" },
{ "$sMethod": "Arr.indexOf" },
{ "$sMethod": "Arr.join" },
{ "$sMethod": "Map.create" },
{ "$sMethod": "Map.has" },
{ "$sMethod": "Map.keys" },
{ "$sMethod": "Math.floor" },
{ "$sMethod": "Math.abs" },
{ "$sMethod": "Math.pow" },
{ "$sMethod": "Math.min" },
{ "$sMethod": "Math.max" },
{ "$sMethod": "Math.round" },
{ "$sMethod": "Bit.and" },
{ "$sMethod": "Bit.or" },
{ "$sMethod": "Bit.xor" },
{ "$sMethod": "Bit.not" },
{ "$sMethod": "Bit.shiftL" },
{ "$sMethod": "Bit.shiftR" },
{ "$sMethod": "Cast.toStr" },
{ "$sMethod": "Cast.toInt" },
{ "$sMethod": "Cast.toFloat" },
{ "$sMethod": "Regex.match" },
{ "$sMethod": "Regex.replace" },
{ "$sMethod": "Regex.test" }
]
}
*/
const $sTestPrimitive = function($sMethod) {
switch ($sMethod) {
case "Str.len": return Cast.toStr(Str.len("abc"));
case "Str.sub": return Str.sub("abc", 1, 1);
case "Str.indexOf": return Cast.toStr(Str.indexOf("abc", "b"));
case "Str.replace": return Str.replace("abc", "b", "x");
case "Str.char": return Cast.toStr(Str.char("abc", 0));
case "Str.fromChar": return Str.fromChar(97);
case "Str.upper": return Str.upper("abc");
case "Str.lower": return Str.lower("ABC");
case "Str.trim": return Str.trim(" abc ");
case "Str.split": {
const $aSplit = Str.split("a,b", ",");
return Arr.join($aSplit, "-");
}
case "Arr.count": return Cast.toStr(Arr.count(["x", "y"]));
case "Arr.push": {
const $aPush = ["x", "y"];
Arr.push($aPush, "z");
return Arr.join($aPush, "-");
}
case "Arr.pop": {
const $aPop = ["x", "y", "z"];
const $sPopped = Arr.pop($aPop);
return "popped: " + "" + $sPopped + "" + " left: " + "" + Arr.join($aPop, "-");
}
case "Arr.shift": {
const $aShift = ["x", "y"];
const $sShifted = Arr.shift($aShift);
return "shifted: " + "" + $sShifted + "" + " left: " + "" + Arr.join($aShift, "-");
}
case "Arr.slice": {
const $aSlice = Arr.slice(["a", "b", "c"], 1, 3);
return Arr.join($aSlice, "-");
}
case "Arr.indexOf": return Cast.toStr(Arr.indexOf(["a", "b", "c"], "b"));
case "Arr.join": return Arr.join(["a", "b"], ",");
case "Map.create": {
const $mTest1 = Map.create("k1", "v1");
if ($mTest1["k1"] === "v1") { return "ok"; }
return "fail";
}
case "Map.has": {
const $mTest2 = Map.create("k1", "v1");
return Cast.toStr(Map.has($mTest2, "k1"));
}
case "Map.keys": {
const $mTest3 = Map.create("k1", "v1", "k2", "v2");
const $aKeys = Map.keys($mTest3);
return Arr.join($aKeys, "-");
}
case "Math.floor": return Cast.toStr(Math.floor(1.9));
case "Math.abs": return Cast.toStr(Math.abs(-5));
case "Math.pow": return Cast.toStr(Math.pow(2, 3));
case "Math.min": return Cast.toStr(Math.min(10, 2));
case "Math.max": return Cast.toStr(Math.max(10, 2));
case "Math.round": return Cast.toStr(Math.round(1.5));
case "Bit.and": return Cast.toStr(Bit.and(3, 1));
case "Bit.or": return Cast.toStr(Bit.or(1, 2));
case "Bit.xor": return Cast.toStr(Bit.xor(1, 3));
case "Bit.not": return Cast.toStr(Bit.not(1));
case "Bit.shiftL": return Cast.toStr(Bit.shiftL(1, 1));
case "Bit.shiftR": return Cast.toStr(Bit.shiftR(2, 1));
case "Cast.toStr": return Cast.toStr(100);
case "Cast.toInt": return Cast.toStr(Cast.toInt("100"));
case "Cast.toFloat": return Cast.toStr(Cast.toFloat("100.5"));
case "Regex.match": {
const $mMatch = Regex.match("^a(b)c$", "abc", "i");
if (Map.has($mMatch, "matched") && $mMatch["matched"] === true) {
return "true";
}
return "false";
}
case "Regex.replace": return Regex.replace("a", "x", "abc", "");
case "Regex.test": return Cast.toStr(Regex.test("^a", "abc", ""));
default: return "Unknown method";
}
};
// @JSOL v0.2.96
/**
@description
# Core Primitives Test Suite - Switch Pattern
A complete validation suite that tests every primitive domain method specified in **JSOL v0.3**.
Designed using a **STRICT SWITCH routing pattern** to specifically stress-test the compiler's
support for `switch` statements without fallthrough. Each method is evaluated in isolation
as a separate row in the **JSOL REPL Interpreter**, preventing a single unimplemented function
from crashing the entire test suite.
## Key Design Decisions
- **Strict Switch Pattern**: Specifically tests compiler support for switch without fallthrough
- **Isolation**: Each method runs independently to prevent cascade failures
- **Complementary Testing**: IF-ELSE version available in `.ifs.jsol.js`
## Parameters
- **@param {string} $sMethod** - The name of the method to evaluate.
## Returns
- **@returns {string}** - The stringified result of the evaluation.
## Test Cases
The following methods are tested across all primitive domains:
### String Methods
- `Str.len`
- `Str.sub`
- `Str.indexOf`
- `Str.replace`
- `Str.char`
- `Str.fromChar`
- `Str.upper`
- `Str.lower`
- `Str.trim`
- `Str.split`
### Array Methods
- `Arr.count`
- `Arr.push`
- `Arr.pop`
- `Arr.shift`
- `Arr.slice`
- `Arr.indexOf`
- `Arr.join`
### Map Methods
- `Map.create`
- `Map.has`
- `Map.keys`
### Math Methods
- `Math.floor`
- `Math.abs`
- `Math.pow`
- `Math.min`
- `Math.max`
- `Math.round`
### Bitwise Methods
- `Bit.and`
- `Bit.or`
- `Bit.xor`
- `Bit.not`
- `Bit.shiftL`
- `Bit.shiftR`
### Casting Methods
- `Cast.toStr`
- `Cast.toInt`
- `Cast.toFloat`
### Regex Methods
- `Regex.match`
- `Regex.replace`
- `Regex.test`
*/
/**
@contract
{
"cases": [
{ "$sMethod": "Str.len" },
{ "$sMethod": "Str.sub" },
{ "$sMethod": "Str.indexOf" },
{ "$sMethod": "Str.replace" },
{ "$sMethod": "Str.char" },
{ "$sMethod": "Str.fromChar" },
{ "$sMethod": "Str.upper" },
{ "$sMethod": "Str.lower" },
{ "$sMethod": "Str.trim" },
{ "$sMethod": "Str.split" },
{ "$sMethod": "Arr.count" },
{ "$sMethod": "Arr.push" },
{ "$sMethod": "Arr.pop" },
{ "$sMethod": "Arr.shift" },
{ "$sMethod": "Arr.slice" },
{ "$sMethod": "Arr.indexOf" },
{ "$sMethod": "Arr.join" },
{ "$sMethod": "Map.create" },
{ "$sMethod": "Map.has" },
{ "$sMethod": "Map.keys" },
{ "$sMethod": "Math.floor" },
{ "$sMethod": "Math.abs" },
{ "$sMethod": "Math.pow" },
{ "$sMethod": "Math.min" },
{ "$sMethod": "Math.max" },
{ "$sMethod": "Math.round" },
{ "$sMethod": "Bit.and" },
{ "$sMethod": "Bit.or" },
{ "$sMethod": "Bit.xor" },
{ "$sMethod": "Bit.not" },
{ "$sMethod": "Bit.shiftL" },
{ "$sMethod": "Bit.shiftR" },
{ "$sMethod": "Cast.toStr" },
{ "$sMethod": "Cast.toInt" },
{ "$sMethod": "Cast.toFloat" },
{ "$sMethod": "Regex.match" },
{ "$sMethod": "Regex.replace" },
{ "$sMethod": "Regex.test" }
]
}
*/
const $sTestPrimitive = function($sMethod) {
switch ($sMethod) {
case "Str.len": return String("abc".length);
case "Str.sub": return "abc".substring( 1, ( 1) + ( 1));
case "Str.indexOf": return String("abc".indexOf( "b"));
case "Str.replace": return "abc".split( "b").join( "x");
case "Str.char": return String("abc".charCodeAt( 0));
case "Str.fromChar": return String.fromCharCode(97);
case "Str.upper": return "abc".toUpperCase();
case "Str.lower": return "ABC".toLowerCase();
case "Str.trim": return " abc ".trim();
case "Str.split": {
const $aSplit = "a,b".split( ",");
return $aSplit.join( "-");
}
case "Arr.count": return String(["x", "y"].length);
case "Arr.push": {
const $aPush = ["x", "y"];
$aPush.push( "z");
return $aPush.join( "-");
}
case "Arr.pop": {
const $aPop = ["x", "y", "z"];
const $sPopped = $aPop.pop();
return "popped: " + "" + $sPopped + "" + " left: " + "" + $aPop.join( "-");
}
case "Arr.shift": {
const $aShift = ["x", "y"];
const $sShifted = $aShift.shift();
return "shifted: " + "" + $sShifted + "" + " left: " + "" + $aShift.join( "-");
}
case "Arr.slice": {
const $aSlice = ["a", "b", "c"].slice( 1, 3);
return $aSlice.join( "-");
}
case "Arr.indexOf": return String(["a", "b", "c"].indexOf( "b"));
case "Arr.join": return ["a", "b"].join( ",");
case "Map.create": {
const $mTest1 = JSOL.dict("k1", "v1");
if ($mTest1["k1"] === "v1") {
return "ok";
}
return "fail";
}
case "Map.has": {
const $mTest2 = JSOL.dict("k1", "v1");
return String(Object.prototype.hasOwnProperty.call($mTest2, "k1"));
}
case "Map.keys": {
const $mTest3 = JSOL.dict("k1", "v1", "k2", "v2");
const $aKeys = Object.keys($mTest3);
return $aKeys.join( "-");
}
case "Math.floor": return String(Math.floor(1.9));
case "Math.abs": return String(Math.abs(-5));
case "Math.pow": return String(Math.pow(2, 3));
case "Math.min": return String(Math.min(10, 2));
case "Math.max": return String(Math.max(10, 2));
case "Math.round": return String(Math.round(1.5));
case "Bit.and": return String((3 & 1));
case "Bit.or": return String((1 | 2));
case "Bit.xor": return String((1 ^ 3));
case "Bit.not": return String((~1));
case "Bit.shiftL": return String((1 << 1));
case "Bit.shiftR": return String((2 >> 1));
case "Cast.toStr": return String(100);
case "Cast.toInt": return String(parseInt("100", 10));
case "Cast.toFloat": return String(parseFloat("100.5"));
case "Regex.match": {
const $mMatch = Rgx.match("^a(b)c$", "abc", "i");
if (Object.prototype.hasOwnProperty.call($mMatch, "matched") && $mMatch["matched"] === true) {
return "true";
}
return "false";
}
case "Regex.replace": return Rgx.replace("a", "x", "abc", "");
case "Regex.test": return String(Rgx.test("^a", "abc", ""));
default: return "Unknown method";
}
};
window['$sTestPrimitive'] = $sTestPrimitive;
<?php
// @JSOL v0.2.96
/**
@description
# Core Primitives Test Suite - Switch Pattern
A complete validation suite that tests every primitive domain method specified in **JSOL v0.3**.
Designed using a **STRICT SWITCH routing pattern** to specifically stress-test the compiler's
support for `switch` statements without fallthrough. Each method is evaluated in isolation
as a separate row in the **JSOL REPL Interpreter**, preventing a single unimplemented function
from crashing the entire test suite.
## Key Design Decisions
- **Strict Switch Pattern**: Specifically tests compiler support for switch without fallthrough
- **Isolation**: Each method runs independently to prevent cascade failures
- **Complementary Testing**: IF-ELSE version available in `.ifs.jsol.js`
## Parameters
- **@param {string} $sMethod** - The name of the method to evaluate.
## Returns
- **@returns {string}** - The stringified result of the evaluation.
## Test Cases
The following methods are tested across all primitive domains:
### String Methods
- `Str.len`
- `Str.sub`
- `Str.indexOf`
- `Str.replace`
- `Str.char`
- `Str.fromChar`
- `Str.upper`
- `Str.lower`
- `Str.trim`
- `Str.split`
### Array Methods
- `Arr.count`
- `Arr.push`
- `Arr.pop`
- `Arr.shift`
- `Arr.slice`
- `Arr.indexOf`
- `Arr.join`
### Map Methods
- `Map.create`
- `Map.has`
- `Map.keys`
### Math Methods
- `Math.floor`
- `Math.abs`
- `Math.pow`
- `Math.min`
- `Math.max`
- `Math.round`
### Bitwise Methods
- `Bit.and`
- `Bit.or`
- `Bit.xor`
- `Bit.not`
- `Bit.shiftL`
- `Bit.shiftR`
### Casting Methods
- `Cast.toStr`
- `Cast.toInt`
- `Cast.toFloat`
### Regex Methods
- `Regex.match`
- `Regex.replace`
- `Regex.test`
*/
/**
@contract
{
"cases": [
{ "$sMethod": "Str.len" },
{ "$sMethod": "Str.sub" },
{ "$sMethod": "Str.indexOf" },
{ "$sMethod": "Str.replace" },
{ "$sMethod": "Str.char" },
{ "$sMethod": "Str.fromChar" },
{ "$sMethod": "Str.upper" },
{ "$sMethod": "Str.lower" },
{ "$sMethod": "Str.trim" },
{ "$sMethod": "Str.split" },
{ "$sMethod": "Arr.count" },
{ "$sMethod": "Arr.push" },
{ "$sMethod": "Arr.pop" },
{ "$sMethod": "Arr.shift" },
{ "$sMethod": "Arr.slice" },
{ "$sMethod": "Arr.indexOf" },
{ "$sMethod": "Arr.join" },
{ "$sMethod": "Map.create" },
{ "$sMethod": "Map.has" },
{ "$sMethod": "Map.keys" },
{ "$sMethod": "Math.floor" },
{ "$sMethod": "Math.abs" },
{ "$sMethod": "Math.pow" },
{ "$sMethod": "Math.min" },
{ "$sMethod": "Math.max" },
{ "$sMethod": "Math.round" },
{ "$sMethod": "Bit.and" },
{ "$sMethod": "Bit.or" },
{ "$sMethod": "Bit.xor" },
{ "$sMethod": "Bit.not" },
{ "$sMethod": "Bit.shiftL" },
{ "$sMethod": "Bit.shiftR" },
{ "$sMethod": "Cast.toStr" },
{ "$sMethod": "Cast.toInt" },
{ "$sMethod": "Cast.toFloat" },
{ "$sMethod": "Regex.match" },
{ "$sMethod": "Regex.replace" },
{ "$sMethod": "Regex.test" }
]
}
*/
$sTestPrimitive = function($sMethod) {
switch ($sMethod) {
case "Str.len": return (is_bool(mb_strlen("abc", "UTF-8")) ? (mb_strlen("abc", "UTF-8") ? 'true' : 'false') : strval(mb_strlen("abc", "UTF-8")));
case "Str.sub": return mb_substr("abc", 1, 1, "UTF-8");
case "Str.indexOf": return (is_bool(JSOL::strIndexOf("abc", "b")) ? (JSOL::strIndexOf("abc", "b") ? 'true' : 'false') : strval(JSOL::strIndexOf("abc", "b")));
case "Str.replace": return str_replace( "b", "x", "abc");
case "Str.char": return (is_bool(mb_ord(mb_substr("abc", 0, 1, "UTF-8"))) ? (mb_ord(mb_substr("abc", 0, 1, "UTF-8")) ? 'true' : 'false') : strval(mb_ord(mb_substr("abc", 0, 1, "UTF-8"))));
case "Str.fromChar": return mb_chr(97, "UTF-8");
case "Str.upper": return mb_strtoupper("abc", "UTF-8");
case "Str.lower": return mb_strtolower("ABC", "UTF-8");
case "Str.trim": return trim(" abc ");
case "Str.split": {
$aSplit = explode( ",", "a,b");
return implode( "-", $aSplit);
}
case "Arr.count": return (is_bool(count(["x", "y"])) ? (count(["x", "y"]) ? 'true' : 'false') : strval(count(["x", "y"])));
case "Arr.push": {
$aPush = ["x", "y"];
$aPush[] = "z";
return implode( "-", $aPush);
}
case "Arr.pop": {
$aPop = ["x", "y", "z"];
$sPopped = array_pop($aPop);
return "popped: " . "" . $sPopped . "" . " left: " . "" . implode( "-", $aPop);
}
case "Arr.shift": {
$aShift = ["x", "y"];
$sShifted = array_shift($aShift);
return "shifted: " . "" . $sShifted . "" . " left: " . "" . implode( "-", $aShift);
}
case "Arr.slice": {
$aSlice = array_slice(["a", "b", "c"], 1, 3);
return implode( "-", $aSlice);
}
case "Arr.indexOf": return (is_bool(JSOL::arrIndexOf(["a", "b", "c"], "b")) ? (JSOL::arrIndexOf(["a", "b", "c"], "b") ? 'true' : 'false') : strval(JSOL::arrIndexOf(["a", "b", "c"], "b")));
case "Arr.join": return implode( ",", ["a", "b"]);
case "Map.create": {
$mTest1 = JSOL::dict("k1", "v1");
if ($mTest1["k1"] === "v1") {
return "ok";
}
return "fail";
}
case "Map.has": {
$mTest2 = JSOL::dict("k1", "v1");
return (is_bool(isset($mTest2[ "k1"])) ? (isset($mTest2[ "k1"]) ? 'true' : 'false') : strval(isset($mTest2[ "k1"])));
}
case "Map.keys": {
$mTest3 = JSOL::dict("k1", "v1", "k2", "v2");
$aKeys = array_keys($mTest3);
return implode( "-", $aKeys);
}
case "Math.floor": return (is_bool(floor(1.9)) ? (floor(1.9) ? 'true' : 'false') : strval(floor(1.9)));
case "Math.abs": return (is_bool(abs(-5)) ? (abs(-5) ? 'true' : 'false') : strval(abs(-5)));
case "Math.pow": return (is_bool(pow(2, 3)) ? (pow(2, 3) ? 'true' : 'false') : strval(pow(2, 3)));
case "Math.min": return (is_bool(min(10, 2)) ? (min(10, 2) ? 'true' : 'false') : strval(min(10, 2)));
case "Math.max": return (is_bool(max(10, 2)) ? (max(10, 2) ? 'true' : 'false') : strval(max(10, 2)));
case "Math.round": return (is_bool(round(1.5)) ? (round(1.5) ? 'true' : 'false') : strval(round(1.5)));
case "Bit.and": return (is_bool((3 & 1)) ? ((3 & 1) ? 'true' : 'false') : strval((3 & 1)));
case "Bit.or": return (is_bool((1 | 2)) ? ((1 | 2) ? 'true' : 'false') : strval((1 | 2)));
case "Bit.xor": return (is_bool((1 ^ 3)) ? ((1 ^ 3) ? 'true' : 'false') : strval((1 ^ 3)));
case "Bit.not": return (is_bool((~1)) ? ((~1) ? 'true' : 'false') : strval((~1)));
case "Bit.shiftL": return (is_bool((1 << 1)) ? ((1 << 1) ? 'true' : 'false') : strval((1 << 1)));
case "Bit.shiftR": return (is_bool((2 >> 1)) ? ((2 >> 1) ? 'true' : 'false') : strval((2 >> 1)));
case "Cast.toStr": return (is_bool(100) ? (100 ? 'true' : 'false') : strval(100));
case "Cast.toInt": return (is_bool(intval("100")) ? (intval("100") ? 'true' : 'false') : strval(intval("100")));
case "Cast.toFloat": return (is_bool(floatval("100.5")) ? (floatval("100.5") ? 'true' : 'false') : strval(floatval("100.5")));
case "Regex.match": {
$mMatch = Rgx::match("^a(b)c$", "abc", "i");
if (isset($mMatch[ "matched"]) && $mMatch["matched"] === true) {
return "true";
}
return "false";
}
case "Regex.replace": return Rgx::replace("a", "x", "abc", "");
case "Regex.test": return (is_bool(Rgx::test("^a", "abc", "")) ? (Rgx::test("^a", "abc", "") ? 'true' : 'false') : strval(Rgx::test("^a", "abc", "")));
default: return "Unknown method";
}
};
declare var JSOL: any;
declare var Rgx: any;
// @JSOL v0.2.96
/**
@description
# Core Primitives Test Suite - Switch Pattern
A complete validation suite that tests every primitive domain method specified in **JSOL v0.3**.
Designed using a **STRICT SWITCH routing pattern** to specifically stress-test the compiler's
support for `switch` statements without fallthrough. Each method is evaluated in isolation
as a separate row in the **JSOL REPL Interpreter**, preventing a single unimplemented function
from crashing the entire test suite.
## Key Design Decisions
- **Strict Switch Pattern**: Specifically tests compiler support for switch without fallthrough
- **Isolation**: Each method runs independently to prevent cascade failures
- **Complementary Testing**: IF-ELSE version available in `.ifs.jsol.js`
## Parameters
- **@param {string} $sMethod** - The name of the method to evaluate.
## Returns
- **@returns {string}** - The stringified result of the evaluation.
## Test Cases
The following methods are tested across all primitive domains:
### String Methods
- `Str.len`
- `Str.sub`
- `Str.indexOf`
- `Str.replace`
- `Str.char`
- `Str.fromChar`
- `Str.upper`
- `Str.lower`
- `Str.trim`
- `Str.split`
### Array Methods
- `Arr.count`
- `Arr.push`
- `Arr.pop`
- `Arr.shift`
- `Arr.slice`
- `Arr.indexOf`
- `Arr.join`
### Map Methods
- `Map.create`
- `Map.has`
- `Map.keys`
### Math Methods
- `Math.floor`
- `Math.abs`
- `Math.pow`
- `Math.min`
- `Math.max`
- `Math.round`
### Bitwise Methods
- `Bit.and`
- `Bit.or`
- `Bit.xor`
- `Bit.not`
- `Bit.shiftL`
- `Bit.shiftR`
### Casting Methods
- `Cast.toStr`
- `Cast.toInt`
- `Cast.toFloat`
### Regex Methods
- `Regex.match`
- `Regex.replace`
- `Regex.test`
*/
/**
@contract
{
"cases": [
{ "$sMethod": "Str.len" },
{ "$sMethod": "Str.sub" },
{ "$sMethod": "Str.indexOf" },
{ "$sMethod": "Str.replace" },
{ "$sMethod": "Str.char" },
{ "$sMethod": "Str.fromChar" },
{ "$sMethod": "Str.upper" },
{ "$sMethod": "Str.lower" },
{ "$sMethod": "Str.trim" },
{ "$sMethod": "Str.split" },
{ "$sMethod": "Arr.count" },
{ "$sMethod": "Arr.push" },
{ "$sMethod": "Arr.pop" },
{ "$sMethod": "Arr.shift" },
{ "$sMethod": "Arr.slice" },
{ "$sMethod": "Arr.indexOf" },
{ "$sMethod": "Arr.join" },
{ "$sMethod": "Map.create" },
{ "$sMethod": "Map.has" },
{ "$sMethod": "Map.keys" },
{ "$sMethod": "Math.floor" },
{ "$sMethod": "Math.abs" },
{ "$sMethod": "Math.pow" },
{ "$sMethod": "Math.min" },
{ "$sMethod": "Math.max" },
{ "$sMethod": "Math.round" },
{ "$sMethod": "Bit.and" },
{ "$sMethod": "Bit.or" },
{ "$sMethod": "Bit.xor" },
{ "$sMethod": "Bit.not" },
{ "$sMethod": "Bit.shiftL" },
{ "$sMethod": "Bit.shiftR" },
{ "$sMethod": "Cast.toStr" },
{ "$sMethod": "Cast.toInt" },
{ "$sMethod": "Cast.toFloat" },
{ "$sMethod": "Regex.match" },
{ "$sMethod": "Regex.replace" },
{ "$sMethod": "Regex.test" }
]
}
*/
const $sTestPrimitive = function($sMethod: any): string {
switch ($sMethod) {
case "Str.len": return String("abc".length);
case "Str.sub": return "abc".substring( 1, ( 1) + ( 1));
case "Str.indexOf": return String("abc".indexOf( "b"));
case "Str.replace": return "abc".split( "b").join( "x");
case "Str.char": return String("abc".charCodeAt( 0));
case "Str.fromChar": return String.fromCharCode(97);
case "Str.upper": return "abc".toUpperCase();
case "Str.lower": return "ABC".toLowerCase();
case "Str.trim": return " abc ".trim();
case "Str.split": {
const $aSplit: any[] = "a,b".split( ",");
return $aSplit.join( "-");
}
case "Arr.count": return String(["x", "y"].length);
case "Arr.push": {
const $aPush: any[] = ["x", "y"];
$aPush.push( "z");
return $aPush.join( "-");
}
case "Arr.pop": {
const $aPop: any[] = ["x", "y", "z"];
const $sPopped: string = $aPop.pop();
return "popped: " + "" + $sPopped + "" + " left: " + "" + $aPop.join( "-");
}
case "Arr.shift": {
const $aShift: any[] = ["x", "y"];
const $sShifted: string = $aShift.shift();
return "shifted: " + "" + $sShifted + "" + " left: " + "" + $aShift.join( "-");
}
case "Arr.slice": {
const $aSlice: any[] = ["a", "b", "c"].slice( 1, 3);
return $aSlice.join( "-");
}
case "Arr.indexOf": return String(["a", "b", "c"].indexOf( "b"));
case "Arr.join": return ["a", "b"].join( ",");
case "Map.create": {
const $mTest1: Record<string, any> = JSOL.dict("k1", "v1");
if ($mTest1["k1"] === "v1") {
return "ok";
}
return "fail";
}
case "Map.has": {
const $mTest2: Record<string, any> = JSOL.dict("k1", "v1");
return String(Object.prototype.hasOwnProperty.call($mTest2, "k1"));
}
case "Map.keys": {
const $mTest3: Record<string, any> = JSOL.dict("k1", "v1", "k2", "v2");
const $aKeys: any[] = Object.keys($mTest3);
return $aKeys.join( "-");
}
case "Math.floor": return String(Math.floor(1.9));
case "Math.abs": return String(Math.abs(-5));
case "Math.pow": return String(Math.pow(2, 3));
case "Math.min": return String(Math.min(10, 2));
case "Math.max": return String(Math.max(10, 2));
case "Math.round": return String(Math.round(1.5));
case "Bit.and": return String((3 & 1));
case "Bit.or": return String((1 | 2));
case "Bit.xor": return String((1 ^ 3));
case "Bit.not": return String((~1));
case "Bit.shiftL": return String((1 << 1));
case "Bit.shiftR": return String((2 >> 1));
case "Cast.toStr": return String(100);
case "Cast.toInt": return String(parseInt("100", 10));
case "Cast.toFloat": return String(parseFloat("100.5"));
case "Regex.match": {
const $mMatch: Record<string, any> = Rgx.match("^a(b)c$", "abc", "i");
if (Object.prototype.hasOwnProperty.call($mMatch, "matched") && $mMatch["matched"] === true) {
return "true";
}
return "false";
}
case "Regex.replace": return Rgx.replace("a", "x", "abc", "");
case "Regex.test": return String(Rgx.test("^a", "abc", ""));
default: return "Unknown method";
}
};
import math
from jsol_core import JSOL
# @JSOL v0.2.96
#*
# @description
#
# # Core Primitives Test Suite - Switch Pattern
#
# A complete validation suite that tests every primitive domain method specified in **JSOL v0.3**.
# Designed using a **STRICT SWITCH routing pattern** to specifically stress-test the compiler's
# support for `switch` statements without fallthrough. Each method is evaluated in isolation
# as a separate row in the **JSOL REPL Interpreter**, preventing a single unimplemented function
# from crashing the entire test suite.
#
# ## Key Design Decisions
#
# - **Strict Switch Pattern**: Specifically tests compiler support for switch without fallthrough
# - **Isolation**: Each method runs independently to prevent cascade failures
# - **Complementary Testing**: IF-ELSE version available in `.ifs.jsol.js`
#
# ## Parameters
#
# - **@param {string} $sMethod** - The name of the method to evaluate.
#
# ## Returns
#
# - **@returns {string}** - The stringified result of the evaluation.
#
#
#
#
# ## Test Cases
#
# The following methods are tested across all primitive domains:
#
# ### String Methods
# - `Str.len`
# - `Str.sub`
# - `Str.indexOf`
# - `Str.replace`
# - `Str.char`
# - `Str.fromChar`
# - `Str.upper`
# - `Str.lower`
# - `Str.trim`
# - `Str.split`
#
# ### Array Methods
# - `Arr.count`
# - `Arr.push`
# - `Arr.pop`
# - `Arr.shift`
# - `Arr.slice`
# - `Arr.indexOf`
# - `Arr.join`
#
# ### Map Methods
# - `Map.create`
# - `Map.has`
# - `Map.keys`
#
# ### Math Methods
# - `Math.floor`
# - `Math.abs`
# - `Math.pow`
# - `Math.min`
# - `Math.max`
# - `Math.round`
#
# ### Bitwise Methods
# - `Bit.and`
# - `Bit.or`
# - `Bit.xor`
# - `Bit.not`
# - `Bit.shiftL`
# - `Bit.shiftR`
#
# ### Casting Methods
# - `Cast.toStr`
# - `Cast.toInt`
# - `Cast.toFloat`
#
# ### Regex Methods
# - `Regex.match`
# - `Regex.replace`
# - `Regex.test`
#
#*
# @contract
# {
# "cases": [
# { "$sMethod": "Str.len" },
# { "$sMethod": "Str.sub" },
# { "$sMethod": "Str.indexOf" },
# { "$sMethod": "Str.replace" },
# { "$sMethod": "Str.char" },
# { "$sMethod": "Str.fromChar" },
# { "$sMethod": "Str.upper" },
# { "$sMethod": "Str.lower" },
# { "$sMethod": "Str.trim" },
# { "$sMethod": "Str.split" },
# { "$sMethod": "Arr.count" },
# { "$sMethod": "Arr.push" },
# { "$sMethod": "Arr.pop" },
# { "$sMethod": "Arr.shift" },
# { "$sMethod": "Arr.slice" },
# { "$sMethod": "Arr.indexOf" },
# { "$sMethod": "Arr.join" },
# { "$sMethod": "Map.create" },
# { "$sMethod": "Map.has" },
# { "$sMethod": "Map.keys" },
# { "$sMethod": "Math.floor" },
# { "$sMethod": "Math.abs" },
# { "$sMethod": "Math.pow" },
# { "$sMethod": "Math.min" },
# { "$sMethod": "Math.max" },
# { "$sMethod": "Math.round" },
# { "$sMethod": "Bit.and" },
# { "$sMethod": "Bit.or" },
# { "$sMethod": "Bit.xor" },
# { "$sMethod": "Bit.not" },
# { "$sMethod": "Bit.shiftL" },
# { "$sMethod": "Bit.shiftR" },
# { "$sMethod": "Cast.toStr" },
# { "$sMethod": "Cast.toInt" },
# { "$sMethod": "Cast.toFloat" },
# { "$sMethod": "Regex.match" },
# { "$sMethod": "Regex.replace" },
# { "$sMethod": "Regex.test" }
# ]
# }
#
def sTestPrimitive(sMethod):
_jsol_switch = sMethod
_jsol_done = False
while not _jsol_done:
_jsol_done = True
if False: pass
elif _jsol_switch == "Str.len": return JSOL.to_str(len("abc"));
elif _jsol_switch == "Str.sub": return "abc"[( 1):( 1)+( 1)];
elif _jsol_switch == "Str.indexOf": return JSOL.to_str(JSOL.str_index_of("abc", "b"));
elif _jsol_switch == "Str.replace": return "abc".replace( "b", "x");
elif _jsol_switch == "Str.char": return JSOL.to_str(ord("abc"[ 0]));
elif _jsol_switch == "Str.fromChar": return chr(97);
elif _jsol_switch == "Str.upper": return "abc".upper();
elif _jsol_switch == "Str.lower": return "ABC".lower();
elif _jsol_switch == "Str.trim": return " abc ".strip();
elif _jsol_switch == "Str.split":
aSplit = "a,b".split( ",");
return "-".join(str(_x) for _x in aSplit);
elif _jsol_switch == "Arr.count": return JSOL.to_str(len(["x", "y"]));
elif _jsol_switch == "Arr.push":
aPush = ["x", "y"];
aPush.append( "z");
return "-".join(str(_x) for _x in aPush);
elif _jsol_switch == "Arr.pop":
aPop = ["x", "y", "z"];
sPopped = aPop.pop();
return "popped: " + "" + sPopped + "" + " left: " + "" + "-".join(str(_x) for _x in aPop);
elif _jsol_switch == "Arr.shift":
aShift = ["x", "y"];
sShifted = aShift.pop(0);
return "shifted: " + "" + sShifted + "" + " left: " + "" + "-".join(str(_x) for _x in aShift);
elif _jsol_switch == "Arr.slice":
aSlice = ["a", "b", "c"][ 1: 3];
return "-".join(str(_x) for _x in aSlice);
elif _jsol_switch == "Arr.indexOf": return JSOL.to_str(JSOL.arr_index_of(["a", "b", "c"], "b"));
elif _jsol_switch == "Arr.join": return ",".join(str(_x) for _x in ["a", "b"]);
elif _jsol_switch == "Map.create":
mTest1 = JSOL.dict("k1", "v1");
if mTest1["k1"] == "v1":
return "ok";
return "fail";
elif _jsol_switch == "Map.has":
mTest2 = JSOL.dict("k1", "v1");
return JSOL.to_str(( "k1" in mTest2));
elif _jsol_switch == "Map.keys":
mTest3 = JSOL.dict("k1", "v1", "k2", "v2");
aKeys = list(mTest3.keys());
return "-".join(str(_x) for _x in aKeys);
elif _jsol_switch == "Math.floor": return JSOL.to_str(math.floor(1.9));
elif _jsol_switch == "Math.abs": return JSOL.to_str(abs(-5));
elif _jsol_switch == "Math.pow": return JSOL.to_str(pow(2, 3));
elif _jsol_switch == "Math.min": return JSOL.to_str(min(10, 2));
elif _jsol_switch == "Math.max": return JSOL.to_str(max(10, 2));
elif _jsol_switch == "Math.round": return JSOL.to_str(round(1.5));
elif _jsol_switch == "Bit.and": return JSOL.to_str((3 & 1));
elif _jsol_switch == "Bit.or": return JSOL.to_str((1 | 2));
elif _jsol_switch == "Bit.xor": return JSOL.to_str((1 ^ 3));
elif _jsol_switch == "Bit.not": return JSOL.to_str((~1));
elif _jsol_switch == "Bit.shiftL": return JSOL.to_str((1 << 1));
elif _jsol_switch == "Bit.shiftR": return JSOL.to_str((2 >> 1));
elif _jsol_switch == "Cast.toStr": return JSOL.to_str(100);
elif _jsol_switch == "Cast.toInt": return JSOL.to_str(int("100"));
elif _jsol_switch == "Cast.toFloat": return JSOL.to_str(float("100.5"));
elif _jsol_switch == "Regex.match":
mMatch = JSOL.regex_match("^a(b)c$", "abc", "i");
if ( "matched" in mMatch) and mMatch["matched"] == True:
return "true";
return "false";
elif _jsol_switch == "Regex.replace": return JSOL.regex_replace("a", "x", "abc", "");
elif _jsol_switch == "Regex.test": return JSOL.to_str(JSOL.regex_test("^a", "abc", ""));
else: return "Unknown method";
Each example started as a test.
The language and compiler improved because of what these examples demanded. The CLRS examples are here for the same reason: if JSOL aims to be a language someone can read rather than just compile, it has to survive contact with computer science, not just invoicing.
Strict Validation
Finance & Rules
Computer Science
What JSOL is NOT
JSOL is not a full-stack framework, and it's not a general-purpose language. It is an isolated, pure, synchronous calculator.
It doesn't touch the DOM, it doesn't make network requests (no fetch or Async), and it doesn't talk to databases.
Every alternative to JSOL (like Haxe or WebAssembly) buys generality or performance at the cost of requiring a toolchain. JSOL buys zero-toolchain portability by aggressively restricting what you can write.
The Honest Tradeoffs (Where JSOL is worse)
JSOL costs more to write than a native implementation. These are the engine-level restrictions you accept when using it:
| Feature | Native JS / PHP | JSOL | Why it was stripped |
|---|---|---|---|
| Developer Speed | Fast (Syntactic sugar, functional methods) | Slower (Spartan syntax, mandatory imperative loops) | Functional arrays and sugar don't map 1:1 across engines without AST pipelines. |
| Control Flow | Async, Promises, Threads | Strictly Synchronous (Single-thread blocking) | Async control flow has no shared syntax between JS and PHP. |
| State & OOP | Classes, this, Prototypes |
Flat Dicts & Primitives (Higher GC pressure) | Classes diverge wildly. Forbidding them guarantees O(1) property access but forces state copying for large loops. |
| Text Parsing | Native Regex (PCRE / V8) | Procedural loops only (No native regex) | Regex engines differ. Complex patterns can cause ReDoS in one engine but not another. |
Design Pillars
Four principles shape every rule in the specification.
1. Clarity
A JSOL algorithm has to be readable by the person who owns the business logic, not just by a compiler.
This is also why JSOL doesn't standardize how you structure code (nested functions vs. flat scope, for instance) — that's implementation shape, not business logic.
2. Portability
The same source runs correctly on every proven target.
This is where Deterministic Parity comes from: given identical inputs, every target's output has to match, bit for bit.
3. Performance
The compiled output should be no heavier and no slower than it has to be.
This is where Zero Dead Code comes from: nothing gets shipped that a given file doesn't actually use.
4. Developer Experience
Writing, compiling, and debugging JSOL should be as frictionless as the constraints allow.
This is where the AST-free compiler pipeline and Zero Runtime Dependencies come from.
This is an open problem, not a finished product
JSOL works today for JavaScript, PHP, TypeScript and Python. The compiler is self-hosting (i.e., it compiles itself) and the fixed-point convergence tests prove that the output is stable across generations and hosts. But the really interesting work is what comes next.
The project's real bet is that the same approach can extend to other targets. TypeScript, Go, C#, Python, Rust, C: each one is a separate compiler backend, and each one teaches you something different about what "portable business logic" actually requires.
If you're a CS educator or student, EXTENDING.md lays out the feasibility matrix, the JSOL-C leverage effect, and the specific compiler design problems involved.
Fork it. Break it. Build a target. The compiler architecture is deliberately modular: adding a language means writing one compiler file, not rewriting the core.