HHYHHY
学习示例扩展规范GitHubEN
EN
HHY

HHY LANGUAGE

HHY 语言手册

V1.3.10Flow-first 系统脚本语言 · 中文完整手册hhylang.dev

CONTENTS

目录

  1. 01快速开始指南
  2. 02语言基础指南
  3. 03Flow 与 Stream指南
  4. 04文件与路径指南
  5. 05文本、JSON 与 CSV指南
  6. 06进程与系统指南
  7. 07HTTP指南
  8. 08并发与监听指南
  9. 09模块与错误指南
  10. 10实战:可直接落地的自动化指南
  11. 11实战项目:FlowGuard实战项目
  12. 12实战项目:DataFlow ETL实战项目
  13. 13实战项目:Asset Governance实战项目
  14. 14实战项目:香港电影公司实战项目
  15. 15实战项目:多 API 数据采集器实战项目
  16. 16实战项目:SiteGraph Auditor实战项目
  17. 17语法完整参考参考
  18. 18标准库函数索引参考
  19. 19CLI 参考参考
  20. 20扩展系统扩展
  21. 21数据库扩展使用指南扩展
  22. 22HTML 扩展与抓取框架扩展
  23. 23语言与 VM 演进路线图路线图
  24. 24编辑器语言支持工具
  25. 25HHY 语言状态报告 · 2026-09-01语言报告

指南 · 01

快速开始

5 分钟安装 HHY、运行第一个 Flow,并掌握日常开发命令。

1.1第 1 分钟:一键安装(推荐)

支持 macOS arm64、Linux x86_64 与 Linux arm64。安装器自动识别平台、下载 V1.3.10 发行包和同名 .sha256,校验通过后才安装;默认不需要 sudo。

sh
curl -fsSL https://hhylang.dev/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
hhy --version
默认安装版本目录为 ~/.local/share/hhy/1.3.10,命令入口为 ~/.local/bin/hhy。安装器默认解析 GitHub 最新稳定版;HHY_VERSION 可用于固定或回滚版本,HHY_INSTALL_ROOT 和 HHY_BIN_DIR 可以覆盖位置。

1.2macOS:通过 Homebrew Tap 安装

Apple Silicon Mac 可以使用仓库内的 Formula。显式绑定 Git 仓库 URL,使当前仓库在独立 homebrew-tap 仓库建立前也能作为 Tap 使用。

sh
brew tap hh696-wq/hhy https://github.com/hh696-wq/hhy-vm.git
brew install hhy
hhy --version
当前 Formula 只支持 macOS arm64,并锁定官方发行包及其 SHA-256。Linux 请使用一键安装器或 Release 包。

1.3方式二:直接下载 Release

不需要修改 HHY Runtime 时,直接使用官方 V1.3.10 发行包最快。根据系统和 CPU 选择 darwin-arm64、linux-x86_64 或 linux-arm64;压缩包已包含 HHY 可执行文件、官方示例与数据库扩展、所需的非系统运行库、文档、许可证和构建信息。

打开 HHY GitHub Releases ↗
下载最新稳定版本、对应的 .sha256 文件或汇总 SHA256SUMS。
https://github.com/hh696-wq/hhy-vm/releases

sh
tar -xzf hhy-1.3.10-PLATFORM-ARCH.tar.gz
cd hhy-1.3.10-PLATFORM-ARCH
./bin/hhy --version
./bin/hhy run examples/07-language-basics.hhy
保持 bin/ 与 lib/ 的相对位置不变,否则便携包可能找不到随包运行库。PLATFORM-ARCH 替换为 darwin-arm64、linux-x86_64 或 linux-arm64。

1.4下载后校验与加入 PATH

运行下载内容前,应使用同名 .sha256 或 SHA256SUMS 验证文件完整性。macOS 自带 shasum,Linux 通常使用 sha256sum。

sh
# macOS
shasum -a 256 -c hhy-1.3.10-darwin-arm64.tar.gz.sha256

# Linux
sha256sum -c hhy-1.3.10-linux-x86_64.tar.gz.sha256

# 当前终端加入 PATH(替换成实际绝对路径)
export PATH="/absolute/path/hhy-1.3.10-PLATFORM-ARCH/bin:$PATH"
hhy --version

长期使用时,把 export PATH 行放进 shell 配置文件;或者继续通过发行目录中的 ./bin/hhy 运行,不需要系统级安装。

1.5方式三:从源码构建

需要开发 Runtime、验证最新源码或自定义安装位置时再选择源码构建。HHY V1.3.10 正式支持 macOS arm64、Linux arm64 和 Linux x86_64;需要 C11 编译器、make、libcurl、PCRE2 与 BDWGC。数据库扩展还需要对应的 PostgreSQL libpq 或 MySQL client 开发库。

sh
brew install curl pcre2 bdw-gc
git clone https://github.com/hh696-wq/hhy-vm.git
cd hhy-vm
make
make test
./build/hhy --version
brew 命令只适用于 macOS。Linux 的依赖包名称因发行版而异,完整说明见仓库 INSTALL.md。

1.6安装源码构建结果

sh
make install PREFIX="$(brew --prefix)"
hhy --version

PREFIX 可以换成自定义绝对路径。确认 PREFIX/bin 已在 PATH 后,所有 .hhy 文件都可以通过 hhy run 执行。

1.7第一个脚本

hello.hhy
let language = "HHY"

["Flow", "Pipe", "System"]
    |> map { word -> "{language}: {word}" }
    |> print
sh
hhy check hello.hhy
hhy run hello.hhy

let 创建绑定;List 字面量保存三个 String;|> 把左侧值注入下一个函数;map 的闭包逐项生成新 String;print 消费结果。check 先验证词法、语法、作用域、模块与已知标准库调用,不执行副作用。

1.8脚本运行与开发流程

任务命令用途
格式化hhy fmt script.hhy写入 HHY 官方格式
检查格式hhy fmt --check script.hhy在 CI 中检查,不修改文件
检查脚本hhy check script.hhy检查语法、作用域和已知 API
运行脚本hhy run script.hhy执行脚本
传递参数hhy run script.hhy input.csv output.json参数进入只读 args
预览计划hhy run --dry-run script.hhy查看脱敏计划,不执行外部副作用

源码使用 .hhy 后缀。查看完整命令:

sh
hhy --help

指南 · 02

语言基础

变量、值、函数、条件、循环和作用域。

2.1动态类型是什么意思

HHY 的变量声明不写类型,值在运行时携带自己的逻辑类型。动态类型不等于随意转换:条件必须得到 Bool,String 不会自动变成 Number、Bool 或 Path,参数数量和不支持的运算都会产生结构化错误。用 type(value) 查看类型,用 is_type(value, name) 判断类型。

hhy
let nothing = null
let enabled = true
let count = 42
let ratio = 0.75
let title = "HHY"
let pattern = /ERROR|WARN/i
let names = ["Ada", "Linus"]
let user = { name: "Ada", active: true }
let indexes = 0..3
let size_limit = 10mib
let timeout_limit = 5s
let completion = 80%

print(type(user))
print(is_type(title, "String"))

2.2标量与单位类型

类型示例用途
Nullnull表示没有值
Booltrue条件与谓词
Int42整数计算
Float3.14浮点计算
String"hello"UTF-8 文本
Regex/ERROR/i文本匹配
Bytes10mib文件或内存大小
Duration5s超时与时间间隔
Percent80%比例
DateTimenow()带时区时间
Pathpath("logs")文件系统路径

String、数字、单位和 Path 的精确边界行为属于 Reference。日常脚本只需记住:HHY 不会在 String、Number、Bool 和 Path 之间做隐式转换。

查看类型与语法参考 →
查阅 UTF-8、数值溢出、运算符和字面量的精确定义。
/zh/learn/syntax-reference

2.3List、Map 与 Range

List 使用从 0 开始的索引,越界产生 IndexError。Map 的键只能是 String,保持插入顺序;map.key 与 map["key"] 等价。普通缺失键返回 null,require 用于区分“键缺失”和“键存在但值是 null”。Range a..b 包含 a、不包含 b,并且不会预先分配 List。

hhy
let original = ["Flow", "System"]
let extended = append(original, "Pipe")
let shortened = remove_at(extended, 1)

let config = { retries: 3, label: null }
let updated = put(config, "timeout", 5s)
let selected = pick(updated, ["retries", "timeout"])

print(original)
print(shortened)
print(get(config, "missing"))
print(require(config, "label"))
print(selected)

List 和 Map 不原地修改。append、remove_at、put、remove_key、pick 都返回新集合,所以示例中的 original 和 config 保持不变。List/Map 支持深度相等;Function、Stream 和系统资源对象不支持值相等。

2.4Result、Stream 与系统对象

类型用于
Result显式保存一次操作的成功值或 Error
Stream惰性处理文件、行、进程、响应和事件
Error携带类别、位置和 Flow stage 的失败
Function用户函数与闭包
系统对象File、Process、HttpResponse 等带只读字段的专用值

系统对象不是 Map。需要写入 JSON 时,先用 map 或 pick 选择普通字段。Stream 的惰性和消费规则在 Flow 章节展开。

2.5变量、作用域与不可变性

hhy
let service = "api"
let mut retries = 0
retries = retries + 1

let 创建不可重新赋值的绑定;需要重新赋值时使用 let mut。List 和 Map 的更新函数返回新值,不修改原集合。变量遵循块级词法作用域,并且必须先声明后使用。

闭包可以捕获外层值。捕获 let mut 的闭包不能发送到 parallel worker;并发限制在“并发与监听”章节说明。

2.6条件、循环与函数

hhy
fn classify(score) {
    if score >= 90 { return "excellent" }
    else if score >= 60 { return "pass" }
    else { return "retry" }
}

let mut total = 0
for score in [98, 72, 55] {
    if score < 60 { continue }
    total = total + score
}

let mut attempts = 0
while attempts < 3 {
    attempts = attempts + 1
}

print(classify(98))
print(total)

支持 if / else if / else、for item in iterable、while、break 和 continue。for 可以遍历 List、Map entries、Range 或 Stream;遍历 Stream 会消费它。函数使用位置参数,参数数量在调用时检查;没有显式 return 时返回 null。

hhy
fn summarize(items) {
    let mut total = 0

    for item in items {
        if item.enabled {
            total = total + item.score
        }
    }

    return total
}

let users = [
    { name: "Ada", enabled: true, score: 98 },
    { name: "Linus", enabled: false, score: 86 }
]

summarize(users) |> print

闭包写作 { item -> expression };多条语句时必须显式写参数并用 return 返回。单参数闭包在明确的 Flow 上下文中可以使用 { it * 2 }。V1.3.10 不支持重载、泛型或默认参数。

指南 · 03

Flow 与 Stream

理解管道传值、惰性流和单次消费语义。

3.1Pipe 如何传值

Pipe 是普通函数调用的组合规则:x |> f 等价于 f(x),x |> f(a) 等价于 f(x, a),x |> obj.f(a) 等价于 obj.f(x, a)。它不会自动把标量变成 Stream、展开嵌套 Stream、访问 it 字段、忽略错误、字符串化值或启动 Shell。

hhy
[1, 2, 3, 4, 5]
    |> stream
    |> map { number -> number * 2 }
    |> where { number -> number > 5 }
    |> take(2)
    |> print

3.2Stream 的生命周期

Stream 是惰性、拉取式、单次消费序列。创建管道只组合 operator;终端开始拉取时,上游才逐项产生数据。生命周期是 open → next* → close,正常结束、take 提前停止、错误和取消都会从下游向上游关闭资源。

阶段发生的事情
创建Source 返回 Stream,但尚未读取数据
组合map、where 等 operator 连接成 Pipeline
消费print、collect、save 等终端开始逐项拉取
关闭完成、提前停止、Error 或取消释放上游资源
Stream 只能消费一次。不要把同一个 Stream 保存后交给两条 Pipeline;需要重复处理时重新创建 Source,或在有限输入上显式 collect。

3.3逐项、过滤与观察算子

hhy
[5, 2, 5, 1, 3]
    |> stream
    |> skip(1)
    |> take(4)
    |> inspect { number -> print("seen {number}") }
    |> where { number -> number >= 3 }
    |> map { number -> number * 10 }
    |> distinct
    |> collect
    |> print

map

map(Stream<T>, Function(T -> U)) -> Stream<U>

惰性地对每项调用闭包,一项输入对应一项输出,不自动展开。

where

where(Stream<T>, Function(T -> Bool)) -> Stream<T>

惰性保留闭包返回 true 的项目;闭包必须返回 Bool。

take

take(Stream<T>, Int) -> Stream<T>

惰性保留前 n 项,达到数量后提前关闭上游。

skip

skip(Stream<T>, Int) -> Stream<T>

惰性丢弃前 n 项,然后传递其余项目。

inspect

inspect(Stream<T>, Function(T -> Value)) -> Stream<T>

为每项执行观察闭包,再原样传递项目。

distinct

distinct(Stream<Hashable>) -> Stream<Hashable>

惰性去除重复的可 Hash 标量,并保存已见集合。

3.4map 与 flat_map 的区别

map 的闭包返回什么,下游就收到什么。如果返回 Stream,结果是 Stream<Stream<T>>。flat_map 要求闭包返回 Stream,并把每个子流依次展开成一条 Stream。

hhy
let batches = [[1, 2], [3, 4]]

batches
    |> stream
    |> flat_map { batch -> batch |> stream }
    |> print

3.5Barrier 和终端算子到底做什么

逐项算子只需保存当前项;Barrier 必须先看完或保存大量输入才能产生正确结果。sort_by 要保存全部输入后排序,group_by 要保存每组的全部 values,collect 把全部项组成 List,reduce/count/sum 等终端算子读取到结束才返回标量。它们都受 max_memory、集合大小和运行时间限制。

hhy
let ordered = [5, 1, 3, 2, 4]
    |> stream
    |> sort_by({ order: "asc" }) { number -> number }
    |> collect

let grouped = [
    { team: "core", name: "Ada" },
    { team: "web", name: "Linus" },
    { team: "core", name: "Grace" }
]
    |> stream
    |> group_by { person -> person.team }
    |> collect

print(ordered)
print(grouped)

sort_by

sort_by(Stream<T>, Map, Function(T -> Comparable)) -> Stream<T>

物化有限输入,按闭包 key 和 asc/desc 选项稳定排序。

group_by

group_by(Stream<T>, Function(T -> Hashable)) -> Stream<Group<T>>

物化有限输入并按 Hash key 输出 Group;Group 含 key 与 values。

collect

collect(Stream<T>) -> List<T>

消费有限 Stream 并物化为 List。

reduce

reduce(Stream<T>, U, Function(State<T,U> -> U)) -> U

以 initial 累积 Stream;闭包接收含 acc/item/index 的 state。

count

count(Stream<T>) -> Int

消费 Stream 并返回项目数。

sum

sum(Stream<Number>) -> Number

消费数值 Stream 并求和,遵守 Int 溢出规则。

min

min(Stream<Number>) -> Number | Null

消费数值 Stream,返回最小值或空流的 null。

max

max(Stream<Number>) -> Number | Null

消费数值 Stream,返回最大值或空流的 null。

first

