基石语言规格(v1.0)

本文件是基石语言的正式语言规格,描述当前已实现的全部语法、语义与 标准库 API 边界。自 v1.0 起,语法/语义/标准库 API 冻结:后续改动须在 docs/设计决策.md 补充决策记录,并遵循语义化版本规则(主版本=不兼容变更, 次版本=新特性,修订=修 bug)。 历史版本:v0.2(M1 阶段)→ v1.0(M15 收敛,冻结于 M0–M14 全部特性)。

1. 文件与运行

2. 关键字

关键字作用
令声明/赋值变量
如果 / 否则如果 / 否则条件分支
遍历 … 在 …for 循环
循环 N 次固定次数循环(次 可省略)
当while 循环
中断 / 继续跳出/跳过循环
函数 / 返回定义函数 / 返回值
导入 模块名导入基石标准库
真 / 假 / 空布尔值与空值
与 / 或 / 非逻辑运算
尝试 / 捕获 … 为 … / 最终异常处理
抛出抛出异常
类 / 继承 / 新建定义类 / 继承 / 创建实例
用 … 为 …上下文管理器(M26.2),见 §7.12
匹配 / 情形模式匹配(M34.1),见 §8.11
枚举枚举(M34.2),见 §8.12

注:匹配 / 枚举 是软前缀——匹配组、枚举值 这些仍可作普通标识符 (见 §5 标识符)。另外 . 后面的属性名允许是关键字(M34 起), 所以 正则.匹配(...) 照常可用。

3. 标点与空白

4. 注释

python# 单行注释

#- 多行
注释 -#

5. 标识符

6. 字面量

类型示例
整数42
小数3.14、2e3、.5
文本"你好"、'单引号'、“中文引号”、'''多行'''
布尔真、假
空空
列表[1, 2, 3](支持尾随逗号 [1, 2, 3,];括号内可跨行书写)
字典{"语文":95}
插值文本(M7)` 你好 {名字},今年 {年龄} 岁 `

