rip-lang 3.16.3 → 3.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/dist/rip.js +707 -251
- package/docs/dist/rip.min.js +191 -191
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/extensions/vscode/print/print-1.0.15.vsix +0 -0
- package/docs/extensions/vscode/print/print-latest.vsix +0 -0
- package/docs/extensions/vscode/rip/rip-latest.vsix +0 -0
- package/docs/extensions/vscode/rip/vscode-rip-0.7.1.vsix +0 -0
- package/package.json +1 -1
- package/src/compiler.js +19 -7
- package/src/dts.js +22 -15
- package/src/lexer.js +30 -1
- package/src/typecheck.js +164 -22
- package/src/types.js +463 -2
package/docs/dist/rip.js
CHANGED
|
@@ -4844,12 +4844,236 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
4844
4844
|
} catch {}
|
|
4845
4845
|
}
|
|
4846
4846
|
|
|
4847
|
+
// src/error.js
|
|
4848
|
+
class RipError extends Error {
|
|
4849
|
+
constructor(message, {
|
|
4850
|
+
code = null,
|
|
4851
|
+
file = null,
|
|
4852
|
+
line = null,
|
|
4853
|
+
column = null,
|
|
4854
|
+
length = 1,
|
|
4855
|
+
source = null,
|
|
4856
|
+
suggestion = null,
|
|
4857
|
+
phase = null
|
|
4858
|
+
} = {}) {
|
|
4859
|
+
super(message);
|
|
4860
|
+
this.name = "RipError";
|
|
4861
|
+
this.code = code;
|
|
4862
|
+
this.file = file;
|
|
4863
|
+
this.line = line;
|
|
4864
|
+
this.column = column;
|
|
4865
|
+
this.length = length;
|
|
4866
|
+
this.source = source;
|
|
4867
|
+
this.suggestion = suggestion;
|
|
4868
|
+
this.phase = phase;
|
|
4869
|
+
}
|
|
4870
|
+
static fromLexer(err, source, file) {
|
|
4871
|
+
let loc = err.location || {};
|
|
4872
|
+
return new RipError(err.message, {
|
|
4873
|
+
code: "E_SYNTAX",
|
|
4874
|
+
file,
|
|
4875
|
+
line: loc.first_line ?? null,
|
|
4876
|
+
column: loc.first_column ?? null,
|
|
4877
|
+
length: loc.last_column != null && loc.first_column != null ? loc.last_column - loc.first_column + 1 : 1,
|
|
4878
|
+
source,
|
|
4879
|
+
phase: "lexer"
|
|
4880
|
+
});
|
|
4881
|
+
}
|
|
4882
|
+
static fromParser(err, source, file) {
|
|
4883
|
+
let h = err.hash || {};
|
|
4884
|
+
let loc = h.loc || {};
|
|
4885
|
+
let line = h.line ?? loc.r ?? null;
|
|
4886
|
+
let column = loc.first_column ?? loc.c ?? null;
|
|
4887
|
+
let suggestion = null;
|
|
4888
|
+
if (h.expected?.length) {
|
|
4889
|
+
let first5 = h.expected.slice(0, 5).map((e) => e.replace(/'/g, ""));
|
|
4890
|
+
suggestion = `Expected ${first5.join(", ")}`;
|
|
4891
|
+
if (h.expected.length > 5)
|
|
4892
|
+
suggestion += `, ... (${h.expected.length} total)`;
|
|
4893
|
+
}
|
|
4894
|
+
let token = h.token || "token";
|
|
4895
|
+
let expectedSet = new Set((h.expected || []).map((e) => e.replace(/'/g, "")));
|
|
4896
|
+
let TERNARY_ENDERS = new Set([
|
|
4897
|
+
"TERMINATOR",
|
|
4898
|
+
",",
|
|
4899
|
+
")",
|
|
4900
|
+
"]",
|
|
4901
|
+
"OUTDENT",
|
|
4902
|
+
"CALL_END",
|
|
4903
|
+
"INDEX_END",
|
|
4904
|
+
"PARAM_END",
|
|
4905
|
+
"EOF"
|
|
4906
|
+
]);
|
|
4907
|
+
if (expectedSet.has(":") && (expectedSet.has("POST_IF") || expectedSet.has("POST_UNLESS") || expectedSet.has("FOR") || expectedSet.has("WHILE")) && TERNARY_ENDERS.has(token)) {
|
|
4908
|
+
suggestion = "Binary `x ? y` was removed — use `x ?? y` for nullish coalescing, or a full ternary `x ? y : z`";
|
|
4909
|
+
}
|
|
4910
|
+
let near = h.text ? ` near '${h.text}'` : "";
|
|
4911
|
+
let message = `Unexpected ${token}${near}`;
|
|
4912
|
+
return new RipError(message, {
|
|
4913
|
+
code: "E_PARSE",
|
|
4914
|
+
file,
|
|
4915
|
+
line,
|
|
4916
|
+
column,
|
|
4917
|
+
length: h.text?.length || 1,
|
|
4918
|
+
source,
|
|
4919
|
+
suggestion,
|
|
4920
|
+
phase: "parser"
|
|
4921
|
+
});
|
|
4922
|
+
}
|
|
4923
|
+
static fromSExpr(message, sexpr, source, file, suggestion) {
|
|
4924
|
+
let loc = sexpr?.loc || {};
|
|
4925
|
+
return new RipError(message, {
|
|
4926
|
+
code: "E_CODEGEN",
|
|
4927
|
+
file,
|
|
4928
|
+
line: loc.r ?? null,
|
|
4929
|
+
column: loc.c ?? null,
|
|
4930
|
+
length: loc.n ?? 1,
|
|
4931
|
+
source,
|
|
4932
|
+
suggestion,
|
|
4933
|
+
phase: "codegen"
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
get locationString() {
|
|
4937
|
+
let parts = [];
|
|
4938
|
+
if (this.file)
|
|
4939
|
+
parts.push(this.file);
|
|
4940
|
+
if (this.line != null) {
|
|
4941
|
+
parts.push(`${this.line + 1}:${(this.column ?? 0) + 1}`);
|
|
4942
|
+
}
|
|
4943
|
+
return parts.join(":");
|
|
4944
|
+
}
|
|
4945
|
+
format({ color = true } = {}) {
|
|
4946
|
+
let c = color ? {
|
|
4947
|
+
red: "\x1B[31m",
|
|
4948
|
+
yellow: "\x1B[33m",
|
|
4949
|
+
cyan: "\x1B[36m",
|
|
4950
|
+
dim: "\x1B[2m",
|
|
4951
|
+
bold: "\x1B[1m",
|
|
4952
|
+
reset: "\x1B[0m"
|
|
4953
|
+
} : { red: "", yellow: "", cyan: "", dim: "", bold: "", reset: "" };
|
|
4954
|
+
let lines = [];
|
|
4955
|
+
let loc = this.locationString;
|
|
4956
|
+
let header = loc ? `${c.cyan}${loc}${c.reset} ` : "";
|
|
4957
|
+
lines.push(`${header}${c.red}${c.bold}error${c.reset}${c.bold}: ${this.message}${c.reset}`);
|
|
4958
|
+
let snippet = this._snippet();
|
|
4959
|
+
if (snippet) {
|
|
4960
|
+
lines.push("");
|
|
4961
|
+
for (let s of snippet) {
|
|
4962
|
+
if (s.type === "source") {
|
|
4963
|
+
lines.push(`${c.dim}${s.gutter}${c.reset}${s.text}`);
|
|
4964
|
+
} else if (s.type === "caret") {
|
|
4965
|
+
lines.push(`${c.dim}${s.gutter}${c.reset}${c.red}${c.bold}${s.text}${c.reset}`);
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
if (this.suggestion) {
|
|
4970
|
+
lines.push("");
|
|
4971
|
+
lines.push(`${c.yellow}hint${c.reset}: ${this.suggestion}`);
|
|
4972
|
+
}
|
|
4973
|
+
return lines.join(`
|
|
4974
|
+
`);
|
|
4975
|
+
}
|
|
4976
|
+
formatHTML() {
|
|
4977
|
+
let lines = [];
|
|
4978
|
+
lines.push('<div class="rip-error">');
|
|
4979
|
+
lines.push("<style>");
|
|
4980
|
+
lines.push(`.rip-error { font-family: ui-monospace, "SF Mono", Menlo, Monaco, monospace; font-size: 13px; line-height: 1.5; padding: 16px 20px; background: #1e1e2e; color: #cdd6f4; border-radius: 8px; overflow-x: auto; }`);
|
|
4981
|
+
lines.push(`.rip-error .re-header { color: #f38ba8; font-weight: 600; }`);
|
|
4982
|
+
lines.push(`.rip-error .re-loc { color: #89b4fa; }`);
|
|
4983
|
+
lines.push(`.rip-error .re-gutter { color: #585b70; user-select: none; }`);
|
|
4984
|
+
lines.push(`.rip-error .re-caret { color: #f38ba8; font-weight: 700; }`);
|
|
4985
|
+
lines.push(`.rip-error .re-hint { color: #f9e2af; }`);
|
|
4986
|
+
lines.push(`.rip-error .re-snippet { margin: 8px 0; }`);
|
|
4987
|
+
lines.push("</style>");
|
|
4988
|
+
let loc = this.locationString;
|
|
4989
|
+
let locSpan = loc ? `<span class="re-loc">${esc(loc)}</span> ` : "";
|
|
4990
|
+
lines.push(`<div class="re-header">${locSpan}error: ${esc(this.message)}</div>`);
|
|
4991
|
+
let snippet = this._snippet();
|
|
4992
|
+
if (snippet) {
|
|
4993
|
+
lines.push('<pre class="re-snippet">');
|
|
4994
|
+
for (let s of snippet) {
|
|
4995
|
+
if (s.type === "source") {
|
|
4996
|
+
lines.push(`<span class="re-gutter">${esc(s.gutter)}</span>${esc(s.text)}`);
|
|
4997
|
+
} else if (s.type === "caret") {
|
|
4998
|
+
lines.push(`<span class="re-gutter">${esc(s.gutter)}</span><span class="re-caret">${esc(s.text)}</span>`);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
lines.push("</pre>");
|
|
5002
|
+
}
|
|
5003
|
+
if (this.suggestion) {
|
|
5004
|
+
lines.push(`<div class="re-hint">hint: ${esc(this.suggestion)}</div>`);
|
|
5005
|
+
}
|
|
5006
|
+
lines.push("</div>");
|
|
5007
|
+
return lines.join(`
|
|
5008
|
+
`);
|
|
5009
|
+
}
|
|
5010
|
+
_snippet() {
|
|
5011
|
+
if (this.source == null || this.line == null)
|
|
5012
|
+
return null;
|
|
5013
|
+
let sourceLines = this.source.split(`
|
|
5014
|
+
`);
|
|
5015
|
+
let errLine = this.line;
|
|
5016
|
+
if (errLine < 0 || errLine >= sourceLines.length)
|
|
5017
|
+
return null;
|
|
5018
|
+
let contextRadius = 2;
|
|
5019
|
+
let start = Math.max(0, errLine - contextRadius);
|
|
5020
|
+
let end = Math.min(sourceLines.length - 1, errLine + contextRadius);
|
|
5021
|
+
let gutterWidth = String(end + 1).length;
|
|
5022
|
+
let result = [];
|
|
5023
|
+
for (let i = start;i <= end; i++) {
|
|
5024
|
+
let lineNum = String(i + 1).padStart(gutterWidth);
|
|
5025
|
+
let gutter = ` ${lineNum} │ `;
|
|
5026
|
+
result.push({ type: "source", gutter, text: sourceLines[i] });
|
|
5027
|
+
if (i === errLine && this.column != null) {
|
|
5028
|
+
let pad = " ".repeat(this.column);
|
|
5029
|
+
let caretLen = Math.max(1, Math.min(this.length || 1, sourceLines[i].length - this.column));
|
|
5030
|
+
let carets = "^".repeat(caretLen);
|
|
5031
|
+
let emptyGutter = " ".repeat(gutterWidth + 2) + "│ ";
|
|
5032
|
+
result.push({ type: "caret", gutter: emptyGutter, text: `${pad}${carets}` });
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return result;
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
function isLexerError(err) {
|
|
5039
|
+
return err instanceof SyntaxError && err.location != null;
|
|
5040
|
+
}
|
|
5041
|
+
function isParserError(err) {
|
|
5042
|
+
return !(err instanceof SyntaxError) && err.hash != null;
|
|
5043
|
+
}
|
|
5044
|
+
function toRipError(err, source, file) {
|
|
5045
|
+
if (err instanceof RipError) {
|
|
5046
|
+
if (file && !err.file)
|
|
5047
|
+
err.file = file;
|
|
5048
|
+
if (source && !err.source)
|
|
5049
|
+
err.source = source;
|
|
5050
|
+
return err;
|
|
5051
|
+
}
|
|
5052
|
+
if (isLexerError(err))
|
|
5053
|
+
return RipError.fromLexer(err, source, file);
|
|
5054
|
+
if (isParserError(err))
|
|
5055
|
+
return RipError.fromParser(err, source, file);
|
|
5056
|
+
return new RipError(err.message, { file, source, phase: "unknown" });
|
|
5057
|
+
}
|
|
5058
|
+
function formatError(err, { source, file, color = true } = {}) {
|
|
5059
|
+
let re = err instanceof RipError ? err : toRipError(err, source, file);
|
|
5060
|
+
return re.format({ color });
|
|
5061
|
+
}
|
|
5062
|
+
function formatErrorHTML(err, { source, file } = {}) {
|
|
5063
|
+
let re = err instanceof RipError ? err : toRipError(err, source, file);
|
|
5064
|
+
return re.formatHTML();
|
|
5065
|
+
}
|
|
5066
|
+
function esc(s) {
|
|
5067
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5068
|
+
}
|
|
5069
|
+
|
|
4847
5070
|
// src/types.js
|
|
4848
5071
|
function installTypeSupport(Lexer) {
|
|
4849
5072
|
let proto = Lexer.prototype;
|
|
4850
5073
|
proto.rewriteTypes = function() {
|
|
4851
5074
|
let tokens = this.tokens;
|
|
4852
5075
|
let typeRefNames = this.typeRefNames = new Set;
|
|
5076
|
+
reclassifyColonTypes(tokens);
|
|
4853
5077
|
let gen = (tag, val, origin) => {
|
|
4854
5078
|
let t = [tag, val];
|
|
4855
5079
|
t.pre = 0;
|
|
@@ -4898,7 +5122,19 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
4898
5122
|
let prevToken = tokens2[i - 1];
|
|
4899
5123
|
if (!prevToken)
|
|
4900
5124
|
return 1;
|
|
4901
|
-
let
|
|
5125
|
+
let isArrowReturn = prevToken[0] === "PARAM_END";
|
|
5126
|
+
let typeTokens = collectTypeExpression(tokens2, i + 1, { stopAtFatArrow: isArrowReturn });
|
|
5127
|
+
if (isArrowReturn && looksLikeBareFunctionType(typeTokens)) {
|
|
5128
|
+
let loc = tokens2[i + 1]?.loc;
|
|
5129
|
+
throw new RipError("A function-type return on an arrow must be parenthesized", {
|
|
5130
|
+
code: "E_SYNTAX",
|
|
5131
|
+
phase: "lexer",
|
|
5132
|
+
line: loc?.r ?? null,
|
|
5133
|
+
column: loc?.c ?? null,
|
|
5134
|
+
length: loc?.n ?? 1,
|
|
5135
|
+
suggestion: "wrap the whole function type in parens — " + "`(x):: ((a: T) => R) => body`, not `(x):: (a: T) => R => body`"
|
|
5136
|
+
});
|
|
5137
|
+
}
|
|
4902
5138
|
let typeStr = buildTypeString(typeTokens);
|
|
4903
5139
|
let target = prevToken;
|
|
4904
5140
|
let propName = "type";
|
|
@@ -5064,26 +5300,444 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
5064
5300
|
}
|
|
5065
5301
|
}
|
|
5066
5302
|
}
|
|
5067
|
-
if (!hasTypes)
|
|
5303
|
+
if (!hasTypes)
|
|
5304
|
+
continue;
|
|
5305
|
+
let overloadTokens = tokens.slice(i, j + 1);
|
|
5306
|
+
let exported = i >= 1 && tokens[i - 1]?.[0] === "EXPORT";
|
|
5307
|
+
let spliceFrom = exported ? i - 1 : i;
|
|
5308
|
+
let spliceCount = j + 1 - spliceFrom;
|
|
5309
|
+
let marker = gen("TYPE_DECL", nameToken[1], nameToken);
|
|
5310
|
+
marker.data = {
|
|
5311
|
+
name: nameToken[1],
|
|
5312
|
+
kind: "overload",
|
|
5313
|
+
overloadTokens,
|
|
5314
|
+
exported
|
|
5315
|
+
};
|
|
5316
|
+
if (nameToken.data?.typeParams)
|
|
5317
|
+
marker.data.typeParams = nameToken.data.typeParams;
|
|
5318
|
+
tokens.splice(spliceFrom, spliceCount, marker);
|
|
5319
|
+
}
|
|
5320
|
+
};
|
|
5321
|
+
}
|
|
5322
|
+
function looksLikeBareFunctionType(typeTokens) {
|
|
5323
|
+
const isOpen = (t) => t === "(" || t === "PARAM_START" || t === "CALL_START";
|
|
5324
|
+
const isClose = (t) => t === ")" || t === "PARAM_END" || t === "CALL_END";
|
|
5325
|
+
if (typeTokens.length < 2 || !isOpen(typeTokens[0][0]))
|
|
5326
|
+
return false;
|
|
5327
|
+
let depth = 0;
|
|
5328
|
+
for (let k = 0;k < typeTokens.length; k++) {
|
|
5329
|
+
const tag = typeTokens[k][0];
|
|
5330
|
+
if (isOpen(tag))
|
|
5331
|
+
depth++;
|
|
5332
|
+
else if (isClose(tag)) {
|
|
5333
|
+
if (--depth === 0 && k !== typeTokens.length - 1)
|
|
5334
|
+
return false;
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
if (depth !== 0)
|
|
5338
|
+
return false;
|
|
5339
|
+
if (typeTokens.length === 2)
|
|
5340
|
+
return true;
|
|
5341
|
+
let d = 0, pendingTernary = false;
|
|
5342
|
+
for (const t of typeTokens) {
|
|
5343
|
+
const tag = t[0];
|
|
5344
|
+
if (isOpen(tag) || tag === "[" || tag === "{" || tag === "INDEX_START")
|
|
5345
|
+
d++;
|
|
5346
|
+
else if (isClose(tag) || tag === "]" || tag === "}" || tag === "INDEX_END")
|
|
5347
|
+
d--;
|
|
5348
|
+
else if (d === 1 && tag === "TERNARY")
|
|
5349
|
+
pendingTernary = true;
|
|
5350
|
+
else if (d === 1 && tag === ":") {
|
|
5351
|
+
if (pendingTernary)
|
|
5352
|
+
pendingTernary = false;
|
|
5353
|
+
else
|
|
5354
|
+
return true;
|
|
5355
|
+
}
|
|
5356
|
+
}
|
|
5357
|
+
return false;
|
|
5358
|
+
}
|
|
5359
|
+
function isCompleteTypeExpr(tokens, a, b) {
|
|
5360
|
+
if (b <= a)
|
|
5361
|
+
return false;
|
|
5362
|
+
const SEP = new Set(["|", "&", ",", ":", "?", ".", "...", "=>"]);
|
|
5363
|
+
let par = 0, brk = 0, brc = 0, gen = 0, atomEnd = false;
|
|
5364
|
+
for (let j = a;j < b; j++) {
|
|
5365
|
+
const t = tokens[j][0], v = tokens[j][1];
|
|
5366
|
+
if (t === "(" || t === "PARAM_START") {
|
|
5367
|
+
par++;
|
|
5368
|
+
atomEnd = false;
|
|
5369
|
+
continue;
|
|
5370
|
+
}
|
|
5371
|
+
if (t === ")" || t === "PARAM_END") {
|
|
5372
|
+
if (--par < 0)
|
|
5373
|
+
return false;
|
|
5374
|
+
atomEnd = true;
|
|
5375
|
+
continue;
|
|
5376
|
+
}
|
|
5377
|
+
if (t === "[" || t === "INDEX_START") {
|
|
5378
|
+
brk++;
|
|
5379
|
+
atomEnd = false;
|
|
5380
|
+
continue;
|
|
5381
|
+
}
|
|
5382
|
+
if (t === "]" || t === "INDEX_END") {
|
|
5383
|
+
if (--brk < 0)
|
|
5384
|
+
return false;
|
|
5385
|
+
atomEnd = true;
|
|
5386
|
+
continue;
|
|
5387
|
+
}
|
|
5388
|
+
if (t === "{") {
|
|
5389
|
+
brc++;
|
|
5390
|
+
atomEnd = false;
|
|
5391
|
+
continue;
|
|
5392
|
+
}
|
|
5393
|
+
if (t === "}") {
|
|
5394
|
+
if (--brc < 0)
|
|
5395
|
+
return false;
|
|
5396
|
+
atomEnd = true;
|
|
5397
|
+
continue;
|
|
5398
|
+
}
|
|
5399
|
+
if (t === "COMPARE") {
|
|
5400
|
+
if (v === "<") {
|
|
5401
|
+
gen++;
|
|
5402
|
+
atomEnd = false;
|
|
5403
|
+
continue;
|
|
5404
|
+
}
|
|
5405
|
+
if (v === ">") {
|
|
5406
|
+
if (gen <= 0)
|
|
5407
|
+
return false;
|
|
5408
|
+
gen--;
|
|
5409
|
+
atomEnd = true;
|
|
5410
|
+
continue;
|
|
5411
|
+
}
|
|
5412
|
+
return false;
|
|
5413
|
+
}
|
|
5414
|
+
if (t === "SHIFT") {
|
|
5415
|
+
if (v === ">>") {
|
|
5416
|
+
if (gen < 2)
|
|
5417
|
+
return false;
|
|
5418
|
+
gen -= 2;
|
|
5419
|
+
atomEnd = true;
|
|
5420
|
+
continue;
|
|
5421
|
+
}
|
|
5422
|
+
return false;
|
|
5423
|
+
}
|
|
5424
|
+
if (t === "=") {
|
|
5425
|
+
if (gen > 0) {
|
|
5426
|
+
atomEnd = false;
|
|
5427
|
+
continue;
|
|
5428
|
+
}
|
|
5429
|
+
return false;
|
|
5430
|
+
}
|
|
5431
|
+
if (SEP.has(t)) {
|
|
5432
|
+
atomEnd = false;
|
|
5433
|
+
continue;
|
|
5434
|
+
}
|
|
5435
|
+
if (t === "IDENTIFIER" || t === "PROPERTY" || t === "NUMBER" || t === "STRING" || t === "NULL" || t === "UNDEFINED" || t === "BOOL") {
|
|
5436
|
+
if (atomEnd)
|
|
5437
|
+
return false;
|
|
5438
|
+
atomEnd = true;
|
|
5439
|
+
continue;
|
|
5440
|
+
}
|
|
5441
|
+
return false;
|
|
5442
|
+
}
|
|
5443
|
+
return par === 0 && brk === 0 && brc === 0 && gen === 0 && atomEnd;
|
|
5444
|
+
}
|
|
5445
|
+
function assignedLaterInBlock(tokens, start, name) {
|
|
5446
|
+
const ASSIGN = new Set(["=", "REACTIVE_ASSIGN", "COMPUTED_ASSIGN", "READONLY_ASSIGN"]);
|
|
5447
|
+
let indent = 0, bracket = 0, closureDepth = 0;
|
|
5448
|
+
const closureAt = [];
|
|
5449
|
+
for (let j = start;j < tokens.length; j++) {
|
|
5450
|
+
const g = tokens[j][0];
|
|
5451
|
+
if (g === "INDENT") {
|
|
5452
|
+
indent++;
|
|
5453
|
+
const p = tokens[j - 1]?.[0];
|
|
5454
|
+
if (p === "->" || p === "=>") {
|
|
5455
|
+
closureAt.push(indent);
|
|
5456
|
+
closureDepth++;
|
|
5457
|
+
}
|
|
5458
|
+
continue;
|
|
5459
|
+
}
|
|
5460
|
+
if (g === "OUTDENT") {
|
|
5461
|
+
if (indent === 0)
|
|
5462
|
+
return false;
|
|
5463
|
+
if (closureAt[closureAt.length - 1] === indent) {
|
|
5464
|
+
closureAt.pop();
|
|
5465
|
+
closureDepth--;
|
|
5466
|
+
}
|
|
5467
|
+
indent--;
|
|
5468
|
+
continue;
|
|
5469
|
+
}
|
|
5470
|
+
if (g === "(" || g === "CALL_START" || g === "PARAM_START" || g === "[" || g === "INDEX_START" || g === "{") {
|
|
5471
|
+
bracket++;
|
|
5472
|
+
continue;
|
|
5473
|
+
}
|
|
5474
|
+
if (g === ")" || g === "CALL_END" || g === "PARAM_END" || g === "]" || g === "INDEX_END" || g === "}") {
|
|
5475
|
+
bracket--;
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
if (closureDepth === 0 && bracket === 0 && (g === "IDENTIFIER" || g === "PROPERTY") && tokens[j][1] === name && ASSIGN.has(tokens[j + 1]?.[0]))
|
|
5479
|
+
return true;
|
|
5480
|
+
}
|
|
5481
|
+
return false;
|
|
5482
|
+
}
|
|
5483
|
+
function reclassifyColonTypes(tokens) {
|
|
5484
|
+
const isOpen = (t) => t === "(" || t === "CALL_START" || t === "PARAM_START" || t === "{" || t === "[" || t === "INDEX_START";
|
|
5485
|
+
const isClose = (t) => t === ")" || t === "CALL_END" || t === "PARAM_END" || t === "}" || t === "]" || t === "INDEX_END";
|
|
5486
|
+
const isDefParamStart = (i) => {
|
|
5487
|
+
let j = i - 1;
|
|
5488
|
+
const g0 = tokens[j]?.[0], v0 = tokens[j]?.[1];
|
|
5489
|
+
if (g0 === "COMPARE" && v0 === ">" || g0 === "SHIFT" && v0 === ">>") {
|
|
5490
|
+
let depth = g0 === "SHIFT" ? 2 : 1;
|
|
5491
|
+
j--;
|
|
5492
|
+
while (j >= 0 && depth > 0) {
|
|
5493
|
+
const g = tokens[j][0], v = tokens[j][1];
|
|
5494
|
+
if (g === "COMPARE" && v === ">")
|
|
5495
|
+
depth++;
|
|
5496
|
+
else if (g === "SHIFT" && v === ">>")
|
|
5497
|
+
depth += 2;
|
|
5498
|
+
else if (g === "COMPARE" && v === "<")
|
|
5499
|
+
depth--;
|
|
5500
|
+
else if (g === "SHIFT" && v === "<<")
|
|
5501
|
+
depth -= 2;
|
|
5502
|
+
j--;
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5505
|
+
if (tokens[j]?.[0] !== "IDENTIFIER" && tokens[j]?.[0] !== "PROPERTY")
|
|
5506
|
+
return false;
|
|
5507
|
+
return tokens[j - 1]?.[0] === "DEF";
|
|
5508
|
+
};
|
|
5509
|
+
const STMT_START = new Set(["TERMINATOR", "INDENT", "OUTDENT", "EXPORT"]);
|
|
5510
|
+
const BINDING_OPS = new Set(["=", "REACTIVE_ASSIGN", "COMPUTED_ASSIGN", "READONLY_ASSIGN"]);
|
|
5511
|
+
const atStatementStart = (t) => !t || STMT_START.has(t[0]);
|
|
5512
|
+
const declBindsBeforeArrow = (start) => {
|
|
5513
|
+
let depth = 0;
|
|
5514
|
+
for (let j = start;j < tokens.length; j++) {
|
|
5515
|
+
const g = tokens[j][0];
|
|
5516
|
+
if (isOpen(g))
|
|
5517
|
+
depth++;
|
|
5518
|
+
else if (isClose(g))
|
|
5519
|
+
depth--;
|
|
5520
|
+
else if (depth === 0) {
|
|
5521
|
+
if (g === "->" || g === "=>")
|
|
5522
|
+
return false;
|
|
5523
|
+
if (BINDING_OPS.has(g))
|
|
5524
|
+
return true;
|
|
5525
|
+
if ((g === "EFFECT" || g === "GATE") && j > start)
|
|
5526
|
+
return true;
|
|
5527
|
+
if (g === "TERMINATOR" || g === "INDENT" || g === "OUTDENT")
|
|
5528
|
+
return false;
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
return false;
|
|
5532
|
+
};
|
|
5533
|
+
const valueIsMethod = (start) => {
|
|
5534
|
+
let depth = 0;
|
|
5535
|
+
for (let j = start;j < tokens.length; j++) {
|
|
5536
|
+
const g = tokens[j][0];
|
|
5537
|
+
if (isOpen(g))
|
|
5538
|
+
depth++;
|
|
5539
|
+
else if (isClose(g))
|
|
5540
|
+
depth--;
|
|
5541
|
+
else if (depth === 0) {
|
|
5542
|
+
if (g === "->" || g === "=>")
|
|
5543
|
+
return true;
|
|
5544
|
+
if (g === "TERMINATOR" || g === "INDENT" || g === "OUTDENT")
|
|
5545
|
+
return false;
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
return false;
|
|
5549
|
+
};
|
|
5550
|
+
let pendingBody = false;
|
|
5551
|
+
const indentStack = [];
|
|
5552
|
+
const inTypedBody = () => indentStack.length > 0 && indentStack[indentStack.length - 1];
|
|
5553
|
+
const nameAtStatementStart = (i) => {
|
|
5554
|
+
const p = tokens[i - 1]?.[0];
|
|
5555
|
+
if (p !== "PROPERTY" && p !== "IDENTIFIER")
|
|
5556
|
+
return false;
|
|
5557
|
+
if (tokens[i - 2]?.[0] === "@")
|
|
5558
|
+
return atStatementStart(tokens[i - 3]);
|
|
5559
|
+
return atStatementStart(tokens[i - 2]);
|
|
5560
|
+
};
|
|
5561
|
+
let inType = false, typeStartDepth = 0;
|
|
5562
|
+
const enterType = () => {
|
|
5563
|
+
inType = true;
|
|
5564
|
+
typeStartDepth = stack.length;
|
|
5565
|
+
};
|
|
5566
|
+
let prevSiblingKV = false, curLineKV = false;
|
|
5567
|
+
const stack = [];
|
|
5568
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
5569
|
+
const tag = tokens[i][0];
|
|
5570
|
+
if (tag === "CLASS" || tag === "COMPONENT") {
|
|
5571
|
+
pendingBody = true;
|
|
5572
|
+
continue;
|
|
5573
|
+
}
|
|
5574
|
+
if (tag === "INDENT") {
|
|
5575
|
+
indentStack.push(pendingBody);
|
|
5576
|
+
pendingBody = false;
|
|
5577
|
+
prevSiblingKV = curLineKV = false;
|
|
5578
|
+
if (inType && stack.length <= typeStartDepth)
|
|
5579
|
+
inType = false;
|
|
5580
|
+
continue;
|
|
5581
|
+
}
|
|
5582
|
+
if (tag === "OUTDENT") {
|
|
5583
|
+
indentStack.pop();
|
|
5584
|
+
prevSiblingKV = curLineKV = false;
|
|
5585
|
+
if (inType && stack.length <= typeStartDepth)
|
|
5586
|
+
inType = false;
|
|
5587
|
+
continue;
|
|
5588
|
+
}
|
|
5589
|
+
if (isOpen(tag)) {
|
|
5590
|
+
let kind = "other";
|
|
5591
|
+
if (!inType) {
|
|
5592
|
+
if (tag === "PARAM_START")
|
|
5593
|
+
kind = "param";
|
|
5594
|
+
else if ((tag === "CALL_START" || tag === "(") && isDefParamStart(i))
|
|
5595
|
+
kind = "defparam";
|
|
5596
|
+
}
|
|
5597
|
+
stack.push({ kind, sawEq: false, sawType: false });
|
|
5598
|
+
continue;
|
|
5599
|
+
}
|
|
5600
|
+
if (isClose(tag)) {
|
|
5601
|
+
const f2 = stack.pop();
|
|
5602
|
+
if (f2?.kind === "defparam") {
|
|
5603
|
+
(tokens[i].data ??= {}).isDefParamEnd = true;
|
|
5604
|
+
}
|
|
5605
|
+
if (inType && stack.length < typeStartDepth)
|
|
5606
|
+
inType = false;
|
|
5607
|
+
continue;
|
|
5608
|
+
}
|
|
5609
|
+
if (tag === "TYPE_ANNOTATION") {
|
|
5610
|
+
if (!inType)
|
|
5611
|
+
enterType();
|
|
5612
|
+
continue;
|
|
5613
|
+
}
|
|
5614
|
+
if (inType) {
|
|
5615
|
+
if (stack.length <= typeStartDepth && (tag === "=" || tag === "," || tag === "TERMINATOR" || tag === "->" || BINDING_OPS.has(tag))) {
|
|
5616
|
+
inType = false;
|
|
5617
|
+
} else {
|
|
5618
|
+
continue;
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
if (tag === "TERMINATOR" && stack.length === 0) {
|
|
5622
|
+
prevSiblingKV = curLineKV;
|
|
5623
|
+
curLineKV = false;
|
|
5624
|
+
}
|
|
5625
|
+
if (tag === ":") {
|
|
5626
|
+
const prev = tokens[i - 1];
|
|
5627
|
+
const prevTag = prev?.[0];
|
|
5628
|
+
if (stack.length === 0 && (prevTag === "IDENTIFIER" || prevTag === "PROPERTY") && atStatementStart(tokens[i - 2]))
|
|
5629
|
+
curLineKV = true;
|
|
5630
|
+
if (prevTag === "PARAM_END" || (prevTag === ")" || prevTag === "CALL_END") && prev.data?.isDefParamEnd) {
|
|
5631
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5632
|
+
enterType();
|
|
5633
|
+
continue;
|
|
5634
|
+
}
|
|
5635
|
+
if ((prevTag === "IDENTIFIER" || prevTag === "PROPERTY") && tokens[i - 2]?.[0] === "DEF") {
|
|
5636
|
+
if (prevTag === "PROPERTY")
|
|
5637
|
+
prev[0] = "IDENTIFIER";
|
|
5638
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5639
|
+
enterType();
|
|
5640
|
+
continue;
|
|
5641
|
+
}
|
|
5642
|
+
if (stack.length === 0 && nameAtStatementStart(i) && declBindsBeforeArrow(i + 1)) {
|
|
5643
|
+
if (prevTag === "PROPERTY" && tokens[i - 2]?.[0] !== "@")
|
|
5644
|
+
prev[0] = "IDENTIFIER";
|
|
5645
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5646
|
+
enterType();
|
|
5647
|
+
continue;
|
|
5648
|
+
}
|
|
5649
|
+
if (stack.length === 0 && nameAtStatementStart(i)) {
|
|
5650
|
+
let depth = 0;
|
|
5651
|
+
for (let j = i + 1;j < tokens.length; j++) {
|
|
5652
|
+
const g = tokens[j][0];
|
|
5653
|
+
if (isOpen(g))
|
|
5654
|
+
depth++;
|
|
5655
|
+
else if (isClose(g)) {
|
|
5656
|
+
if (depth === 0)
|
|
5657
|
+
break;
|
|
5658
|
+
depth--;
|
|
5659
|
+
} else if (depth === 0) {
|
|
5660
|
+
if (g === "TERMINATOR" || g === "INDENT" || g === "OUTDENT")
|
|
5661
|
+
break;
|
|
5662
|
+
if (g === "=" && isCompleteTypeExpr(tokens, i + 1, j)) {
|
|
5663
|
+
if (prevTag === "PROPERTY" && tokens[i - 2]?.[0] !== "@")
|
|
5664
|
+
prev[0] = "IDENTIFIER";
|
|
5665
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5666
|
+
enterType();
|
|
5667
|
+
break;
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
if (tokens[i][0] === "TYPE_ANNOTATION")
|
|
5672
|
+
continue;
|
|
5673
|
+
}
|
|
5674
|
+
if (inTypedBody() && stack.length === 0 && nameAtStatementStart(i) && !valueIsMethod(i + 1)) {
|
|
5675
|
+
if (prevTag === "PROPERTY" && tokens[i - 2]?.[0] !== "@")
|
|
5676
|
+
prev[0] = "IDENTIFIER";
|
|
5677
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5678
|
+
enterType();
|
|
5679
|
+
continue;
|
|
5680
|
+
}
|
|
5681
|
+
if (stack.length === 0 && nameAtStatementStart(i) && tokens[i - 2]?.[0] !== "@") {
|
|
5682
|
+
let depth = 0, end = -1;
|
|
5683
|
+
for (let j = i + 1;j < tokens.length; j++) {
|
|
5684
|
+
const g = tokens[j][0];
|
|
5685
|
+
if (isOpen(g))
|
|
5686
|
+
depth++;
|
|
5687
|
+
else if (isClose(g)) {
|
|
5688
|
+
if (depth === 0)
|
|
5689
|
+
break;
|
|
5690
|
+
depth--;
|
|
5691
|
+
} else if (depth === 0) {
|
|
5692
|
+
if (g === "TERMINATOR") {
|
|
5693
|
+
end = j;
|
|
5694
|
+
break;
|
|
5695
|
+
}
|
|
5696
|
+
if (g === "INDENT" || g === "OUTDENT" || g === "=" || BINDING_OPS.has(g))
|
|
5697
|
+
break;
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
const nk = tokens[end + 1];
|
|
5701
|
+
const nextKV = nk && (nk[0] === "IDENTIFIER" || nk[0] === "PROPERTY") && tokens[end + 2]?.[0] === ":";
|
|
5702
|
+
if (end > i + 1 && nk && nk[0] !== "OUTDENT" && !prevSiblingKV && !nextKV && isCompleteTypeExpr(tokens, i + 1, end) && assignedLaterInBlock(tokens, end + 1, prev[1])) {
|
|
5703
|
+
if (prevTag === "PROPERTY")
|
|
5704
|
+
prev[0] = "IDENTIFIER";
|
|
5705
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5706
|
+
enterType();
|
|
5707
|
+
continue;
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
const f = stack[stack.length - 1];
|
|
5712
|
+
if (f && (f.kind === "param" || f.kind === "defparam")) {
|
|
5713
|
+
if (tag === ",") {
|
|
5714
|
+
f.sawEq = false;
|
|
5715
|
+
f.sawType = false;
|
|
5068
5716
|
continue;
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5717
|
+
}
|
|
5718
|
+
if (tag === "=") {
|
|
5719
|
+
f.sawEq = true;
|
|
5720
|
+
continue;
|
|
5721
|
+
}
|
|
5722
|
+
if (tag === ":" && !f.sawEq && !f.sawType) {
|
|
5723
|
+
const prev = tokens[i - 1];
|
|
5724
|
+
const prevTag = prev?.[0];
|
|
5725
|
+
if (prevTag === "PROPERTY" || prevTag === "IDENTIFIER") {
|
|
5726
|
+
if (prevTag === "PROPERTY" && tokens[i - 2]?.[0] !== "@")
|
|
5727
|
+
prev[0] = "IDENTIFIER";
|
|
5728
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5729
|
+
f.sawType = true;
|
|
5730
|
+
enterType();
|
|
5731
|
+
} else if (prevTag === "}" || prevTag === "]" || prevTag === "INDEX_END") {
|
|
5732
|
+
tokens[i][0] = "TYPE_ANNOTATION";
|
|
5733
|
+
f.sawType = true;
|
|
5734
|
+
enterType();
|
|
5735
|
+
}
|
|
5736
|
+
}
|
|
5083
5737
|
}
|
|
5084
|
-
}
|
|
5738
|
+
}
|
|
5085
5739
|
}
|
|
5086
|
-
function collectTypeExpression(tokens, j) {
|
|
5740
|
+
function collectTypeExpression(tokens, j, opts = {}) {
|
|
5087
5741
|
let typeTokens = [];
|
|
5088
5742
|
let depth = 0;
|
|
5089
5743
|
let bracketStack = [];
|
|
@@ -5122,6 +5776,8 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
5122
5776
|
break;
|
|
5123
5777
|
}
|
|
5124
5778
|
if (depth === 0) {
|
|
5779
|
+
if (opts.stopAtFatArrow && tTag === "=>")
|
|
5780
|
+
break;
|
|
5125
5781
|
if (tTag === "INDENT" && typeTokens.length > 0 && typeTokens[typeTokens.length - 1][0] === "=>") {
|
|
5126
5782
|
j++;
|
|
5127
5783
|
let nest = 1;
|
|
@@ -6224,6 +6880,11 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
6224
6880
|
depth--;
|
|
6225
6881
|
if (depth === 0 && tk[0] === "TYPE_ANNOTATION")
|
|
6226
6882
|
return false;
|
|
6883
|
+
if (depth === 0 && tk[0] === ":") {
|
|
6884
|
+
let pv = this.tokens[k - 1];
|
|
6885
|
+
if (pv && (pv[0] === ")" || pv[0] === "PARAM_END" || pv[0] === "CALL_END"))
|
|
6886
|
+
return false;
|
|
6887
|
+
}
|
|
6227
6888
|
if (depth === 0 && tk[0] === "IDENTIFIER" && tk[1] === "type")
|
|
6228
6889
|
return false;
|
|
6229
6890
|
if (tk[0] === "INTERFACE")
|
|
@@ -6753,7 +7414,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
6753
7414
|
} else if (tg === "(" || tg === "[" || tg === "{" || tg === "CALL_START" || tg === "PARAM_START" || tg === "INDEX_START" || tg === "COMPARE" && tk[1] === "<") {
|
|
6754
7415
|
depth--;
|
|
6755
7416
|
} else if (depth === 0) {
|
|
6756
|
-
if (tg === "TYPE_ANNOTATION") {
|
|
7417
|
+
if (tg === "TYPE_ANNOTATION" || tg === ":") {
|
|
6757
7418
|
if (j > 0 && this.tokens[j - 1][0] === ")")
|
|
6758
7419
|
found = j - 1;
|
|
6759
7420
|
break;
|
|
@@ -6766,6 +7427,22 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
|
|
|
6766
7427
|
if (found < 0)
|
|
6767
7428
|
return this.tagDoIife();
|
|
6768
7429
|
closeIdx = found;
|
|
7430
|
+
} else {
|
|
7431
|
+
let d = 0, op = -1;
|
|
7432
|
+
for (let k = closeIdx;k >= 0; k--) {
|
|
7433
|
+
let tg = this.tokens[k][0];
|
|
7434
|
+
if (tg === ")" || tg === "CALL_END" || tg === "PARAM_END")
|
|
7435
|
+
d++;
|
|
7436
|
+
else if (tg === "(" || tg === "CALL_START" || tg === "PARAM_START") {
|
|
7437
|
+
if (--d === 0) {
|
|
7438
|
+
op = k;
|
|
7439
|
+
break;
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
if (op > 1 && this.tokens[op - 1][0] === "TYPE_ANNOTATION" && this.tokens[op - 2]?.[0] === ")") {
|
|
7444
|
+
closeIdx = op - 2;
|
|
7445
|
+
}
|
|
6769
7446
|
}
|
|
6770
7447
|
let i = closeIdx;
|
|
6771
7448
|
let stack = [];
|
|
@@ -11315,229 +11992,6 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
|
|
|
11315
11992
|
return name;
|
|
11316
11993
|
}
|
|
11317
11994
|
|
|
11318
|
-
// src/error.js
|
|
11319
|
-
class RipError extends Error {
|
|
11320
|
-
constructor(message, {
|
|
11321
|
-
code = null,
|
|
11322
|
-
file = null,
|
|
11323
|
-
line = null,
|
|
11324
|
-
column = null,
|
|
11325
|
-
length = 1,
|
|
11326
|
-
source = null,
|
|
11327
|
-
suggestion = null,
|
|
11328
|
-
phase = null
|
|
11329
|
-
} = {}) {
|
|
11330
|
-
super(message);
|
|
11331
|
-
this.name = "RipError";
|
|
11332
|
-
this.code = code;
|
|
11333
|
-
this.file = file;
|
|
11334
|
-
this.line = line;
|
|
11335
|
-
this.column = column;
|
|
11336
|
-
this.length = length;
|
|
11337
|
-
this.source = source;
|
|
11338
|
-
this.suggestion = suggestion;
|
|
11339
|
-
this.phase = phase;
|
|
11340
|
-
}
|
|
11341
|
-
static fromLexer(err, source, file) {
|
|
11342
|
-
let loc = err.location || {};
|
|
11343
|
-
return new RipError(err.message, {
|
|
11344
|
-
code: "E_SYNTAX",
|
|
11345
|
-
file,
|
|
11346
|
-
line: loc.first_line ?? null,
|
|
11347
|
-
column: loc.first_column ?? null,
|
|
11348
|
-
length: loc.last_column != null && loc.first_column != null ? loc.last_column - loc.first_column + 1 : 1,
|
|
11349
|
-
source,
|
|
11350
|
-
phase: "lexer"
|
|
11351
|
-
});
|
|
11352
|
-
}
|
|
11353
|
-
static fromParser(err, source, file) {
|
|
11354
|
-
let h = err.hash || {};
|
|
11355
|
-
let loc = h.loc || {};
|
|
11356
|
-
let line = h.line ?? loc.r ?? null;
|
|
11357
|
-
let column = loc.first_column ?? loc.c ?? null;
|
|
11358
|
-
let suggestion = null;
|
|
11359
|
-
if (h.expected?.length) {
|
|
11360
|
-
let first5 = h.expected.slice(0, 5).map((e) => e.replace(/'/g, ""));
|
|
11361
|
-
suggestion = `Expected ${first5.join(", ")}`;
|
|
11362
|
-
if (h.expected.length > 5)
|
|
11363
|
-
suggestion += `, ... (${h.expected.length} total)`;
|
|
11364
|
-
}
|
|
11365
|
-
let token = h.token || "token";
|
|
11366
|
-
let expectedSet = new Set((h.expected || []).map((e) => e.replace(/'/g, "")));
|
|
11367
|
-
let TERNARY_ENDERS = new Set([
|
|
11368
|
-
"TERMINATOR",
|
|
11369
|
-
",",
|
|
11370
|
-
")",
|
|
11371
|
-
"]",
|
|
11372
|
-
"OUTDENT",
|
|
11373
|
-
"CALL_END",
|
|
11374
|
-
"INDEX_END",
|
|
11375
|
-
"PARAM_END",
|
|
11376
|
-
"EOF"
|
|
11377
|
-
]);
|
|
11378
|
-
if (expectedSet.has(":") && (expectedSet.has("POST_IF") || expectedSet.has("POST_UNLESS") || expectedSet.has("FOR") || expectedSet.has("WHILE")) && TERNARY_ENDERS.has(token)) {
|
|
11379
|
-
suggestion = "Binary `x ? y` was removed — use `x ?? y` for nullish coalescing, or a full ternary `x ? y : z`";
|
|
11380
|
-
}
|
|
11381
|
-
let near = h.text ? ` near '${h.text}'` : "";
|
|
11382
|
-
let message = `Unexpected ${token}${near}`;
|
|
11383
|
-
return new RipError(message, {
|
|
11384
|
-
code: "E_PARSE",
|
|
11385
|
-
file,
|
|
11386
|
-
line,
|
|
11387
|
-
column,
|
|
11388
|
-
length: h.text?.length || 1,
|
|
11389
|
-
source,
|
|
11390
|
-
suggestion,
|
|
11391
|
-
phase: "parser"
|
|
11392
|
-
});
|
|
11393
|
-
}
|
|
11394
|
-
static fromSExpr(message, sexpr, source, file, suggestion) {
|
|
11395
|
-
let loc = sexpr?.loc || {};
|
|
11396
|
-
return new RipError(message, {
|
|
11397
|
-
code: "E_CODEGEN",
|
|
11398
|
-
file,
|
|
11399
|
-
line: loc.r ?? null,
|
|
11400
|
-
column: loc.c ?? null,
|
|
11401
|
-
length: loc.n ?? 1,
|
|
11402
|
-
source,
|
|
11403
|
-
suggestion,
|
|
11404
|
-
phase: "codegen"
|
|
11405
|
-
});
|
|
11406
|
-
}
|
|
11407
|
-
get locationString() {
|
|
11408
|
-
let parts = [];
|
|
11409
|
-
if (this.file)
|
|
11410
|
-
parts.push(this.file);
|
|
11411
|
-
if (this.line != null) {
|
|
11412
|
-
parts.push(`${this.line + 1}:${(this.column ?? 0) + 1}`);
|
|
11413
|
-
}
|
|
11414
|
-
return parts.join(":");
|
|
11415
|
-
}
|
|
11416
|
-
format({ color = true } = {}) {
|
|
11417
|
-
let c = color ? {
|
|
11418
|
-
red: "\x1B[31m",
|
|
11419
|
-
yellow: "\x1B[33m",
|
|
11420
|
-
cyan: "\x1B[36m",
|
|
11421
|
-
dim: "\x1B[2m",
|
|
11422
|
-
bold: "\x1B[1m",
|
|
11423
|
-
reset: "\x1B[0m"
|
|
11424
|
-
} : { red: "", yellow: "", cyan: "", dim: "", bold: "", reset: "" };
|
|
11425
|
-
let lines = [];
|
|
11426
|
-
let loc = this.locationString;
|
|
11427
|
-
let header = loc ? `${c.cyan}${loc}${c.reset} ` : "";
|
|
11428
|
-
lines.push(`${header}${c.red}${c.bold}error${c.reset}${c.bold}: ${this.message}${c.reset}`);
|
|
11429
|
-
let snippet = this._snippet();
|
|
11430
|
-
if (snippet) {
|
|
11431
|
-
lines.push("");
|
|
11432
|
-
for (let s of snippet) {
|
|
11433
|
-
if (s.type === "source") {
|
|
11434
|
-
lines.push(`${c.dim}${s.gutter}${c.reset}${s.text}`);
|
|
11435
|
-
} else if (s.type === "caret") {
|
|
11436
|
-
lines.push(`${c.dim}${s.gutter}${c.reset}${c.red}${c.bold}${s.text}${c.reset}`);
|
|
11437
|
-
}
|
|
11438
|
-
}
|
|
11439
|
-
}
|
|
11440
|
-
if (this.suggestion) {
|
|
11441
|
-
lines.push("");
|
|
11442
|
-
lines.push(`${c.yellow}hint${c.reset}: ${this.suggestion}`);
|
|
11443
|
-
}
|
|
11444
|
-
return lines.join(`
|
|
11445
|
-
`);
|
|
11446
|
-
}
|
|
11447
|
-
formatHTML() {
|
|
11448
|
-
let lines = [];
|
|
11449
|
-
lines.push('<div class="rip-error">');
|
|
11450
|
-
lines.push("<style>");
|
|
11451
|
-
lines.push(`.rip-error { font-family: ui-monospace, "SF Mono", Menlo, Monaco, monospace; font-size: 13px; line-height: 1.5; padding: 16px 20px; background: #1e1e2e; color: #cdd6f4; border-radius: 8px; overflow-x: auto; }`);
|
|
11452
|
-
lines.push(`.rip-error .re-header { color: #f38ba8; font-weight: 600; }`);
|
|
11453
|
-
lines.push(`.rip-error .re-loc { color: #89b4fa; }`);
|
|
11454
|
-
lines.push(`.rip-error .re-gutter { color: #585b70; user-select: none; }`);
|
|
11455
|
-
lines.push(`.rip-error .re-caret { color: #f38ba8; font-weight: 700; }`);
|
|
11456
|
-
lines.push(`.rip-error .re-hint { color: #f9e2af; }`);
|
|
11457
|
-
lines.push(`.rip-error .re-snippet { margin: 8px 0; }`);
|
|
11458
|
-
lines.push("</style>");
|
|
11459
|
-
let loc = this.locationString;
|
|
11460
|
-
let locSpan = loc ? `<span class="re-loc">${esc(loc)}</span> ` : "";
|
|
11461
|
-
lines.push(`<div class="re-header">${locSpan}error: ${esc(this.message)}</div>`);
|
|
11462
|
-
let snippet = this._snippet();
|
|
11463
|
-
if (snippet) {
|
|
11464
|
-
lines.push('<pre class="re-snippet">');
|
|
11465
|
-
for (let s of snippet) {
|
|
11466
|
-
if (s.type === "source") {
|
|
11467
|
-
lines.push(`<span class="re-gutter">${esc(s.gutter)}</span>${esc(s.text)}`);
|
|
11468
|
-
} else if (s.type === "caret") {
|
|
11469
|
-
lines.push(`<span class="re-gutter">${esc(s.gutter)}</span><span class="re-caret">${esc(s.text)}</span>`);
|
|
11470
|
-
}
|
|
11471
|
-
}
|
|
11472
|
-
lines.push("</pre>");
|
|
11473
|
-
}
|
|
11474
|
-
if (this.suggestion) {
|
|
11475
|
-
lines.push(`<div class="re-hint">hint: ${esc(this.suggestion)}</div>`);
|
|
11476
|
-
}
|
|
11477
|
-
lines.push("</div>");
|
|
11478
|
-
return lines.join(`
|
|
11479
|
-
`);
|
|
11480
|
-
}
|
|
11481
|
-
_snippet() {
|
|
11482
|
-
if (this.source == null || this.line == null)
|
|
11483
|
-
return null;
|
|
11484
|
-
let sourceLines = this.source.split(`
|
|
11485
|
-
`);
|
|
11486
|
-
let errLine = this.line;
|
|
11487
|
-
if (errLine < 0 || errLine >= sourceLines.length)
|
|
11488
|
-
return null;
|
|
11489
|
-
let contextRadius = 2;
|
|
11490
|
-
let start = Math.max(0, errLine - contextRadius);
|
|
11491
|
-
let end = Math.min(sourceLines.length - 1, errLine + contextRadius);
|
|
11492
|
-
let gutterWidth = String(end + 1).length;
|
|
11493
|
-
let result = [];
|
|
11494
|
-
for (let i = start;i <= end; i++) {
|
|
11495
|
-
let lineNum = String(i + 1).padStart(gutterWidth);
|
|
11496
|
-
let gutter = ` ${lineNum} │ `;
|
|
11497
|
-
result.push({ type: "source", gutter, text: sourceLines[i] });
|
|
11498
|
-
if (i === errLine && this.column != null) {
|
|
11499
|
-
let pad = " ".repeat(this.column);
|
|
11500
|
-
let caretLen = Math.max(1, Math.min(this.length || 1, sourceLines[i].length - this.column));
|
|
11501
|
-
let carets = "^".repeat(caretLen);
|
|
11502
|
-
let emptyGutter = " ".repeat(gutterWidth + 2) + "│ ";
|
|
11503
|
-
result.push({ type: "caret", gutter: emptyGutter, text: `${pad}${carets}` });
|
|
11504
|
-
}
|
|
11505
|
-
}
|
|
11506
|
-
return result;
|
|
11507
|
-
}
|
|
11508
|
-
}
|
|
11509
|
-
function isLexerError(err) {
|
|
11510
|
-
return err instanceof SyntaxError && err.location != null;
|
|
11511
|
-
}
|
|
11512
|
-
function isParserError(err) {
|
|
11513
|
-
return !(err instanceof SyntaxError) && err.hash != null;
|
|
11514
|
-
}
|
|
11515
|
-
function toRipError(err, source, file) {
|
|
11516
|
-
if (err instanceof RipError) {
|
|
11517
|
-
if (file && !err.file)
|
|
11518
|
-
err.file = file;
|
|
11519
|
-
if (source && !err.source)
|
|
11520
|
-
err.source = source;
|
|
11521
|
-
return err;
|
|
11522
|
-
}
|
|
11523
|
-
if (isLexerError(err))
|
|
11524
|
-
return RipError.fromLexer(err, source, file);
|
|
11525
|
-
if (isParserError(err))
|
|
11526
|
-
return RipError.fromParser(err, source, file);
|
|
11527
|
-
return new RipError(err.message, { file, source, phase: "unknown" });
|
|
11528
|
-
}
|
|
11529
|
-
function formatError(err, { source, file, color = true } = {}) {
|
|
11530
|
-
let re = err instanceof RipError ? err : toRipError(err, source, file);
|
|
11531
|
-
return re.format({ color });
|
|
11532
|
-
}
|
|
11533
|
-
function formatErrorHTML(err, { source, file } = {}) {
|
|
11534
|
-
let re = err instanceof RipError ? err : toRipError(err, source, file);
|
|
11535
|
-
return re.formatHTML();
|
|
11536
|
-
}
|
|
11537
|
-
function esc(s) {
|
|
11538
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
11539
|
-
}
|
|
11540
|
-
|
|
11541
11995
|
// src/compiler.js
|
|
11542
11996
|
var _typesEmitter = null;
|
|
11543
11997
|
var meta = (node, key) => node instanceof String ? node[key] : undefined;
|
|
@@ -13011,10 +13465,10 @@ function _setDataSection() {
|
|
|
13011
13465
|
let ret = this.inlineReturnType(name);
|
|
13012
13466
|
return `${isAsync ? "async " : ""}function${isGen ? "*" : ""} ${cleanName}(${paramList})${ret} ${bodyCode}`;
|
|
13013
13467
|
}
|
|
13014
|
-
inlineReturnType(
|
|
13468
|
+
inlineReturnType(node) {
|
|
13015
13469
|
if (!this.options.inlineTypes)
|
|
13016
13470
|
return "";
|
|
13017
|
-
let rt = meta(
|
|
13471
|
+
let rt = meta(node, "returnType");
|
|
13018
13472
|
return rt ? `: ${ripToTs(rt)}` : "";
|
|
13019
13473
|
}
|
|
13020
13474
|
emitThinArrow(head, rest, context, sexpr) {
|
|
@@ -13026,7 +13480,8 @@ function _setDataSection() {
|
|
|
13026
13480
|
let bodyCode = this.emitFunctionBody(body, params, sideEffectOnly);
|
|
13027
13481
|
let isAsync = this.containsAwait(body);
|
|
13028
13482
|
let isGen = this.containsYield(body);
|
|
13029
|
-
let
|
|
13483
|
+
let ret = this.inlineReturnType(sexpr?.[0]);
|
|
13484
|
+
let fn = `${isAsync ? "async " : ""}function${isGen ? "*" : ""}(${paramList})${ret} ${bodyCode}`;
|
|
13030
13485
|
return context === "value" ? `(${fn})` : fn;
|
|
13031
13486
|
}
|
|
13032
13487
|
emitFatArrow(head, rest, context, sexpr) {
|
|
@@ -13035,7 +13490,8 @@ function _setDataSection() {
|
|
|
13035
13490
|
params = ["it"];
|
|
13036
13491
|
let sideEffectOnly = sexpr.isVoid || false;
|
|
13037
13492
|
let paramList = this.emitParamList(params);
|
|
13038
|
-
let
|
|
13493
|
+
let ret = this.inlineReturnType(sexpr?.[0]);
|
|
13494
|
+
let isSingle = !ret && params.length === 1 && typeof params[0] === "string" && !paramList.includes("=") && !paramList.includes("...") && !paramList.includes("[") && !paramList.includes("{");
|
|
13039
13495
|
let paramSyntax = isSingle ? paramList : `(${paramList})`;
|
|
13040
13496
|
let isAsync = this.containsAwait(body);
|
|
13041
13497
|
let prefix = isAsync ? "async " : "";
|
|
@@ -13047,18 +13503,18 @@ function _setDataSection() {
|
|
|
13047
13503
|
let code = this.emit(expr, "value");
|
|
13048
13504
|
if (code[0] === "{")
|
|
13049
13505
|
code = `(${code})`;
|
|
13050
|
-
return `${prefix}${paramSyntax} => ${code}`;
|
|
13506
|
+
return `${prefix}${paramSyntax}${ret} => ${code}`;
|
|
13051
13507
|
}
|
|
13052
13508
|
}
|
|
13053
13509
|
if (!Array.isArray(body) || body[0] !== "block") {
|
|
13054
13510
|
let code = this.emit(body, "value");
|
|
13055
13511
|
if (code[0] === "{")
|
|
13056
13512
|
code = `(${code})`;
|
|
13057
|
-
return `${prefix}${paramSyntax} => ${code}`;
|
|
13513
|
+
return `${prefix}${paramSyntax}${ret} => ${code}`;
|
|
13058
13514
|
}
|
|
13059
13515
|
}
|
|
13060
13516
|
let bodyCode = this.emitFunctionBody(body, params, sideEffectOnly);
|
|
13061
|
-
return `${prefix}${paramSyntax} => ${bodyCode}`;
|
|
13517
|
+
return `${prefix}${paramSyntax}${ret} => ${bodyCode}`;
|
|
13062
13518
|
}
|
|
13063
13519
|
emitReturn(head, rest, context, sexpr) {
|
|
13064
13520
|
if (rest.length === 0)
|
|
@@ -16467,8 +16923,8 @@ if (typeof globalThis !== 'undefined') {
|
|
|
16467
16923
|
return new CodeEmitter({}).getComponentRuntime();
|
|
16468
16924
|
}
|
|
16469
16925
|
// src/browser.js
|
|
16470
|
-
var VERSION = "3.
|
|
16471
|
-
var BUILD_DATE = "2026-06-
|
|
16926
|
+
var VERSION = "3.17.1";
|
|
16927
|
+
var BUILD_DATE = "2026-06-28@00:08:17GMT";
|
|
16472
16928
|
if (typeof globalThis !== "undefined") {
|
|
16473
16929
|
if (!globalThis.__rip)
|
|
16474
16930
|
new Function(getReactiveRuntime())();
|