first(Stream<T>) -> T | Null

返回第一项或 null,并提前关闭上游。

last

last(Stream<T>) -> T | Null

消费 Stream 并返回最后一项或 null。

any

any(Stream<T>, Function(T -> Bool)) -> Bool

任一项目满足谓词即返回 true,并短路关闭上游。

all

all(Stream<T>, Function(T -> Bool)) -> Bool

所有项目满足谓词才返回 true;首个 false 时短路。

不要把 watch、every 或没有明确上限的输入直接送入 sort_by、group_by 或 collect。先用 take、时间窗口或其他业务边界把输入限制为有限流,否则 Runtime 会产生 PlanError。

3.6副作用、错误与并发

只有终端或 Action 才会真正消费 Pipeline。print、for_each、save_*、run 和 send 会执行输出、文件、进程或网络操作。普通 Error 默认终止 Pipeline;需要逐项保留失败时使用 attempt,需要替换整条失败上游时使用 on_error。

parallel(n) 使用隔离 worker 并保持输出顺序。并发数量、可发送值和取消语义在“并发与监听”章节展开。

指南 · 04

文件与路径

遍历目录、读取文本并安全写入结果。

4.1Path 不是 String

所有文件 API 都要求 Path。path(text) 做词法规范化:折叠重复分隔符和 .,消除可以解析的 ..,但不访问文件系统也不解析符号链接。相对 Path 始终基于进程启动目录,不随被 import 的文件位置变化。

hhy
let source = path("./src/../src/main.c")
let target = path_join(source.parent, "runtime.c")

print(source)
print(source.name)
print(source.extension)
print(source.parent)
print(target)

name、extension、parent 是 Path 的只读字段,不是 path_name()、path_extension()、path_parent() 函数。extension 包含前导点,无扩展名时为空字符串;path_join(base, child) 返回组合后的新 Path。

4.2files:遍历、glob 与元数据

hhy
path("./logs")
    |> files("**/*.log")
    |> where { file -> file.size > 1mib }
    |> flat_map { file -> read_lines(file.path) }
    |> where { line -> contains(line, "ERROR") }
    |> save_lines(path("errors.txt"))

files(root, pattern, options?) 返回惰性的 Stream<File | Directory>,不会返回遍历根本身。pattern 支持 *、?、**;默认不跟随目录符号链接,{ follow_symlinks: true } 可开启并自动跳过检测到的目录循环。

字段含义
path完整 Path
name文件或目录名
extension包含前导点的扩展名
sizeBytes 大小
created创建时间;不可可靠取得时为 null
modified修改时间
is_file / is_dir / is_symlink对象种类标记

File 和 Directory 是系统对象,不是 Map。写入 JSON 前,先把需要的字段映射成普通 Map。

4.3读取文本与二进制

read_text

read_text(Path) -> String

完整读取 UTF-8 文件为 String。

read_lines

read_lines(Path) -> Stream<String>

逐行惰性读取 UTF-8 文件并移除行终止符。

read_bytes

read_bytes(Path) -> BytesBuffer

完整读取二进制文件为 BytesBuffer。

文本 API 验证 UTF-8。图片、压缩包等任意二进制使用 read_bytes 和 write_bytes,不要放进 String。

4.4写入、追加与原子保存

hhy
let input = path("notes.txt")
let backup = path("backup/notes.txt")

write_text(input, "first line
", { overwrite: true })
append_text(input, "second line
")
copy(input, backup, { overwrite: false, create_parents: true })

read_lines(backup)
    |> map { line -> upper(line) }
    |> save_lines(path("backup/upper.txt"), { create_parents: true })

write_text

write_text(Path, String, Map?) -> Path

以原子替换方式写 String,支持 overwrite/create_parents。

append_text

append_text(Path, String) -> Path

把 String 追加到文件末尾。

write_bytes

write_bytes(Path, BytesBuffer, Map?) -> Path

以原子替换方式写 BytesBuffer。

save_text

save_text(String | Stream<String>, Path, Map?) -> Path

把 String 或文本 Stream 边拉取边原子保存。

save_lines

save_lines(Stream<String>, Path, Map?) -> Path

把 String Stream 逐项写入并补 LF,最终原子替换。

write_text、write_bytes、save_text、save_lines 的 options 支持 overwrite(默认 true)和 create_parents(默认 false)。这些 API 通过同目录临时文件加 rename 提交;overwrite: false 使用原子 no-replace,避免先检查后写入的竞态覆盖。

4.5复制、移动、删除与 dry-run

copy

copy(Path, Path, Map?) -> Path

复制文件,支持原子 no-replace 与创建父目录。

move

move(Path, Path, Map?) -> Path

移动或重命名文件,遵守覆盖选项。

remove

remove(Path) -> Path

删除明确 Path,并返回该 Path。

sh
hhy run --dry-run backup.hhy
hhy run backup.hhy

先检查 dry-run 计划,再执行包含复制、移动或删除的脚本。

文件读取、遍历、写入、进程和网络操作都可能被 RuntimeLimits、取消或宿主权限中止。不要依赖 GC 关闭系统资源;Runtime 会在正常完成、错误、return、exit 和 cancel 路径显式清理。

4.6查阅完整 API

路径与文件 API Reference →
查阅全部签名、参数形式和函数锚点。
/zh/learn/standard-library#fn-path

指南 · 05

文本、JSON 与 CSV

处理 UTF-8 文本、正则表达式和结构化数据。

5.1String 与 UTF-8

String 是不可变 UTF-8 字节序列。length 统计 Unicode code point,byte_length 统计编码后的字节;索引返回一个 code point 对应的单字符 String。文本函数返回新值,不修改原 String。

hhy
let line = "  ERROR: timeout  "

line
    |> trim
    |> replace("ERROR", "WARN")
    |> lower
    |> print

trim

trim(String) -> String

移除 String 两端空白。

split

split(String, String) -> List<String>

按分隔文本把 String 分割成 List<String>。

join

join(List<String>, String) -> String

用分隔文本连接 List<String>。

replace

replace(String, String, String) -> String

返回把匹配文本替换后的新 String。

contains

contains(String | List, Value) -> Bool

判断 String 是否含子串,或 List 是否含相等值。

starts_with

starts_with(String, String) -> Bool

判断 String 是否以指定文本开头。

ends_with

ends_with(String, String) -> Bool

判断 String 是否以指定文本结尾。

lower

lower(String) -> String

返回 Unicode 小写转换后的新 String。

upper

upper(String) -> String

返回 Unicode 大写转换后的新 String。

5.2Regex

Regex 字面量写作 /pattern/flags,支持 i(忽略大小写)、m(多行)、s(点匹配换行)和 u。regex_match 只返回是否匹配;regex_captures 返回完整匹配、字节位置、groups 编号捕获与 named 命名捕获,不匹配时返回 null。

V1.3.10 使用 PCRE2 8-bit,并限制 pattern、subject、match、depth、heap 和捕获组数量;超限产生 ResourceLimitError,避免恶意正则耗尽运行时。

5.3JSON 的类型映射与错误

hhy
read_text(path("users.json"))
    |> parse_json
    |> get("users")
    |> stream
    |> where { user -> user.active == true }
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path("active-users.json"))
JSONHHY
objectMap
arrayList
stringString
integerInt
decimalFloat
true / falseBool
nullNull

parse_json 的错误包含行列。encode_json 可以使用 { pretty: true } 输出可读格式。Function、Stream 和系统对象不能直接编码;先选择普通字段。

5.4CSV 是流式 record

parse_csv 接受完整 String 或 Stream<String>,返回 Stream<Map>;encode_csv 接受 Stream<Map>,返回不带行终止符的 Stream<String>。两者不需要加载完整文件。

hhy
read_lines(path("employees.csv"))
    |> parse_csv({ header: true })
    |> where { row -> row.active == "true" }
    |> encode_csv({ header: true })
    |> save_lines(path("active-employees.csv"))

header 控制首行字段名,delimiter 和 quote 必须是单字符。CSV 不做 schema 推断;数字和 Bool 需要显式转换。encode_csv 不附加换行符,与 save_lines 配合写出。

5.5查阅完整 API

文本与结构化数据 API Reference →
查阅文本、Regex、JSON 和 CSV 的完整函数签名。
/zh/learn/standard-library#fn-contains

指南 · 06

进程与系统

运行命令、消费输出并检查系统状态。

6.1run 与 shell 的安全边界

hhy
run(["git", "log", "--oneline"], { timeout: 5s })
    |> stdout_lines
    |> take(10)
    |> print

run(argv, options?) 直接把 List<String> 交给操作系统,不经过 Shell,因此空格、通配符、$、重定向和管道不会被二次解释。只有确实需要 Shell 语法时才使用 shell(command, options?);Checker 会对 shell 给出安全提示。

选项用途
cwd子进程工作目录 Path
env只覆盖子进程环境
stdin传给命令的标准输入文本
timeout命令最长运行时间
max_outputstdout 与 stderr 捕获上限
包含用户输入时优先使用 run。shell 会解释重定向、管道和变量展开,只在明确需要 Shell 语义时使用。

6.2CommandResult

run 与 shell 默认等待结束并返回 CommandResult,而不是把非零退出码自动当作 HHY Error。脚本应读取 exit_code 决定业务成功。

字段内容
exit_code子进程退出码
stdout标准输出 String
stderr标准错误 String
duration命令运行 Duration

非零 exit_code 不会自动变成 HHY Error。脚本需要根据命令约定判断成功。stdout_lines(result) 可把已捕获输出作为行 Stream 继续处理。

6.3进程快照与字段

processes() 返回当前时刻的 Stream<Process> 快照。Process 不是 Map,提供 pid、name、cpu、memory、status、command 只读字段;转 JSON 前必须显式映射成普通 Map。

排序示例使用 sort_by({ order: "desc" });order 只能是 asc 或 desc,默认 asc。排序是稳定 barrier,会物化有限快照。

6.4args、env、system 与 stdin

值内容
args不含脚本路径的 List<String>
env只读环境变量视图
systemOS、架构、主机、CPU、内存和目录信息
stdin_lines()标准输入行 Stream
hhy
if length(args) != 1 {
    print_error("usage: script.hhy <input>")
    exit(3)
}

let input = path(args[0])

6.5查阅完整 API

进程与系统 API Reference →
查阅 run、shell、processes、stdin_lines 和 every 的完整签名。
/zh/learn/standard-library#fn-run

指南 · 07

HTTP

构建请求,配置超时与重试,并处理响应。

7.1Request → Policy → Send → Response

hhy
http.get("https://example.com/users")
    |> timeout(5s)
    |> retry({ count: 3, backoff: 200ms })
    |> send
    |> response_body
    |> parse_json
    |> print

http.get/post/put/delete(url, options?) 只创建不可变 HttpRequest,不访问网络。timeout(request, duration) 与 retry(request, options) 返回修改策略后的新 Request;send(request) 才产生 network effect 并返回 HttpResponse。这样 dry-run 能完整展示而不执行请求。

7.2请求选项与安全默认值

选项用途
queryURL 查询参数
headers请求 header
body请求内容
proxy代理地址
follow_redirects重定向策略
allow_private_networks设为 false 时在实际连接地址上阻止私网、loopback 与 link-local

TLS 验证默认开启。Authorization 和 Cookie 等敏感 header 会在计划、日志和 Error 中脱敏。响应体受 max_http_body 限制。

7.3超时、重试与幂等性

retry({ count, backoff }) 默认只重试连接错误、timeout、429 和部分 5xx。GET、PUT、DELETE 可以按策略重试;POST 默认不自动重试,避免重复创建或扣款。timeout 和 Ctrl+C 都会取消 libcurl 操作并清理响应资源。

重试不是让失败消失。为每个请求设置 timeout,谨慎评估 POST 幂等性,并让最终错误保留 URL(脱敏)、方法、尝试次数和 Flow stage。

7.4HttpResponse 与响应 body

send 返回内存中的 HttpResponse。使用 response_body 读取 UTF-8 文本,使用 response_bytes 读取二进制;send_to(request, path) 则在 curl 回调中直接写同目录临时文件,成功后原子发布,响应只保留 path 和 size。

hhy
http.get("https://api.example.com/status")
    |> timeout(3s)
    |> send
    |> response_body
    |> parse_json
    |> print

7.5查阅完整 API

HTTP API Reference →
查阅请求构造、timeout、retry、send 和响应读取函数。
/zh/learn/standard-library#fn-http-get

指南 · 08

并发与监听

有界并发处理、取消和文件事件流。

8.1parallel 是有界并发 map

hhy
let urls = [
    "https://example.com",
    "https://example.org"
]

urls
    |> parallel(2) { url ->
    http.get(url)
        |> timeout(5s)
        |> send
}
    |> print
行为保证
并发上限最多运行 n 个 worker,并受 RuntimeLimits 约束
输出顺序与输入顺序一致
背压输入队列和结果缓冲都有界
错误首个未处理 Error 取消剩余任务
返回值等同并发 map,不自动展开子 Stream

如果闭包返回 Stream,在 parallel 后显式使用 flat_map。dry-run 不创建 worker,但仍会按顺序检查闭包中的 Effect。

8.2Sendable 与隔离

worker 收到输入和闭包捕获值的冻结快照,不共享可变对象。Null、Bool、数字、String、单位、Path,以及字段均可发送的普通 List/Map/系统快照可复制过去。

捕获 let mut Cell、Stream、打开的 File handle、请求 body stream 或其他进程内资源会产生 CheckError。HHY V1.3.10 不公开线程、锁或 async/await。

8.3watch 与 FileEvent

hhy
watch(path("./src"))
    |> where { event -> event.kind == "write" }
    |> debounce(300ms)
    |> for_each { event ->
    print(event.path)
}

watch(path, { recursive? }) 返回无限 Stream<FileEvent>。FileEvent 有 kind、path、old_path、timestamp 只读字段;kind 是 created、modified、removed 或 renamed,old_path 仅 renamed 时存在。

字段内容
kindcreated、modified、removed 或 renamed
path事件目标 Path
old_pathrenamed 的原 Path,其余事件为 null
timestamp事件 DateTime

watch 是无限 Stream。使用 Ctrl+C、timeout 或 cancel 结束监听;递归监听受 max_open_files 限制。底层文件系统可能合并短时间内的重复事件。

8.4debounce 与 every

debounce(window) 使用 leading-edge:某个值或同一 kind + path 的 FileEvent 第一项立即输出,窗口内重复项被合并,并从最后一次重复重新计时;不同事件 key 互不阻塞。

every(duration) 返回无限 tick Stream。若下游还在处理,上游遵守背压,不重叠执行同一个 tick。定时和监听流进入 collect/sort/group 前必须先有 take 或业务窗口。

8.5取消与清理

Ctrl+C、timeout、cancel() 和未处理错误触发同一个根 CancellationToken。watcher、sleep、HTTP、子进程与 worker 定期检查它;取消后关闭队列和句柄、终止子进程,并让 Stream close 从下游传播到上游。

指南 · 09

模块与错误

组织代码,传播结构化错误并可靠清理资源。

9.1导入形式与路径解析

hhy
import { add } from "./math.hhy"

add(20, 22) |> print
写法用途
import "./lib/report.hhy" as report导入本地模块命名空间
import { parse } from "./lib/data.hhy"具名导入
import { validate as check } from "./lib/data.hhy"具名导入并设置别名
import http导入标准库模块

相对路径基于当前源码文件目录。标准库使用裸名称;本地文件显式使用 ./、../ 或绝对 Path。

9.2export、作用域与执行

hhy
export let version = "1.0"

export fn normalize_name(name) {
    return name |> trim |> lower
}

fn internal_helper() {
    return null
}

只有 export 名称对外可见。模块拥有独立顶层作用域,并在首次 import 时执行一次、随后缓存。循环依赖在执行前产生 CheckError。V1.3.10 支持标准库、本地模块,以及通过本地包安装的进程扩展模块。

9.3Error 的字段与类别

所有失败都使用 Error,而不是靠 null 或打印文本表达。Error 提供 kind、code、message、source、stage、cause、stack、context 字段;敏感 header、凭据和完整文件内容不会默认进入 context。

内置类别包括 SyntaxError、CheckError、TypeError、ValueError、IndexError、KeyError、EncodingError、IoError、ProcessError、HttpError、HttpStatusError、TimeoutError、CancelledError、ResourceLimitError 和 PlanError。

9.4try/catch 与重新抛出

hhy
try {
    read_text(path("config.json"))
        |> parse_json
        |> print
} catch err {
    print_error(err)
    exit(1)
}

catch 捕获 try 块传播出的第一个错误。catch 正常结束后脚本继续;无法处理时用 throw(err) 保留错误链重新抛出。未处理错误让脚本以非零状态退出。

9.5Flow 错误与单项 Result

hhy
path("./configs")
    |> files("**/*.json")
    |> map { file -> attempt { read_text(file.path) } }
    |> where { result -> result.ok }
    |> map { result -> result.value }
    |> print

Stream 中未处理的 Error 默认终止整条 Pipeline。attempt 把单次操作转换为 Result,适合批处理中显式保留成功项和失败项。on_error 用于替换整条失败的上游 Stream,不会自动跳过错误项。

9.6资源清理保证

Error、return、exit、timeout、Ctrl+C 和 cancel 都走统一 unwind。Stream close 幂等;原子保存失败会删除临时文件并保留旧文件;子进程、HTTP response、watcher 和 worker 都会响应取消。

指南 · 10

实战:可直接落地的自动化

完整收录 examples/00–08,并增加发布门禁、安全审计、订单对账、租户快照和素材治理。

10.100 · Hello HHY 与 Flow 入门

最小可运行案例:把 List 转成 Stream,依次完成映射和过滤,最后输出结果。对应 examples/00-hello.hhy。

00-hello.hhy
let language = "HHY"

["Flow", "Pipe", "System"]
    |> map { word -> "{language}: {word}" }
    |> print
$ hhy run examples/00-hello.hhy
HHY: Flow
HHY: Pipe
HHY: System

✓ exit 0 · Flow 管道执行完成

10.2并发提取日志告警

递归扫描大日志文件,使用 4 个 worker 提取 ERROR/WARN 行,并将来源文件写入结果。适合服务器日志归档、故障排查和定时任务。

log-errors.hhy
if length(args) != 2 {
    print_error("usage: hhy run log-errors.hhy <log-dir> <output-file>")
    exit(3)
}

let log_dir = path(args[0])
let output_file = path(args[1])

log_dir
    |> files("**/*.log")
    |> where { file -> file.size > 1mib }
    |> parallel(4) { file ->
    read_lines(file.path)
        |> where { line -> regex_match(line, /ERROR|WARN/) }
        |> map { line -> "{file.path}: {line}" }
        |> collect
}
    |> flat_map { lines -> lines |> stream }
    |> save_lines(output_file)
    |> on_error { err ->
    print_error(err)
    throw(err)
}
sh
hhy run log-errors.hhy ./logs ./output/errors.txt
$ hhy run log-errors.hhy ./logs ./output/errors.txt && head -3 ./output/errors.txt
logs/api.log: 2026-08-25T09:18:42Z ERROR database timeout after 3000ms
logs/worker.log: 2026-08-25T09:18:44Z WARN retrying job #1842
logs/api.log: 2026-08-25T09:18:47Z ERROR upstream returned 502

✓ exit 0 · 3 条告警已写入 output/errors.txt

10.3从 API 同步活跃用户

请求用户接口,经过超时、重试、JSON 解析和字段裁剪后,只把活跃用户原子写入本地文件。对应 examples/02-active-users.hhy。

active-users.hhy
if length(args) != 2 {
    print_error("usage: hhy run active-users.hhy <url> <output-file>")
    exit(3)
}

http.get(args[0])
    |> timeout(5s)
    |> retry({ count: 3, backoff: 200ms })
    |> send
    |> response_body
    |> parse_json
    |> get("users")
    |> stream
    |> where { user -> user.active == true }
    |> map { user ->
    { id: user.id, name: user.name, email: user.email }
}
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path(args[1]))
    |> on_error { err ->
    print_error(err)
    throw(err)
}
sh
hhy run active-users.hhy https://api.example.com/users active-users.json
$ hhy run active-users.hhy http://127.0.0.1:9000/users active-users.json && cat active-users.json
[
  { "id": 101, "name": "Ada", "email": "ada@example.com" },
  { "id": 108, "name": "Linus", "email": "linus@example.com" }
]

