积木文本语法
积木页文本、命令行(gandi)、本机 MCP 和积木注释里的 gandi-dsl 片段,都用同一种文本来描述积木。
控制、运算、变量和列表写成 JavaScript 的样子,其余积木写成 分类.积木名(...)。文本从不执行,
只是积木的另一种写法:积木打印成文本、文本编回积木,结构完全一致。
const score = stage.variable("score", 0);
const items = sprite.list("items", []);
when.flagclicked(() => {
score = 0;
for (let i = 1; i <= 10; i++) {
items.push(i * 2);
if (i % 3 == 0 && !sensing.mousedown()) {
score += 1;
} else if (i > 8) {
looks.say(`第 ${i} 个`);
}
}
repeat(3, () => { motion.movesteps(10); });
});旧的块式写法(control.if(operator.gt(a, 1), () => { ... })、data.set(x, 1))一直可用,
编出的积木相同。读回积木时,能写成 JavaScript 的地方都写成 JavaScript;写不成的保持块式(见细节)。
声明#
要新建变量、列表或广播,在文件开头声明,const 和 let 等价:
| 写法 | 含义 |
|---|---|
const x = stage.variable("x", 0); |
全局变量,初始值可省 |
const x = sprite.variable("x", 0); |
当前角色的变量 |
const L = sprite.list("L", []); / stage.list(...) |
列表 |
const msg = broadcast("消息"); |
广播消息 |
项目里已有的变量和列表不用声明,直接按名字写(x = 1;、L.push(v);)。只有三种情况要声明:新建一个;
角色变量和全局变量同名(不声明会报 E_AMBIGUOUS_VAR,声明时选 sprite.variable 还是 stage.variable);
同名的变量和列表要用列表写法(L.push(...))。引用从不新建变量,名字不存在报 E_UNKNOWN_VAR。
for 的循环变量也一样:要么项目里已有,要么先声明,例如 const i = sprite.variable("i", 0);。
读回积木时只声明这一页用到的变量,声明里的字符串是变量的真名,标识符可以不同:名字写不成标识符
(my score、☁ x、_)叫 _variable;和积木分类同名(data、motion……)、和这一页任何自制积木的形参同名的,
标识符加数字后缀(p → p2),重名的往后编号。例如变量 p 和自制积木形参 p 同名时:
const p2 = sprite.variable("p", 0); // 真名还是 "p"
define("f %n", (p) => { p2 = p; }); // 形参 p 和变量 p2 不会混控制#
| 积木 | 写法 |
|---|---|
| 如果 | if (条件) { ... } |
| 如果…否则 | if (条件) { ... } else { ... },else if 链是嵌套的「如果…否则」 |
| 重复执行 | while (true) { ... } |
| 当…重复执行 | while (条件) { ... } |
| 对于每个 | for (let i = 1; i <= n; i++) { ... },i 必须是项目里已有或已声明的变量,起点只能是 1,语义见for 的语义 |
| 重复执行…次 | repeat(n, () => { ... }); |
| 重复执行直到 | repeatUntil(条件, () => { ... }); |
| 等待 | wait(秒);、waitUntil(条件); |
| 停止 | stop("all"); |
| 跳出循环 / 跳到下一轮 | break;、continue;(Gandi 专有积木,见Gandi 专有积木) |
| 返回 | return 值;,只能写在自制积木的定义里;顶层或 hat 里写 return 语句报 E_RETURN_OUTSIDE |
while (true) 的循环体里有 break; 时,它是「当 真 重复执行」而不是「重复执行」:
「重复执行」是终结积木,后面不能再接积木,会结束的循环可以。break; 和 continue;
只能写在 while、for 语句里;repeat、repeatUntil 的回调里写 control.break()、
control.continue()。
定义之外孤立的「返回」积木在运行时合法(相当于停止这个脚本,TurboWarp 作品里有),读回时写成块式
procedures.return(值),编译只给 W_RETURN_OUTSIDE 警告;要停止脚本写 stop("this script")。
for 的语义#
for (let i = 1; i <= n; i++) 编成「对于每个 i(1 到 n)」积木,和 JavaScript 的 for 不一样(VM 实测,解释器和编译执行一致):
| 情形 | 实际行为 | JavaScript 里 |
|---|---|---|
n 每一轮重新求值 |
和 JavaScript 一致,循环里改 n 会影响轮数 |
一致 |
n = 2.5 |
跑 3 轮(i 取 1、2、3) |
跑 2 轮 |
循环体里改 i |
不影响迭代,仍然跑满 | 会影响 |
循环结束后的 i |
等于 n |
等于 n + 1 |
n < 1 |
一轮都不跑,i 不会被置成 1,保持原来的值 |
i 被置成起点 |
起点只能写 1,步长只能是 ++ 或 += 1,条件只能是 i <= n,别的写法报 E_UNSUPPORTED_FOR。
运算#
运算符的优先级与 JavaScript 相同,a + b * 2 是 a + (b * 2),积木是嵌套的两个运算积木。
| 积木 | 写法 |
|---|---|
| 加、减、乘、除、取余、乘方 | a + b、a - b、a * b、a / b、a % b、a ** b(乘方是 Gandi 专有积木) |
| 取负 | -a(等于 0 - a) |
| 大于、小于、等于 | a > b、a < b、a == b |
| 不等于、小于等于、大于等于 | a != b、a <= b、a >= b,是对应比较外面套一个「不成立」 |
| 区分大小写的等于 | a === b、a !== b(Gandi 专有积木,不是严格类型相等,见下) |
| 与、或、不成立 | a && b、a || b、!a |
| 三元 | 条件 ? a : b(Gandi 专有积木) |
| 连接 | 模板字符串 `你好 ${名字}` |
| 四舍五入、绝对值、向下取整、向上取整、平方根 | Math.round(x)、Math.abs(x)、Math.floor(x)、Math.ceil(x)、Math.sqrt(x) |
| 乘方 | Math.pow(a, b)(和 a ** b 是同一块,Gandi 专有) |
| ln、log、e ^ | Math.log(x)、Math.log10(x)、Math.exp(x) |
| 三角函数 | sin(x)、cos(x)、tan(x)、asin(x)、acos(x)、atan(x),参数和结果都是角度 |
| 随机数 | random(a, b) |
| 字符串 | s.length、s[i]、s.includes(t) |
&&、||、! 和 if、while 的条件必须是布尔积木:比较、true / false、侦测里的判断等。
变量不是布尔值,要写成 x != 0。
变量与列表#
| 积木 | 写法 |
|---|---|
| 将变量设为 | x = 值; |
| 将变量增加 | x += 值;、x -= 值;、x++;、x--; |
| 乘、除、取余、乘方后设回 | x *= 值;、x /= 值;、x %= 值;、x **= 值;,编成「设为」加运算积木 |
| 加入列表 | L.push(值); |
| 插入列表 | L.insert(位置, 值); |
| 删除列表的第几项 | L.remove(位置); |
| 删除列表的全部项目 | L.clear(); |
| 替换列表的第几项 | L[位置] = 值; |
| 列表的第几项 | L[位置] |
| 列表的项目数 | L.length |
| 列表包含 | L.includes(值) |
| 列表中第一个…的编号 | L.indexOf(值),找不到是 0 |
显示、隐藏变量仍写 data.showvariable(x)、data.hidevariable(x)。运动、外观、声音、事件、侦测等
其余积木都写成 分类.积木名(...),需要的积木名用 gandi blocks 关键词 查。
和 JavaScript 不同的地方#
| 写法 | 实际含义 |
|---|---|
s[i]、L[i]、L.insert、L.remove、L.indexOf |
位置从 1 数起。作品装了「高级数据结构」后,变量、成员、调用结果上的 x[i] 是属性访问(对象的键 / 对象列表的第 i 项),只有字符串字面量和模板后面的 [i] 才是取字符;变量里取字符写 operator.letter_of(i, x),见高级数据结构的文本写法 |
a + b |
任一边是字符串字面量、模板字符串或连接积木时是连接,否则是数字加法 |
a == b |
不区分大小写,数字形式的文字按数值比较;a === b 区分大小写 |
a % b |
结果的符号跟除数一致,-7 % 3 是 2 |
sin(x) 等 |
参数是角度。没有 Math.sin |
x = x + 1 与 x += 1 |
前者是「将变量设为」加一个加法积木,后者是「将变量增加」,两种写法各自保留,不互相转换 |
a < b < c |
报错,写成 a < b && b < c |
for |
计数循环只支持 for (let i = 1; i <= n; i++),语义和 JavaScript 不同,见for 的语义;for...of 只在作品装了集市版「高级数据结构」时有,是它的「遍历」积木,见高级数据结构 |
| 函数形参 | 不能赋值,要先放进已声明的变量 |
s.includes(t)、L.includes(v)、L.indexOf(v) |
不区分大小写 |
a < b、a > b |
两边有一边是文字(不能当数字读)就按字符串比较,"10" < "9" 成立 |
NaN 的比较 |
退化成字符串比较:NaN > 1、NaN >= 1 得 true,NaN <= 1 得 false,NaN == NaN 得 true;不要依赖 NaN 参与比较 |
(12345).length |
数字当文字取长度,是 5 |
"" == 0 |
false(空串不当 0) |
s2 + s3(两个变量,值都是文字) |
变量不是字符串字面量,按数字加,"a" 和 "b" 得 0,不是 "ab";连接要写模板字符串 `${s2}${s3}` |
s + 4,s 的值是 "3" |
得 7(数字形式的文字按数值加) |
1 === "1" |
true:=== 只是区分大小写的等于,不比较类型 |
s[0]、s[越界] |
得空串(序号从 1 起);字面量 0 会给 W_INDEX_FROM_ONE 警告,L[0] 同理 |
random(a, b) |
a、b 都是整数才取整数,有小数就取小数;a > b 时自动交换 |
x / 0、x % 0 |
x / 0 是 Infinity(0 / 0 是 NaN),x % 0 是 NaN |
不支持函数表达式、new、typeof、??、switch、do...while、async。对象和数组只能写在其他写法
列出的位置(可增减的参数组、命名参数),不能当值用。作品装了「高级数据结构」时,对象和数组字面量、typeof、new Set(...)
是它的积木,见高级数据结构的文本写法。
Gandi 专有积木#
===、!==、**(Math.pow)、条件 ? a : b、break、continue 编成 Gandi 才有的积木
(operator_strictequals、operator_power、operator_ternary、control_break、control_continue)。
原版 Scratch 没有这些操作码,含有它们的作品导出到原版 Scratch 后打不开。check 和写入时编译会给
W_GANDI_ONLY 警告,列出用到的积木,不阻断写入;作品要在原版 Scratch 里打开就别用:
=== 换 ==,break / continue 换条件变量加 while / repeatUntil,**、三元换乘法和 if。
其他写法#
- 命名参数:
looks.say({MESSAGE: "hi"}),键是积木的输入名或字段名,写了不存在的键报E_UNKNOWN_ARG, 新积木缺必填字段报E_MISSING_ARG。命名参数和位置参数不能混用;有回调时回调是第二个参数。 - 可增减的参数组(扩展积木的 ➕➖ 参数):固定参数照常写,后面每个组写成数组或对象:
gandiScene.switchToWithParams("main", {关卡: 1, 难度: 2})(键 = 值两格一组写成对象)、ext.block(a, [x, y, z])(一格一组写成数组)、[[键, 值], ...](键写不成属性名时)。数字样的键、typed/reference/opcode等保留名不能当对象键,会退回[[键, 值], ...]。核心积木的多操作数写成operator.add(a, b, c)、混合运算符写成operator.arithmetic(a, "+", b, "-", c)。 扩展声明了「逐槽选类型」(types)的组,每个槽放什么由槽里的值定:布尔积木是布尔槽(槽里没有文字框),数字是数字槽, 文字是文字槽;类型存在积木的argtypes里,带底写回原样保留,纯文本重编会按槽里的值重新写出。 超过个数上限报一条E_VARIADIC_LIMIT(不是每个多出来的槽一条未知输入),积木上带着items="2"这类和槽数一致的旧属性,写回时原样保留。 - 阈值型 hat:
when.greaterthan("LOUDNESS", 10, () => { ... })的阈值是数字框,可以换成报告器 (when.greaterthan("TIMER", sensing.answer(), ...));它没有参数椭圆,写回调形参报E_HAT_PARAMS。 - hat 回调的形参:带参数椭圆的 hat 把椭圆名写成回调形参,体内直接用:
gandiScene.whenSceneStartsWithParams((level, 难度) => { looks.say(level); })。形参只在这个回调里有效, 不能赋值;椭圆名写不成标识符或和变量重名时退回["名字", ...]加ccw.hat_parameter("名字")。 hat 没有参数椭圆却写了形参报E_HAT_PARAMS。回调形参_表示「不要这个参数」,参数名真叫_时退回字符串位置写法。 - 自制积木:
define("go %n", (steps) => { ... });和call["go %n"](10);,形参%n数字、%s文字、%b布尔、%c积木堆(体内body()调用)。变量和形参同名时形参优先,读回时变量会改名(见声明)。 - 积木注释:积木前写
/** 文字 */,多行用每行*开头的 JSDoc 样式;文字有首尾空白、*/、\r时写成精确 写法/** @text "..." */。空注释写/** */。挂在 reporter 上的注释写成(/** 文字 */ 表达式),括号让 注释挂在这一整块上。普通注释(//、/* */)不会存进积木,会给W_COMMENT_DROPPED警告;else /** 注释 */ if这种不在语句或表达式前面的注释同样被丢并警告。 - 装饰器:
@at(x, y)、@warp、@global、@reporter、@boolean、@collapsed、@id("...")、@size、@color、@locked、@note(...)只能写在顶层语句或frame()前面(中间只隔空白和注释);写在回调里、或后面没有语句, 报E_DECORATOR。 - 深度上限:语句和表达式嵌套超过 400 层报
E_TOO_DEEP(带上限数),长链(几百项的+、&&、模板) 拆成几条语句。读回积木时嵌套超过 180 层也会拒绝打印并报同一个错,不会截断。
回调形参#
积木上有「参数槽」时,参数槽写成回调的形参。参数槽是积木上一个只能放自己那块参数积木的输入:遍历积木的「键」「值」、
map 积木的「项」「序号」、reduce 的「累积值」……(hat 积木的参数椭圆是同一类,见上面的 hat 回调)。
ext.each(list, (key, value) => { looks.say(value); }); // C 形积木:回调体是积木堆
r = ext.map(list, (item, index) => item * 2); // 回调体是一个表达式(lambda 积木)- 回调永远是最后一个参数,前面是积木上其余的固定参数(按积木上的顺序)。具名写法把回调放在回调体输入的键里
(
{LIST: list, SUBSTACK: (key, value) => {...}})或者作第二个参数。没有形参的() => { ... }也认。 - 形参依次绑定参数槽,个数不能超过槽数(
E_HAT_PARAMS),少写的槽照样在积木上;形参名只是文字里的写法。体里用形参就是 引用槽里那块参数积木,所以形参只在这个回调体里有效,不能赋值(E_ASSIGN_PARAM),回调外面再用报E_UNKNOWN_VAR。 - 回调体的种类要对:C 形口写
{ ... },lambda 写表达式,写反了报E_SLOT_TYPE。lambda 体里的true/false、字面量照常编。 - 参数槽的名字:槽里是自己的可再生积木的(
item、key……),打印时取槽名的小写(IDX写index);槽里是默认名的参数椭圆的,取椭圆名。 重名或和变量冲突就加数字(item2)。 - 里层回调盖住外层的同一块参数积木:两个回调积木用的是同一块参数积木(例如都有
item)时,运行时读最近一层的值。 在里层体里写外层的形参报E_PARAM_SHADOWED,要用就先放进变量;这包括里层没写形参的槽。 - 参数槽被别的积木盖住、缺输入、体不是标准形状的积木,读回时保持位置参数写法(参数槽里的标准影子写成它自己的调用,
ext.forEachKey()),编译回去是同一块积木。 - 老的「每个槽都写出来」的位置写法(
ext.each(list, "ITEM", "POS", () => {...})、参数槽里写参数积木的调用)照常可用。
带点和特殊字符的扩展 id#
积木写成 扩展id.积木名(...)。扩展 id 不一定是单个标识符,写法按 id 的样子定,打印和解析互逆(积木 → 文本 → 积木结构一致):
| 扩展 id | 积木写法 |
|---|---|
music、my_ext(下划线属于 id) |
music.playNote(...)、my_ext.go(...) |
test.moreDataTypes(带点,每一段都是标识符) |
成员链 test.moreDataTypes.getNewSet(...);去掉最后一段方法名,其余用点连起来就是 id |
my-ext、中文、a b(有一段写不成标识符) |
ext["my-ext"].go(...) |
if、null、class、when、call、Math、JSON、Object、store、ads、stage……(第一段是 JavaScript 保留字或 DSL 自己占用的名字) |
ext["if"].go(...):写成 if.go(...)、null.go(...) 读不回 |
积木名写不成标识符(do-it、two words) |
ext["my-ext"]["do-it"](...),普通 id 也一样 |
- 积木的操作码是
扩展id_积木名;解析成积木后和普通扩展没有区别,E_UNKNOWN_BLOCK的报错里是完整的操作码, 没装的扩展(test.moreDataTypes.getNewSet(...))报「积木不存在」并带上完整 id,宿主据此去装扩展。 - 分类名、带点 id 的第一段(
test)和ext在文本里是前缀:变量、形参不能叫这些名字(读回积木时同名的变量会改名, 如test2,声明里的字符串真名不变)。文件里声明了同名变量时,那个名字就是变量,不再当扩展前缀。 - 装了「高级数据结构」时,没对上已装扩展 id 的成员链(
o.a.b.push(v))是对象属性路径,不是积木调用。
细节#
下列积木打印时保持块式,因为写成 JavaScript 读回来会变样:
- 在比较下拉里选了
≠、≥、≤、≡的紧凑比较积木,以及带可增减参数的算术、逻辑、连接、三元积木:operator.compare(...)、operator.arithmetic(...)、operator.logic(...)、operator.join(...)、operator.ternary({...})。 - 带
else if分支的「如果」积木(多条件的紧凑形态)。 - 「否则」槽里的内层「如果」带注释、或下面还有别的积木时,写成
else { ... },不写成else if。 - 嵌套在左边的连接积木
连接(连接(a, b), c);只有嵌套在右边的链才写成模板字符串。 - 条件恰好是
true而循环体里没有break的「当…重复执行」:写成control.while(true, ...)。 - 循环体里有
break的「重复执行」:写成control.forever(...)。 repeat、repeatUntil回调里的「跳出循环」:写成control.break()。- 名字和积木分类同名的变量(
data、motion……)、和自制积木形参同名的变量、写不成标识符的名字(含_): 打印时改标识符(加后缀,如data2、p2;写不成标识符的叫_variable),声明里的字符串真名不变。 - 定义之外的「返回」积木:写成
procedures.return(值),不写成return。 - 带注释的 reporter:写成
(/** 注释 */ 表达式)。
没装扩展的积木页是只读的#
作品用了还没装的扩展时,读这一页会先自动装上它(和写入同一套:协作中要有 edit.project、要用户同意,已授权的设备不再逐次确认;
装第三方代码,所以这是读取会改动环境的一处,结果里带 installedExtensions)。装不上的页(扩展库里没有、没权限、不同意、超时)
退回只读预览:扩展积木写成 扩展.积木({ 输入名: 值 }),结果带 degraded: true 和 missingExtensions。
预览看不到积木上的隐藏结构(mutation、菜单影子、布尔槽的空位),写回会悄悄改掉它们,所以含预览的页一律不能写:
write_file、edit_file、apply_patch、transaction 都报 E_DEGRADED_WRITE(check 也报,details.missingExtensions 列出缺的扩展),
页和积木表原样不动。先装好扩展,重新读这一页拿到正式写法,再改。
- 扩展 id 带下划线(
my_ext)时,按已知的扩展 id(已装的、扩展库里的)取最长前缀还原,不会当成my。 search_files先在预览上搜,只为命中的缺扩展页装扩展,再重新打印命中页;大列表折叠成占位的页搜不到列表里的内容, 结果带folded: true、totalExact: false。- 多场景:积木页按角色所在场景的舞台解析变量和广播,那个舞台取不到时读、检查、写入都报
E_STAGE_CONTEXT,不会悄悄换成入口场景的舞台。 页面里指向看不见的变量(别的场景舞台上的、已删除的)的旧引用,写回时沿用原来的 id,不新建变量,给W_VARIABLE_NOT_VISIBLE警告。 场景在读和写之间改过名,写入会因为修订号变了报E_CONFLICT;文本里的场景名和积木原来指向的场景对不上时给W_SCENE_RENAMED。
报错#
| 代码 | 原因 | 改法 |
|---|---|---|
E_CHAINED_COMPARE |
a < b < c |
a < b && b < c |
E_ASSIGN_PARAM |
给自制积木的参数赋值 | 复制到已声明的变量再改 |
E_ASSIGN_TARGET |
给整个列表赋值 | L.push(v)、L[i] = v 或 L.clear() |
E_UNKNOWN_VAR |
变量没有声明 | 在文件开头 const x = sprite.variable("x", 0); |
E_UNSUPPORTED_FOR |
for 不是计数形式 |
for (let i = 1; i <= n; i++),或用 while |
E_UNSUPPORTED |
for...of(作品里没有「遍历」积木时,或写法不是 for (const [k, v] of Object.entries(x)) / for (const v of x))、do...while、switch |
改用 while、if 链;见遍历 |
E_JS_EXPR |
不支持的表达式 | 报错的 fix 里给出对应的积木写法 |
E_SLOT_TYPE |
布尔槽里放了非布尔值,数字槽里放了文字,值槽里放了 true / false,终结积木后面接了积木 |
布尔槽写比较,文字用 text("..."),值槽写 1 / 0;while (true) 后面要接语句就在循环里加 break |
E_PARSE |
不是合法的 JavaScript 语法 | 按报错位置改;repeat 回调里的 break; 写 control.break() |
E_DECL |
声明写错:重复、不在文件开头、不是 stage.variable / sprite.variable / sprite.list / broadcast(...) |
照声明表写,声明放在文件开头、frame() 外面 |
E_UNKNOWN_ARG |
命名参数里有不存在的键,或位置参数多了 | fix 里列出这块积木的输入和字段名 |
E_MISSING_ARG |
新积木缺必填的输入或字段(data.set() 没写变量) |
补上缺的参数 |
E_UNKNOWN_BLOCK |
积木不存在(拼错、扩展没装、raw(...)) |
fix 给相近的写法;缺扩展按 fix 里的 id 先装扩展(add_extension) |
E_MDT_MISSING |
写了「高级数据结构」的写法(store.set、JSON.parse、o.has("k")、size(o)……),作品里没装这个扩展;或装的线上版没有集市版才有的积木(o.add(x)、o.map(...)) |
先装扩展:线上版 moreDataTypes,集市版 test.moreDataTypes,见高级数据结构 |
E_BAD_OPTION |
菜单、字段的值不在选项里 | 用 fix 列出的选项 |
E_UNKNOWN_SCENE |
场景积木里写的场景名不存在(gandiScene.switchTo("第三关")) |
message 列出所有场景名,fix 给最接近的一个,见 场景积木 |
E_SCENE_AMBIGUOUS |
场景名同时对上多个场景 | 写完整的场景 id |
E_DYNAMIC_LIMIT |
可增减的参数组少于个数下限 | 按 message 里的范围写 |
E_VARIADIC_LIMIT |
可增减的参数组超过个数上限(写多了,或积木上的旧数据超限) | 按 message 里的上限拆成几块积木 |
E_DEGRADED_WRITE |
写入的页里还有没装扩展的积木(只读预览) | 先装 details.missingExtensions 里的扩展,重新读这一页再改 |
E_STAGE_CONTEXT |
角色所在场景的舞台没有加载,变量、广播解析不了 | 先加载那个场景 |
E_POSITION |
@at 写在嵌套的积木上 |
@at 只能写在顶层脚本前 |
E_PROC |
自制积木的定义或调用写错(模板、参数个数、返回类型) | 调用写 call["完整模板"](...) |
E_NOTE |
游离注释不是 @note(x, y, w, h) comment("...") |
照格式写;积木上的注释用 /** ... */ |
E_FRAME |
frame() 写法错(嵌套、没有脚本、在里面声明变量) |
frame("标题", () => { 脚本 }),声明放在外面 |
E_BROADCAST |
广播菜单里写了字符串 | 用声明过的广播标识符 |
E_AMBIGUOUS_VAR |
角色和全局有同名变量,或变量和列表同名 | 按 fix 声明要用的那个 |
E_HAT_PARAMS |
回调形参个数和 hat 的参数椭圆(或积木上的参数槽)对不上 | 去掉多余的形参 |
E_PARAM_SHADOWED |
里层回调体里用了外层回调的形参,而里层绑定了同一块参数积木,读到的是里层的值 | 外层的值先放进变量,见回调形参 |
E_RETURN_OUTSIDE |
return 语句写在 define 之外 |
放进定义里;停止脚本写 stop("this script") |
E_DECORATOR |
装饰器写在回调里,或后面没有语句 | 写在顶层语句或 frame() 前 |
E_TOO_DEEP |
嵌套超过上限(解析 400 层,打印 180 层) | 拆成几条语句 |
E_INTERNAL |
编译器遇到意外错误 | 报告问题,附上源文 |
警告(warnings,不阻断写入):
| 代码 | 含义 |
|---|---|
W_FOREACH_BREAK |
for...of(遍历积木)的循环体里写了 break / continue:编译模式里不起作用(解释执行有效);改法:把后面的语句放进 if。嵌套的 for...of 里的 break 只算里层那个循环 |
W_GANDI_ONLY |
用了 Gandi 专有积木(===、**、三元、break、continue),原版 Scratch 打不开导出的作品 |
W_COMMENT_DROPPED |
注释没存进积木:普通注释,或不在语句 / 表达式前面 |
W_INDEX_FROM_ONE |
字面量序号 0:Scratch 序号从 1 起,s[0]、L[0] 总是空 |
W_RETURN_OUTSIDE |
procedures.return 写在定义之外,只会停止脚本 |
W_LITERAL_CHANGED |
写进输入框的字面量读回来和写的不一样(不该发生) |
W_SCENE_REF_DANGLING |
场景积木引用的场景已被删除:保留原值,积木不执行任何操作 |
W_SCENE_RENAMED |
文本里的场景名和积木原来指向的场景(现在叫另一个名字)对不上:读完文本之后场景改过名,积木会改指到文本里名字对应的场景 |
W_VARIABLE_NOT_VISIBLE |
积木引用的变量在这里看不见(别的场景舞台上的、已删除的):沿用原来的引用,没有新建变量 |
W_STALE_CALL_IDS、W_REPORTER_LOOP_NOT_WARP、W_FRAME_LOOP_NOT_WARP、W_MENU_AS_VALUE |
自制积木调用绑定、@warp、菜单积木当值用的提示,见各自的 message |