Files
Interpreter/tests/src/machine_test.cpp
T
Admin 924c0c1923 阶段2-4/2-5:Stb V2(头 128B/槽表段/值段/常量表 8B)+ Codegen V2 重写
Stb.h/.cpp V2:
- 头 128B:kOffSlots/kOffValues/kOffNSlots/kOffValuesSize/kOffMeta/kOffMaxStack
- 常量表 8B(无 tag)、槽表行 8B {addr,预留}、static_assert 更新
- StbView:新字段访问器 + slots_bytes + 段校验 6 段(含元数据空段)

Codegen V2:
- 变长指令发射(Codec 位号,emit/E_rr..E_cal/E_slot_off)
- 槽表→值段布局(1/2/4/8 对齐;实例=1 槽表条目指向字段块)
- 常量表位模式去重(LOADK 按 func 解释);字节化跳转回填
- max_stack(调用图 DAG 最长路径 + 环检测递归报错)
- 用户 FB 内联(LOAD_OFF/STORE_OFF 字段访问);内建 FB → CAL fb_id,slot
- 头 128B 拼装(version=2/STATOR2/段序)

配套:main.cpp 常量显示去 tag;codegen_test 临时剥离(阶段 3 重写);
machine_test 修正(72 op + 负例修复)。ctest:10/13 绿(vm/cases 预期内剥离)。
2026-08-25 20:14:01 +08:00

