From c782198ddd576f5d9a9da90741d480080f09e685 Mon Sep 17 00:00:00 2001 From: MerlijnW70 <196433316+MerlijnW70@users.noreply.github.com> Date: Wed, 5 Aug 2026 17:13:21 +0200 Subject: [PATCH 1/3] add ViperJS to /engines Embeddable JavaScript engine in safe Rust with zero runtime dependencies, its own backtracking RegExp engine, and a no-panic invariant. Built and smoke-tested locally on jsz-rust/amd64. Co-Authored-By: Claude Opus 5 (1M context) --- engines/viperjs/Dockerfile | 19 +++++++++++++++++++ engines/viperjs/Makefile | 6 ++++++ engines/viperjs/README.md | 20 ++++++++++++++++++++ harness/config.yml | 13 +++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 engines/viperjs/Dockerfile create mode 100644 engines/viperjs/Makefile create mode 100644 engines/viperjs/README.md diff --git a/engines/viperjs/Dockerfile b/engines/viperjs/Dockerfile new file mode 100644 index 00000000..c750a27d --- /dev/null +++ b/engines/viperjs/Dockerfile @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2026 Ivan Krasilnikov +# SPDX-License-Identifier: MIT + +ARG BASE=jsz-rust +FROM $BASE + +WORKDIR /src +ARG REPO=https://github.com/MerlijnW70/viperjs.git +RUN git clone --depth=1 "$REPO" . + +ARG REV=master +RUN git fetch --depth=1 origin "$REV" && git checkout FETCH_HEAD && git rev-parse HEAD + +# No system dependencies: the engine has zero runtime dependencies and an empty +# dependency table, so the base image's stable toolchain is all that is needed. +RUN cargo build --release --bin viper + +COPY build/dist.py ./ +RUN ./dist.py /dist/viperjs --binary=/src/target/release/viper diff --git a/engines/viperjs/Makefile b/engines/viperjs/Makefile new file mode 100644 index 00000000..56866004 --- /dev/null +++ b/engines/viperjs/Makefile @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2026 Ivan Krasilnikov +# SPDX-License-Identifier: MIT + +include ../../build/build.mk + +$(eval $(call build_engine,viperjs,Dockerfile)) diff --git a/engines/viperjs/README.md b/engines/viperjs/README.md new file mode 100644 index 00000000..9ac9c574 --- /dev/null +++ b/engines/viperjs/README.md @@ -0,0 +1,20 @@ +# ViperJS + +Embeddable JavaScript engine in safe Rust, with zero runtime dependencies. + +* Repository: [MerlijnW70/viperjs](https://github.com/MerlijnW70/viperjs.git) StarsLast commit +* LOC: [79132](# "cloc --not_match_d='(?i)(test)' src") +* Language: Rust +* License: MIT OR Apache-2.0 +* Standard: ES2023 (partial) +* Years: 2026- +* Interpreter: stack-based VM +* Regex engine: own (backtracking) + +Notable for what it refuses rather than what it adds: the dependency table is empty and checked +in CI, the crate is `#![forbid(unsafe_code)]`, and no input may panic. `RegExp` is therefore its +own backtracking engine rather than a crate, and there is no `require`, no `fs` and no module +loading in the command-line host — the embedder provides I/O. + +The command line binds one function, `print`. A run can be given a wall-clock budget that a +script cannot `catch`, which is what makes an untrusted script safe to embed. diff --git a/harness/config.yml b/harness/config.yml index 8ba29bd1..53706e17 100644 --- a/harness/config.yml +++ b/harness/config.yml @@ -1426,6 +1426,19 @@ yantra: &yantra timeout_sec: 10 <<: *oom_prone +viperjs: + console_log: print + crash_re: + - *rust_crash_re + stderr_replace_re: + - *rust_crash_norm_re + errors_re: + # viper: TypeError: cannot read a property of something that is not an object + # An uncaught throw is reported on stderr, prefixed with the program name, and exits 1. + - '^viper: (?P[A-Za-z0-9]*Error): (?P.+)$' + # A thrown value that is not an Error keeps whatever ToString gives it. + - '^viper: (?P.+)$' + yrm006: console_log: print stdout_replace_re: From af238d4b123f6a14e2b65cc55ff18cd9818bbeba Mon Sep 17 00:00:00 2001 From: MerlijnW70 Date: Fri, 7 Aug 2026 19:55:28 +0200 Subject: [PATCH 2/3] viperjs: the host binds a console now, and the line count moved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README said the command line binds one function. It binds `print` and a `console` of six logging methods as of 2026-08-06 — `print` is unchanged and still what `console_log` points at, so the harness entry needs nothing. LOC re-measured with the command the README documents: 79132 -> 82328. --- engines/viperjs/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engines/viperjs/README.md b/engines/viperjs/README.md index 9ac9c574..2cfe49da 100644 --- a/engines/viperjs/README.md +++ b/engines/viperjs/README.md @@ -3,7 +3,7 @@ Embeddable JavaScript engine in safe Rust, with zero runtime dependencies. * Repository: [MerlijnW70/viperjs](https://github.com/MerlijnW70/viperjs.git) StarsLast commit -* LOC: [79132](# "cloc --not_match_d='(?i)(test)' src") +* LOC: [82328](# "cloc --not_match_d='(?i)(test)' src") * Language: Rust * License: MIT OR Apache-2.0 * Standard: ES2023 (partial) @@ -16,5 +16,7 @@ in CI, the crate is `#![forbid(unsafe_code)]`, and no input may panic. `RegExp` own backtracking engine rather than a crate, and there is no `require`, no `fs` and no module loading in the command-line host — the embedder provides I/O. -The command line binds one function, `print`. A run can be given a wall-clock budget that a -script cannot `catch`, which is what makes an untrusted script safe to embed. +The command line binds `print` and a `console` of six logging methods — `log`, `info` and `debug` +to standard output, `warn`, `error` and `trace` to standard error. A run can be given a wall-clock +budget that a script cannot `catch`, and a memory budget it cannot exceed, which is what makes an +untrusted script safe to embed. From 381273c3aa2038df74caa7a6b08160313360322f Mon Sep 17 00:00:00 2001 From: Merlijn Date: Wed, 12 Aug 2026 22:26:57 +0200 Subject: [PATCH 3/3] viperjs: re-measure the line count, most of the growth being generated tables cloc with the command the README documents gives 103829, up from 82328. 42017 of that is four generated Unicode tables (properties, normalization, case folding, identifiers), so hand-written is 61812; the growth since the last measurement is String.prototype.normalize and case-insensitive matching data rather than engine. --- engines/viperjs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/viperjs/README.md b/engines/viperjs/README.md index 2cfe49da..f2870f72 100644 --- a/engines/viperjs/README.md +++ b/engines/viperjs/README.md @@ -3,7 +3,7 @@ Embeddable JavaScript engine in safe Rust, with zero runtime dependencies. * Repository: [MerlijnW70/viperjs](https://github.com/MerlijnW70/viperjs.git) StarsLast commit -* LOC: [82328](# "cloc --not_match_d='(?i)(test)' src") +* LOC: [103829](# "cloc --not_match_d='(?i)(test)' src") * Language: Rust * License: MIT OR Apache-2.0 * Standard: ES2023 (partial)