Loment 快速上手
github.com/FujoJTOP/loment);未达的那一项(M100)是第三方审计——那一半作者无法自证。下面的命令今天可用。本页语言与工具部分的每一条命令与输出都是在一台装好 Loment 的机器上实跑得到的,不是示意;安装那两行取自安装器自己的用法说明。如果哪条跟你跑出来的不一样,那是我们其中一方的版本不对,请以你的输出为准。
拿到它
包本身已经做好了:同一份 IR 各链一遍,Linux 出 ELF、Windows 出原生 PE(.exe),链接器是包里自带的 loment-lomelf。装完的机器上不需要 clang,不需要 WSL,也不需要 Python——loment build 在一台干净的 Windows 上开箱即用。
源代码已经公开:github.com/FujoJTOP/loment——发行包随 tag 发布在同一处。Lompi 是另一个仓库(github.com/FujoJTOP/lompi),它随包一起安装,但不是 Loment 官方工具。还没过的是 M100 的第三方审计——那一项作者无法自证。想从源码自己构建,见本页最后一节。
powershell -File install.ps1
# 默认装到 %LOCALAPPDATA%\Loment;-Prefix D:\Loment 可换
# -NoPath 不加 PATH,-NoSkill 不装 agent 指南,-DryRun 先看要做什么
安装器做完六件事:校验 SHA256SUMS、把 bin/ 与 share/ 拷进前缀、把 bin 加进用户 PATH、注册 .lomt/.lom 的文件类型、跑一次冒烟测试(loment version 加编一个 user_hello.lomt)、再把 agent 指南写到 ~/.claude/skills/loment/。装完自查一条命令就知道齐没齐:
loment doctor Health check ok loment-driver ok loment-lsp ok loment-fmt ok loment-doc ok loment-lomelf ok loment-cli ok version Loment 0.1.4 Pre2 (0.1.4-pre2) all green
loment 自己的输出是纯 ASCII,而且这是判据守着的——936 代码页的控制台上中文必乱码,与其时好时坏,不如一条都不留。所以这个页面上工具的输出是英文、正文是中文。语言自己的诊断(编译器那侧)仍然可以说中文。
六十秒
两条命令。第一条写出一份能跑的骨架,第二条编出来并运行:
loment new hi wrote hi.lomt run it: loment run hi.lomt loment run hi.lomt hello from Loment
要一个可执行文件,就把 run 换成 build。产物是本机原生格式——Windows 上 .exe,Linux 上 ELF——而且没有 clang 参与:
loment build hi.lomt -o hi loment: hi.exe
一个最小程序
上面那条 new 写出来的就是这份。语法是 Rust 的严格子集,所以如果你写过 Rust,这里没有新东西要学——新东西在能力域那一层。
module hi
fn _start() {
let s: str = "hello from Loment\n";
syscall4(1, 1, str_ptr(s) as u64, str_len(s) as u64);
syscall4(60, 0, 0, 0);
}
module 是必需的。_start 是入口——它就是进程入口,没有 libc 在前面垫一层,也没有运行时帮你把参数收好,所以收尾要自己 syscall4(60, ...) 退出。syscall4 是语言的内建,不是库:Loment 没有标准库可依赖,能碰系统的就这一层。
能力域:真正的新东西
你想让某段代码只能碰磁盘块 0 到 4,并且可以随时被收回。这不是一个运行时检查函数,而是一条语言声明:
module cap
capability blk_write : disk[0..4] revocable
fn write(slot: u32) -> u32 {
guard blk_write(slot); // 字面量越界:编译期就拒
return slot;
}
把 guard 里的实参换成一个越界字面量,程序编不出来——不是警告,是错误:
loment check cap.lomt # 域是 disk[0..4],这里 guard 了 9
fujoc-s: 静态检查未通过
E4 @27 line 5: blk_write
| 一件事,四处生效 | 发生时机 |
|---|---|
| 越界字面量直接编译失败 | 编译时 |
| 动态越界落到运行期 trap | 运行时 |
| 每次 guard 落一条审计计数 | 每次使用 |
| 域描述表写进形式对象 | 编译时 |
配套的声明还有 excluded,用来明确写出「本单元不申请哪些能力」——碰了它划出去的区间就报 E5。更值得记住的是工具自己给出的那条诚实边界:
loment caps honest limit: `guard` only constrains the INDEX to the domain, it is NOT authorisation - it does not check whether the current subject holds that capability. Subject-to-capability binding lives in the kernel.
也就是说 guard 管的是下标不越界,不是你有没有这个权限。谁持有哪个能力,是内核的事(M37/M39 仍在内核线上排队)。细节见 能力域即语言构造。
出错了会看到什么
把 g(1) 写成 g(1, 2),编译器直接告诉你哪一行哪个符号、以及是哪一类错:
loment check bad.lomt fujoc-s: 静态检查未通过 E3 @27 line 4: g
E3 是类别,@27 是第 27 个 token,line 4 是源行。类别总共 E1 到 E21 二十一种,而且按「该做什么」分组,不按措辞分组——同一类错误换了说法也还是同一个号。查表一条命令:
loment codes E1 type mismatch (return / payload / builtin argument) E2 something is not declared - usually a missing type annotation or a misspelt name E3 wrong number of arguments E4 capability domain problem (undeclared / out of range / duplicate) E5 used space that an `excluded` declaration put out of bounds E6 value has been moved E7 borrow conflict (mutable borrow next to a borrow / two mutable borrows) E8 match / enum (not exhaustive, duplicate pattern, bad payload binding) E9 name clashes with a base type / empty struct / empty enum E10 `?` used where there is no Result or Option E11 slice mutability (cannot write a read-only slice; the parameter needs `mut`) E12 dangling reference E13 duplicate definition / duplicate name E14 assignment target is not an lvalue E15 field or index (no such field, missing field, duplicate init, field on a non-struct) E16 array literal / length does not match the declaration E17 illegal `as` cast E18 `use <name>` does not resolve - rename it, add the file, or use the path form E19 parse error - fix that line as the `line:col` in the message says E20 more than 300 `use` in one file - split the facade
要看一条的细节:loment explain E4。每一类都有一条对应的反例在仓库里真的会触发——也就是说这不是文档里的一张表,是活着的代码路径。这张表目前印到 E20:E21(extern fn 的签名形态不支持)已经在语言里发出,表还没跟上——写在这里而不是等它对齐再提。
命令面:38 条
loment 不是一层壳。它有 38 条命令、分六组,而命令面本身就是用 Loment 写的——一个 lomcli.lomt。前两组由启动器直接转发给对应的工具,其余落在 loment-cli 里。分区跟 loment help 打出来的完全一致:
编译与运行
| ir FILE | 把 LLVM IR 打到 stdout |
| check FILE | 只检查,丢弃 IR(诊断走 stderr) |
| build FILE [-o NAME] | 编译并链接成可执行文件 |
| run FILE | 编译、链接、运行 |
| version | 打版本行 |
| lsp | 语言服务(stdio) |
源码工具
| fmt FILE | 格式化(打到 stdout,不改原文件) |
| doc FILE | 从 /// 注释生成 API 文档 |
| skill [--print] | agent 指南(路径,或全文) |
读源码
| cat FILE | 带行号打印 |
| stat FILE | 行数 / 字节数 / 最长行 |
| count FILE | 函数 / 结构体 / 枚举计数 |
| fns FILE | 列出函数签名 |
| tokens FILE | token 直方图(词法层近似) |
| grep PAT FILE | 子串搜索,带行号(不是正则) |
| todo FILE | 列出 TODO / FIXME / XXX |
| hash FILE | 内容 sha256 |
工程
| ls [DIR] | 列目录(目录带尾随 /) |
| tree [DIR] | 递归目录树 |
| new NAME | 写出 hello 骨架(不覆盖已存在的文件) |
| examples | 列出包内自带的示例 |
| example NAME | 打印其中一个示例 |
语言速查
| syntax | 语法速查表 |
| builtins | 内建函数表 |
| types | 类型表 |
| keywords | 关键字 |
| caps | 能力域 / guard |
| codes | 错误码表 E1–E19 |
| explain CODE | 解释单个错误码 |
| cheat | 一页速查 |
本机
| tools | 这个包里的工具:在或不在 |
| where [TOOL] | 某个工具的绝对路径(不认识的名字退 2) |
| env | 安装前缀与环境 |
| doctor | 体检:齐了就绿退 0,缺了就红退 1 |
| about | 构建信息 |
| color [on|off] | ANSI 颜色开关 |
| commands | 只打命令名(给补全用) |
| help [COMMAND] | 这张总览,或单条命令 |
loment。源码仓库里另有一个开发侧入口 python tools/loment.py,它要 Python,有 12 条子命令:fmt doc diag ir test bench cov dbg build pkg lsp lib。测试、覆盖率、基准、调试符号化、库系统都只在这一侧——它们不在产品路径上,也不必跟着包发出去。所以「loment cov」敲不出来是正常的:那是开发侧的命令。
lib / pkg 只在源码仓库侧可用(python tools/loment.py lib ...)——发行包里没有 Python,也就没有它。把它列进 help 而敲下去得到「未知命令」,那是骗人。Lompi 也不在这张表里,而且理由不同。它是 Loment 库的包管理器,随 Loment 一起安装,但它不是 Loment 官方工具:不编 Loment、不读源码树,是另一个命令。装在一起不等于它是同一件工具的部件——所以要用就直接敲
lompi,见 Lompi 一页。
另一条线:L0
上面讲的都是 L1(语言本体)。还有一条更靠底下的线:.lom 文件是布局与契约的单一真源,由 lomc 生成 Rust / C / Python / JSON。它也是 0.1.4 里离开 Python的工具之一——四个后端与 Python 版逐字节相同。
python tools/lomc.py lom/fuc.lom --emit-rust out.rs \
--emit-c out.h \
--emit-python out.py \
--emit-json out.json
# 或者不落盘,只核对磁盘产物是否与生成结果一致:
python tools/lomc.py lom/fuc.lom --check
L1 的源文件可以 use 一个 L0 文件——声明来自 L0,行为来自 .lomt。这是「Loment 是 .lom 的超集」这句话的实际含义。见 L0 单一真源。
从源码重建:起点不是 clang 了
没有包、想从源码把编译器重建出来的话,一条脚本。注意它现在的起点是一份提交进仓库的 genesis 二进制,不是 clang——clang 降级成了后备路线:
sh loment/bootstrap.sh
== 起点: genesis (lomelf-linux-x64.elf) —— 无 clang, 无解释器
== 1/4 种子 -> stage1
== 2/4 stage1 编译 loment/selfhost/driver.lomt -> 必须等于种子
== 3/4 stage2 -> stage3 定点
== 4/4 stage1 与 stage2 对非自身入口一致
SEED BOOTSTRAP OK: 无 Python, 无解释器, 无 clang (genesis 起头); 种子自复现 + 三阶段定点
要分清两个东西:genesis 是那个工具(lomelf 的二进制,90 504 B,提交进仓库),种子是它汇编的输入(selfhost_driver.ll,1 641 696 B)。四条判据依次证明:stage1 编译驱动单元的产物与种子逐字节相同(种子自身就是个定点);再链一轮仍是定点;换一个非自身的入口,两个阶段的产物也一致。最后一条是关键:定点不能是「只会编译自己」的巧合。找不到 genesis 时才退回 clang(CC= 可以指定)。细节见 docs/159。
现在还不能做什么
- 源代码已经公开,第三方审计还没过 —— 版本本身已经完成并冻结(M96 完成:语法与类型规则、诊断 E1–E19、单元装载、跨线发射符号约定、两后端逐字节等价,附 7 条已知开放项);触及冻结面的改动要走
docs/158§5 的流程,不再是随手改。100 个里程碑里完成 96 个、部分完成 2 个(M56 的 LSP 宿主已就位、编辑器里人工点验待做;M92 的 aarch64 交叉编译通过但没有模拟器可验)。未达的是发布与外部审计(M100)——缺的不是门禁(tools/loment_audit.py一条命令跑完 24 条主张并落盘证据),是第三方复核本身。 - 内核侧已经接上了 —— 这一片原先整排标着 P7 等内核线排期,现在只剩一项:撤销由内核真正实施(M37,串口
INV_RUN … rev=2 nonrev=0)、A1–A4 断言接进内核并启动自检(M40/M50,CAP_ASSERTS n=2 bad=0 guards=2)、域宽随质量台账变化可观测(M42)、中断与断言表接入(M33)都已完成,证据来自 compat 线 2026-09-15 的报告。唯一没翻的是 M39(与内核域模型对齐),而那次复核的结论是内核侧不缺东西:域表早已从静态初值搬进 arena、由replay_init()在启动时填满,而对比工具tools/loment_caps_diff.py还在找静态初值——那两条红是假阳性。要修的是工具,不是内核。 - 没有 TTY 探测,也没有单条命令的手册页 —— 颜色默认开,重定向到文件时不会自己关掉,要
--no-color。单条命令的手册页只覆盖了 13 条,其余help <名>会明说「没有更详细的手册页」并指回总览,不装样子。另外tokens是词法层近似、grep是子串匹配不是正则、tree有 16 层深度上限。 - 测试判据仍是 Python —— 这是有意留的:它不在产品路径上,只影响开发期判据。产品路径上已经没有解释器了——格式化器、文档生成器、语言服务、包管理器、L0 生成器全部有 Loment 实现,判据是与 Python 版逐字节相同。
- 自举版比参考实现慢约 10 倍 —— 目前只记了基线与护栏(M86),没有做优化——所以别把它当性能版本用。原生后端也明确不做寄存器分配,产物比
clang -O1大且慢;v0 要的是正确性。