387 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file machine_test.cpp
* @brief machine.toml V2 加载与强校验测试(阶段 2)
* @author
* @date 2026-08-21
*/
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <string>
#include "compiler/MachineConfig.h"
#include "compiler/Stb.h"
#include "compiler/TypeInfo.h"
#ifndef REPO_ROOT
#define REPO_ROOT "."
#endif
static int g_checks = 0;
#define CHECK(cond) \
do { \
if (!(cond)) { \
std::printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
return false; \
} \
++g_checks; \
} while (0)
// ---- 写临时 toml ----
static std::string write_tmp(const char* name, const std::string& content) {
const std::filesystem::path dir = std::filesystem::temp_directory_path();
const std::filesystem::path path = dir / name;
std::FILE* f = std::fopen(path.string().c_str(), "w");
std::fputs(content.c_str(), f);
std::fclose(f);
return path.string();
}
static bool expect_load_err(const char* name, const std::string& content, const char* keyword) {
const std::string path = write_tmp(name, content);
compiler::MachineConfig cfg;
std::string err;
if (cfg.load(path, &err)) {
std::printf("FAIL %s: loaded ok\n", name);
std::remove(path.c_str());
return false;
}
if (err.find("machine error") != 0) {
std::printf("FAIL %s: want 'machine error', got '%s'\n", name, err.c_str());
std::remove(path.c_str());
return false;
}
if (err.find(keyword) == std::string::npos) {
std::printf("FAIL %s: want '%s', got '%s'\n", name, keyword, err.c_str());
std::remove(path.c_str());
return false;
}
++g_checks;
std::remove(path.c_str());
return true;
}
// 合法 type 模板(19 条全集,可注入损坏;缺 DT 时用于"缺全集"负例)
static const char* kTypesAll =
"[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"bool\"\nfunc = 0\n"
"[[type]]\nname = \"BYTE\"\nbase = \"uint8\"\nkind = \"bit\"\nfunc = 0\n"
"[[type]]\nname = \"WORD\"\nbase = \"uint16\"\nkind = \"bit\"\nfunc = 2\n"
"[[type]]\nname = \"DWORD\"\nbase = \"uint32\"\nkind = \"bit\"\nfunc = 4\n"
"[[type]]\nname = \"LWORD\"\nbase = \"uint64\"\nkind = \"bit\"\nfunc = 6\n"
"[[type]]\nname = \"SINT\"\nbase = \"int8\"\nkind = \"int\"\nfunc = 1\n"
"[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 3\n"
"[[type]]\nname = \"DINT\"\nbase = \"int32\"\nkind = \"int\"\nfunc = 5\n"
"[[type]]\nname = \"LINT\"\nbase = \"int64\"\nkind = \"int\"\nfunc = 7\n"
"[[type]]\nname = \"USINT\"\nbase = \"uint8\"\nkind = \"uint\"\nfunc = 0\n"
"[[type]]\nname = \"UINT\"\nbase = \"uint16\"\nkind = \"uint\"\nfunc = 2\n"
"[[type]]\nname = \"UDINT\"\nbase = \"uint32\"\nkind = \"uint\"\nfunc = 4\n"
"[[type]]\nname = \"ULINT\"\nbase = \"uint64\"\nkind = \"uint\"\nfunc = 6\n"
"[[type]]\nname = \"TIME\"\nbase = \"int64\"\nkind = \"time\"\nfunc = 7\n"
"[[type]]\nname = \"REAL\"\nbase = \"float32\"\nkind = \"float\"\nfunc = 8\n"
"[[type]]\nname = \"LREAL\"\nbase = \"float64\"\nkind = \"float\"\nfunc = 9\n"
"[[type]]\nname = \"DATE\"\nbase = \"uint32\"\nkind = \"date\"\nfunc = 4\n"
"[[type]]\nname = \"TOD\"\nbase = \"uint32\"\nkind = \"date\"\nfunc = 4\n"
"[[type]]\nname = \"DT\"\nbase = \"uint64\"\nkind = \"date\"\nfunc = 6\n";
// 合法 op 模板(含 CAL 与 RET,可注入损坏)
static const char* kOpsBasic =
"[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n"
"[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n"
"[[op]]\nname = \"RET\"\nprefix = \"10\"\nop = 1\nfmt = \"NONE\"\nfunc = \"none\"\nparams = []\nenabled = true\n";
// 合法 fb 模板(15 条全集,可注入损坏)
static const char* kFbsAll =
"[[fb]]\nname = \"TON\"\nfb_id = 0\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
"[[fb]]\nname = \"TOF\"\nfb_id = 1\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
"[[fb]]\nname = \"TP\"\nfb_id = 2\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
"[[fb]]\nname = \"CTU\"\nfb_id = 3\nfields = [[\"cu\", \"BOOL\"], [\"r\", \"BOOL\"], [\"pv\", \"INT\"], [\"q\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
"[[fb]]\nname = \"DCTU\"\nfb_id = 4\nfields = [[\"cu\", \"BOOL\"], [\"r\", \"BOOL\"], [\"pv\", \"DINT\"], [\"q\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
"[[fb]]\nname = \"CTD\"\nfb_id = 5\nfields = [[\"cd\", \"BOOL\"], [\"ld\", \"BOOL\"], [\"pv\", \"INT\"], [\"q\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
"[[fb]]\nname = \"DCTD\"\nfb_id = 6\nfields = [[\"cd\", \"BOOL\"], [\"ld\", \"BOOL\"], [\"pv\", \"DINT\"], [\"q\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
"[[fb]]\nname = \"CTUD\"\nfb_id = 7\nfields = [[\"cu\", \"BOOL\"], [\"cd\", \"BOOL\"], [\"r\", \"BOOL\"], [\"lu\", \"BOOL\"], [\"pv\", \"INT\"], [\"qu\", \"BOOL\"], [\"qd\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
"[[fb]]\nname = \"DCTUD\"\nfb_id = 8\nfields = [[\"cu\", \"BOOL\"], [\"cd\", \"BOOL\"], [\"r\", \"BOOL\"], [\"lu\", \"BOOL\"], [\"pv\", \"DINT\"], [\"qu\", \"BOOL\"], [\"qd\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
"[[fb]]\nname = \"R_TRIG\"\nfb_id = 9\nfields = [[\"clk\", \"BOOL\"], [\"q\", \"BOOL\"]]\n"
"[[fb]]\nname = \"F_TRIG\"\nfb_id = 10\nfields = [[\"clk\", \"BOOL\"], [\"q\", \"BOOL\"]]\n"
"[[fb]]\nname = \"SR\"\nfb_id = 11\nfields = [[\"S1\", \"BOOL\"], [\"R\", \"BOOL\"], [\"Q1\", \"BOOL\"]]\n"
"[[fb]]\nname = \"RS\"\nfb_id = 12\nfields = [[\"SET\", \"BOOL\"], [\"RESET1\", \"BOOL\"], [\"Q1\", \"BOOL\"]]\n"
"[[fb]]\nname = \"PWM\"\nfb_id = 13\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"duty\", \"REAL\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
"[[fb]]\nname = \"RTC\"\nfb_id = 14\nfields = [[\"enable\", \"BOOL\"], [\"date\", \"DATE\"], [\"tod\", \"TOD\"]]\n";
// ---- 1. 正例:仓库 machine.toml ----
static bool test_positive() {
compiler::MachineConfig cfg;
std::string err;
CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &err));
CHECK(cfg.ok());
CHECK(cfg.model_name() == "STATOR");
CHECK(cfg.version() == 2);
CHECK(cfg.types().size() == 19);
const compiler::ConfigType* bt = cfg.find_type("BOOL");
CHECK(bt != nullptr && bt->base == "uint8" && bt->kind == "bool" && bt->func == 0);
CHECK(cfg.find_type("INT") != nullptr && cfg.find_type("INT")->base == "int16" &&
cfg.find_type("INT")->kind == "int" && cfg.find_type("INT")->func == 3);
CHECK(cfg.find_type("REAL") != nullptr && cfg.find_type("REAL")->func == 8);
CHECK(cfg.find_type("LREAL") != nullptr && cfg.find_type("LREAL")->func == 9);
CHECK(cfg.find_type("DATE") != nullptr && cfg.find_type("DATE")->func == 4);
CHECK(cfg.find_type("TOD") != nullptr && cfg.find_type("TOD")->func == 4);
CHECK(cfg.find_type("DT") != nullptr && cfg.find_type("DT")->func == 6);
CHECK(cfg.find_type("NOPE") == nullptr);
CHECK(cfg.ops().size() == 72);
const compiler::ConfigOp* move = cfg.find_op("MOVE");
CHECK(move != nullptr && move->prefix == "11" && move->op == 0 && move->fmt == "RR" &&
move->func_mode == "width" && move->params.size() == 2);
const compiler::ConfigOp* load = cfg.find_op("LOAD");
CHECK(load != nullptr && load->prefix == "010001" && load->fmt == "SLOT" &&
load->func_mode == "full");
const compiler::ConfigOp* cal = cfg.find_op("CAL");
CHECK(cal != nullptr && cal->prefix == "010101" && cal->fmt == "CAL" &&
cal->func_mode == "none" && cal->params.size() == 2);
CHECK(cfg.find_op_by_key("11", 0) != nullptr &&
cfg.find_op_by_key("11", 0)->name == "MOVE");
CHECK(cfg.find_op_by_key("010001", 1) != nullptr &&
cfg.find_op_by_key("010001", 1)->name == "STORE");
CHECK(cfg.op_enabled("11", 0) && cfg.op_enabled("010101", 0));
CHECK(!cfg.op_enabled("11", 63));
CHECK(cfg.find_op("NOPE") == nullptr);
CHECK(cfg.fbs().size() == 15);
const compiler::ConfigFb* ton = cfg.find_fb("TON");
CHECK(ton != nullptr && ton->fb_id == 0 && ton->fields.size() == 4);
CHECK(cfg.find_fb("DCTU") != nullptr && cfg.find_fb("DCTU")->fb_id == 4 &&
cfg.find_fb("DCTU")->fields[2].type == "DINT");
CHECK(cfg.find_fb_by_id(14) != nullptr && cfg.find_fb_by_id(14)->name == "RTC");
CHECK(cfg.find_fb_by_id(15) == nullptr);
// 基元表
CHECK(compiler::MachineConfig::find_prim("int16") != nullptr);
const compiler::PrimType* p = compiler::MachineConfig::find_prim("uint8");
CHECK(p != nullptr && p->width == 1 && !p->is_signed && !p->is_float);
CHECK(compiler::MachineConfig::find_prim("float64") != nullptr);
CHECK(compiler::MachineConfig::find_prim("bfloat16") == nullptr);
return true;
}
// ---- 2. 负例:V2 校验项 ----
static bool test_negative() {
const std::string m = "[meta]\nname = \"STATOR\"\nversion = 2\n";
// version != 2
if (!expect_load_err("mc_v2_bad1.toml",
"[meta]\nname = \"STATOR\"\nversion = 1\n" + std::string(kTypesAll) +
kOpsBasic + kFbsAll,
"version must be 2")) {
return false;
}
// type 缺全集(去掉 DT
{
std::string types = kTypesAll;
const std::string dt = "[[type]]\nname = \"DT\"\nbase = \"uint64\"\nkind = \"date\"\nfunc = 6\n";
const size_t pos = types.find(dt);
types.erase(pos, dt.size());
if (!expect_load_err("mc_v2_bad2.toml", m + types + kOpsBasic + kFbsAll,
"missing 'DT'")) {
return false;
}
}
// base 未命中基元
{
std::string types = kTypesAll;
const std::string old = "[[type]]\nname = \"BYTE\"\nbase = \"uint8\"\nkind = \"bit\"\nfunc = 0\n";
const std::string bad = "[[type]]\nname = \"BYTE\"\nbase = \"bigint\"\nkind = \"bit\"\nfunc = 0\n";
types.replace(types.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad3.toml", m + types + kOpsBasic + kFbsAll,
"unknown base")) {
return false;
}
}
// func 与 base 互锁破坏(INT func=0
{
std::string types = kTypesAll;
const std::string old = "[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 3\n";
const std::string bad = "[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 0\n";
types.replace(types.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad4.toml", m + types + kOpsBasic + kFbsAll,
"func 0 mismatches base")) {
return false;
}
}
// kind 非法
{
std::string types = kTypesAll;
const std::string old = "[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"bool\"\nfunc = 0\n";
const std::string bad = "[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"weird\"\nfunc = 0\n";
types.replace(types.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad5.toml", m + types + kOpsBasic + kFbsAll,
"bad kind")) {
return false;
}
}
// prefix 非法
{
std::string ops = kOpsBasic;
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"99\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
ops.replace(ops.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad6.toml", m + kTypesAll + ops + kFbsAll,
"bad prefix")) {
return false;
}
}
// prefix-fmt 互锁破坏(11 + RRR
{
std::string ops = kOpsBasic;
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RRR\"\nfunc = \"width\"\nparams = [\"rd\", \"ra\", \"rb\"]\nenabled = true\n";
ops.replace(ops.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad7.toml", m + kTypesAll + ops + kFbsAll,
"must pair with fmt")) {
return false;
}
}
// (prefix, op) 分区内重复
{
std::string ops = kOpsBasic;
ops += "[[op]]\nname = \"DUP\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"a\", \"b\"]\nenabled = true\n";
if (!expect_load_err("mc_v2_bad8.toml", m + kTypesAll + ops + kFbsAll,
"duplicate (prefix, op)")) {
return false;
}
}
// func 类别非法
{
std::string ops = kOpsBasic;
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"magic\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
ops.replace(ops.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad9.toml", m + kTypesAll + ops + kFbsAll,
"bad func mode")) {
return false;
}
}
// params 数量与 fmt 不符(CAL 应为 2)
{
std::string ops = kOpsBasic;
const std::string old = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n";
const std::string bad = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\"]\nenabled = true\n";
ops.replace(ops.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad10.toml", m + kTypesAll + ops + kFbsAll,
"params count")) {
return false;
}
}
// fb 缺全集(去掉 RTC
{
std::string fbs = kFbsAll;
const std::string rtc = "[[fb]]\nname = \"RTC\"\nfb_id = 14\nfields = [[\"enable\", \"BOOL\"], [\"date\", \"DATE\"], [\"tod\", \"TOD\"]]\n";
fbs.erase(fbs.find(rtc), rtc.size());
if (!expect_load_err("mc_v2_bad11.toml", m + kTypesAll + kOpsBasic + fbs,
"missing fb_id 14")) {
return false;
}
}
// fb 字段类型未知
{
std::string fbs = kFbsAll;
const std::string old = "[[\"in\", \"BOOL\"], [\"pt\", \"TIME\"]";
const std::string bad = "[[\"in\", \"NOPE\"], [\"pt\", \"TIME\"]";
fbs.replace(fbs.find(old), old.size(), bad);
if (!expect_load_err("mc_v2_bad12.toml", m + kTypesAll + kOpsBasic + fbs,
"unknown field type")) {
return false;
}
}
// 缺 CALop-fb 互锁)
{
std::string ops = kOpsBasic;
const std::string cal = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n";
ops.erase(ops.find(cal), cal.size());
if (!expect_load_err("mc_v2_bad13.toml", m + kTypesAll + ops + kFbsAll,
"op-fb interlock")) {
return false;
}
}
// 语法错误
if (!expect_load_err("mc_v2_bad14.toml", "[meta\nname = \"S\"\n", "parse error")) {
return false;
}
return true;
}
// ---- 3. 类型元数据(TypeInfoV2----
static bool test_type_meta() {
compiler::MachineConfig cfg;
std::string err;
CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &err));
// BOOL1 字节、无符号、kind bool、func 0
const compiler::TypeMeta b = compiler::type_meta(cfg, "BOOL");
CHECK(b && b.width() == 1 && !b.is_signed() && !b.is_float() && b.func() == 0);
CHECK(b.kind() == "bool");
// 大小写不敏感(Linker type_name 是小写)
const compiler::TypeMeta b2 = compiler::type_meta(cfg, "bool");
CHECK(b2 && b2.func() == 0 && b2.width() == 1);
// INT2 字节、有符号、kind int、func 3
const compiler::TypeMeta i = compiler::type_meta(cfg, "int");
CHECK(i && i.width() == 2 && i.is_signed() && !i.is_float() && i.func() == 3);
CHECK(i.kind() == "int");
// REAL4 字节、浮点、func 8TOD4 字节、func 4
const compiler::TypeMeta r = compiler::type_meta(cfg, "REAL");
CHECK(r && r.width() == 4 && r.is_float() && r.func() == 8);
const compiler::TypeMeta tod = compiler::type_meta(cfg, "TOD");
CHECK(tod && tod.width() == 4 && tod.func() == 4);
// 未定义类型 → 空
CHECK(!compiler::type_meta(cfg, "NOPE"));
CHECK(!compiler::type_meta(cfg, ""));
return true;
}
// ---- 4. SHA-256 已知向量 + 型号标识 ----
static bool test_sha256() {
{
uint8_t out[compiler::kSha256Size];
compiler::sha256(nullptr, 0, out);
const uint8_t want[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
CHECK(std::memcmp(out, want, 32) == 0);
}
{
const uint8_t abc[] = {'a', 'b', 'c'};
uint8_t out[compiler::kSha256Size];
compiler::sha256(abc, 3, out);
const uint8_t want[32] = {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
CHECK(std::memcmp(out, want, 32) == 0);
}
// 型号标识:STATOR + 2 → "STATOR2" 补 '\0'
char mid[compiler::kModelIdSize];
compiler::fill_model_id("STATOR", 2, mid);
CHECK(std::strncmp(mid, "STATOR2", 7) == 0);
CHECK(mid[7] == '\0');
CHECK(mid[31] == '\0');
return true;
}
int main() {
if (!test_positive()) return 1;
if (!test_negative()) return 1;
if (!test_type_meta()) return 1;
if (!test_sha256()) return 1;
std::printf("machine_test: %d checks passed\n", g_checks);
return 0;
}