|
11 | 11 | })(typeof self !== 'undefined' ? self : null, function () { |
12 | 12 | "use strict"; |
13 | 13 |
|
14 | | - const APP = { version: "S1.00", name: "Simple", lang: "SIMPLE" }; |
| 14 | + const APP = { version: "S1.01", name: "Simple", lang: "SIMPLE" }; |
15 | 15 | // 当前发布形态:r=标准(+py) / m=轻量(仅hic) / x=全能(+py+cpp)。 |
16 | 16 | // 导出的 HTML 会在 head 写入 window.SIMPLE_EDITION,由内建编译器宿主据此决定编译哪些语言。 |
17 | 17 | let EDITION = "x"; // 源码/网页在线版默认全能(X);离线单文件按 R/M/X 各自注入。可用 SimpleLang.setEdition() 覆盖。 |
18 | 18 | function setEdition(e) { EDITION = String(e || "").toLowerCase()[0] === "r" ? "r" : String(e || "").toLowerCase()[0] === "m" ? "m" : "x"; } |
19 | | - // S1.00 三版发布:R(标准,+py) / M(轻量,仅hic) / X(全能,+py+cpp)。 |
| 19 | + // S1.01 三版发布:R(标准,+py) / M(轻量,仅hic) / X(全能,+py+cpp)。 |
20 | 20 | // 引擎统一解析全部语言块,具体版本决定「哪些语言可被 SIMPLE 编译进 HTML」以及打包形态。 |
21 | 21 | // 块语法:html:(…)end(原样 HTML)、py:(…)end(SIMPLE 编译 Python→HTML)、cpp:(…)end(SIMPLE 编译 C++→HTML) |
22 | 22 | const BLOCK_LANG = { html: "html", py: "py", py3: "py", cpp: "cpp", cxx: "cpp" }; |
|
80 | 80 | if (FULLWIDTH_OPS[c]) { out.push({ t: FULLWIDTH_OPS[c], v: FULLWIDTH_OPS[c] }); i++; continue; } |
81 | 81 | if (c === "(") { out.push({ t: "(", v: c }); i++; continue; } |
82 | 82 | if (c === ")") { out.push({ t: ")", v: c }); i++; continue; } |
83 | | - /* ---- S1.00 扩展:列表/字典字面量 token ---- */ |
| 83 | + /* ---- S1.01 扩展:列表/字典字面量 token ---- */ |
84 | 84 | if (c === "[") { out.push({ t: "[", v: c }); i++; continue; } |
85 | 85 | if (c === "]") { out.push({ t: "]", v: c }); i++; continue; } |
86 | 86 | if (c === "{") { out.push({ t: "{", v: c }); i++; continue; } |
|
120 | 120 | const sL = String(l), sR = String(r); |
121 | 121 | if (op === "==") return numL && numR ? l === r : sL === sR; |
122 | 122 | if (op === "!=") return numL && numR ? l !== r : sL !== sR; |
123 | | - /* ---- S1.00 扩展:列表/字典 in 操作符 ---- */ |
| 123 | + /* ---- S1.01 扩展:列表/字典 in 操作符 ---- */ |
124 | 124 | if (op === "in") { |
125 | 125 | if (Array.isArray(r)) return r.indexOf(l) >= 0; |
126 | 126 | if (r && typeof r === "object") return l in r; |
|
135 | 135 | return false; |
136 | 136 | } |
137 | 137 |
|
138 | | - /* ---- S1.00 扩展:evalExpr 内置函数库 ---- */ |
| 138 | + /* ---- S1.01 扩展:evalExpr 内置函数库 ---- */ |
139 | 139 | const BUILTINS = { |
140 | 140 | len: function (x) { |
141 | 141 | if (x == null) return 0; |
|
198 | 198 | if (typeof v === "number") return v !== 0; |
199 | 199 | return String(v).length > 0; |
200 | 200 | } |
201 | | - /* ---- S1.00 扩展:primary 处理列表、字典、内置函数调用 ---- */ |
| 201 | + /* ---- S1.01 扩展:primary 处理列表、字典、内置函数调用 ---- */ |
202 | 202 | function primary() { |
203 | 203 | const t = next(); |
204 | 204 | if (!t) return ""; |
|
275 | 275 | } |
276 | 276 | return v; |
277 | 277 | } |
278 | | - /* ---- S1.00 扩展:字符串拼接(+ 操作数含字符串时用 String() 拼接)---- */ |
| 278 | + /* ---- S1.01 扩展:字符串拼接(+ 操作数含字符串时用 String() 拼接)---- */ |
279 | 279 | function addSub() { |
280 | 280 | let v = mulDiv(); |
281 | 281 | while (peek() && (peek().t === "+" || peek().t === "-")) { |
|
368 | 368 | // for 循环头:for 变量 in 迭代源: |
369 | 369 | const form = line.match(/^for\s+([A-Za-z_\u4e00-\u9fff][A-Za-z0-9_\u4e00-\u9fff]*)\s+in\s+(.+?)\s*:\s*$/i); |
370 | 370 | if (form) return { kind: "for", var: form[1], iter: form[2].trim() }; |
371 | | - /* ---- S1.00 扩展:新语句分类(while / break / continue / set / let / opset / say)---- */ |
| 371 | + /* ---- S1.01 扩展:新语句分类(while / break / continue / set / let / opset / say)---- */ |
372 | 372 | // while 条件: 循环头 |
373 | 373 | const whileM = line.match(/^while\s+(.+?)\s*:\s*$/i); |
374 | 374 | if (whileM) return { kind: "while", cond: whileM[1].replace(/:\s*$/, "").trim() }; |
375 | 375 | // break / continue |
376 | 376 | if (/^break\s*$/.test(line)) return { kind: "break" }; |
377 | 377 | if (/^continue\s*$/.test(line)) return { kind: "continue" }; |
378 | | - /* ---- S1.00 扩展:fn 定义 / fn end / call / return / raise ---- */ |
| 378 | + /* ---- S1.01 扩展:fn 定义 / fn end / call / return / raise ---- */ |
379 | 379 | const fnStart = line.match(/^fn\s+([A-Za-z_\u4e00-\u9fff][A-Za-z0-9_\u4e00-\u9fff]*)\s*\(([^)]*)\)\s*:\s*$/i); |
380 | 380 | if (fnStart) { |
381 | 381 | const params = fnStart[2].split(",").map(function (s) { return s.trim(); }).filter(Boolean); |
|
461 | 461 | for (let li = 0; li < rawLines.length; li++) { |
462 | 462 | const raw = rawLines[li]; |
463 | 463 | const mt = raw.match(/^[ \t]*/)[0]; |
464 | | - /* ---- S1.00 扩展:// 多行注释 ---- */ |
| 464 | + /* ---- S1.01 扩展:// 多行注释 ---- */ |
465 | 465 | const lt = raw.replace(/(^|[ \t])\/\/.*$/, "").replace(/(^|[ \t])#.*$/, "").trim(); |
466 | 466 | if (/^(html|py|py3|cpp|cxx)\s*:\s*\(\s*$/i.test(lt)) { |
467 | 467 | const lang = mapLang(lt.match(/^([a-z0-9]+)\s*:/i)[1]); |
|
519 | 519 | const bodyEndFor = collectUntil(i, end, indentGoal); |
520 | 520 | out.push({ kind: "for", var: st.var, iter: st.iter, body: build(i, bodyEndFor, minIndent(i, bodyEndFor)) }); |
521 | 521 | i = bodyEndFor; |
522 | | - /* ---- S1.00 扩展:while 块收集 ---- */ |
| 522 | + /* ---- S1.01 扩展:while 块收集 ---- */ |
523 | 523 | } else if (st.kind === "while") { |
524 | 524 | if (pendingIf) { out.push(pendingIf); pendingIf = null; } |
525 | 525 | i++; |
526 | 526 | const bodyEndW = collectUntil(i, end, indentGoal); |
527 | 527 | out.push({ kind: "while", cond: st.cond, body: build(i, bodyEndW, minIndent(i, bodyEndW)) }); |
528 | 528 | i = bodyEndW; |
529 | | - /* ---- S1.00 扩展:fn 块收集 ---- */ |
| 529 | + /* ---- S1.01 扩展:fn 块收集 ---- */ |
530 | 530 | } else if (st.kind === "fnStart") { |
531 | 531 | if (pendingIf) { out.push(pendingIf); pendingIf = null; } |
532 | 532 | const fnName = st.name; const fnParams = st.params; |
|
615 | 615 | collectVars(n.body, vars); |
616 | 616 | n.chains.forEach(function (c) { collectVars(c.body, vars); }); |
617 | 617 | if (n.orphan) { /* orphan body already collected */ } |
618 | | - /* ---- S1.00 扩展:fnStart 跳过 body(编译期内联时才处理)---- */ |
| 618 | + /* ---- S1.01 扩展:fnStart 跳过 body(编译期内联时才处理)---- */ |
619 | 619 | } else if (n.kind === "while") { |
620 | 620 | collectVars(n.body, vars); |
621 | 621 | } else if (n.kind === "fnStart") { |
|
719 | 719 | return 0; |
720 | 720 | } |
721 | 721 |
|
722 | | - /* ---- S1.00 扩展:函数表收集(编译期内联用)---- */ |
| 722 | + /* ---- S1.01 扩展:函数表收集(编译期内联用)---- */ |
723 | 723 | function collectFns(nodes, out) { |
724 | 724 | const o = out || {}; |
725 | 725 | // 简化:仅收集顶层 fn,不进 fn body 内部(不支持嵌套高阶函数) |
|
737 | 737 |
|
738 | 738 | function renderNodes(nodes, vars, ctx, out) { |
739 | 739 | nodes.forEach(function (n) { |
740 | | - /* ---- S1.00 扩展:break/continue/return/raise 传播 ---- */ |
| 740 | + /* ---- S1.01 扩展:break/continue/return/raise 传播 ---- */ |
741 | 741 | if (ctx && (ctx.breakFlag || ctx.continueFlag || ctx.returnFlag || ctx.raiseFlag)) return; |
742 | 742 | if (n.kind === "it") { |
743 | 743 | out.push(n); // 声明保留(供变量面板) |
|
759 | 759 | // 逐个取值渲染循环体,循环变量按普通变量注入 |
760 | 760 | const vals = iterVals(n.iter, vars); |
761 | 761 | vals.forEach(function (val) { |
762 | | - /* ---- S1.00 扩展:循环内 break/continue/return/raise 传播 ---- */ |
| 762 | + /* ---- S1.01 扩展:循环内 break/continue/return/raise 传播 ---- */ |
763 | 763 | if (ctx && (ctx.breakFlag || ctx.returnFlag || ctx.raiseFlag)) { ctx.breakFlag = false; return; } |
764 | 764 | const prev = vars[n.var]; |
765 | 765 | vars[n.var] = { type: "ordinary", value: val, isImg: false }; |
|
796 | 796 | out.push({ kind: "cppBlock", lang: "cpp", code: n.code }); |
797 | 797 | } else if (n.kind === "textline") { |
798 | 798 | out.push({ kind: "textline", text: n.text }); |
799 | | - /* ---- S1.00 扩展:break / continue / while / set / let / opset / say / fn / call / return / raise ---- */ |
| 799 | + /* ---- S1.01 扩展:break / continue / while / set / let / opset / say / fn / call / return / raise ---- */ |
800 | 800 | } else if (n.kind === "break") { |
801 | 801 | if (ctx) ctx.breakFlag = true; |
802 | 802 | return; |
|
839 | 839 | // 编译期 while 展开:条件动态求值,最多 50 次(安全上限,不是语言限制) |
840 | 840 | let safety = 0; |
841 | 841 | while (safety++ < 50) { |
842 | | - /* ---- S1.00 扩展:while 内 break/return/raise 传播 ---- */ |
| 842 | + /* ---- S1.01 扩展:while 内 break/return/raise 传播 ---- */ |
843 | 843 | if (ctx && (ctx.breakFlag || ctx.returnFlag || ctx.raiseFlag)) { ctx.breakFlag = false; break; } |
844 | 844 | let condVal = false; |
845 | 845 | try { condVal = evalExpr(n.cond, vars); } catch (e) {} |
|
899 | 899 | v.value = (f && f.dataURL) || ""; |
900 | 900 | } |
901 | 901 | }); |
902 | | - /* ---- S1.00 扩展:收集函数表并传入 renderNodes ---- */ |
| 902 | + /* ---- S1.01 扩展:收集函数表并传入 renderNodes ---- */ |
903 | 903 | const FN_TABLE = collectFns(nodes, {}); |
904 | 904 | const items = renderNodes(nodes, vars, { fnTable: FN_TABLE }, []); |
905 | 905 | return { vars, items }; |
|
953 | 953 | ".hic-ext-out{margin-top:8px;padding:12px 16px;border-radius:12px;background:rgba(217,174,107,.08);border:1px dashed rgba(217,174,107,.35);}", |
954 | 954 | ".hic-ext-state{font-size:12.5px;color:#8d7f63;}", |
955 | 955 | ".hic-ext-run{margin:0;padding-top:6px;font:13px/1.6 ui-monospace,Consolas,Menlo,monospace;color:#d9ae6b;white-space:pre-wrap;word-break:break-word;}", |
956 | | - /* ---- S1.00 扩展:raise 样式 ---- */ |
| 956 | + /* ---- S1.01 扩展:raise 样式 ---- */ |
957 | 957 | ".hic-raise{color:#c05a5a;font-weight:700;}", |
958 | 958 | "@media(max-width:700px){.hic-text{font-size:32px;}}" |
959 | 959 | ].join("\n"); |
|
1035 | 1035 | if (it.kind === "textline") { |
1036 | 1036 | return '<p class="hic-item hic-body">' + esc(it.text) + "</p>"; |
1037 | 1037 | } |
1038 | | - /* ---- S1.00 扩展:say / raise 输出 ---- */ |
| 1038 | + /* ---- S1.01 扩展:say / raise 输出 ---- */ |
1039 | 1039 | if (it.kind === "say") { |
1040 | 1040 | return '<p class="hic-item hic-body">' + esc(it.text) + "</p>"; |
1041 | 1041 | } |
|
0 commit comments