✓ exit 0 · 2 位活跃用户已写入 active-users.json

10.4进程 CPU / 内存监控

每 5 秒读取一次进程快照,找出 CPU 超过 70% 或内存超过 1 GiB 的进程,并按内存倒序输出前 10 个。对应 examples/03-process-monitor.hhy。

03-process-monitor.hhy
every(5s)
    |> for_each { tick ->
    processes
        |> where { process ->
        process.cpu > 70% or process.memory > 1gib
    }
        |> sort_by({ order: "desc" }) { process -> process.memory }
        |> take(10)
        |> map { process ->
        {
            pid: process.pid,
            name: process.name,
            cpu: process.cpu,
            memory: process.memory
        }
    }
        |> print
}
$ hhy run examples/03-process-monitor.hhy
[{ pid: 8421, name: "node", cpu: 82.4%, memory: 1.42 GiB },
 { pid: 9107, name: "hhy",  cpu: 74.1%, memory: 86.3 MiB }]

next sample in 5s… · Ctrl+C 安全退出

10.5批量服务健康检查

并发探测多个服务,统一设置超时与重试;单个接口失败时记录错误,不中断整批巡检。可接入发布检查或 CI。

health-check.hhy
let services = [
    { name: "users", url: "https://api.example.com/users/health" },
    { name: "orders", url: "https://api.example.com/orders/health" },
    { name: "billing", url: "https://api.example.com/billing/health" }
]

services
    |> stream
    |> parallel(3) { service ->
    let response = attempt {
        http.get(service.url)
            |> timeout(3s)
            |> retry({ count: 2, backoff: 100ms })
            |> send
            |> response_body
            |> parse_json
    }

    let mut status = "unreachable"
    let mut error_message = null

    if response.ok {
        status = response.value.status
    } else {
        error_message = response.error.message
    }

    return {
        name: service.name,
        ok: response.ok,
        status: status,
        error: error_message
    }
}
    |> collect
    |> encode_json({ pretty: true })
    |> print
$ hhy run health-check.hhy
[
  { "name": "users",   "ok": true,  "status": "healthy", "error": null },
  { "name": "orders",  "ok": true,  "status": "healthy", "error": null },
  { "name": "billing", "ok": false, "status": "unreachable", "error": "request timed out" }
]

✓ exit 0 · 3 个服务并发完成,单点失败未中断批次

10.6业务进阶 01 · 发布质量门禁

在发布前并行执行测试、Lint 和生产构建,生成机器可读报告;任一检查失败就用稳定退出码阻止发布。适合 CI/CD、灰度发布和交付验收。

release-gate.hhy
let checks = [
    { name: "unit-tests", command: ["make", "test"] },
    { name: "lint", command: ["npm", "run", "lint"] },
    { name: "production-build", command: ["npm", "run", "build"] }
]

let report = checks
    |> stream
    |> parallel(3) { check ->
    let result = run(check.command, { timeout: 10min, max_output: 8mib })
    return {
        name: check.name,
        passed: result.exit_code == 0,
        exit_code: result.exit_code,
        output: result.stdout
    }
}
    |> collect

report |> encode_json({ pretty: true }) |> save_text(path("release-gate.json"))

if report |> any { check -> check.passed == false } {
    print_error("release blocked: one or more checks failed")
    exit(1)
}

print("release gate passed")
$ hhy run release-gate.hhy
unit-tests       PASS  4.28s
lint             PASS  1.14s
production-build PASS  6.72s
release-gate.json written

✓ exit 0 · release gate passed

10.7业务进阶 02 · 源码敏感信息审计

并发扫描配置与源码,定位疑似 API Key、密码和私钥内容,汇总成可供安全团队复核的报告。适合提交前检查和合规巡检。

secret-audit.hhy
if length(args) != 2 {
    print_error("usage: hhy run secret-audit.hhy <source-dir> <report-file>")
    exit(3)
}

path(args[0])
    |> files("**/*")
    |> where { file ->
    file.extension == ".env" or
    file.extension == ".yml" or
    file.extension == ".json" or
    file.extension == ".ts"
}
    |> parallel(4) { file ->
    read_lines(file.path)
        |> where { line ->
        regex_match(line, /API_KEY|SECRET|PASSWORD|BEGIN PRIVATE KEY/)
    }
        |> map { line -> "{file.path}: {line}" }
        |> collect
}
    |> flat_map { matches -> matches |> stream }
    |> save_lines(path(args[1]))
$ hhy run secret-audit.hhy ./services secret-findings.txt
services/billing/.env: PAYMENT_API_KEY=***
services/auth/config.yml: PASSWORD: ***

✓ exit 0 · 2 条疑似敏感信息待复核
示例输出已脱敏。实际落地时应限制报告权限,并在流水线中避免打印秘密原文。

10.8业务进阶 03 · 订单与支付自动对账

把订单 CSV 与支付 CSV 合并为一条数据流,按 order_id 分组,找出缺少记录或金额不一致的异常订单。适合每日财务对账。

reconcile.hhy
if length(args) != 3 {
    print_error("usage: hhy run reconcile.hhy <orders.csv> <payments.csv> <report.json>")
    exit(3)
}

[path(args[0]), path(args[1])]
    |> stream
    |> flat_map { input ->
    read_lines(input) |> parse_csv({ header: true })
}
    |> group_by { record -> record.order_id }
    |> where { group ->
    (group.values |> count) != 2 or
    (group.values |> map { record -> record.amount } |> distinct |> count) != 1
}
    |> map { group ->
    { order_id: group.key, records: group.values, issue: "missing_or_amount_mismatch" }
}
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path(args[2]))
$ hhy run reconcile.hhy orders.csv payments.csv exceptions.json
orders: 12,480 · payments: 12,472
matched: 12,461
exceptions: 19 → exceptions.json

✓ exit 0 · 对账报告已原子写入

10.9业务进阶 04 · SaaS 多租户用量快照

有界并发拉取各租户用量,统一处理超时和重试;单租户失败被隔离并记录,不影响整份快照生成。适合计费、容量分析和客户成功报表。

tenant-snapshot.hhy
let tenants = [
    { id: "acme", url: "https://api.example.com/acme/usage" },
    { id: "nova", url: "https://api.example.com/nova/usage" },
    { id: "orbit", url: "https://api.example.com/orbit/usage" }
]

tenants
    |> stream
    |> parallel(3) { tenant ->
    let result = attempt {
        http.get(tenant.url)
            |> timeout(5s)
            |> retry({ count: 3, backoff: 200ms })
            |> send
            |> response_body
            |> parse_json
    }

    if result.ok {
        return { tenant: tenant.id, ok: true, usage: result.value, error: null }
    }

    return { tenant: tenant.id, ok: false, usage: null, error: result.error.message }
}
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path("tenant-usage-snapshot.json"))
$ hhy run tenant-snapshot.hhy
acme  ✓ requests=184203 storage_gb=82.4
nova  ✓ requests=99102  storage_gb=41.8
orbit ✗ request timed out

✓ exit 0 · tenant-usage-snapshot.json 包含成功数据与失败原因

10.10业务进阶 05 · 大体积素材治理

遍历图片与视频素材,筛选超过 5 MiB 的文件并按体积倒序生成 JSON 清单,帮助内容团队定位需要压缩或迁移的资产。

asset-audit.hhy
if length(args) != 2 {
    print_error("usage: hhy run asset-audit.hhy <asset-dir> <report.json>")
    exit(3)
}

path(args[0])
    |> files("**/*")
    |> where { file ->
    file.is_file and
    (file.extension == ".png" or file.extension == ".jpg" or file.extension == ".mp4")
}
    |> where { file -> file.size > 5mib }
    |> sort_by({ order: "desc" }) { file -> file.size }
    |> map { file ->
    { path: file.path, bytes: file.size, extension: file.extension }
}
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path(args[1]))
$ hhy run asset-audit.hhy ./public asset-report.json
scanned 1,842 assets
large assets: 27
largest: public/video/launch.mp4 · 184.2 MiB

✓ exit 0 · asset-report.json 已生成

10.11监听源码并自动构建

监听 C 代码变化,通过 debounce 合并短时间内的连续保存,再执行 make。构建失败只打印错误,监听任务继续运行。

watch-build.hhy
if length(args) != 1 {
    print_error("usage: hhy run watch-build.hhy <source-dir>")
    exit(3)
}

let source_dir = path(args[0])

watch(source_dir, { recursive: true })
    |> where { event ->
    event.kind != "removed" and
    (event.path.extension == ".c" or event.path.extension == ".h")
}
    |> debounce(300ms)
    |> for_each { event ->
    print("changed: {event.path}")

    let result = run(["make"], { timeout: 2min, cwd: system.cwd })

    if result.exit_code != 0 {
        print_error(result.stderr)
    } else {
        print(result.stdout)
    }
}
sh
hhy run watch-build.hhy ./src
$ hhy run watch-build.hhy ./src
watching ./src recursively…
changed: src/runtime/flow.c
cc -std=c11 -O2 -c src/runtime/flow.c
cc build/*.o -lcurl -lpcre2-8 -lgc -o build/hhy
Build complete: build/hhy

✓ watcher remains active · waiting for the next change

10.12从 CSV 生成部门汇总报表

读取员工 CSV,筛选在职人员,按部门统计人数和薪资总额,最后原子写入格式化 JSON。输入列为 name、department、active、salary。

csv-report.hhy
if length(args) != 2 {
    print_error("usage: hhy run csv-report.hhy <input.csv> <output.json>")
    exit(3)
}

read_lines(path(args[0]))
    |> parse_csv({ header: true })
    |> where { employee -> employee.active == "true" }
    |> group_by { employee -> employee.department }
    |> map { group ->
    {
        department: group.key,
        employees: group.values |> count,
        total_salary: group.values
            |> map { employee -> employee.salary |> to_float }
            |> sum
    }
}
    |> collect
    |> encode_json({ pretty: true })
    |> save_text(path(args[1]))
sh
hhy run csv-report.hhy employees.csv department-report.json
$ hhy run csv-report.hhy employees.csv department-report.json && cat department-report.json
[
  { "department": "Engineering", "employees": 12, "total_salary": 2160000 },
  { "department": "Product", "employees": 5, "total_salary": 810000 }
]

✓ exit 0 · department-report.json 已原子写入

10.13大文件备份(支持 dry-run)

找出超过 100 MiB 的文件并复制到备份目录。先用 dry-run 检查动作计划,确认无误后再真实执行。

backup-large.hhy
if length(args) != 2 {
    print_error("usage: hhy run backup-large.hhy <source-dir> <backup-dir>")
    exit(3)
}

let source_dir = path(args[0])
let backup_dir = path(args[1])

source_dir
    |> files("**/*")
    |> where { file -> file.is_file and file.size > 100mib }
    |> for_each { file ->
    let target = path_join(backup_dir, file.name)
    print("copy {file.path} -> {target}")
    copy(file.path, target, { overwrite: false, create_parents: true })
}
    |> on_error { err ->
    print_error(err)
    throw(err)
}
sh
hhy run --dry-run backup-large.hhy ./downloads ./backup
hhy run backup-large.hhy ./downloads ./backup
$ hhy run --dry-run backup-large.hhy ./downloads ./backup
copy downloads/archive.tar -> backup/archive.tar
copy downloads/database.dump -> backup/database.dump
[dry-run] copy downloads/archive.tar → backup/archive.tar
[dry-run] copy downloads/database.dump → backup/database.dump

