我为什么要创造一门中文编程语言
言有所指,序有所行。
这便是“言序”这个名字最初的含义。
我是刘秀。
我写过网站,做过服务,维护过机器人和游戏项目,也经常花很多时间折腾那些并不会立刻带来回报的东西。
有些项目是为了解决问题,有些项目是为了学习技术,还有一些项目,只是因为心里始终有一个问题没有得到答案。
言序,属于最后一种。
我想知道:
中文能不能不只是出现在变量名和注释里,而是真正成为一门现代编程语言的表达基础?
不是把 if 改成“如果”,把 function 改成“函数”,再把 Python 或 JavaScript 的语法重新涂上一层中文外壳。
而是从词法、语法、类型、模块、错误信息、工具链到运行时,都重新思考一次:
当我们使用中文描述程序时,代码究竟应该是什么样子?

关于言序,以及我想寻找的另一种程序表达方式。
中文编程,为什么总像一个玩笑?
第一次听到“中文编程语言”时,很多人的反应大概都是相似的:
“是不是把英文关键词翻译成中文?”
“这不就是儿童编程吗?”
“写代码为什么不用英语?”
“中文歧义这么多,真的适合编程吗?”
这些问题并不冒犯,甚至非常合理。
过去的不少中文编程尝试,确实容易停留在关键词替换、语法演示或者教学玩具阶段。它们能够证明“中文可以写代码”,却很少继续回答另一个更困难的问题:
中文写出来的程序,能不能像一门真正的语言一样长期演进?
一门编程语言不仅要有几条漂亮的示例代码。
它还要面对变量作用域、闭包、类型检查、模块边界、依赖管理、异常传播、调试协议、编辑器补全、格式化、版本兼容、运行性能和软件供应链。
当一个项目开始面对这些问题时,它才真正从“语法创意”走向“语言工程”。
我不想让言序只停留在一张能够发到社交平台上的截图里。
我希望它能够运行真实程序,能够拆分模块,能够管理依赖,能够定位错误,能够在编辑器里补全和跳转,也能够在版本升级以后继续运行过去写下的代码。
所以从一开始,我真正想做的就不是“中文语法展示器”。
我想做的是一门语言。

关键词翻译只改变表面;语言设计必须建立完整而稳定的工程结构。
我想寻找一种属于中文的程序节奏
英文编程语言有自己已经成熟的表达习惯。
if、else、return、class、import,经过几十年的使用,早已成为程序员下意识能够识别的符号。
中文当然可以直接翻译它们。
但我越来越觉得,单纯翻译并不能构成真正的中文表达。
比如,函数一定要叫“函数”吗?
代码文件一定要叫“文件”吗?
返回值一定要写成“返回”吗?
一个程序块结束时,中文有没有比右花括号更具有节奏感的表达方式?
在言序里,我选择了“法”表示可调用的方法与过程,用“文卷”称呼源代码文件,用“归”交回计算结果,用“终”收束一段结构。
一段简单的代码可以写成:
1 | 公 类 人 则 |
这段代码并不是文言文。
至少,它不是为了模仿古人说话而设计的文言文。
我更愿意把它称为一种文言风格的现代程序表达。
它保留中文短句的节奏和收束感,但不会为了追求古雅而牺牲精确性。因为程序语言首先必须明确,其次才谈得上美感。
“法”“归”“终”这些词存在的意义,也不是为了让代码看起来更古老,而是希望它们在长时间使用后,能够形成属于言序自己的阅读习惯。
我希望使用者看到“归”时,能够像看到 return 一样立刻理解它的作用。
看到“终”时,能够自然意识到一段结构已经闭合。
看到“文卷”时,想到的不是一张普通磁盘文件,而是一份能够被解释、检查、格式化和执行的程序文本。
语言的成立,从来不仅依赖语法规则。
它还依赖使用者在长期阅读中逐渐建立的直觉。
中文不是为了排斥英文
创造一门中文编程语言,并不意味着我认为英文编程语言有什么问题。
相反,言序本身就是使用 Rust 编写的。
它的实现离不开 Rust 生态,也离不开操作系统、编辑器协议、版本管理、自动化构建和许多已有的开源项目。
言序使用中文,不是为了证明中文比英文“更先进”,更不是为了制造语言之间的对立。
我只是认为,编程语言本来就不应该只有一种文化外观。
一门语言可以来自工程需求,也可以来自数学传统、教育场景、艺术实验,或者某种对表达方式的好奇。
有人喜欢极简符号,有人喜欢强类型约束,有人喜欢函数式表达,有人愿意把程序写得接近自然语言。
那么,为什么不能有人尝试让中文本身成为程序结构的一部分?
这不是要替代什么。
它更像是在已经非常宽广的编程语言世界里,再开辟一条小路。
这条路未必通向所有人,也未必会成为主流。
但只要它能够走得足够远,沿途就一定会出现过去没有见过的风景。