插值文本用反引号 ` ` 包裹,{表达式} 内的内容会被求值并转成文本插入; {{ / }}` 表示字面花括号:

python令 名字 = "小明"
令 年龄 = 18
打印(`你好 {名字},今年 {年龄} 岁`)   # 你好 小明,今年 18 岁
打印(`{3} + {4} = {3 + 4}`)           # 3 + 4 = 7

7. 运算符

可用于列表(按值)、字典(按键)、文本(找子串),与 列表.包含() 语义一致

空/真/假按单例判断;数字与文本按值判断(避免 Python is 那种 「有时真有时假」的随机感);列表/字典/实例/函数按对象身份判断

(//= 与 **= 在 M25 之前因词法器最长匹配出错而不可用,已修复)

优先级(松 → 紧,同一行同级):

或  <  与  <  非  <  比较(== != < > <= >= 在 不在 是 不是)  <  + -  <  * / // %  <  **

非 的优先级在 M23 修正为「比比较松、比与或紧」,与 Python 的 not 一致。 修正前 非 年龄 &gt;= 18 会被解析成 (非 年龄) &gt;= 18(恒为假,静默给错答案); 现在解析为 非 (年龄 &gt;= 18),符合阅读直觉。 常见写法:非 甲 与 乙 = (非 甲) 与 乙;非 1 == 2 = 非 (1 == 2)。

链式比较里也可以混用关键字运算符:0 &lt;= x 在 [1, 2] 等价于 0 &lt;= x 且 x 在 [1, 2](中间值只求值一次)。

7.5 集合(M24)

python令 甲 = {1, 2, 2, 3}        # 字面量,自动去重 → {1, 2, 3}
令 乙 = 集合([3, 1, 3])      # 从列表造 → {3, 1}
令 空集 = 集合()            # 空集合(注意 {} 是空字典)
令 平方集 = {x * x 遍历 x 在 范围(4)}   # 集合推导式

打印与遍历顺序稳定可复现(这也是为什么不用「无序」的哈希集合)。

方法说明
添加(值) / 移除(值) / 丢弃(值)增删;移除 找不到会报错,丢弃 不报错
包含(值)与 值 在 集合 等价
并集(可迭代) / 交集(可迭代)返回新集合
差集(可迭代) / 对称差(可迭代)返回新集合
转列表() / 复制() / 清空()转换与清空

去重的常见写法:令 唯一 = 集合(原列表) 或 令 唯一 = 集合(原列表).转列表()。

7.6 切片赋值(M24)

python令 分数 = [90, 55, 70, 88, 60]
分数[1:3] = [95, 96]     # 替换一段
分数[:2] = [100]         # 替换开头
分数[1:] = []            # 删掉末尾
分数[::2] = [1, 2, 3]    # 带步长(要求两边个数正好相等)

读取切片(M18)与写入切片共用同一条求值路径,分量同样可以省略、可以用变量。 带步长赋值时两边个数必须相等,否则报中文错(提示长度对不上)。 文本只能读切片,不能写。

7.7 匿名函数与数据流水线(M24)

python令 加倍 = 函数(x):x * 2          # 单表达式函数体,自动作为返回值
令 加基数 = 函数(x):x + 基数      # 捕获外层变量(闭包)
令 加 = 函数(x):函数(y):x + y    # 柯里化,加(3)(4) → 7

数 = [1, 2, 3, 4, 5]
数.映射(函数(x):x * x)                    # [1, 4, 9, 16, 25]
数.过滤(函数(x):x % 2 == 1)               # [1, 3, 5]
数.排序按(函数(x):-x)                     # 从大到小
数.归约(函数(累计, x):累计 + x, 0)          # 15

需要多行逻辑就定义具名函数(函数 名字(参数): 后面换行缩进)。

既可以传匿名函数,也可以传具名函数。

7.8 迭代协议(M24)

自定义对象只要定义 迭代(自身) 方法,就能用于 遍历、推导式, 以及 总和 / 最大 / 最小 / 长度 等会遍历的内建:

python类 成绩表:
    函数 初始化(自身, 记录):
        自身.记录 = 记录
    函数 迭代(自身):
        返回 自身.记录

令 表 = 新建 成绩表([90, 80])
遍历 分 在 表:
    打印(分)
打印(总和(表), 长度(表))     # 170 2

迭代 应返回一个可遍历的东西(列表、文本、集合、字典…)。返回自身会 无限循环,解释器会拦下并报中文错。

7.9 类型标注(M24)

python函数 折扣(价格: 小数, 比例: 小数) -> 小数:
    返回 价格 * 比例

哪个参数、期望什么、实际是什么。三执行器行为一致。

布尔 / 空 / 函数 / 任意(值)。布尔 不算 整数(刻意区分)。

自定义类型名不会被误报。

不做编译期检查,没写标注的参数零开销。

7.10 变长参数(M25)

python函数 求和(*数):            # 收下所有位置实参,是个列表
    令 总 = 0
    遍历 x 在 数:
        总 += x
    返回 总
打印(求和())                # 0
打印(求和(1, 2, 3))         # 6

函数 配置(**选项):          # 收下未匹配的关键字,是个字典
    返回 选项
打印(配置(甲 = 1, 乙 = 2))   # {'甲': 1, '乙': 2}

函数 混合(甲, *余, **选):    # 三者可以组合
    返回 [甲, 余, 选]

都没收到时是空列表 / 空字典(不会报错)。

要检查请在函数体里用 断言)。

函数 f(甲, 乙 = 10, *余) 调用 f(1) 得到 甲=1、乙=10、余=[]。

传列表就是「一个参数」。需要展开时先自己转换。

7.11 星号解包(M25)

python令 甲, *余 = [1, 2, 3, 4]      # 甲=1,余=[2, 3, 4]
令 首, *中, 尾 = [1, 2, 3, 4, 5]  # 首=1,中=[2, 3, 4],尾=5
令 x, *y = [1]                  # x=1,y=[](可以为空)
令 头, *尾 = "你好世界"          # 头='你',尾=['好', '世', '界']
a, *b = [9, 8, 7]               # 不加「令」也一样

(提示可以写「*余」来收剩下的)。

7.12 上下文管理器 用 … 为(M26)

python用 打开("数据.txt") 为 文件:
    遍历 行 在 文件:
        打印(行)
# 走到这里文件已经自动关闭

正常结束、返回、中断、抛出 都会走到(尝试/最终 的语义)。

否则「出问题快速找到」会变难。

它等价于下面这段(解析期就是这样脱糖的,所以三个执行器行为必然一致):

python__用_1__ = 打开("数据.txt")        # 临时变量存原对象
文件 = 进入上下文(__用_1__)
尝试:
    ……你的代码……
最终:
    退出上下文(__用_1__)

退出作用在原来的对象上,而不是绑定后的名字——进入 完全可以返回 别的东西(Python 的 __enter__ 也允许),拿返回值去退出会找错对象。

文件对象(打开)

python用 打开("a.txt", "写") 为 f:
    f.写行("第一行")
用 打开("a.txt", "追加") 为 f:
    f.写("追加的内容")
用 打开("a.txt") 为 f:
    遍历 行 在 f:            # 文件本身可遍历(按行)
        打印(行)

模式:读 / 写 / 追加 / 读写(也认 r w a r+ w+ a+)。 一律按 UTF-8 读写——Windows 上的默认编码是 GBK,中文会写乱。

方法作用
读(数量?)读整篇;给了数量就读前 N 个字符
读行()读一行(不含换行符);已经到末尾给「空」
读所有行()一次读成列表
写(内容)写文本(不加换行)
写行(内容)写一行(自动加换行)
关闭()关闭(重复调用不报错)
刷新() / 位置() / 定位(偏移)落盘 / 当前位置 / 跳到位置

打印文件对象显示 &lt;文件 路径(状态)&gt;,便于排错。

跨语言宿主(Node / Rust)都已同步 打开 与 进入上下文 / 退出上下文 (Node 在 M27、Rust 在 M29,两边都有对拍测试),所以 用 … 为 与文件 操作在那边照常可用。

7.13 自定义对象打印:文本()(M26)

python类 分数:
    函数 初始化(自身, 分子, 分母):
        自身.分子 = 分子
        自身.分母 = 分母
    函数 文本(自身):
        返回 文本(自身.分子) + "/" + 文本(自身.分母)

打印(新建 分数(1, 3))        # 1/3

放进列表、字典里打印也一样生效。

7.14 精确小数(M26)

python打印(0.1 + 0.2 == 0.3)                          # 假(二进制浮点)
打印(精确("0.1") + 精确("0.2") == 精确("0.3"))    # 真

令 价 = 精确("19.99")
打印(价 * 3)         # 59.97
打印(价.舍入(2))      # 19.99(四舍五入)

所以 精确(0.1) 就是 0.1,不会把二进制尾巴带进来。

混算时按十进制处理(所以 精确(&quot;0.3&quot;) == 0.3 为真)。

绝对值()、转文本()。

需要精确的地方显式写 精确(...)。

Rust 侧零依赖手写 BigInt(M29),两边的 精确(&quot;1&quot;)/精确(&quot;3&quot;) 都与 Python 逐字节一致(有对拍)。

7.15 值的显示规则(M27 统一)

一个值只有一种写法。打印(值)、文本(值)、字符串插值 ` {值} 、 打印([值])、REPL 回显,全部走同一套规则(runtime.jishi_repr`):

值顶层显示容器内显示
空空空
真 / 假真 / 假真 / 假
文本原样:甲带引号:&#x27;甲&#x27;
列表[1, 真, 空, &#x27;甲&#x27;]同左
字典{&#x27;键&#x27;: 1}同左
自定义对象文本() 的返回值,否则 &lt;甲 实例&gt;同左
精确小数1.50同左
文件&lt;文件 路径(状态)&gt;同左
字节字节(0C FF 00)同左
python打印(空, 真, 假)              # 空 真 假
打印([1, 真, 空, "甲"])        # [1, 真, 空, '甲']
打印(`结果是 {真}`)            # 结果是 真

True/False/None 会直接报错并提示中文写法(见 §11 容错解析)。

(否则分不清 [&#x27;甲&#x27;] 里的是文本还是变量)——与 Python 的 print/repr 分工一致。REPL 回显算「容器内」这一侧:&gt;&gt;&gt; &quot;甲&quot; 回显 &#x27;甲&#x27;。

所以 路径.存在(...) 显示「真/假」而不是 True/False。

7.16 字节(M113)

一串 0–255 的整数,用来装图片、压缩包、加密盐这类二进制数据。

python导入 编码

令 图 = 编码.十六进制解码("89504E47")      # 源码里造一串字节就用它
打印(类型(图))          # 字节
打印(图)                # 字节(89 50 4E 47)
打印(长度(图), 图[0])    # 4 128
打印(图[0:2])           # 字节(89 50)
打印(图 + 编码.十六进制解码("0D0A"))    # 字节(89 50 4E 47 0D 0A)
打印(图 * 2)            # 字节(89 50 4E 47 89 50 4E 47)
遍历 x 在 图:           # 逐个给整数
    打印(x)             # 137 / 80 / 78 / 71
打印(编码.十六进制编码(图, 真))   # 89504E47(要全量内容时用它)

(字节(00 01 … 共 1024 个字节))。要全量内容用 编码.十六进制编码(...) —— 显示是有损的,那是有意的(读一个 1 MB 文件不该刷屏)。

编码.文本字节(文本)、编码.十六进制解码(文本)、编码.base64解码(文本)、 加密.安全随机字节(个数)、文件.读字节(路径)。

编码.字节文本(图)(解不出合法 UTF-8 会明确报错,不返回乱码)。

但 字节 &lt; 文本 会报错——两种东西不该混着比。

给你「所有字节值之和」。

编码.base64编码(...) 转成文本。数据库 里字节走 BLOB,原样往返。

7.17 并发(M114)

⚠️ 基石没有「语言级的线程 / 锁 / 队列 / 异步」,而且这是有意的 (见「不做清单」与 docs/设计决策.md D80)。有的是标准库 并发 模块:

python导入 并发

令 摘要们 = 并发.批量摘要(路径们)          # 一批文件同时算(默认 sha256,4 路)
令 内容们 = 并发.批量读(路径们, 8)          # 一批文件同时读成「字节」
令 正文们 = 并发.并行取(网址们)             # 一批网址同时取(GET)

并发.批量摘要(路径们)[3] 就是 路径们[3] 那一份的摘要。

但大文件、纯计算(算数、字符串处理)不要用它 —— 线程只是白加调度开销。 收益取决于瓶颈在哪:IO 等待能重叠才有用(详见 docs/设计决策.md D80 的实测表)。

结果一模一样,只是不快(不是「不支持」,所以不会报错)。

「共享状态被两个线程同时改」这类问题,代价见 D80)。想并行跑自己的逻辑, 把它放进一批文件 / 网址里,用上面三个函数。

7.18 HTTP 服务端(M115)

python导入 HTTP服务端

函数 处理(请求):
    如果 请求["方法"] == "GET" 与 请求["路径"] == "/":
        返回 {"正文": "<h1>你好</h1>", "内容类型": "text/html; charset=utf-8"}
    返回 {"状态": 404, "正文": "没有这一页"}

HTTP服务端.启动(8000, 处理, 最多请求数=2)     # 收 2 个请求后干净退出

返回要么是文本(自己用 构造响应 拼好的完整响应), 要么是字典 {状态, 正文, 内容类型, 头}(框架替你拼,日常用这种)。

⚠️ 数的是真正处理过的请求(连上就断的探测连接不算)。

不会因为一条坏请求把整个本地服务带走。

正文按 UTF-8。

起不了(会报一句说清原因的话);解析请求 / 构造响应 是纯函数, 哪里都能用。理由见 docs/设计决策.md D81。

7.19 给模型看的两份事实(M8 / M116)

语言事实有两份投影,都从同一个来源(build_lang_spec())生成,不另写一套说辞:

命令形态给谁
jishi --lang-specJSON(关键字 / 内建 / 标准库含签名与说明 / 异常 / 指纹)程序化对接(MCP、agent 自己解析)
jishi --ai-cardMarkdown 语言卡(贴进系统提示词就能用)直接当提示词

语言卡(M116 起:带签名 + 可分片)

bashjishi --ai-card                  # 全量卡(「一贴就能用」)
jishi --ai-card 文本             # 只要「文本」这一个模块的卡
jishi --ai-card --任务 表格      # 按任务打包:常用模块 + 该任务的惯用法
jishi --ai-card --统计           # 只看各种形态多大(字符数),不打印卡

认不出值的默认值写成 参数=…(表明「可以省」,但不把内部常量名漏给你)。

想量语言卡这一路,加 --规格 card [--卡分片 模块或任务]。

8. 语句

变量

python令 分数 = 60
分数 += 5          # 复合赋值
数据[0] = 100      # 下标赋值

下标(含负索引,R6.5)

python令 列 = [1, 2, 3]
列[0]          # 1           第一个(从 0 数)
列[-1]         # 3           最后一个(**负号从末尾数**)
列[-3]         # 1
列[-4]         # 索引错误     折算完仍越界 → 报「列表下标越界」(**不绕回开头**)
列[-1] = 9     # [1, 2, 9]   负索引也能赋值
列.弹出(-1)     # 弹最后一个
列.插入(-1, 9)  # [1, 2, 9, 3] 插到最后一个元素**之前**(负数先 + 长度,再夹到 [0, 长度])
文 = "甲乙丙"
文[-1]         # 丙          文本同样支持,且按**码点**取

⚠️ 负索引是 R6.5 才在两个宿主上补齐的:三个 Python 执行器底下就是 Python 的 list / str,一直支持;两个宿主原先显式要求「下标 ≥ 0」——于是同一个程序 在 Python 上给 3、在宿主上报「索引错误」。规格里本来就写着 弹出(位置=-1),文档与实现不一致就是 bug。 📌 折算里的「长度」是元素的个数:文本按码点数(&quot;a😀b&quot;[-1] 是 b), 不是字节数、也不是 UTF-16 码元数。 📌 字典的下标是键,不做负索引:{1: &quot;甲&quot;}[-1] 报「找不到这个键」。

切片(M18.1)

python令 a = [1, 2, 3, 4, 5]
a[1:3]        # [2, 3]     起:止
a[::-1]       # [5, 4, 3, 2, 1]   倒序
a[:2]         # [1, 2]     省略起
a[2:]         # [3, 4, 5]  省略止
a[::2]        # [1, 3, 5]  步长
a[:]          # [1, 2, 3, 4, 5]   全复制

"你好世界"[1:3]   # "好世"   字符串同样支持

多赋值与解包(M7)

python令 a, b = [1, 2]        # 列表解包(数目须精确匹配)
a, b = b, a             # 交换两个变量
令 x, y = 计算坐标()     # 函数多值返回 → 解包

返回 1, 2               # 多值返回:等价于 返回 [1, 2]

表达式语句

以值开头的行都是合法语句(REPL 中会回显结果,非空值时显示):

python1 + 2          # 顶层表达式
"你好"
[1, 2] + [3]

条件

python如果 分数 >= 90:
    打印("优秀")
否则如果 分数 >= 60:
    打印("及格")
否则:
    打印("不及格")

循环

python遍历 分数 在 [85, 92, 78]:
    打印(分数)

遍历 名字, 年龄 在 [["小明", 8], ["小红", 9]]:   # 多变量解包(M41)
    打印(名字, 年龄)

遍历 序, 名 在 配对(["甲", "乙"], [1, 2]):        # 常与「配对」「带下标」连用
    打印(序, 名)

循环 3 次:
    打印("你好")

当 分数 < 100:
    分数 += 1

遍历 支持多变量解包(M41):写成 遍历 甲, 乙 在 可迭代:,每次迭代把 元素解成两个名字(余 也能用,语义与 令 甲, 余 = … 一致)。实现走 解析期脱糖(临时循环变量 + 循环体首句解包赋值),所以三个执行器与两个 宿主的行为必然一致。

推导式(M7)

python[x * 2 遍历 x 在 [1, 2, 3]]              # [2, 4, 6]
[x 遍历 x 在 [1, 2, 3, 4] 如果 x > 2]     # [3, 4]
{x: x * x 遍历 x 在 [1, 2, 3]}            # {1:1, 2:4, 3:9}

函数

python函数 求和(a, b):
    返回 a + b

打印(求和(3, 4))

默认参数(M7)

python函数 打招呼(名字, 语气 = "你好"):
    打印(语气, 名字)

打招呼("小明")          # 你好 小明
打招呼("小明", "欢迎")  # 欢迎 小明

导入

python导入 随机                          # 基石标准库(中文 API)
令 n = 随机.随机整数(1, 100)

导入 math 从 python                 # Python 生态桥接(M3)
打印(math.sqrt(16))                 # 4.0

导入 math 从 python 为 数学          # 起别名
打印(数学.sqrt(9))                   # 3.0

导入 数学工具 从 本地包              # 本地包(M10.2)
打印(数学工具.平方(8))

导入 文本 为 t                      # 普通导入也支持别名(M18.4)
打印(t.计数("香蕉苹果", "香"))       # 1

会遮蔽内建 文本();用 导入 文本 为 t 可两全,导入时会打印一次中文提示)

Python 桥接规则(M3):

本地包规则(M10.2):

包清单 包.json 字段:

json{
  "名字": "某包",
  "版本": "1.0.0",
  "依赖": {"基础库": ">=1.0.0"},
  "描述": "可选说明"
}

满足约束后,把依赖包对象注入到该包模块的命名空间(模块里可直接 依赖名.成员, 无需重复导入)。

^1.2.3 主版本锁定(>=1.2.3 且 <2.0.0)。约束不满足报中文错误。

远端索引格式(M10.2,先静态 JSON 文件托管,不建站):

json{
  "格式": "jishi-package-index",
  "版本": 1,
  "包": {
    "某包": {
      "版本": "1.0.0",
      "下载地址": "https://例/某包-1.0.0.zip",
      "依赖": {"基础库": ">=1.0.0"},
      "描述": "……"
    }
  }
}

version_satisfies),供 jishi 安装 命令(M14)复用。

包管理命令(M14.2):

bashjishi 安装 包名 --local-dir 目录          # 从本地目录安装(含 包.json)
jishi 安装 包名 --local-zip 包.zip        # 从本地 zip 安装(内含 包名/ 顶层目录)
jishi 安装 包名 --from-index 索引.json     # 从远端索引拉包(本地文件或 URL)
jishi 安装 包名 --force                   # 覆盖已安装的同名包
jishi 卸载 包名                            # 卸载本地包
jishi 列表                                 # 列出已安装的包(名字/版本/描述)

⚠️ 卸载 有两个含义(M110 起):

bashjishi 卸载 包名        # 卸**包**(`.jishi/packages/` 里的东西)
jishi 卸载 --自身      # 卸**语言本体**(解释器自己)
jishi 卸载             # 不带包名 = 同上(必须二次确认,非交互要 --是)
jishi 升级             # 把语言本体升到最新版(--演练 / --本地包 / --源)

(先项目后用户目录)。

关键字参数(M3)

python导入 json 从 python
打印(json.dumps({"姓名": "小明"}, ensure_ascii=假))  # 中文不被转义

函数 介绍(姓名, 年龄):
    返回 姓名 + "今年" + 文本(年龄) + "岁"
打印(介绍(姓名 = "小红", 年龄 = 8))     # 基石函数同样支持
打印(介绍("小刚", 年龄 = 20))           # 位置参数 + 关键字参数

规则:

报错会提示对应的中文写法

8.9 异常处理

python尝试:
    令 结果 = 整数("不是数字")
捕获 类型错误 为 e:
    打印("输入不对:", e.消息)
捕获 异常 为 e:            # 「异常」是所有错误的基类,抓得住一切
    打印("其他错误:", e.类型)
最终:
    打印("无论如何都会执行")

类型错误/值错误/索引错误/键错误/除零错误/文件错误/断言错误。

捕获 断言错误 精确接住,也能用 捕获 运行期错误 兜住。

—— 与 如果 / 循环 / 遍历 / 当 / 尝试 体 / 最终 一样, 基石没有块级作用域(文档里「循环变量写入当前作用域」是同一条口径)。 所以捕获体里赋的值,出了捕获体照样读得到;捕获名也会覆盖外层同名变量。

python函数 取折扣价(原价, 折扣):
    如果 折扣 <= 0 或 折扣 > 1:
        抛出 值错误("折扣必须在 0 到 1 之间")
    返回 原价 * 折扣

8.10 类与继承

python类 动物:
    函数 初始化(自身, 名字):
        自身.名字 = 名字
    函数 叫(自身):
        打印(自身.名字, "在叫")

类 猫 继承 动物:
    函数 叫(自身):            # 覆盖基类方法
        打印(自身.名字, "喵喵")

令 咪咪 = 新建 猫("咪咪")
咪咪.叫()

空类占位(单独一行 :——基石没有 pass 关键字)。写别的(表达式语句、 += 这类增强赋值、下标/属性赋值)在解析期就报错并给出正确写法。 以前这条不统一:树遍历会报错,而两个字节码执行器会静默忽略 (x += 5 甚至被当成 x = 5 静默算错),所以统一挪到解析期拦下。

调用 实例.方法(...) 时自动绑定。

没定义 初始化 则 新建 类() 造空实例,传参报错。

类变量(M23)——写在类体里、所有实例共享的名字:

python类 计数器:
    总数 = 0                  # 类变量
    名字 = "计数器"
    函数 加(自身, n):
        计数器.总数 += n        # 用类名读写,或 自身.总数 读也行

同名时实例字段遮蔽类变量;

超() 调父类方法(M23):

python类 动物:
    函数 初始化(自身, 名字):
        自身.名字 = 名字
    函数 叫(自身):
        返回 自身.名字 + "叫了一声"

类 狗 继承 动物:
    函数 初始化(自身, 名字, 品种):
        超().初始化(名字)          # 调基类的构造方法
        自身.品种 = 品种
    函数 叫(自身):
        返回 超().叫() + ",汪汪"   # 调基类同名方法再追加

(小狗 → 狗 → 动物 三级链能正确逐层向上,与 Python 的零参数 super() 一致);

参数的方法里,解析期即报错并给出写法提示;

8.11 模式匹配 匹配 / 情形(M34)

python匹配 分数:
    情形 90:                    # 单值
        打印("优秀")
    情形 80, 85:                # 多值:命中任一个即可
        打印("良好")
    情形 如果 分数 >= 60:        # 只有条件(守卫链,最常见的写法)
        打印("及格")
    情形 其他:                  # 兜底,要放最后
        打印("继续努力")

四种分支写法:

写法含义
情形 值:待匹配值与「值」相等即命中
情形 值1, 值2:命中任一个即可
情形 值 如果 条件:先比较值,再看条件
情形 如果 条件:只有条件(相当于一个 如果 分支)
情形 其他:兜底(不带条件的通配,必须放最后)

写 情形 (其他):(加括号走普通表达式);

(树遍历 / Python VM / C VM)与两个跨语言宿主(Node / Rust)行为必然一致。

8.12 枚举 枚举(M34)

python枚举 颜色:
    红 = 1
    绿 = 2
    蓝 = 3

枚举 方向:      # 不写值:自动接着编号(从 1 起)
    上
    下
    左
    右

(容器里也一样),.名字 / .值 分别取名字与值;

(与 Python 的 Enum 一致);

遍历 c 在 颜色.全部:;

(没法自动编号,报错会说清);

8.13 条件表达式 甲 如果 条件 否则 乙(M36)

「在一行里二选一」的表达式写法(三元表达式):

python令 年龄 = 20
令 等级 = "成年" 如果 年龄 >= 18 否则 "未成年"
打印(等级)                      # 成年

# 可嵌套(**右结合**):先判第一个条件,不成立再往后判
打印("优" 如果 分数 >= 90 否则 "良" 如果 分数 >= 60 否则 "差")

选它是因为零新增关键字——如果/否则 本来就是语句关键字, 词法器、粘连检查、既有 API 都不用动(加关键字的成本与风险见 AGENTS.md 的「加关键字的检查清单」)。

是「先算 假 或 真,再拿它当条件」。

都成立。

`` 甲 如果 条件 否则 乙 ⇓ (函数(): 如果 条件: 返回 甲 返回 乙 )() ``

所以三个执行器与 Node / Rust 两个宿主一行都没改(本项目第六次用这个手法)。

  1. 推导式的过滤子句:[x 遍历 x 在 y 如果 条件] 里的「如果」仍是过滤子句

——可迭代对象那一层不认条件表达式;

  1. 匹配的守卫:情形 90 如果 加分: 里的「如果」仍是守卫

——值那一层不认条件表达式。

两处都跟 Python 同一个思路:把「可迭代对象 / 情形值」限制在不含 conditional_expression 的层级(Python 的 comp_for 只允许到 or_test)。 想让这些位置用条件表达式,加括号即可:[x 遍历 x 在 (a 如果 c 否则 b)]、 情形 (a 如果 c 否则 b):。

9. 内建函数

函数说明
打印(...)输出内容(空/真/假 显示为中文,见 §7.15)
输入(&quot;提示&quot;)读取一行输入(返回文本)
整数(x) / 小数(x) / 文本(x)类型转换
长度(x)列表/文本/字典的长度
范围(起, 止, 步长)生成整数序列,1~3 个参数:范围(5)、范围(1, 5)、范围(1, 10, 2)
带下标(可迭代, 起始)造 [下标, 元素] 对(M41,同 Python 的 enumerate):带下标([&quot;甲&quot;,&quot;乙&quot;]) → [[0,&#x27;甲&#x27;],[1,&#x27;乙&#x27;]]
配对(甲, 乙, …)按位置配成 [甲[i], 乙[i], …](M41,同 Python 的 zip,取最短)
最大(列表) / 最小(列表)取最大值 / 最小值;也支持多参数 最小(a, b)、最小(a, b, c)(M18.3)
总和(列表)求和
类型(x)值的类型名:整数/小数/文本/列表/字典/布尔/空/函数…
异常(msg) / 类型错误(msg) / 值错误(msg) / 索引错误(msg) / 键错误(msg) / 除零错误(msg) / 文件错误(msg)构造异常对象(配合 抛出 使用)
反转(列表或文本)反转
断言(条件, 消息=空)条件为假就抛「断言错误」(M23),消息可省
是实例(值, 类)值是不是这个类(或其子类)的实例(M23)
超()在方法里调基类的同名方法(M23),见「类与继承」
集合(可迭代=空)去重造集合(M24),见「集合」
位与(a, b) / 位或(a, b) / 位异或(a, b) / 位取反(a)按位运算(M36)。**没有 `& \^ 语法**:日常业务代码罕见,加运算符要动三执行器 + 两宿主,按「关 0」做成内建;只收整数,真/假`/小数/文本一律明确报错
左移(值, 位数) / 右移(值, 位数)位移(M36)。位数须是非负整数且 ≤ 1000000(防 1 &lt;&lt; 10**9 申请 125 MB);右移 对负数是算术右移(向下取整)

9.5 对象方法(M1)

方法通过 对象.方法(...) 调用;列表与字典的方法为原地修改,文本方法返回新值。

对象方法
列表追加(v) 插入(位置, v) 移除(v) 弹出(位置=-1) 排序() 反转() 清空() 索引(v) 计数(v) 包含(v) 映射(f) 过滤(f) 排序按(f) 归约(f, 初值)(后四个是 M24 起就有的,这份表以前漏列了)
字典获取(键, 默认=空) 键() 值() 包含(键) 更新(字典) 合并(字典)(返回新字典,不动双方,M36) 弹出(键, 默认=空) 清空()
文本拆分(分隔符=&quot; &quot;) 替换(旧, 新) 查找(子串)(找不到返回 -1) 大写() 小写() 去空白() 开头是(前缀) 结尾是(后缀) 包含(子串) 转整数() 转小数()

10. 标准库(M2)

全部为中文 API,底层薄封装 Python 成熟实现。导入 模块名 引入。

模块主要功能
随机随机整数 / 随机小数 / 随机选择 / 洗牌
数学开方 / 平方 / 幂 / 绝对值 / 向上向下取整 / 四舍五入 / 最大公约数 / 最小公倍数 / 阶乘 / 圆周率 / 正弦余弦正切 / 角度转弧度 / 对数 / 常用对数
时间现在 / 今天 / 此刻(返回年月日时分秒星期字典)/ 时间戳 / 格式化时间戳 / 星期名 / 加天数 / 高精度时间 / 睡眠
文件写文本 / 读文本 / 追加文本 / 写行 / 按行读 / 读字节(M113:整个文件 → 字节)/ 写字节(M113)/ 文件存在 / 是文件 / 是目录 / 列出目录 / 创建目录 / 删除文件 / 复制 / 文件大小 / 原子写(M108:先写临时再改名) / 路径拼接 / 文件名 / 扩展名
编码base64编码 / base64解码(M113:→ 字节)/ 十六进制编码 / 十六进制解码(M113:→ 字节,源码里造字节就用它)/ url编码 / url解码 / 文本字节(M113:文本 → 字节)/ 字节文本(M113:字节 → 文本,解不出 UTF-8 明确报错)
表格读表格(表头+数据行)/ 写表格 / 写字典表格 / 读字典表格 / 追加 / 挑选(一列或多列)/ 筛选 / 排序按 / 汇总(个数总和平均最大最小)/ 分组汇总(M106:按列分组再统计)/ 连接(M106:按键内连接两表)/ 转置 / 从记录(M107:字典列表→表格)/ 转记录(M107:表格→字典列表)
文本拼接 / 居中 / 左右对齐(M106 起按「显示宽度」补:一个汉字算 2 列)/ 填充 / 显示宽度(M106)/ 补零 / 重复 / 计数 / 是数字 / 是字母 / 是空白 / 首字母大写 / 去前缀 / 去后缀 / 格式化 / 按行拆分 / 截断
json转文本(中文不转义)/ 解析 / 读文件 / 写文件
数据库打开 / 关闭 / 表们 / 有表 / 建表 / 建索引 / 插入 / 批量插入(事务)/ 查询 / 条数 / 汇总 / 修改 / 删除 / 执行 / 执行查询(M112;字节列按 BLOB 原样往返,M113)
并发批量摘要(M114:并行算一批文件的摘要)/ 批量读(并行读成 字节)/ 并行取(并行 GET 一批网址)—— 结果顺序与输入严格一致
HTTP服务端启动(M115:起一个只监听本机的小服务)/ 空闲端口 / 解析请求 / 构造响应 —— 前两个要 socket,Node 宿主与浏览器试玩页用不了
日期今天 / 解析 / 格式化 / 加天数 / 减天数 / 加月(M109:按日历月,月末收口)/ 加年 / 解析ISO(M109:只取字面日期)/ 相差天数 / 早于 / 晚于 / 相等 / 星期名 / 今年 / 本月 / 本年天数
正则匹配 / 搜索 / 查找全部 / 替换 / 拆分 / 分组
网络获取 / 提交 / 获取JSON(默认 10 秒超时,都能带 请求头 字典);提交JSON(M107,发 JSON);获取详情(M107,返回状态码/响应头/正文,非 2xx 不抛);下载(M107,存文件给字节数)
html转义 / 原样 / 标签 / 空元素 / 链接 / 属性文本 / 有序无序列表(生成方向);取文本 / 取链接 / 取表格(M107,解析方向)
路径存在 / 是文件 / 是目录 / 绝对路径 / 父目录 / 文件名 / 后缀 / 无后缀名 / 连接 / 当前目录 / 主目录 / 创建目录 / 删除 / 递归删除(M108)/ 列出 / 递归列出(M41)/ 按模式找(M108:报告*.md 这类通配)/ 重命名 / 大小 / 修改时间 / 系统临时目录 / 临时目录 / 临时文件(M108)
加密摘要 / md5 / sha1 / sha256 / sha512 / 文件摘要 / HMAC(M109:带密钥的签名)/ 口令摘要(M109:PBKDF2,默认 10 万次)/ 安全随机字节(M113:系统熵源 → 字节;M109 起有,返回类型 M113 改对了)/ 支持的算法
压缩打包(文件或目录→zip)/ 解压 / 列出内容 / 压缩文件(M109:单文件 → .gz)/ 解压文件(M109)
系统系统名 / 系统版本 / 机器架构 / 处理器 / 当前目录 / 改目录 / 环境变量 / 设环境变量 / 执行(外部命令)/ 退出码 / 打开(M108:默认程序开文件/网址)/ 主机名 / 参数(命令行参数,M18.2)
容器计数 / 最多 / 按值排序 / 分组 / 取前 / 取后 / 分块(M41;模块名不叫「集合」——那是内建函数名)
迭代分组 / 滑窗 / 去重 / 展开 / 取前 / 取后 / 求和 / 计数(M41)/ 归约(M106:通用 reduce)/ 分区(M106:按判定分两堆)/ 累积 / 组合 / 排列 / 笛卡尔积
参数新建 / 选项 / 标志 / 用法 / 解析(M41,命令行选项解析)
日志级别们 / 设级别 / 取级别 / 设前缀 / 调试 / 信息 / 警告 / 错误(M41)
测试用例 / 相等 / 不等 / 为真 / 为假 / 近似 / 包含 / 抛出 / 统计 / 汇总 / 重置(M41)

命令行参数(M18.2):jishi 脚本.jsh 参数1 参数2 中,脚本名之后的参数 传给脚本,脚本内 系统.参数() 返回这些参数组成的列表(不含脚本名); 用 -- 分隔可把 -- 开头的内容也当脚本参数(jishi 脚本.jsh -- --foo)。 注意:导入 文本 后,内建转换函数 文本(...) 会被模块遮蔽,导入时会打印一次 中文提示;如需两全,用别名 导入 文本 为 t(M18.4)。 正则模式写 &quot;\d+&quot;(基石的未知转义会保留反斜杠,无需 r 前缀)。 路径/压缩 涉及文件系统访问、系统 涉及执行外部命令,沙箱默认拦截 (需显式开启 allow_write / allow_network);加密 纯摘要计算,沙箱默认放行。

11. 中文报错

所有错误以中文呈现,带错误码、行列定位与修正建议:

错误 E0106:关键字与后面的内容粘连了(「如果分数」被当成了一个名字,但它的开头是关键字「如果」)
  ┌─ 文件.jsh:1:1
  │
1 │ 如果分数 > 60:
  │ ~^
  │
  提示:你是不是想写「如果 分数」?关键字和后面的内容之间要留空格

错误码分段:E01xx 词法、E02xx 语法、E03xx 语义、E2xxx 运行期。

11.0 调用栈回溯(M17)

运行期错误若发生在函数调用深处,报错下方会附带「调用链(从外到内)」,标明 每一层是「哪个函数」在「第几行」被调用:

错误 E2003:索引越界(列表下标越界)
  ┌─ 脚本.jsh:3:9
  3 │     打印(x[10])
    │         ^
  │
调用链(从外到内):
  外层 ← 第 8 行
  中层 ← 第 7 行
  里层 ← 第 5 行

list index out of range / &#x27;键&#x27;(键的 repr)这种宿主语言的原文 —— 与「一个字符 = 一个码点」「不把内部结构泄进文案」是同一条规矩。

独立宿主(Rust 单二进制)按 filename 现读源文件画出同一份 (源码行 + ^ + 调用链),由 tools/check_engines.py 守着。

11.1 容错解析(M7.5)

基石会识别「用英文写了 Python 关键字/内建」的常见错误(大模型写中文代码时 容易 fallback 回英文),并直接给出中文对应建议:

pythondef f(x):        # → 「def」是英文关键字,你是不是想写「函数」?
print(1)         # → 「print」是 Python 内建,基石里叫「打印」
令 x = True      # → 「True」是英文写法,你是不是想写「真」?
令 y = 1 and 2   # → 「and」是英文写法,你是不是想写「与」?

覆盖三类:英文语句关键字(def/if/for/while/return/import/class/try…)、 值/运算符关键字(True/False/None/and/or/not/in/is)、内建函数 (print/len/range/int/float/str/type/min/max/sum/reversed)。 英文普通变量名(a、data 等)不受影响。

12. 已知边界(v1.0 冻结时的诚实声明)

以下特性当前不支持,已诚实标注,留待后续版本评估:

  1. Rust 宿主的剩余边界(M33 后:标准库已补齐到 14 个模块):

整数到 i128 就到边界(越界明确报错)、绑定方法的 是/不是 明确报错、 精确小数的 只支持整数指数、压缩.打包 写 stored(不压缩, 文件大一点但完全合规)、非 Windows 平台上 https:// 明确报错。 已支持的(方法调用/高阶方法/集合/文件与上下文/精确小数/类型标注/同一性/ 切片/输入/排序/14 个标准库模块**)全部有对拍测试; 详见 docs/embed.md 的支持程度表与 rust/README.md。

  1. JS 宿主的剩余边界:node/ 已补齐到 M34(含 M32 的大整数

BigInt、类与函数显示、精确小数精度,以及 M34 的类变量与 模式匹配/枚举),剩下的是 导入 … 从 python 不支持(无 Python 运行时)、 网络 是子进程同步封装(每次请求多约 40ms)。

以上边界均属「已知、诚实标注、留待演进」,不影响 v1.0 的核心语言特性冻结。