✓ exit 0 · 仅生成计划,没有写入文件
备份脚本默认不覆盖同名文件,并自动创建目标目录;正式执行前仍建议先运行 dry-run。

10.1407 · 语言基础综合练习

用一个小型汇总任务串起变量、List、Map、函数、条件、循环、作用域和错误处理。对应 examples/07-language-basics.hhy。

07-language-basics.hhy
fn summarize(items) {
    let mut total = 0

    for item in items {
        if item.enabled {
            total = total + item.score
        }
    }

    return total
}

let users = [
    { name: "Ada", enabled: true, score: 98 },
    { name: "Linus", enabled: false, score: 86 }
]

summarize(users) |> print
$ hhy run examples/07-language-basics.hhy
{
  "count": 2,
  "total": 40,
  "average": 20
}

✓ exit 0 · 汇总结果已生成

实战项目 · 11

实战项目:FlowGuard

用 HHY v1.3.10 构建完整的代码仓库体检与质量门禁应用,包含真实数据、并发检查、JSON 报告和端到端测试。

11.1这不是语法 Demo

FlowGuard 是一个使用 HHY v1.3.10 运行并通过自测的完整应用。它接收项目目录与 JSON 配置,检查必需文件、扫描文件和疑似凭据、并发执行质量命令与 HTTP 健康检查,最终原子写入结构化报告,并用稳定退出码决定质量门禁是否通过。

应用能力使用的 HHY 能力
项目结构检查Path、read_text、attempt、List
文件与安全扫描files、Stream、Regex、Bytes
质量命令run、parallel、Duration、CommandResult
服务健康检查http.get、timeout、retry、parallel
报告与门禁Map、encode_json、原子 save_text、exit

在 GitHub 查看 FlowGuard 完整源码 ↗
包含 HHY 入口、六个业务模块、配置、测试项目、HTTP 服务和报告断言。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/flowguard

11.2项目目录

入口脚本只负责编排,具体检查被拆分到 lib 中;config 保存两套场景,fixtures 提供可以重复测试的项目数据。output 和 __pycache__ 被忽略,不进入仓库。