不同的表达路径,可以共同构成同一个开放的技术生态。
真正困难的,从来不是把关键词换成中文
言序最早也只是从词法分析、语法解析和树遍历解释器开始。
源码被切分成一个个词法单元,再被组合成抽象语法树。解释器沿着语法树执行变量、分支、循环、函数、递归和闭包。
到了这里,我已经能够让一些中文代码运行起来。
但那只是最开始的部分。
当我继续往下做,问题很快变得复杂。
如何让错误信息准确指向中文全角字符?
如何让函数、类和模块拥有清晰的可见性边界?
如何检查参数类型、返回类型和不可变变量?
如何实现联合类型、泛型容器和控制流收窄?
如何让模块之间能够导入、缓存并识别循环依赖?
如何让同一份源码既可以由树解释器执行,也可以编译成字节码交给虚拟机运行?
如何确保两种执行器不会产生悄无声息的语义差异?
如何让 VS Code 提供补全、跳转、重命名、悬停和格式化?
如何让程序能够设置断点、单步执行并查看作用域变量?
如何管理项目依赖、锁定版本并支持离线安装?
又该怎样保证语言升级之后,过去的源码不会突然失效?
这些问题与中文还是英文已经没有太大关系了。
它们是任何一门认真发展的编程语言都必须面对的问题。
也是在处理这些问题的过程中,我逐渐确认:
我真正感兴趣的,并不只是中文语法,而是语言从无到有的完整过程。
现在的言序,已经走到了哪里?
截至写下这篇文章时,言序已经不再只是最初的解释器原型。
它拥有一套使用 Rust 编写的语言核心,包括词法分析、语法解析、语义检查、静态类型检查和源码级诊断。
它同时保留了两条执行路径:
一条是作为语义参考的树解释器。
另一条是不依赖抽象语法树回退的独立字节码虚拟机。
函数、闭包、类、继承、协议、异常、模块、容器和任务,都需要在两条执行路径中保持一致。每当语言加入一种新能力,我都不能只让其中一套实现“看起来能跑”,而是要让它们在正常结果、错误行为和边界条件上互相验证。
在语言之外,言序也开始拥有自己的工具链:
- 静态检查与格式化;
- REPL 交互环境;
- LSP 语言服务器;
- DAP 调试适配器;
- VS Code 官方扩展;
- Tree-sitter 语法;
- API 文档生成;
- 项目清单与锁文件;
- 独立包管理器“言包”;
- Rust 嵌入接口、C ABI 与 WASI 入口;
- 版本化语言规范与兼容语料;
- 面向旧语法的自动迁移工具。
此外,我还使用言序本身编写了“言据”。
言据是一种纯中文数据交换格式。它的解析器和序列化器没有使用 Rust 重写,也没有借用 JSON 解析器,而是由言序源码直接实现。
对一个成熟语言来说,这或许只是一个很小的库。
但对言序而言,它意味着这门语言开始不只能够运行演示代码,还能够反过来建设属于自己的生态。

