javascript/demo/demo_std.js · 9089 字节 · 下载原文
// demo_std.js —— **第 1 层:标准输入输出**(JavaScript 的 console.log)
// demo_std.js -- **layer 1: standard output** (JavaScript's console.log)
//
// 这一层就是语言自己的标准输出:往 stdout 写文本。
// This layer is just the language's own standard output: writing text to stdout.
// 也是最基础的一层,也是**唯一有逐字节确定性判据**的一层 —— 下面的输出
// It is also the most basic layer, and the **only one with a byte-for-byte deterministic criterion** -- the output below
// 跑两遍完全一样(不读输入、不用随机数、不看时间)。
// is identical on two runs (it reads no input, uses no random numbers and looks at no clock).
//
// ## 判据
// ## The criterion
//
// vmlcli Examples/javascript/demo_std.js
//
// 期望 stdout 逐字节等于本文件末尾「期望输出」那段。
// The expected stdout is byte-for-byte equal to the "expected output" block at the end of this file.
//
// ## ⚠ 本前端实测的三条限制(写 demo 时避开)
// ## ⚠ Three measured limitations of this frontend (avoid them when writing a demo)
//
// · ~~**字符串 + 数字编出来的结果是错的**~~ —— ✅ **已修(v0.96.831,清单 BUG-04)**:
// 现在 `"a=" + a` 真的拼出 `a=17`(字符串拼接走 `js_string_concat`)。
// · ~~**String + number compiles to a wrong result**~~ -- ✅ **fixed (v0.96.831, list item BUG-04)**:
// `"a=" + a` now really yields `a=17` (concatenation goes through `js_string_concat`).
// · (以下是**修复前**的旧记录,留着备查)**字符串 + 数字编出来的结果是错的** —— `console.log("a=" + a)` 打出
// · **String + number compiles to a wrong result** -- `console.log("a=" + a)` prints
// `2109`(地址量级的值),`console.log("line " + i)` 打出 `1059/1060/1061`。
// `2109` (an address-sized value), and `console.log("line " + i)` prints `1059/1060/1061`.
// 所以本 demo **一个 `"..." + n` 都不用**,靠 `console.log` 的**多实参**
// So this demo uses **not a single `"..." + n`**, relying instead on the **multiple arguments** of `console.log`
// (`console.log("a=", a)` → `a=17`,数字实参本身是对的)。
// (`console.log("a=", a)` -> `a=17`; the numeric argument itself is correct).
// · `console.log` **不插分隔符**:`console.log("line", i)` 打出 `line0`。
// · `console.log` **inserts no separator**: `console.log("line", i)` prints `line0`.
// · **没有 `String(n)` / `n.toString()`**(两个都报「未定义的函数」),
// · **There is no `String(n)` / `n.toString()`** (both report "undefined function"),
// 而 `int_to_str(n)` 恒返回 `0`(实测)⇒ 数字转字符串这条路是断的。
// and `int_to_str(n)` always returns `0` (measured) => the number-to-string path is broken.
// 彩色控制台那一层因此改用**字面量光标坐标**,见 demo_tty.js。
// The color console layer therefore uses **literal cursor coordinates**, see demo_tty.js.
// ⚠ **2026-10-04 复验仍成立**:三条都还在 —— `console.log("a=" + a)` 打出 `1721`(地址量级),`console.log("line " + i)` 打出 `1712`;
// ⚠ **still holds on 2026-10-04**: all three remain -- `console.log("a=" + a)` prints `1721` (address-sized value), `console.log("line " + i)` prints `1712`;
// `console.log("line", 3)` 打出 `line3`(不插分隔符);`String(5)` / `a.toString()` 都报「未定义的函数」;
// `console.log("line", 3)` prints `line3` (no separator); `String(5)` / `a.toString()` both report 「undefined function」;
// `int_to_str(123)` 仍不可用(`console.log` 打出地址 `1721`,trace-draw 里该串画成 `str="0"`)。
// `int_to_str(123)` is still unusable (`console.log` prints the address `1721`; in trace-draw the string draws as `str="0"`).
//
// ## 外部函数:~~必须显式声明~~ —— ✅ **2026-10-04 复验:库函数不声明也能解析;不认识的函数名改报编译错误**
// ## External functions: ~~must be declared explicitly~~ -- ✅ **re-checked 2026-10-04: library functions resolve without a declaration, and an unknown function name is now a compile error**
//
// ~~对不认识的函数名,本前端会先找 `func_<名>`、都没有就**把名字当变量**、~~
// ~~For an unknown function name this frontend first looks for `func_<name>`, and if that is missing it **treats the name as a variable**,~~
// ~~编成「MOVE R1, var_<名>;CALL R0」⇒ 运行期跳野地址。~~(那是**旧行为**,✅ **已修好**:现在直接编译失败)
// ~~compiling "MOVE R1, var_<name>; CALL R0" => a wild jump at run time.~~ (that was the **old behaviour**, ✅ **fixed**: it is now a compile error)
// 实测:不认识的函数名 `noSuchFunc(3)` → `error: 未定义的函数 'noSuchFunc'`;
// measured: an unknown function name `noSuchFunc(3)` -> `error: undefined function 'noSuchFunc'`;
// 而**库函数不用声明也能解析** —— 把本文件的 `#include "vml_ui.js"` 从 /tmp 副本删掉,`✔ 编译完成` 且照常跑完(`ui_scr_get_language()` 取到真值)。
// while **library functions resolve without a declaration** -- delete `#include "vml_ui.js"` from a /tmp copy and it still `✔ compiles` and runs to completion (`ui_scr_get_language()` returns the real value).
// (所以那条 `#include` 是**显式引用**、不是强制项 —— 本文件**照旧**留着它,能跑就别动。)
// (so that `#include` is an **explicit reference**, not a mandatory item -- this file **keeps** it anyway; if it runs, leave it alone.)
// `console.log` 是前端内建的,不用声明。
// `console.log` is built into the frontend, so it needs no declaration.
// UI 库声明走显式引用(文件由 GenLib 产出),不再手抄原型。
// UI declarations come from an explicit include (file generated by GenLib), not hand-copied prototypes.
#include "vml_ui.js"
// 界面语言:开局查一次(`ui_scr_get_language` 是 syscall,别每处都调)
// UI language: queried once at start (`ui_scr_get_language` is a syscall, do not call it everywhere)
let lang = ui_scr_get_language();
const A = 17;
const B = 25;
console.log("=== demo_std (JavaScript) ===");
// ⚠ 这里用**单行 `if/else`** 而不是三元 —— `console.log` 对**非字面量**实参一律编成
// ⚠ A **one-line `if/else`** is used here instead of a ternary -- `console.log` compiles a **non-literal** argument
// `print_int`(实测:`console.log(cond ? "a" : "b")` 打出的是字符串地址,不是文字),
// to `print_int` (measured: `console.log(cond ? "a" : "b")` prints the string address, not the text),
// 只有**字面量**实参才走字符串输出。三元的写法留给 `print_str` / `println` / `ui_*`。
// and only a **literal** argument goes down the string path. The ternary is left to `print_str` / `println` / `ui_*`.
if (lang == 0) { console.log("纯字符串一行"); } else { console.log("A plain string line"); }
if (lang == 0) { console.log("转义:制表\t反斜杠\\引号\""); } else { console.log("escapes: tab\tbackslash\\quote\""); }
console.log("a=", A, " b=", B);
console.log("a+b=", A + B, " a-b=", A - B, " a*b=", A * B);
console.log("a/b=", A / B, " a%b=", A % B);
if (lang == 0) { console.log("负数: ", 0 - A, " ", 0 - (A * B)); } else { console.log("negatives: ", 0 - A, " ", 0 - (A * B)); }
// 循环算一个结果,证明这一层和语言本身是通的
// Compute one result in a loop, proving this layer and the language itself are wired up
let i = 1;
let total = 0;
while (i <= 10) {
total = total + i * i;
i = i + 1;
}
console.log("1^2+...+10^2 = ", total);
// 九九表的一小段(多行)
// A short stretch of the multiplication table (several lines)
i = 1;
while (i <= 5) {
console.log(i, " x 7 = ", i * 7);
i = i + 1;
}
if (lang == 0) { console.log("=== 完成 ==="); } else { console.log("=== done ==="); }
// ── 期望输出(逐字节)────────────────────────────────────────────
// -- Expected output (byte-for-byte; each line below is printed in Chinese, and the line under it is its translation) --
// === demo_std (JavaScript) ===
// 纯字符串一行
// A plain string line
// 转义:制表 反斜杠\引号"
// Escapes: tab\tbackslash\\quote"
// a=17 b=25
// a+b=42 a-b=-8 a*b=425
// a/b=0.68 a%b=17
// 负数: -17 -425
// Negative numbers: -17 -425
// 1^2+...+10^2 = 385
// 1 x 7 = 7
// 2 x 7 = 14
// 3 x 7 = 21
// 4 x 7 = 28
// 5 x 7 = 35
// === 完成 ===
// === Done ===
// ────────────────────────────────────────────────────────────────