FlowGuard 项目目录树,展示 config、fixtures、lib、入口脚本和测试工具
FlowGuard 的真实目录结构;output 与 __pycache__ 是本地自测产物,不在 Git 中。
路径职责
flowguard.hhy读取参数和配置,组合检查,写报告并设置退出码
lib/*.hhy结构、文件、安全、命令、健康和报告模块
config/*.json健康与风险场景配置
fixtures/*确定性的被检查项目数据
self-test.sh启动测试服务并验证两个端到端场景

11.3运行完整自测

在仓库根目录执行一条命令。自测会启动仅监听 127.0.0.1:18991 的临时 HTTP 服务,先检查 HHY 模块,再运行健康和风险两套场景,并用 Python 对生成的 JSON 报告做结构与结果断言。

sh
cd hhy-vm
sh practical-projects/flowguard/self-test.sh
FlowGuard 端到端自测的终端输出,健康场景全部通过,风险场景发现五项失败,最终自测通过
真实运行结果:healthy-service 8 项通过;risky-service 正确发现 5 项失败;最终 FlowGuard self-test passed。

11.4健康场景与风险场景

场景输入数据预期结果
healthy-serviceREADME、LICENSE、package.json、源码、两个成功命令和 2xx 健康端点8 passed,退出码 0
risky-service缺少 LICENSE、模拟 DEMO_TOKEN、失败命令和 404 端点5 failed,退出码 1;自测将这个非零状态视为正确结果
风险场景里的凭据是明确标注的假数据。FlowGuard 报告只保存文件名和 content_redacted: true,不保存匹配内容。

11.5配置自己的项目

text
{
  "project": { "name": "my-service" },
  "required_files": ["README.md", "LICENSE"],
  "limits": { "large_file": "4kib" },
  "commands": [
    { "name": "tests", "argv": ["npm", "test"] }
  ],
  "health_checks": [
    { "name": "api", "url": "http://127.0.0.1:8080/health" }
  ]
}

命令使用 argv 数组直接交给 run,不经过 shell 拼接;每个命令限制为 15 秒和 1 MiB 输出。当前示例接受 256b、1kib、4kib 或 1mib 文件阈值。

sh
hhy run \
  --limit max_runtime=2min \
  --limit max_memory=256mib \
  --limit max_processes=8 \
  practical-projects/flowguard/flowguard.hhy \
  /path/to/project \
  practical-projects/flowguard/config/my-project.json \
  report.json

11.6为什么它能代表 HHY

FlowGuard 把文件系统、进程、HTTP 和数据处理统一进同一条可靠工作流。单项失败通过 attempt 转换为结构化检查结果,不会阻止其他检查完成;parallel 提供有上限的并发;最终报告可以直接交给 CI/CD 读取。这正是 HHY 相比复杂 Shell 脚本最有辨识度的应用方向。

阅读 FlowGuard 中文使用说明 ↗
查看配置字段、手动运行方式、测试设计与真实项目接入命令。
https://github.com/hh696-wq/hhy-vm/blob/main/practical-projects/flowguard/README.zh-CN.md

实战项目 · 12

实战项目:DataFlow ETL

从 CSV、JSON 目录和 HTTP API 同步数据,完成清洗、过滤、并发补全、分组汇总及 JSON/CSV 双输出。

12.1完整的数据同步管道

DataFlow ETL 是完全由 HHY v1.3.10 运行并通过端到端自测的数据同步应用。它读取客户 CSV 和事件 JSON 目录,规范化姓名与邮箱,过滤停用和低消费客户,并发请求本地画像 API,按部门 group_by 汇总,最后原子写入 JSON 报告和 CSV 明细。

阶段实现
采集read_lines + parse_csv;files + parse_json
清洗trim、lower、to_int 与结构化 Map
补全parallel(4) + http.get + timeout + retry
汇总where、sort_by、group_by、sum
输出encode_json/save_text 与 encode_csv/save_lines

在 GitHub 查看 DataFlow ETL 完整源码 ↗
包含 HHY 模块、CSV/JSON 测试数据、画像 API、报告断言和一键自测。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/dataflow-etl

12.2真实目录与数据流

DataFlow ETL 项目目录树
真实项目目录:入口、四个 HHY 模块、CSV/JSON fixtures、配置和测试工具。
text
customers.csv + events/*.json + HTTP profiles
                    ↓
            parse / trim / lower
                    ↓
          active + minimum spend filter
                    ↓
          parallel HTTP enrichment
                    ↓
          group_by department + sum
                    ↓
              report.json + customers.csv

12.3实际自测结果

sh
cd hhy-vm
sh practical-projects/dataflow-etl/self-test.sh
DataFlow ETL 实际端到端自测结果
真实运行:3 条合格客户、2 个事件文件、2 个部门汇总,HTTP 补全及 JSON/CSV 断言全部通过。
测试服务只监听 127.0.0.1:18992。测试会验证客户过滤和排序、邮箱清洗、远程 region/tier 字段、部门消费汇总以及两种输出格式。

12.4运行自己的同步任务

复制 config/test.json,替换项目名、API 地址和最低消费阈值,再准备 customers.csv 与 events/*.json。HTTP 单项失败会变成结构化 error,报告 ok=false 并返回退出码 1。

sh
hhy run practical-projects/dataflow-etl/etl.hhy \
  ./input \
  ./config.json \
  ./output/report.json \
  ./output/customers.csv

实战项目 · 13

实战项目:Asset Governance

扫描项目资产、生成治理报告,并用 Runtime 原生 dry-run 安全执行 copy、move、remove 整改动作。

13.1审计与整改分离

Asset Governance 由 audit.hhy 和 cleanup.hhy 两个程序组成。审计器扫描源码、配置、图片、视频和构建产物,发现超大、过旧、命名不规范、重复文本内容和疑似凭据;清理器只接受审计报告中的白名单动作,不通过 shell 拼接命令。

检查或动作HHY 实现
文件清单和大小files、File.size、Bytes
旧文件File.modified、now、Duration
命名与敏感信息Regex、read_text、脱敏 finding
重复内容group_by 文本内容,不把原文写进报告
整改copy、move、remove 与 --dry-run EffectDispatcher

在 GitHub 查看 Asset Governance 完整源码 ↗
包含审计器、清理器、四个 HHY 模块、风险 fixtures 和 dry-run/正式整改断言。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/asset-governance

13.2项目目录

Asset Governance 项目目录树
真实目录包含审计与清理入口、治理模块,以及故意准备的大文件、旧文件、重复文件和敏感配置 fixtures。
程序职责
audit.hhy扫描项目并原子生成 report.json;存在 critical finding 时返回 1
cleanup.hhy读取 report.actions,执行受控 copy/move/remove
self-test.sh创建隔离 mktemp 工作区,先 dry-run 再正式整改并逐项断言

13.3实际自测与 dry-run

sh
cd hhy-vm
sh practical-projects/asset-governance/self-test.sh
Asset Governance 审计、dry-run 和正式整改的真实终端输出
真实运行:识别 large/naming/stale/sensitive/duplicate finding;dry-run 输出副作用计划且文件不变;正式执行三个动作后断言通过。
截图中的 Processed 表示程序走到了该动作;dry-run 阶段由 Runtime 拦截副作用。测试随后确认目标目录完全未改变,正式运行后才验证 copy、move 和 remove 生效。

13.4两阶段运行

先运行审计并阅读 report.json。存在 critical finding 时 audit 返回 1,但报告仍完整生成。确认 actions 后先执行 dry-run,检查 Runtime 输出的 effect 计划,最后再正式整改。

sh
hhy run practical-projects/asset-governance/audit.hhy ./project ./config.json ./report.json
hhy run --dry-run practical-projects/asset-governance/cleanup.hhy ./project ./report.json
hhy run practical-projects/asset-governance/cleanup.hhy ./project ./report.json

实战项目 · 14

实战项目:香港电影公司

使用 MediaWiki API 并发抓取“香港電影公司”候选页面,清洗、筛选并汇总为 CSV 和 JSON 报告。

14.1用 HHY 完成真实网络数据研究

这个项目使用 HHY v1.3.10 调用维基百科官方 MediaWiki API。程序先按“香港電影公司”搜索 10 个候选页面,再用 parallel(3) 并发抓取 page ID、正式 URL、更新时间与限定长度的简介;随后筛选同时包含香港、电影和公司语义的条目,按标题排序并原子写入 CSV 与 JSON。

阶段HHY 实现
搜索http.get + timeout + retry + parse_json
去重group_by(pageid) + Map
详情parallel(3) + attempt,单页失败不终止其他任务
筛选Stream + where + contains + sort_by
输出encode_csv/encode_json + atomic save

在 GitHub 查看完整源码 ↗
包含 HHY 抓取程序、配置、模块、本地 MediaWiki fixture、CSV/JSON 断言和中英文说明。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/hong-kong-film-companies

14.2项目结构

香港电影公司 HHY 维基百科抓取项目目录树
真实目录:crawl.hhy 负责编排,api.hhy 负责搜索和并发详情请求,transform.hhy 负责去重、筛选、排序与报表结构。
文件职责
crawl.hhy读取配置、组合数据流并原子输出 CSV/JSON
lib/api.hhyMediaWiki 搜索、HTTP 策略和 bounded parallel
lib/transform.hhy语义过滤、稳定排序和输出字段
self-test.sh启动本地 fixture 并验证 5→3 的确定性结果

14.3真实维基百科运行结果

2026-08-26 的实际运行抓取 10 个候选页面,10 个详情请求全部成功,筛出 7 个公司相关结果,包括中國星集團、國泰機構、天下一電影、東方電影(香港)、邵氏兄弟、電影工作室和香港電影公司列表。

sh
./build/hhy run --limit max_runtime=2min --limit max_parallelism=8 \
  practical-projects/hong-kong-film-companies/crawl.hhy \
  practical-projects/hong-kong-film-companies/config/wikipedia.json \
  practical-projects/hong-kong-film-companies/output/wikipedia-report.json \
  practical-projects/hong-kong-film-companies/output/wikipedia-hong-kong-film-companies.csv
HHY 并发抓取香港电影公司维基百科数据的真实终端结果
真实联网运行:Candidates 10、Fetched 10、Companies 7,并成功写出 CSV 和 JSON 报告。
维基百科搜索结果和页面内容会变化,因此这是可复现的动态研究样本,不是完整公司注册名录。项目的 self-test 使用本地模拟 API,避免把外部网络变化当成代码回归。

14.4并发、边界与可重复验证

默认并发度为 3,每页简介限制为 600 字符,避免不受控响应占用 worker 通道。网络请求具有 10 秒 timeout 和两次 retry;每个详情任务由 attempt 隔离。中文搜索词在配置中的 search_url 已百分号编码,以兼容 HHY 1.1.1 当前非 ASCII query Map 编码限制。

sh
sh practical-projects/hong-kong-film-companies/self-test.sh

阅读中文运行说明 ↗
查看输出字段、真实抓取命令、配置限制与确定性测试设计。
https://github.com/hh696-wq/hhy-vm/blob/main/practical-projects/hong-kong-film-companies/README.zh-CN.md

实战项目 · 15

实战项目:多 API 数据采集器

并发采集 OpenAlex、Crossref 和 GitHub 分页数据,统一字段、记录失败并增量汇总为 CSV。

15.1一条可靠的数据采集 Flow

这个项目使用 HHY v1.3.10 同时采集 OpenAlex 学术成果、Crossref 论文元数据和 GitHub 仓库。每个来源请求 2 页,HTTP 下载由 parallel(3) 有界并发完成,异构 JSON 随后统一成 source、external_id、title、url、record_type、metric_name 和 metric_value。

能力实现
分页与并发6 个任务 + parallel(3)
网络容错250ms 限速 + 10s timeout + 2 次 retry + attempt
数据治理字段统一 + source/external_id 去重 + 稳定排序
增量保存读取已有 CSV,新记录覆盖同键旧记录,atomic save
故障审计失败来源、页码和错误写入 failures.json

在 GitHub 查看完整源码 ↗
包含 HHY 入口、分页任务、三源适配器、增量合并、配置和确定性自测。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/multi-api-data-collector

15.2项目结构

HHY 多 API 数据采集器目录结构
collector.hhy 负责编排,jobs.hhy 生成分页任务,sources.hhy 下载并标准化三种 API,merge.hhy 完成去重与增量合并。
文件职责
collector.hhy组合采集、统计和原子输出
lib/jobs.hhy生成 OpenAlex、Crossref、GitHub 分页任务
lib/sources.hhy限速、超时、重试、并发下载和字段统一
lib/merge.hhy读取旧 CSV、去重、排序和增量覆盖

15.3运行与增量结果

sh
./build/hhy run practical-projects/multi-api-data-collector/collector.hhy \
  practical-projects/multi-api-data-collector/config/public-apis.json \
  practical-projects/multi-api-data-collector/output/records.csv \
  practical-projects/multi-api-data-collector/output/report.json \
  practical-projects/multi-api-data-collector/output/failures.json
HHY 多 API 数据采集器自测终端结果
确定性端到端验证:6 页、12 条输入、9 条唯一记录;第二次运行读取 9 条旧记录,增量合并后仍为 9 条。
公开 API 数据和额度会变化。正式输出保留来源 URL;本地 fixture 只用于回归测试并在退出后删除,不会写入正式 output。

15.4验证

sh
sh practical-projects/multi-api-data-collector/self-test.sh

测试连续运行两次,验证分页、并发、字段统一、跨页去重、稳定排序、失败列表和增量覆盖。并发用于等待 HTTP,而不是把数值计算伪装成 HHY 的优势。

实战项目 · 16

实战项目:SiteGraph Auditor

递归建立文档站页面清单与规范化链接图,用 metadata、失败和安全边界实施质量门禁。

16.1一个真正使用安全 Spider 的质量门禁

SiteGraph Auditor 基于 HHY v1.3.10 和 my-crawler 的安全递归引擎。它从 seed 开始逐层发现页面,同时输出 inventory、规范链接图、report 和 failures;报告以稳定退出码阻止缺失 metadata 或存在抓取失败的站点通过。

新能力项目中的实际用途
URL 规范化相对链接、点路径、fragment、host 和默认端口统一成稳定 URL
链接发现main a[href] 持续补充下一层 Frontier
Frontier按深度批次并发,保留 page/depth/source 上下文
硬边界domain/path/depth/pages/frontier/links 六类限制
指纹去重进入 Frontier 前去重,链接图另统计同源重复边
SSRF正式配置禁止私网,在实际 socket 地址上覆盖 DNS 与重定向

查看 SiteGraph Auditor 完整源码 ↗
包含三个 HHY 模块、四层健康站点、风险站点、报告断言和 SSRF 负向测试。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/sitegraph-auditor

16.2健康与风险双场景

sh
make
./practical-projects/sitegraph-auditor/self-test.sh
$ ./practical-projects/sitegraph-auditor/self-test.sh
SiteGraph Auditor healthy
Pages 4 / 4 Edges 5
Duplicates 3 Rejected 1 Findings 0
SiteGraph Auditor risky
Pages 1 / 2 Edges 2
Duplicates 0 Rejected 1 Findings 3
SiteGraph Auditor self-test passed

健康站点包含四层页面、相对 URL、点路径、fragment 重复和跨域引用,必须通过。风险站点包含缺失 description/canonical、404 和越界路径,必须返回失败;最后再证明安全模式会拒绝 loopback。

16.3输出与当前边界

输出内容
inventory.jsontitle、description、canonical、heading、source_url
graph.jsonsource、原始 href、规范目标、fingerprint、允许状态和拒绝原因
report.json页面、边、重复、拒绝、限制、错误、warning 和 findings
failures.jsonURL、深度和稳定错误
默认模式仍是静态站点审计,不绕过认证、验证码、robots.txt 或反爬策略。v1.1.5 可选择原子 checkpoint Frontier 与严格断点恢复,也可通过隔离的 Playwright Renderer 执行 JavaScript。

参考 · 17

语法完整参考

V1.3.10 的词法、字面量、运算符、语句、闭包和模块语法。

17.1源文件与词法

项目规则
文件.hhy、UTF-8、LF 或 CRLF
标识符大小写敏感;ASCII 字母、数字和下划线,不能以数字开头
语句结束换行或可选分号
续行未闭合括号或行首/行尾的 |>
注释# 单行注释;首行允许 shebang
/表达式起点为 Regex,已有左操作数后为除法

17.2字面量与原生单位

hhy
let nothing = null
let flags = [true, false]
let numbers = [42, -10, 0xff, 0b1010, 1.5, 1e6]
let name = "HHY"
let strings = ["hello", "Hello, {name}"]
let pattern = /ERROR|WARN/i
let list = [1, 2, 3]
let record = { name: "Tom", age: 20 }
let interval = 1..10
let units = [10mib, 5s, 80%]

Range 包含起点、不包含终点。Bytes 支持 b/kb/mb/gb/kib/mib/gib;Duration 支持 ns/us/ms/s/min/h;紧贴数字的 % 是 Percent。String 支持插值以及 \, ", \n, \r, \t, \b, \f, \0 转义。

17.3运算符优先级(高到低)

text
()  []  .
not  -  +
*  /  %
+  -
<  <=  >  >=
==  !=
and
or
??
|>
=

and、or 与 ?? 短路执行;= 只允许给 let mut 绑定赋值;|> 左结合。条件必须是 Bool,不存在把 0、空字符串或 null 自动当作 false 的规则。

17.4声明、控制流、函数与模块

hhy
let name = "HHY"
let mut count = 0
count = count + 1
let enabled = true
let items = ["Flow", "Pipe"]

if enabled { print("yes") } else { print("no") }
for item in items { print(item) }
while count < 3 { count = count + 1 }

fn add(a, b) { return a + b }
let doubled = [1, 2] |> stream |> map { number -> number * 2 } |> collect

try { read_text(path("config.json")) } catch err { print_error(err) }
let result = attempt { read_text(path("config.json")) }

import { add as sum_two } from "./math.hhy"
export fn public_api(value) { return value }
结构形式
调用name(args)
Pipex |> f(a) 等价于 f(x, a)
闭包{ param -> expression }
Map{ key: value }
控制流if、for、while、break、continue、return
模块import、as、export

17.5核心值类型

text
Null Bool Int Float String Regex BytesBuffer
List Map Range Function Error Result Stream
Bytes Duration Percent DateTime Path
File Directory FileEvent Process CommandResult
HttpRequest HttpResponse
HHY 是动态类型语言,但不会进行危险的 String/Number 或 String/Bool 隐式转换。Int 是有符号 64 位整数,Float 是 IEEE 754 double。

参考 · 18

标准库函数索引

运行时 Registry 中全部 96 个 V1.3.10 核心 callable 的签名与用途。

18.1如何阅读签名

本页以 V1.3.10 Runtime 的 Callable Contract Registry 为权威来源,共 96 个核心 callable;扩展动态注册的 callable 在各扩展文档中说明。T/U 表示泛型占位值,? 表示可选参数或可空结果,Map? 表示可选 options Map。所有函数都可普通调用;在管道中,左侧值会注入为第一个参数。

这是完整 callable 清单,不含 args、env、system 等只读特殊值,也不把 File.path、HttpResponse.status 等只读字段误列为函数。

18.2核心值、集合、环境与控制(22)

print

print(Value...) -> Null

把值写到标准输出;传入 Stream 时逐项输出并消费它。

print_error

print_error(Value...) -> Null

把值写到标准错误;适合诊断信息。

exit

exit(Int?) -> Never

立即以给定状态码结束脚本,省略时使用 0,并触发资源清理。

length

length(String | List | Map) -> Int

返回 String 的 code point 数或 List/Map 的元素数;Stream 应使用 count。

byte_length

byte_length(String | BytesBuffer) -> Int

返回 String 的 UTF-8 字节数或 BytesBuffer 大小。

type

type(Value) -> String

返回值的逻辑类型名。

is_type

is_type(Value, String) -> Bool

判断值是否具有指定逻辑类型,返回 Bool。

to_int

to_int(Int | Float | String) -> Int

把 Int/Float/String 显式转换为 Int,失败或溢出产生 ValueError。

to_float

to_float(Int | Float | String) -> Float

把 Int/Float/String 显式转换为 Float,失败产生 ValueError。

get

get(List | Map | Record, Int | String) -> Value | Null

安全读取 List 索引、Map 键或对象字段;缺失返回 null。

require

require(Map, String) -> Value

读取必需 Map 键;键缺失产生 KeyError,存在且为 null 时返回 null。

pick

pick(Map, List<String>) -> Map

返回只保留指定键的新 Map,并保留存在的 null 字段。

put

put(Map, String, Value) -> Map

返回新增或替换一个键的新 Map,不修改原 Map。

remove_key

remove_key(Map, String) -> Map

返回移除指定键的新 Map。

append

append(List<T>, T) -> List<T>

返回末尾增加一个元素的新 List。

remove_at

remove_at(List<T>, Int) -> List<T>

返回移除指定索引的新 List;越界产生 IndexError。

now

now() -> DateTime

返回带时区的当前 DateTime。

datetime.parse

datetime.parse(String, String, String) -> DateTime

按明确的格式和时区解析 DateTime,非法输入产生 ValueError。

require_env

require_env(String) -> String

读取必需环境变量;不存在时产生 KeyError。

sleep

sleep(Duration) -> Null

可取消地等待指定 Duration。

cancel

cancel() -> Never

触发当前执行的根取消令牌并开始统一清理。

throw

throw(Error) -> Never

抛出 Error,并沿调用栈或 Flow 传播。

18.3Flow 与 Stream(25)

map/where/take 等转换保持惰性;collect、count、reduce 等终端操作消费 Stream;sort_by 与 group_by 会在资源上限内物化输入。parallel 使用有界隔离 worker 并保持输出顺序。

stream

stream(List<T> | Map | Range) -> Stream<T>

把 List、Map entries 或 Range 转成惰性单次消费 Stream。

range

range(Int, Int) -> Stream<Int>

创建从 start 到 end(不含 end)的 Int Stream。

map

map(Stream<T>, Function(T -> U)) -> Stream<U>

惰性地对每项调用闭包,一项输入对应一项输出,不自动展开。

flat_map

flat_map(Stream<T>, Function(T -> Stream<U>)) -> Stream<U>

对每项返回一个子 Stream,并惰性地把子流依次展开。

where

where(Stream<T>, Function(T -> Bool)) -> Stream<T>

惰性保留闭包返回 true 的项目;闭包必须返回 Bool。

take

take(Stream<T>, Int) -> Stream<T>

惰性保留前 n 项,达到数量后提前关闭上游。

skip

skip(Stream<T>, Int) -> Stream<T>

惰性丢弃前 n 项,然后传递其余项目。

inspect

inspect(Stream<T>, Function(T -> Value)) -> Stream<T>

为每项执行观察闭包,再原样传递项目。

distinct

distinct(Stream<Hashable>) -> Stream<Hashable>

惰性去除重复的可 Hash 标量,并保存已见集合。

sort_by

sort_by(Stream<T>, Map, Function(T -> Comparable)) -> Stream<T>

物化有限输入,按闭包 key 和 asc/desc 选项稳定排序。

group_by

group_by(Stream<T>, Function(T -> Hashable)) -> Stream<Group<T>>

物化有限输入并按 Hash key 输出 Group;Group 含 key 与 values。

debounce

debounce(Stream<T>, Duration) -> Stream<T>

在指定 Duration 内合并快速连续事件,常用于 watch。

on_error

on_error(Stream<T>, Function(Error -> Stream<T>)) -> Stream<T>

当 Stream 失败时调用闭包,用返回的 Stream 恢复或替换后续输出。

parallel

parallel(Stream<T>, Int, Function(T -> U)) -> Stream<U>

用最多 n 个隔离 worker 并发处理,保序、有界缓冲且 fail-fast。

collect

collect(Stream<T>) -> List<T>

消费有限 Stream 并物化为 List。

count

count(Stream<T>) -> Int

消费 Stream 并返回项目数。

first

first(Stream<T>) -> T | Null

返回第一项或 null,并提前关闭上游。

last

last(Stream<T>) -> T | Null

消费 Stream 并返回最后一项或 null。

min

min(Stream<Number>) -> Number | Null

消费数值 Stream,返回最小值或空流的 null。

max

max(Stream<Number>) -> Number | Null

消费数值 Stream,返回最大值或空流的 null。

sum

sum(Stream<Number>) -> Number

消费数值 Stream 并求和,遵守 Int 溢出规则。

reduce

reduce(Stream<T>, U, Function(State<T,U> -> U)) -> U

以 initial 累积 Stream;闭包接收含 acc/item/index 的 state。

any

any(Stream<T>, Function(T -> Bool)) -> Bool

任一项目满足谓词即返回 true,并短路关闭上游。

all

all(Stream<T>, Function(T -> Bool)) -> Bool

所有项目满足谓词才返回 true;首个 false 时短路。

for_each

for_each(Stream<T>, Function(T -> Value)) -> Null

消费 Stream 并为每项执行闭包,返回 null。

18.4文本、Regex、JSON 与 CSV(18)

contains

contains(String | List, Value) -> Bool

判断 String 是否含子串,或 List 是否含相等值。

upper

upper(String) -> String

返回 Unicode 大写转换后的新 String。

lower

lower(String) -> String

返回 Unicode 小写转换后的新 String。

trim

trim(String) -> String

移除 String 两端空白。

trim_start

trim_start(String) -> String

移除 String 开头空白。

trim_end

trim_end(String) -> String

移除 String 末尾空白。

starts_with

starts_with(String, String) -> Bool

判断 String 是否以指定文本开头。

ends_with

ends_with(String, String) -> Bool

判断 String 是否以指定文本结尾。

replace

replace(String, String, String) -> String

返回把匹配文本替换后的新 String。

split

split(String, String) -> List<String>

按分隔文本把 String 分割成 List<String>。

join

join(List<String>, String) -> String

用分隔文本连接 List<String>。

regex_match

regex_match(String, Regex) -> Bool

判断 PCRE2 Regex 是否匹配 String,受正则资源限制。

regex_captures

regex_captures(String, Regex) -> Map | Null

返回完整匹配、字节位置、编号和命名捕获;不匹配返回 null。

url_resolve

url_resolve(String, String?) -> Map

解析绝对或相对 HTTP(S) URL,移除 fragment、默认端口与点路径,并返回 host、path 和稳定指纹。

parse_json

parse_json(String) -> JsonValue

严格解析 JSON String 为普通 HHY 值,错误包含行列。

encode_json

encode_json(JsonValue, Map?) -> String

把可编码普通值转成 JSON;options 可启用 pretty。

parse_csv

parse_csv(String | Stream<String>, Map?) -> Stream<Map>

把 String 或行 Stream 流式解析成 Stream<Map>。

encode_csv

encode_csv(Stream<Map>, Map?) -> Stream<String>

把 Stream<Map> 流式编码为不含换行符的 CSV record Stream。

18.5路径、文件与监听(15)

read_* 是读取操作;write_* 直接写入;save_* 使用临时文件加原子替换。文件系统 action 会被 dry-run 拦截。

path

path(String) -> Path

把 String 词法规范化为 Path,不访问文件系统。

path_join

path_join(Path, String | Path) -> Path

组合 Path 与子路径并返回规范化的新 Path。

files

files(Path, String, Map?) -> Stream<File | Directory>

按 glob 惰性遍历根目录,返回 File/Directory Stream。

read_text

read_text(Path) -> String

完整读取 UTF-8 文件为 String。

read_lines

read_lines(Path) -> Stream<String>

逐行惰性读取 UTF-8 文件并移除行终止符。

read_bytes

read_bytes(Path) -> BytesBuffer

完整读取二进制文件为 BytesBuffer。

write_text

write_text(Path, String, Map?) -> Path

以原子替换方式写 String,支持 overwrite/create_parents。

append_text

append_text(Path, String) -> Path

把 String 追加到文件末尾。

write_bytes

write_bytes(Path, BytesBuffer, Map?) -> Path

以原子替换方式写 BytesBuffer。

save_text

save_text(String | Stream<String>, Path, Map?) -> Path

把 String 或文本 Stream 边拉取边原子保存。

save_lines

save_lines(Stream<String>, Path, Map?) -> Path

把 String Stream 逐项写入并补 LF,最终原子替换。

copy

copy(Path, Path, Map?) -> Path

复制文件,支持原子 no-replace 与创建父目录。

move

move(Path, Path, Map?) -> Path

移动或重命名文件,遵守覆盖选项。

remove

remove(Path) -> Path

删除明确 Path,并返回该 Path。

watch

watch(Path, Map?) -> Stream<FileEvent>

返回无限 FileEvent Stream,支持 recursive 选项并响应取消。

18.6进程、标准输入与定时(6)

run 直接传递 argv,不经过 Shell;只有 shell 明确采用 Shell 解析。进程启动会受 timeout、输出和进程数限制。

run

run(List<String>, Map?) -> CommandResult

直接执行 argv,不经过 Shell;返回 CommandResult。

shell

shell(String, Map?) -> CommandResult

显式用 Shell 执行 String;仅在需要重定向、管道等 Shell 语义时使用。

stdout_lines

stdout_lines(CommandResult) -> Stream<String>

把 CommandResult.stdout 转为惰性行 Stream。

processes

processes() -> Stream<Process>

获取当前进程快照的 Stream<Process>。

stdin_lines

stdin_lines() -> Stream<String>

惰性读取标准输入行,直到 EOF 或取消。

every

every(Duration) -> Stream<Int>

按指定 Duration 产生无限计时 tick Stream。

18.7HTTP(10)

http.* 只构造不可变请求计划,timeout/retry 修改计划,只有 send 产生网络副作用。response_body 返回 UTF-8 文本,二进制响应使用 response_bytes。

http.get

http.get(String, Map?) -> HttpRequest

构造 GET HttpRequest 计划,不发送网络请求。

http.post

http.post(String, Map?) -> HttpRequest

构造 POST HttpRequest 计划,不发送网络请求。

http.put

http.put(String, Map?) -> HttpRequest

构造 PUT HttpRequest 计划,不发送网络请求。

http.delete

http.delete(String, Map?) -> HttpRequest

构造 DELETE HttpRequest 计划,不发送网络请求。

timeout

timeout(HttpRequest, Duration) -> HttpRequest

返回设置请求超时的新 HttpRequest。

retry

retry(HttpRequest, Map) -> HttpRequest

返回配置重试次数和退避的新 HttpRequest。

send

send(HttpRequest) -> HttpResponse

执行 HttpRequest 网络副作用并返回 HttpResponse。

send_to

send_to(HttpRequest, Path) -> HttpResponse

把 HTTP body 流式写入原子文件,返回包含 path 和 size 的 HttpResponse。

response_body

response_body(HttpResponse) -> String

验证响应状态并把有界 body 解码为 UTF-8 String。

response_bytes

response_bytes(HttpResponse) -> BytesBuffer

验证响应状态并返回有界二进制 BytesBuffer。

参考 · 19

CLI 参考

运行、检查、格式化、REPL、dry-run 与性能分析。

19.1版本与发布信息

使用 --version 确认当前二进制版本、项目作者、开源许可证和官方联系方式。源码构建使用 ./build/hhy;发行包或安装到 PATH 后可直接使用 hhy。

HHY · 版本信息 · $ ./build/hhy --version
hhy 1.3.10
© 2026 HHY Language contributors
Author: houhuiyang
License: Apache License 2.0
https://hhylang.dev/
huiyang.hou@qq.com

HHY 1.3.10 的真实命令输出;版本、作者、许可证、官网和联系邮箱由 CLI 直接提供。

如果从正式发行包运行,请在解压目录执行 ./bin/hhy --version;如果已经 make install 或加入 PATH,则执行 hhy --version。

19.2完整命令

sh
hhy script.hhy [args...]
hhy run script.hhy [args...]
hhy repl
hhy check script.hhy...
hhy fmt script.hhy...
hhy fmt --check script.hhy...
hhy ast script.hhy
hhy bytecode script.hhy
hhy bytecode --metrics script.hhy
hhy tokens script.hhy
hhy run --dry-run script.hhy
hhy run --limit max_runtime=30s --limit max_memory=256mib script.hhy
hhy profile script.hhy [args...]
hhy profile --cpu script.hhy
hhy profile --heap --format json --output profile.json script.hhy
hhy --version
hhy --help
命令用途
hhy run使用默认 Bytecode 引擎运行脚本并传递 args
hhy run --engine ast|bytecode显式选择 AST 回退或 Bytecode 引擎
hhy profile分析实际引擎的 CPU 热点、调用次数和托管 Heap 分配
hhy repl启动交互环境
hhy check检查语法和核心语义
hhy fmt写入官方格式
hhy fmt --check只检查格式
hhy ast输出 AST
hhy bytecode编译、验证并反汇编 Bytecode
hhy bytecode --metrics输出 compile/verify/prepare 的缓存准入测量 JSON
hhy tokens输出 Lexer Token
hhy run --dry-run预览脱敏执行计划

hhy script.hhy 是 hhy run script.hhy 的简写。v1.3.10 默认使用 Bytecode;可用 --engine ast 或 HHY_ENGINE=ast 立即回退。脚本参数可能以 - 开头时,在 Runtime 选项后使用 -- 分隔。

19.3Bytecode 缓存准入证据

v1.3.10 新增只读的 --metrics 输出,用真实 compile+verify 与 execution-plan verify 时间评估缓存是否值得引入。固定五负载、21 次配对冷进程测量中,compile+verify 中位数为 0.004–0.012 ms,仅占冷运行墙钟 0.0078%–0.1341%,没有达到 1 ms 且 20% 的双门槛。

$ hhy bytecode --metrics examples/00-hello.hhy
{"bytecode_format_version":1,"compile_verify_ns":9000,"constants":21,"instructions":40,"schema_version":1,"source_bytes":167,"stream_kernel_version":1,"stream_kernels":1,"tool":"hhy bytecode --metrics","verify_prepare_ns":4000}
因此当前没有进程内或磁盘 Bytecode 缓存,也不接受第三方预编译 Bytecode。未来只有真实性能证据触发评审后,才可实现绑定源码、递归依赖、语言/格式/Kernel 版本、编译 feature、target 与安全策略的完整指纹;命中后仍必须经过 checksum、有界解析、完整 Verifier 和 execution-plan verify。

19.4CPU 与 Heap 性能分析

profile 会真实执行脚本,默认在一次运行中同时收集 CPU 和托管 Heap 数据。报告写入 stderr,因此脚本 stdout 保持不变;命令返回脚本原有退出码。

sh
hhy profile --engine bytecode examples/09-profile-algorithms.hhy -- fibonacci 20
hhy profile --engine ast examples/09-profile-algorithms.hhy -- fibonacci 20
hhy profile --heap --format json --output profile.json examples/09-profile-algorithms.hhy -- fibonacci 20
选项行为
--engine ast|bytecode显式分析 AST 或 Bytecode;默认 bytecode,报告 Summary 显示实际 Engine
--cpu只收集 1ms 进程 CPU 采样和调用次数
--heap只收集累计分配、分配次数、Heap 峰值和 GC 后占用
--format text|json选择人类可读或机器可读报告;默认 text
--output <path>把报告写入文件,而不是 stderr
--limit NAME=VALUE与 run 相同,覆盖 Runtime 资源限制
--dry-run与 run 相同,拦截外部副作用并分析计划执行
$ hhy profile --engine bytecode examples/09-profile-algorithms.hhy -- fibonacci 20
HHY profile: examples/09-profile-algorithms.hhy

Summary
  Engine           bytecode
  Wall time        0.008 s
  CPU time         0.005 s
  CPU utilization  70.3%
  CPU samples      3
  Heap peak        1.8 MiB
  Heap after GC    84.0 KiB
  Allocated        1.7 MiB
  Allocations      33007

CPU hotspots
  CPU%    Samples      Calls  Function
  100.0%        3      21891  fibonacci  examples/09-profile-algorithms.hhy:5:1
    0.0%        0          1  <bytecode-top-level>  examples/09-profile-algorithms.hhy:1:1

Allocation hotspots
  Bytes          Objects  Function
  1.7 MiB            32856  fibonacci  examples/09-profile-algorithms.hhy:5:1

fibonacci 6765
CPU 使用进程 CPU 时间采样,文件、HTTP 和进程等待不会被误算成 CPU 热点。运行不足数毫秒的脚本可能样本太少,应增大输入或重复负载。Heap 只统计 HHY 的 Boehm GC 托管内存,不包含扩展子进程或原生库自行管理的内存。

19.5解释器性能架构演进

v1.3.10 默认使用经 Compiler/Verifier 验证的 Bytecode VM。原生 Opcode dispatch、静态槽位、可复用调用帧和低分配 Closure 快路径降低 CPU 开销;AST Interpreter 永久保留为语义 oracle 与显式回退。

AST 与 Bytecode VM 性能演进

Compiler/Verifier → 原生 Opcode dispatch → Slot/CallFrame → 低分配 Closure → 性能门禁;v1.3.5 Bytecode 默认,AST 回退。

v1.3.10 的 run、profile 与脚本简写默认使用 Bytecode;可用 --engine ast 或 HHY_ENGINE=ast 立即回退。profile 的 Engine、<top-level>/<bytecode-top-level> 会明确标记实际路径。

19.6Runtime 资源限制

run 的 --limit NAME=VALUE 可以重复出现。大小必须带 b/kb/mb/gb/kib/mib/gib,时间必须带 ns/us/ms/s/min/h,计数值不带单位。

sh
hhy run --limit max_runtime=30s --limit max_memory=256mib script.hhy
限制默认值
max_memory512mib
max_open_files256
max_processes16
max_parallelism16
max_http_body16mib
max_regex_steps1000000
max_recursion256
max_runtime0(CLI 默认不设总时限)

19.7稳定退出码

text
0  成功
1  未处理的运行时错误
2  语法或静态检查错误
3  CLI 用法错误
4  文件 I/O、进程或网络错误
5  超时或取消

自动化脚本应按稳定退出码而不是错误文本进行分支。

扩展 · 20

扩展系统

v1.3.10 进程扩展机制:官方签名 Registry、源码编译、包清单、权限声明、Protocol 1 与 callable 注册。

20.1当前已实现的扩展边界

v1.3.10 已实现本地 install/list/remove、Ed25519 签名 Registry、manifest 与 SHA-256 校验、隔离进程握手、动态 callable 注册、同步调用、结构化错误和 shutdown。脚本可以直接 import 已安装的扩展包。
能力当前状态边界
扩展分发已实现官方签名 Registry 或本地源码构建;安装前验证身份、target、签名与文件哈希
进程协议已实现handshake、register、call、call_result、error、shutdown
值传输已实现Null、Bool、数字、String、List、Map 的 JSON 协议映射
Stream / handle / cancel未实现属于后续协议扩展
公开 Native ABI未承诺只有进程协议无法满足且有性能证据时再评估

包名就是顶级命名空间:package_name 只能注册 package_name.*,不能覆盖 hhy.*、std.*、核心 callable 或其他包。导入未安装的包会得到 ModuleNotFoundError。

20.2现有官方扩展

扩展版本发布时间状态能力
database0.2.02026-08-26已发布MySQL/PostgreSQL 查询、写入与事务
html0.1.02026-08-27已发布Lexbor CSS Selector、文本/属性读取与结构化抽取

数据库扩展使用指南
安装 database 0.2.0,并完成 MySQL/PostgreSQL 查询、写入与事务。
/zh/learn/database-extension

HTML 扩展与抓取框架
使用 html 0.2.0、可观察批量抽取、URL 规范化、安全 Frontier、去重和 SSRF 防护构建静态 Spider。
/zh/learn/html-crawler-framework

20.3在哪里获取扩展

来源适合场景地址或操作
HHY 官方 Registry下载经过签名、按平台区分的官方扩展https://registry.hhylang.dev(索引:/index.json;信任根:/root.json)
GitHub 源码查看代码、审计变更或自行编译https://github.com/hh696-wq/hhy-vm/tree/main/extensions
本地自行编译开发扩展或需要本机依赖组合make -C extensions/<name>,然后从本地目录安装
sh
# 从源码构建并安装(示例:html)
git clone https://github.com/hh696-wq/hhy-vm.git
cd hhy-vm
make
make -C extensions/html
./build/hhy install ./extensions/html

# 查看已安装扩展
./build/hhy list

查看官方扩展索引 ↗
同一扩展版本按 darwin-arm64、linux-x86_64、linux-arm64 和 windows-x86_64 分发,安装器只选择当前平台 target。
https://registry.hhylang.dev/index.json

在 GitHub 查看扩展源码 ↗
包含 sample、html 与 database 的源码、hhy.toml、测试和构建脚本。
https://github.com/hh696-wq/hhy-vm/tree/main/extensions

GitHub Release 暂不作为扩展下载入口。官方 Registry 提供签名分发;GitHub 提供可审计源码。自行编译时必须在目标操作系统和架构上构建,不能把 macOS 二进制改名用于 Linux 或 Windows。

20.4安装、查看与移除

sh
./build/hhy install ./path/to/extension
./build/hhy list
./build/hhy remove package-name
步骤实际行为
install读取 hhy.toml;校验包名、作者、requires_hhy、协议、命令和完整性;展示 capability 后由用户确认安装
import / load重新校验已安装文件的 SHA-256,启动扩展进程,握手并注册 callable
list显示已安装包的名称、版本、作者、协议和声明的 capability
remove删除本地包记录和安装目录;之后 import 会失败
默认扩展目录是 ~/.hhy/extensions;设置 HHY_EXTENSION_HOME 可为 CI 或测试提供隔离目录。capability 是安装时可审查的声明,不等同于通用操作系统沙箱;第三方扩展仍应按原生可执行文件对待。

20.5通用 hhy.toml 清单

text
[package]
name = "package-name"
version = "0.1.0"
author = "Your Organization"
requires_hhy = ">=1.1,<2.0"

[extension]
kind = "process"
command = "bin/hhy-package"
protocol = "1"

[capabilities]
read = []
write = []
network = []
process = false
字段开发者约束
package.name唯一顶级命名空间,只允许小写字母、数字和连字符
package.author安装与 list 时展示,明确官方或第三方来源
requires_hhy安装器检查 Runtime 版本范围
extension.command必须是包内 bin/ 下的可执行文件,不能逃出包目录
extension.protocol当前只接受 Protocol 1
capabilities声明需要审查的文件、网络和子进程访问范围

20.6扩展如何加载

扩展加载流程

HHY 脚本 → Runtime 校验 → 隔离扩展进程 → 协议注册 → 调用执行 → 结构化结果或错误。

阶段Runtime 与扩展的职责
resolveRuntime 根据 import package_name 定位已安装包,解析清单并校验命令与完整性
spawnRuntime 以 --protocol 1 启动独立进程,并建立 stdin/stdout 协议管道
handshake双方确认 extension_id 与 protocol_version=1.0
register扩展发送一次注册消息;Runtime 验证包命名空间和 contract 后写入 callable registry
callRuntime 发送可序列化参数;request_id 关联 call 与 call_result
shutdownRuntime 发送 shutdown 并回收协议流和子进程
Protocol 1 是同步、逐次调用协议,不提供 Stream、Opaque handle 或协议级 cancel。

20.7扩展作者需要实现什么

部分要求
包提供 hhy.toml、包内可执行命令和安装器可验证的 SHA-256 完整性信息
启动只接受 --protocol 1;协议消息只写 stdout,日志写 stderr
handshake验证 extension_id 与 protocol_version,并返回匹配身份
register恰好发送一次初始注册;名称必须位于包命名空间且 contract 完整
call按 request_id 返回 call_result 或结构化 error,不泄露凭据或敏感诊断
shutdown幂等释放连接、内存和其他扩展资源
测试至少覆盖身份不匹配、非法参数、扩展退出、协议错误和资源清理

扩展进程不会继承完整宿主环境;Runtime 只通过协议传递脚本显式提供的参数。错误应可定位,但不得包含密码、令牌、完整连接地址或其他敏感信息。

扩展 · 21

数据库扩展使用指南

安装官方 database 0.2.0 扩展,通过 JSON 配置连接 MySQL/PostgreSQL,并完成查询、写入与事务。

21.1database 扩展是什么

database 0.2.0 随 HHY v1.1.0 发布,是仓库中真实可运行的 C11 进程扩展。当前支持 MySQL、PostgreSQL、参数化查询、参数化写入和第一版事务;连接 handle、连接池、流式查询与完整数据库类型映射属于后续版本。
Callable用途当前边界
database.ping(url)验证连接并返回数据库信息每次调用建立短连接
database.query(url, sql, params, max_rows?)执行有界参数化查询结果包含 columns 与 rows
database.execute(url, sql, params)执行参数化写入或受控 DDL返回受影响行数
database.transaction(url, statements)原子执行 1–100 条写语句仅 INSERT/UPDATE/DELETE;失败整体回滚

21.2安装扩展与四个 callable

sh
make -C extensions/database
./build/hhy install ./extensions/database
./build/hhy list

install 会校验 hhy.toml、HHY 版本范围、扩展命令和 SHA-256 完整性,并在安装前展示网络 capability。安装成功后,脚本中的 import database 会启动隔离扩展进程、完成 Protocol 1 握手并注册四个 callable。

21.3连接配置与凭据安全

sh
cd extensions/database/examples/hhy_extension_test
cp config.example.json config.local.json
chmod 600 config.local.json
config.local.json
{
  "url": "mysql://root:CHANGE_ME@127.0.0.1:3306/hhy_extension_test",
  "database": "hhy_extension_test",
  "max_rows": 1000
}
驱动连接 URL 示例参数占位符
MySQLmysql://user:password@127.0.0.1:3306/hhy_extension_test?
PostgreSQLpostgresql://user:password@127.0.0.1:5432/hhy_extension_test$1、$2……
把 CHANGE_ME 替换为本机密码。config.local.json 已加入示例目录的 .gitignore;不要把真实密码写进 .hhy 源码、文档或 Git。示例脚本还会强制检查 database 必须是 hhy_extension_test,避免误操作业务库。

21.4实战一:只读检查测试库

sh
./build/hhy run \
  extensions/database/examples/hhy_extension_test/read.hhy \
  extensions/database/examples/hhy_extension_test/config.local.json
read.hhy
import database
import { load_database_config } from "./lib/config.hhy"

let config = load_database_config(args[0])
let result = database.query(
    config.url,
    "SELECT COUNT(*) AS table_count FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'",
    [config.database],
    1
)

print("Database", config.database)
print("Table count", result.rows[0].table_count)

仓库中的完整 read.hhy 还会列出每张表的名称、存储引擎和估算行数。SQL 值通过 params 传给驱动的 prepared statement,不会拼接进查询文本。

21.5实战二:受控写入与事务

sh
./build/hhy run extensions/database/examples/hhy_extension_test/write-demo.hhy \
  extensions/database/examples/hhy_extension_test/config.local.json --write

./build/hhy run extensions/database/examples/hhy_extension_test/transaction.hhy \
  extensions/database/examples/hhy_extension_test/config.local.json --write
transaction-example.hhy
database.transaction(config.url, [
    { sql: "INSERT INTO _hhy_transaction_test (id, message) VALUES (?, ?)", params: [1, "created"] },
    { sql: "UPDATE _hhy_transaction_test SET message = ? WHERE id = ?", params: ["committed", 1] }
]) |> print
两个写示例都要求显式 --write,并且只操作 hhy_extension_test 中的专用临时表。transaction 不接受 SELECT 或 DDL;任一语句失败时扩展会回滚整个事务。

21.6当前边界与错误排查

现象检查项
ModuleNotFoundError先执行 install,并用 hhy list 确认 database 0.2.0 已安装
cannot open .../read.hhy从仓库根目录运行完整路径,目录名是 hhy_extension_test
连接失败检查服务、端口、用户名、密码、库名及 hhy.toml 声明的本机网络范围
SQL 参数错误MySQL 使用 ?;PostgreSQL 使用 $1、$2……;标识符不能作为值参数

继续阅读扩展系统原理
了解清单校验、权限声明、进程加载、Protocol 1 握手和扩展开发者约束。
/zh/learn/extensions-roadmap

扩展 · 22

HTML 扩展与抓取框架

用官方 HTML 扩展和安全 Frontier 完成 URL 规范化、链接发现、递归去重及有界静态抓取。

22.1HTML 扩展是什么

官方 html 0.2.0 是一个无网络、无文件副作用的进程扩展。它用 Lexbor 解析不可信 HTML、执行 CSS Selector,并通过 extract_report 返回批量记录和明确的截断元数据。

HTML 扩展只负责解析和抽取,不下载 URL、不调度页面,也不返回 DOM handle。HTTP、TLS、超时、重试和安全策略由 HHY Runtime 与上层爬虫框架负责。

22.2构建与安装 HTML 扩展

sh
brew install jansson lexbor
make -C extensions/html
./build/hhy install ./extensions/html
./build/hhy list
完整签名用途
html.text(String html, String selector, Map?) -> String?读取首个节点的规范化文本
html.text_all(String html, String selector, Map?) -> List<String>读取全部匹配节点的文本
html.attr(String html, String selector, String name, Map?) -> String?读取首个节点的属性
html.attr_all(String html, String selector, String name, Map?) -> List<String>读取全部匹配节点的属性
html.exists(String html, String selector) -> Bool判断 Selector 是否命中
html.extract(String html, String selector, Map schema, Map?) -> List<Map>一次解析文档,并按 schema 投影重复记录
选项适用方法行为
trim: Booltext、text_all、attr、attr_all是否清理首尾空白,默认开启
max_results: Inttext_all、attr_all、extract默认 1000,硬上限 10000

扩展把输入限制在 768 KiB,以便协议消息始终有界。extract 的 schema 字段使用 { selector, value: "text" } 或 { selector, value: "attr", name };空 selector 表示读取当前 root。它不返回 DOM handle:Protocol 1 只运输 JSON 可表达的值,因此 html.extract 在扩展内一次完成解析和字段投影。

22.3从 HTML 扩展到安全爬虫框架

静态 Spider 把多个职责组合成闭环:Runtime 的 url_resolve 规范化并解析相对 URL;HTML 扩展发现链接;按深度推进的 Frontier 在入队前检查域名、路径、页面数、队列大小和请求指纹;HTTP 网络层在实际连接地址上阻止 SSRF。

能力当前实现程度
url_resolve(url, base?)返回 url、scheme、host、port、path、query 与稳定 fingerprint
链接发现follow_selector 提取 href,逐层加入 Frontier
Frontier 与去重按深度、有界并发;规范 URL 指纹在入队前去重
边界限制allowed_domains、path prefixes、max_depth/pages/frontier/links
SSRF 防护在每次实际 socket 连接时阻止 loopback、私网及 link-local,覆盖重定向

22.4项目一:my-crawler 基础闭环

sh
make
./practical-projects/my-crawler/init.sh
./practical-projects/my-crawler/self-test.sh
./practical-projects/my-crawler/run.sh

my-crawler 是最小可运行 Spider:读取 JSON 配置,递归发现链接,按边界抓取并输出 records、report 和 failures。init.sh 默认复用 ~/.hhy/extensions;CI 与自测使用临时 HHY_EXTENSION_HOME。

config/hhylang.json
{
  "seeds": ["https://hhylang.dev/zh/learn/cli-reference"],
  "allowed_domains": ["hhylang.dev"],
  "allowed_path_prefixes": ["/zh/learn/"],
  "follow_selector": "main article a[href]",
  "parallelism": 2,
  "max_depth": 2,
  "max_pages": 50,
  "max_frontier": 100,
  "max_links_per_page": 200,
  "allow_private_networks": false,
  "root_selector": "main article h2",
  "max_results": 100,
  "schema": { "title": { "selector": "", "value": "text" } }
}
$ ./practical-projects/my-crawler/self-test.sh
HHY Collector Framework Crawler Fixture
Pages 3 / 3 Records 3 Failures 0
HHY Collector Framework self-test passed

查看 my-crawler 完整源码
适合先理解配置、递归抓取、结构化抽取、失败归档和确定性自测。
https://github.com/hh696-wq/hhy-vm/tree/main/practical-projects/my-crawler

22.5项目二:SiteGraph Auditor 挑战项目

SiteGraph Auditor 在基础 Spider 上增加页面 inventory、规范化链接图、metadata 审计和 CI 质量门禁,同时运行健康站点与风险站点双场景。

输出内容
inventory.json页面 metadata、主标题和来源 URL
graph.json规范化链接边、fingerprint、允许状态与拒绝原因
report.json页面、边、重复、限制、错误、warning 与 findings
failures.json失败 URL、深度和稳定错误

进入 SiteGraph Auditor 挑战项目
继续完成站点图谱、内容质量审计、SSRF 负例和 CI 门禁。
/zh/learn/sitegraph-auditor-project

22.6适用范围与明确边界

当前支持内存或原子 checkpoint Frontier、严格配置匹配的断点恢复,以及 send_to 流式响应文件。可选 Playwright Renderer 能执行 JavaScript;它与无副作用的 Lexbor HTML 扩展隔离,并对主文档、重定向和子资源执行域名与 DNS 私网检查。

不要用它绕过 robots.txt、登录、验证码或反爬策略。只采集你有权访问的站点,并保持可识别 User-Agent、保守并发和明确页面上限。

路线图 · 23

语言与 VM 演进路线图

v1.3.10 已完成 Bytecode 默认切换后的特化、IR、Profiler 与缓存治理,AST 永久保留为语义 oracle 和回退引擎。

23.1当前版本与后续两阶段

v1.3.3–v1.3.10 已完成原生 Opcode、Bytecode 默认切换、Stream Int fusion、具名特化 metadata、Compiler/Verifier Stream Kernel IR、Profiler/资源一致性与缓存治理。最终 CI 的 1M CPU、短任务、JSON/I/O 和 Profiler 门禁均通过;真实数据未触发缓存准入。AST 继续作为语义 oracle 与 --engine ast 回退。
语言与 VM 演进路线图

核心语义冻结后,依次推进性能加固、官方扩展工具链,以及由真实生态证据驱动的 ABI 决策。

23.2版本谱系、时间与验收门槛

版本建议窗口核心交付进入下一阶段前必须满足
v1.0.0 · 已发布2026-08-25核心语言与 VM 语义冻结Pipe、Value、Stream、Error、核心标准库和三平台发行证据完成
v1.1.0 · 已发布2026-08-26本地进程扩展与官方数据库扩展安装/加载完整性、Protocol 1 同步调用、database 0.2.0 和三平台发行证据完成
v1.1.1 · 已发布2026-08-27性能优化与临界资源稳定性hhy profile、解释器热点基线和 Runtime 资源边界完成
v1.1.2 · 已发布2026-08-27HTML 扩展与静态采集框架三平台 CI、扩展协议测试、本机 fixture 与真实 hhylang.dev 抓取完成
v1.1.3 · 已发布2026-08-28Runtime 正确性与性能加固GC 压力回归、sanitizer、哈希索引、稳定诊断与三平台发布证据完成
v1.1.4 · 已发布2026-08-28安全静态 SpiderURL 规范化、链接发现、Frontier、边界、指纹去重与连接级 SSRF 防护
v1.1.5 · 已发布2026-08-30可恢复 Spider 与浏览器渲染持久 Frontier、断点恢复、流式落盘、可选 Playwright 与 Windows MSYS2 构建证据
v1.1.6 · 已完成2026-08-31稳定基线与测试治理宿主能力探测、分层 CI、机器可读性能基线与发布一致性门禁
v1.1.7 · 已完成2026-08-31诊断与编辑器基线版本化 JSON diagnostics、Contract Registry JSON、最小 LSP 与 VS Code 编辑闭环
v1.1.8 · 已完成2026-08-31Runtime 渐进治理首个模块边界、内部所有权 API、sanitizer/GC stress 与阻断式性能回归门禁
v1.2.0 · 已发布2026-08-31官方扩展分发与签名命名空间身份、Ed25519 签名索引与包描述、确定性依赖解析、dry-run 和事务式安装
v1.2.1 · 已发布2026-09-01锁定、离线与安全回滚同一 lock 得到同一依赖图;离线可重建;失败升级不破坏旧环境
v1.2.2 · 已发布2026-09-01官方 HTML 复杂扩展验证真实 fixture、可观察截断、结构化错误和四平台发行全部通过
v1.3.0-alpha · 已预发布2026-09-01Bytecode 编译器骨架核心语法可编译;非法 Bytecode 可拒绝;AST 仍为默认引擎
v1.3.0-beta · 阶段门禁已完成并入 v1.3.0Bytecode VM 执行核心执行桥、Verifier、资源边界和完整双引擎 fixture 已验收
v1.3.0-rc · 阶段门禁已完成并入 v1.3.0性能、Profiler、Stack trace 与默认切换门禁三平台和故障证据已完整;CPU 收益门槛未通过,因此 AST 保持默认
v1.3.0 · 已发布2026-09-01可选 Bytecode 正式执行路径完整套件双引擎通过;性能决策保持 AST 默认并保留显式回退
v1.3.1 · 已发布2026-09-01真实负载兼容加固官方 workload 双引擎矩阵和能力探测证据已通过三平台 CI
v1.3.2 · 已发布2026-09-01VM 内部边界稳定化版本化 Bytecode Runtime 边界、静态治理与持续 AST oracle
v1.3.3 · 已完成并入 v1.3.5原生 Opcode 执行闭环正常 Bytecode 路径不再调用 AST evaluator,完整双引擎语义对照通过
v1.3.4 · 已完成并入 v1.3.5VM 数据路径优化1M CPU workload ratio 0.6805;短任务与 JSON/I/O 无明显回退
v1.3.5 · 已发布2026-09-01Bytecode 默认引擎run/profile/简写默认 Bytecode;AST 显式回退与 oracle 永久保留
v1.3.6 · 已发布2026-09-01Stream Int fusion 性能闭环安全形状保守融合;未知形状无损回退;双引擎与跨平台门禁通过
v1.3.7 · 已发布2026-09-01特化实现加固具名 metadata、统一 stack/error、fallback reason 与三路径差分通过
v1.3.8 · 已发布2026-09-01Compiler/Verifier 优化 IRRuntime 不读取 AST 形状;Stream Kernel 独立验证并可靠回退
v1.3.9 · 已发布2026-09-01Profiler 与资源一致性普通执行与观测共用优化决策;开销、取消和 Heap 归因门禁通过
v1.3.10 · 已发布2026-09-01Bytecode 缓存治理五负载实测未达准入门槛;不实现缓存,不接受未验证外部 Bytecode
v1.4 · 规划v1.3 稳定后旗舰场景与外部采用模板、CI、运维文档和 3–5 个外部真实案例
v2.0 · 条件规划生态证据充分后生态开放与 ABI 决策至少两个真实集成证明进程协议不足;否则继续使用进程协议并不开放 Native ABI

说明:以上时间为建议窗口,不构成发布承诺。

23.3演进原则

原则约束
语义先冻结Pipe、Value、Stream、Error 与取消语义先稳定,再扩展生态表面
可用、可测先于高性能每项能力先具备确定错误、资源上限和跨平台测试,再进行优化
协议优先第三方能力优先通过 Process Extension Protocol 接入,不并行发明第二套语言语义
ABI 有条件开放Native ABI 只有在 Runtime 足够稳定且测量证明必要时才评估;不开放也是有效结论

路线图每个季度应重新评审一次:只调整尚未冻结版本;已经发布的语义、协议兼容承诺和迁移路径不能因排期变化而被削弱。

23.4明确不在路线中承诺的事项

  • 不会为了版本号引入第二套 Pipe、Stream 或 Error 模型。
  • 不会在缺少兼容策略时直接公开 Runtime 内部 C 结构体。
  • 不会把建议时间窗口当作牺牲测试、安全或跨平台验证的理由。
  • 不会同时推进远程包仓库、Native ABI 和多套官方扩展而绕过阶段验收。

工具 · 24

编辑器语言支持

为 VS Code 与 Sublime Text 安装由统一语法源生成的 HHY 语言包。

24.1HHY Language Support 0.1.0

编辑器语言包识别 .hhy 文件,提供 HHY 语法高亮、# 注释、shebang、字符串与转义、Regex、数字与单位、关键字和运算符,并配置括号自动闭合、缩进与常用代码片段。VS Code 使用 TextMate Grammar,Sublime Text 使用 .sublime-syntax。

0.1.0 是不启动 HHY 进程的轻量语言支持:当前不提供保存时格式化、诊断、跳转定义或 LSP。语法规则以仓库中的 editors/syntax/hhy-syntax.json 为唯一事实源。

查看编辑器语言包源码 ↗
包含统一语法源、生成脚本、VS Code 与 Sublime Text 包以及真实 .hhy 回归样例。
https://github.com/hh696-wq/hhy-vm/tree/main/editors

24.2生成并验证语言包

sh
git clone https://github.com/hh696-wq/hhy-vm.git
cd hhy-vm/editors
npm install
npm run generate
npm run check
npm run package

package 生成 dist/hhy-language-support-0.1.0.vsix 与 dist/HHY-0.1.0.sublime-package。check 会核对 Lexer 关键字和字面量后缀、插件元数据、生成文件新鲜度,并用真实 HHY 二进制检查 fixtures。

24.3安装到 VS Code

sh
code --install-extension editors/dist/hhy-language-support-0.1.0.vsix

也可以在 VS Code 中打开“扩展”,从右上角菜单选择“从 VSIX 安装”。安装后打开任意 .hhy 文件,语言模式会自动识别为 HHY。

24.4安装到 Sublime Text

把 editors/dist/HHY-0.1.0.sublime-package 复制到 Sublime Text 的 Installed Packages 目录。开发时也可以把 editors/sublime 复制到 Packages/HHY。之后打开 .hhy 文件即可自动启用 HHY 语法。

HHY Lexer 会根据前一个 token 区分 Regex 与除法。编辑器语法采用保守的表达式起始上下文识别 Regex,宁可少高亮一个 Regex,也避免把除法表达式的后续内容误判为 Regex。

语言报告 · 25

HHY 语言状态报告 · 2026-09-01

发布 HHY 当前语义、Runtime、性能与工程质量状态,包含可复核的 CI 实测数据。

25.1发布摘要

HHY v1.3.10 已正式发布:v1.3.7–v1.3.10 依次完成特化 metadata 加固、Compiler/Verifier Stream Kernel IR、Profiler/资源一致性和数据驱动缓存治理。Bytecode 保持默认执行引擎,AST 永久保留为语义 oracle 与紧急回退;四平台 Actions、Release 资产与 SHA256SUMS 均已验收。
报告维度回答的问题当前结论
语言基线核心语义是否稳定Pipe、Value、Stream、Error 与核心 callable contract 保持稳定,AST/Bytecode 持续对照
Runtime 健康度资源、内存与取消边界是否可靠资源上限、GC stress、sanitizer、fuzz、故障注入与显式所有权治理通过
执行引擎Bytecode 是否适合默认启用原生 Opcode 路径语义门禁与性能门禁通过,Bytecode 默认,AST 可显式回退
工程治理变化是否可审计四平台 CI、真实 workload、分层门禁、版本一致性和发行证据形成闭环

25.2本期数据概览

数据项结果证据口径
当前正式版本v1.3.10四平台 Release、逐包 SHA-256 与 SHA256SUMS
执行引擎Bytecode 默认 / AST 回退完整双引擎套件与机器可读决策
核心 callable96Runtime Callable Contract Registry
持续验证平台4 个macOS arm64、Linux arm64、Linux x86_64、Windows x86_64
最终 CI 引擎门禁全部通过1M CPU 0.3695;短任务 1.0088;持续 JSON 1.0207
Profiler 开销1.0269× / +2.786 ms9 次样本;门槛 1.35× 且 12 ms
Bytecode 缓存不准入5 个负载 × 21 次;compile+verify 不构成主要成本
完整实战项目6 个AST/Bytecode 端到端 acceptance 与稳定退出码

25.3总体基线与兼容性

基线稳定承诺验证方式
语言语义不引入第二套 Pipe、Stream 或 Error 模型规范示例、Parser/Checker fixtures 与合法程序回归
Callable contract名称、arity、effect、lazy、cancellable 和 threading 可机器读取Contract Registry JSON 与 96 项 contract 一致性检查
诊断CLI 文本与 JSON/LSP 使用同一 Core 检查路径诊断 schema 与 LSP 协议测试
扩展边界第三方能力优先走 Process Extension Protocol清单完整性、Protocol 1 与官方扩展验收
C ABI当前不公开 Runtime 内部 ABI只有真实集成证据证明进程协议不足时才重新决策

当前正式基线为 v1.3.10。Bytecode 是默认引擎,AST evaluator 继续作为语义 oracle,可通过 --engine ast 或 HHY_ENGINE=ast 显式使用。Compiler 产生的 Stream Kernel 必须独立通过 Verifier;动态或未知形状无损回退通用 Bytecode。

25.4v1.2.2 发行与扩展状态

能力当前状态验收结果
扩展分发Ed25519 签名 Registry、确定性依赖解析篡改、来源不明和依赖冲突稳定拒绝
可复现环境Lockfile、content-addressed 离线缓存同一 lock 得到同一依赖图,干净环境可离线重建
安全变更事务式安装、升级和显式回滚失败升级不破坏旧环境
HTML 0.2.0Lexbor、CSS selector、单次解析多字段投影畸形 HTML、硬上限、截断和结构化错误通过四平台验收
协议决策保留同步有界批量 API没有真实证据需要 Stream credit、跨调用取消或 Opaque Handle
v1.2.2 正式 Release 已包含 macOS arm64、Linux x86_64、Linux arm64、Windows x86_64 归档、逐包 SHA-256 与合并 SHA256SUMS。HTML 扩展保持 effect = none,不自行读取文件、访问网络或执行子进程。

查看 HHY Language v1.2.2 正式发行
下载四平台归档、校验文件并查看完整发行说明。
https://github.com/hh696-wq/hhy-vm/releases/tag/v1.2.2

25.5v1.3.7–v1.3.10 Bytecode 加固状态

版本核心交付已验证结论
v1.3.7具名 specialization metadata、统一 stack/error、fallback reason无 magic kind;三路径差分与变形测试通过
v1.3.8Compiler 生成版本化 Stream Kernel IRRuntime 不读取 AST 形状;Kernel 独立 verify;动态形状安全回退
v1.3.9普通执行与 Profiler 共用优化决策kernel/opcode、取消、CPU/Heap 归因与机器报告一致;开销门禁通过
v1.3.10真实性能触发的缓存治理数据未触发准入;无进程/磁盘缓存;不接受未验证外部 Bytecode
四个版本均按顺序完成实现、Release/Debug 测试、sanitizer、fuzz、真实性能、四平台 Actions、正式 Release 和 Homebrew Formula 校验后才进入下一版本。

查看 HHY Language v1.3.10 正式发行
包含四平台归档、逐包 SHA-256、SHA256SUMS 与缓存治理发行说明。
https://github.com/hh696-wq/hhy-vm/releases/tag/v1.3.10

25.6性能实测

最终 v1.3.10 CI 数据来自提交 4ddc8c3、GitHub Actions Ubuntu 24.04 的 schema-2 paired/interleaved benchmark 和独立 Profiler/缓存决策 artifact。数值是 Bytecode/AST 墙钟比;小于 1 表示 Bytecode 更快。

门禁实测上限结果
1M CPU0.3695×0.90×通过
短任务1.0088×1.25×通过
持续 JSON/I/O1.0207×1.10×通过
Profiler 开销1.0269× / +2.786 ms1.35× / +12 ms通过
缓存准入负载compile+verify 中位数冷运行中位数占比
Hello0.0097 ms5.860 ms0.1649%
Advanced Flow0.0269 ms5.916 ms0.4546%
Stdlib0.0286 ms7.003 ms0.4086%
Sustained JSON0.0089 ms33.518 ms0.0266%
Core Flow 1M0.0105 ms166.285 ms0.0063%
缓存联合门槛为 compile+verify ≥ 1 ms 且占冷运行 ≥ 20%。五项均远低于门槛,即使假设缓存读取成本为零也无可复现收益,因此 v1.3.10 不实现进程/磁盘缓存,并继续拒绝未验证外部 Bytecode。

25.7v1.3.10 六语言同机重测

2026-09-01 在 macOS 26.6.2 arm64 上重新实测 HHY 1.3.10、PHP 8.5.10、Go 1.27.0、Python 3.14.7、Lua 5.5.1 和 OpenJDK 26.0.2.1。固定任务为 range(0, 1,000,000) → 乘 2 → 保留可被 3 整除的值 → 稳定去重 → 物化 → 计数;六种实现都验证输出 333334。每种语言先预热 2 次,再做两轮独立测量;每轮 7 个 fresh process,固定种子随机交错运行,墙钟包含进程启动;Go 与 Java 预先编译,编译时间不计入。

实现版本第 1 轮中位数第 2 轮中位数两轮范围
Go1.27.07.995 ms7.969 ms7.622–15.325 ms
Lua5.5.118.368 ms17.957 ms17.582–19.822 ms
PHP8.5.1043.174 ms43.549 ms42.588–49.033 ms
JavaOpenJDK 26.0.2.149.394 ms48.153 ms46.995–53.066 ms
HHY Bytecode1.3.1055.297 ms53.404 ms51.027–78.702 ms
Python3.14.781.747 ms86.459 ms79.993–87.774 ms
比较第 1 轮第 2 轮解读
HHY / PHP1.28×1.23×该任务 HHY 比 PHP 多用约 23%–28% 墙钟
HHY / Java1.12×1.11×包含 JVM fresh-process 启动时,Java 略快
HHY / Python0.68×0.62×HHY 在该任务上用时更少
HHY / Lua3.01×2.97×Lua 在该整数循环上更快
HHY / Go6.92×6.70×预编译 Go 显著更快
这是一个特定 CPU/物化 workload,不是通用语言排名。各实现使用惯用循环与去重容器;Java 使用 HashSet/ArrayList 并包含 fresh JVM 启动。全部 84 个计时样本、版本、顺序和源程序保存在本地 performance-analysis/2026-09-01-v1.3.10-language-comparison/,该目录按项目规则不提交 GitHub。

25.8治理结论与后续观察

  • 总体状态:v1.3.10 已正式发布;v1.3.7–v1.3.10 的语义、三路径、Profiler、资源与缓存治理门禁完整。
  • 执行引擎策略:Bytecode 默认;AST 永久保留为语义 oracle、差分测试和 --engine ast 紧急回退。
  • 性能结论:最终 CI 的 1M CPU ratio 0.3695,短任务 1.0088、持续 JSON 1.0207,Profiler 开销 1.0269×,全部通过。
  • 缓存结论:compile+verify 不构成冷运行主要成本;当前不引入缓存,未来必须由新数据和完整威胁模型重新触发。
  • 跨语言结论:本次仅说明同机固定任务;Go/Lua/PHP/Java 更快,HHY 快于 Python,不能外推到所有场景。
  • 更新规则:发布基线、测量方法、引擎/缓存决策或总体风险结论变化时同步更新本报告。

查看 v1.3.10 最终持续验证证据
四平台构建、sanitizer、fuzz、Profiler、缓存决策、性能门禁与真实项目验收。
https://github.com/hh696-wq/hhy-vm/actions/runs/33497617218

HHYHHY Language

一门以 Flow 为核心的系统脚本语言。

© 2026 HHY Language contributors
学习快速开始完整手册CLI 参考
项目关于 HHYGitHub规范Apache 2.0
联系 hhylang.dev huiyang.hou@qq.comhouhuiyang.com