从中文源码到双执行路径,再从语言核心延伸到编辑器、调试、包管理与生态工具。
为什么选择 Rust?
很多人看到中文编程语言,可能会下意识觉得它更适合使用 Python 或 JavaScript 快速实现。
我最终选择 Rust,并不是因为它最容易。
恰恰相反,在开发初期,Rust 的所有权、生命周期和类型约束,确实让不少原本可以快速拼出来的结构变得更加谨慎。
但我希望言序不是一段只在某台电脑上能够运行的实验代码。
语言实现需要长期处理大量复杂状态:语法树、环境链、闭包捕获、对象引用、调用帧、模块缓存、虚拟机堆、错误踪迹和宿主权限。
Rust 的约束让我不得不更早面对这些结构的边界。
它也让我能够在保持原生性能的同时,减少许多内存安全问题,并较为自然地构建命令行程序、动态库和 WASM/WASI 入口。
更重要的是,我喜欢 Rust 所代表的那种工程态度:
很多事情不能因为“当前能够运行”就算完成。
边界必须明确,错误必须被处理,接口必须经过设计。
这与我希望赋予言序的性格十分接近。
言序的表面是中文的,内部却不应该含糊。
它可以有文言的节奏,但必须拥有现代工程需要的精确。
中文错误信息,不只是把英文报错翻译过来
中文语言还有一个常被忽略的问题:错误信息。
当程序出现问题时,用户真正面对的不是语言宣传页上的示例,而是终端里那一行失败提示。
如果错误信息只告诉你“语法错误”,却不说明错在哪里、为什么错、应该如何修改,那么无论语法多漂亮,这门语言都很难真正使用。
所以言序从早期开始,就尝试让词法、语法、语义、类型和运行时错误共享统一的源码位置。
报错不仅需要指出文件和行列,还要显示对应源码片段,用指示符标出具体范围,并在函数和模块调用之间保留调用踪迹。
而中文又带来了额外的问题。
汉字、全角标点和 ASCII 字符在终端中的显示宽度并不相同。如果只按照字节或普通字符数量计算位置,错误指示符就会发生偏移。
这是一件很小的事。
但一门语言是否认真,往往就体现在这些很小的地方。
我不希望言序只在正确运行时显得优雅。
我希望它在程序写错的时候,也能够认真地和使用者说话。
我并不认为“中文”天然更容易
中文编程经常会与“降低学习门槛”联系在一起。
但我对此一直比较谨慎。
把关键词写成中文,确实能够减少初学者面对陌生英文单词时的距离感。可编程真正困难的部分,从来不是记住几个关键词。
变量、状态、抽象、递归、并发、类型、复杂度,这些概念不会因为换成中文就自动变得简单。
一门糟糕的中文语言,甚至可能因为自然语言歧义而增加理解成本。
所以我不想宣称言序能够让所有人“零门槛学会编程”。
它真正能够提供的,是另一种进入程序世界的方式。
对于以中文思考和写作为主的人来说,代码中的语义或许可以更加直接。
对于编程语言爱好者来说,它可以成为研究 Unicode、语法、类型系统和工具链的实验场。
对于我自己来说,它则是一段持续学习的过程。
我通过它理解解释器、虚拟机、垃圾回收、语言服务器、调试协议、包管理和版本兼容。
中文只是这条道路的起点。
真正让我不断走下去的,是它背后几乎没有尽头的工程世界。
言序不会因为发布 1.0 就结束
软件项目很容易陷入对版本号的追逐。
仿佛只要写下 1.0.0,一个项目就突然成熟了。
但对于编程语言而言,1.0 的意义不应该是“功能很多”,而应该是从某个时间点开始,语言愿意为使用者承担兼容责任。
源码语义不能随意改变。
包清单和锁文件需要稳定。
字节码与机器输出要有明确版本。
新语法必须同步解释器、虚拟机、类型检查、格式化器、编辑器和文档。
被弃用的能力需要迁移周期,而不是在某次更新中突然消失。
因此,我更愿意把言序的 1.0 看作一份承诺,而不是一座终点。
它意味着这门语言终于完成了最基础的自我约束,也意味着之后的每一次变化,都不能再只考虑“这样写起来是不是更酷”。
语言设计者需要开始考虑那些已经写下代码的人。

1.0 是一座稳定的里程碑,也是通向标准库、生态、自举与社区的道路起点。
我希望言序最终成为什么?
我当然希望有一天,言序能够使用言序编写自己的更多组成部分。
现在,言据已经证明它能够承载真实的库实现。
未来,或许会有更多标准库、构建工具和生态项目逐渐由言序自身编写。再往后,它是否能够走向更完整的编译能力,甚至参与构建自己的编译器,是一个值得长期尝试的方向。
但比“自举”更重要的是,我希望言序拥有一种清晰的性格。
它应该是中文的,但不封闭。
它应该有传统文字的节奏,但不沉迷复古。
它应该允许代码显得优雅,但不能牺牲精确。
它应该欢迎实验,却对稳定版本保持克制。
它不需要假装自己能够替代现有主流语言,也不应该只满足于成为一次短暂的话题。
我希望它最终能够成为这样一门语言:
有人第一次看到它时,会因为中文代码感到新鲜。
有人继续了解它时,会发现它拥有真正的类型、运行时和工具链。
有人实际使用它时,会觉得其中一些设计确实自然。
也许最后,只有很少一部分人愿意长期使用它。
这也没有关系。
独立项目的价值,并不完全由用户数量决定。
有些项目的意义,是解决一个普遍问题。
有些项目的意义,是创造一个过去不存在的选择。
而言序对我来说,更接近后者。
写在最后
我创造言序,并不是因为世界缺少编程语言。
恰恰相反,这个世界已经有太多优秀的语言。
我创造它,是因为在这些语言之间,我仍然没有看到自己想要的那一种中文表达。
所以我决定亲手试一试。
从一个词法分析器开始,从第一棵语法树开始,从第一条能够运行的中文语句开始。
然后是类型、模块、解释器、虚拟机、编辑器、调试器、包管理器和语言规范。
每解决一个问题,后面都会出现更多问题。
但这大概正是创造一门语言最有趣的地方。
你永远无法真正“写完”它。
你只能让它在一次次选择中,逐渐变成自己应该成为的样子。
言有所指。
序有所行。
这就是言序。
也是我为什么想要创造一门中文编程语言。