@mojir/dvala 0.0.16 → 0.0.17
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/dist/cli/cli.js +314 -14
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -118,7 +118,8 @@ const NodeTypes = {
|
|
|
118
118
|
SpecialBuiltinSymbol: 7,
|
|
119
119
|
ReservedSymbol: 8,
|
|
120
120
|
Binding: 9,
|
|
121
|
-
Spread: 10
|
|
121
|
+
Spread: 10,
|
|
122
|
+
TemplateString: 11
|
|
122
123
|
};
|
|
123
124
|
const NodeTypesSet = new Set(Object.values(NodeTypes));
|
|
124
125
|
function getNodeTypeName(type) {
|
|
@@ -477,7 +478,7 @@ function findAllOccurrences(input, pattern) {
|
|
|
477
478
|
}
|
|
478
479
|
//#endregion
|
|
479
480
|
//#region package.json
|
|
480
|
-
var version = "0.0.
|
|
481
|
+
var version = "0.0.17";
|
|
481
482
|
//#endregion
|
|
482
483
|
//#region src/typeGuards/string.ts
|
|
483
484
|
function isString(value, options = {}) {
|
|
@@ -25810,6 +25811,94 @@ const tokenizeShebang = (input, position) => {
|
|
|
25810
25811
|
}
|
|
25811
25812
|
return NO_MATCH;
|
|
25812
25813
|
};
|
|
25814
|
+
const tokenizeTemplateString = (input, position) => {
|
|
25815
|
+
if (input[position] !== "`") return NO_MATCH;
|
|
25816
|
+
let value = "`";
|
|
25817
|
+
let length = 1;
|
|
25818
|
+
while (position + length < input.length) {
|
|
25819
|
+
const char = input[position + length];
|
|
25820
|
+
if (char === "`") {
|
|
25821
|
+
value += "`";
|
|
25822
|
+
length += 1;
|
|
25823
|
+
return [length, ["TemplateString", value]];
|
|
25824
|
+
}
|
|
25825
|
+
if (char === "$" && input[position + length + 1] === "{") {
|
|
25826
|
+
value += "${";
|
|
25827
|
+
length += 2;
|
|
25828
|
+
let braceDepth = 1;
|
|
25829
|
+
while (position + length < input.length && braceDepth > 0) {
|
|
25830
|
+
const c = input[position + length];
|
|
25831
|
+
if (c === "{") {
|
|
25832
|
+
braceDepth += 1;
|
|
25833
|
+
value += c;
|
|
25834
|
+
length += 1;
|
|
25835
|
+
} else if (c === "}") {
|
|
25836
|
+
braceDepth -= 1;
|
|
25837
|
+
value += c;
|
|
25838
|
+
length += 1;
|
|
25839
|
+
} else if (c === "\"") {
|
|
25840
|
+
value += c;
|
|
25841
|
+
length += 1;
|
|
25842
|
+
let escaping = false;
|
|
25843
|
+
while (position + length < input.length) {
|
|
25844
|
+
const sc = input[position + length];
|
|
25845
|
+
value += sc;
|
|
25846
|
+
length += 1;
|
|
25847
|
+
if (escaping) escaping = false;
|
|
25848
|
+
else if (sc === "\\") escaping = true;
|
|
25849
|
+
else if (sc === "\"") break;
|
|
25850
|
+
}
|
|
25851
|
+
} else if (c === "'") {
|
|
25852
|
+
value += c;
|
|
25853
|
+
length += 1;
|
|
25854
|
+
let escaping = false;
|
|
25855
|
+
while (position + length < input.length) {
|
|
25856
|
+
const sc = input[position + length];
|
|
25857
|
+
value += sc;
|
|
25858
|
+
length += 1;
|
|
25859
|
+
if (escaping) escaping = false;
|
|
25860
|
+
else if (sc === "\\") escaping = true;
|
|
25861
|
+
else if (sc === "'") break;
|
|
25862
|
+
}
|
|
25863
|
+
} else if (c === "`") {
|
|
25864
|
+
const [nestedLength, nestedToken] = tokenizeTemplateString(input, position + length);
|
|
25865
|
+
if (nestedLength === 0 || !nestedToken) return [length, [
|
|
25866
|
+
"Error",
|
|
25867
|
+
value,
|
|
25868
|
+
void 0,
|
|
25869
|
+
`Unclosed nested template string at position ${position + length}`
|
|
25870
|
+
]];
|
|
25871
|
+
if (nestedToken[0] === "Error") return [length + nestedLength, [
|
|
25872
|
+
"Error",
|
|
25873
|
+
value + nestedToken[1],
|
|
25874
|
+
void 0,
|
|
25875
|
+
nestedToken[3]
|
|
25876
|
+
]];
|
|
25877
|
+
value += nestedToken[1];
|
|
25878
|
+
length += nestedLength;
|
|
25879
|
+
} else {
|
|
25880
|
+
value += c;
|
|
25881
|
+
length += 1;
|
|
25882
|
+
}
|
|
25883
|
+
}
|
|
25884
|
+
if (braceDepth > 0) return [length, [
|
|
25885
|
+
"Error",
|
|
25886
|
+
value,
|
|
25887
|
+
void 0,
|
|
25888
|
+
`Unclosed interpolation in template string at position ${position}`
|
|
25889
|
+
]];
|
|
25890
|
+
} else {
|
|
25891
|
+
value += char;
|
|
25892
|
+
length += 1;
|
|
25893
|
+
}
|
|
25894
|
+
}
|
|
25895
|
+
return [length, [
|
|
25896
|
+
"Error",
|
|
25897
|
+
value,
|
|
25898
|
+
void 0,
|
|
25899
|
+
`Unclosed template string at position ${position}`
|
|
25900
|
+
]];
|
|
25901
|
+
};
|
|
25813
25902
|
const tokenizeSingleLineComment = (input, position) => {
|
|
25814
25903
|
if (input[position] === "/" && input[position + 1] === "/") {
|
|
25815
25904
|
let length = 2;
|
|
@@ -25834,6 +25923,7 @@ const tokenizers = [
|
|
|
25834
25923
|
tokenizeLBrace,
|
|
25835
25924
|
tokenizeRBrace,
|
|
25836
25925
|
tokenizeString,
|
|
25926
|
+
tokenizeTemplateString,
|
|
25837
25927
|
tokenizeRegexpShorthand,
|
|
25838
25928
|
tokenizeBasePrefixedNumber,
|
|
25839
25929
|
tokenizeNumber,
|
|
@@ -26628,6 +26718,11 @@ function findUnresolvedSymbolsInNode(node, contextStack, builtin) {
|
|
|
26628
26718
|
});
|
|
26629
26719
|
}
|
|
26630
26720
|
case NodeTypes.Spread: return findUnresolvedSymbolsInNode(node[1], contextStack, builtin);
|
|
26721
|
+
case NodeTypes.TemplateString: {
|
|
26722
|
+
const unresolvedSymbols = /* @__PURE__ */ new Set();
|
|
26723
|
+
for (const segment of node[1]) findUnresolvedSymbolsInNode(segment, contextStack, builtin)?.forEach((symbol) => unresolvedSymbols.add(symbol));
|
|
26724
|
+
return unresolvedSymbols;
|
|
26725
|
+
}
|
|
26631
26726
|
default: throw new DvalaError(`Unhandled node type: ${nodeType}`, node[2]);
|
|
26632
26727
|
}
|
|
26633
26728
|
}
|
|
@@ -27562,6 +27657,176 @@ function parseObject(ctx) {
|
|
|
27562
27657
|
return withSourceCodeInfo([NodeTypes.SpecialExpression, [specialExpressionTypes.object, params]], firstToken[2]);
|
|
27563
27658
|
}
|
|
27564
27659
|
//#endregion
|
|
27660
|
+
//#region src/tokenizer/minifyTokenStream.ts
|
|
27661
|
+
function minifyTokenStream(tokenStream, { removeWhiteSpace }) {
|
|
27662
|
+
const tokens = tokenStream.tokens.filter((token) => {
|
|
27663
|
+
if (isSingleLineCommentToken(token) || isMultiLineCommentToken(token) || isShebangToken(token) || removeWhiteSpace && isWhitespaceToken(token)) return false;
|
|
27664
|
+
return true;
|
|
27665
|
+
});
|
|
27666
|
+
return {
|
|
27667
|
+
...tokenStream,
|
|
27668
|
+
tokens
|
|
27669
|
+
};
|
|
27670
|
+
}
|
|
27671
|
+
//#endregion
|
|
27672
|
+
//#region src/parser/subParsers/parseTemplateString.ts
|
|
27673
|
+
/**
|
|
27674
|
+
* Scan from `start` inside a `${...}` interpolation until the matching `}`.
|
|
27675
|
+
* Returns the expression source text (without the outer `${` and `}`) and
|
|
27676
|
+
* the number of characters consumed (including the closing `}`).
|
|
27677
|
+
*/
|
|
27678
|
+
function scanExpression(raw, start) {
|
|
27679
|
+
let i = start;
|
|
27680
|
+
let expr = "";
|
|
27681
|
+
let depth = 1;
|
|
27682
|
+
while (i < raw.length && depth > 0) {
|
|
27683
|
+
const c = raw[i];
|
|
27684
|
+
if (c === "{") {
|
|
27685
|
+
depth++;
|
|
27686
|
+
expr += c;
|
|
27687
|
+
i++;
|
|
27688
|
+
} else if (c === "}") {
|
|
27689
|
+
depth--;
|
|
27690
|
+
if (depth > 0) expr += c;
|
|
27691
|
+
i++;
|
|
27692
|
+
} else if (c === "\"") {
|
|
27693
|
+
const { str, consumed } = scanString(raw, i);
|
|
27694
|
+
expr += str;
|
|
27695
|
+
i += consumed;
|
|
27696
|
+
} else if (c === "'") {
|
|
27697
|
+
const { str, consumed } = scanQuotedSymbol(raw, i);
|
|
27698
|
+
expr += str;
|
|
27699
|
+
i += consumed;
|
|
27700
|
+
} else if (c === "`") {
|
|
27701
|
+
const { str, consumed } = scanNestedTemplate(raw, i);
|
|
27702
|
+
expr += str;
|
|
27703
|
+
i += consumed;
|
|
27704
|
+
} else {
|
|
27705
|
+
expr += c;
|
|
27706
|
+
i++;
|
|
27707
|
+
}
|
|
27708
|
+
}
|
|
27709
|
+
return {
|
|
27710
|
+
expr,
|
|
27711
|
+
consumed: i - start
|
|
27712
|
+
};
|
|
27713
|
+
}
|
|
27714
|
+
function scanString(raw, start) {
|
|
27715
|
+
let i = start + 1;
|
|
27716
|
+
let str = "\"";
|
|
27717
|
+
let escaping = false;
|
|
27718
|
+
while (i < raw.length) {
|
|
27719
|
+
const c = raw[i];
|
|
27720
|
+
str += c;
|
|
27721
|
+
i++;
|
|
27722
|
+
if (escaping) escaping = false;
|
|
27723
|
+
else if (c === "\\") escaping = true;
|
|
27724
|
+
else if (c === "\"") break;
|
|
27725
|
+
}
|
|
27726
|
+
return {
|
|
27727
|
+
str,
|
|
27728
|
+
consumed: i - start
|
|
27729
|
+
};
|
|
27730
|
+
}
|
|
27731
|
+
function scanQuotedSymbol(raw, start) {
|
|
27732
|
+
let i = start + 1;
|
|
27733
|
+
let str = "'";
|
|
27734
|
+
let escaping = false;
|
|
27735
|
+
while (i < raw.length) {
|
|
27736
|
+
const c = raw[i];
|
|
27737
|
+
str += c;
|
|
27738
|
+
i++;
|
|
27739
|
+
if (escaping) escaping = false;
|
|
27740
|
+
else if (c === "\\") escaping = true;
|
|
27741
|
+
else if (c === "'") break;
|
|
27742
|
+
}
|
|
27743
|
+
return {
|
|
27744
|
+
str,
|
|
27745
|
+
consumed: i - start
|
|
27746
|
+
};
|
|
27747
|
+
}
|
|
27748
|
+
/**
|
|
27749
|
+
* Scan a full nested template string starting at `start` (pointing at the opening backtick).
|
|
27750
|
+
* Handles ${...} spans inside the template recursively.
|
|
27751
|
+
*/
|
|
27752
|
+
function scanNestedTemplate(raw, start) {
|
|
27753
|
+
let i = start + 1;
|
|
27754
|
+
let str = "`";
|
|
27755
|
+
while (i < raw.length) {
|
|
27756
|
+
const c = raw[i];
|
|
27757
|
+
if (c === "`") {
|
|
27758
|
+
str += c;
|
|
27759
|
+
i++;
|
|
27760
|
+
break;
|
|
27761
|
+
} else if (c === "$" && raw[i + 1] === "{") {
|
|
27762
|
+
str += "${";
|
|
27763
|
+
i += 2;
|
|
27764
|
+
const { expr, consumed } = scanExpression(raw, i);
|
|
27765
|
+
str += `${expr}}`;
|
|
27766
|
+
i += consumed;
|
|
27767
|
+
} else {
|
|
27768
|
+
str += c;
|
|
27769
|
+
i++;
|
|
27770
|
+
}
|
|
27771
|
+
}
|
|
27772
|
+
return {
|
|
27773
|
+
str,
|
|
27774
|
+
consumed: i - start
|
|
27775
|
+
};
|
|
27776
|
+
}
|
|
27777
|
+
/**
|
|
27778
|
+
* Split the raw content of a template string (between the surrounding backticks)
|
|
27779
|
+
* into alternating literal and expression segments.
|
|
27780
|
+
*/
|
|
27781
|
+
function splitSegments(raw) {
|
|
27782
|
+
const segments = [];
|
|
27783
|
+
let i = 0;
|
|
27784
|
+
let literal = "";
|
|
27785
|
+
while (i < raw.length) if (raw[i] === "$" && raw[i + 1] === "{") {
|
|
27786
|
+
if (literal.length > 0) {
|
|
27787
|
+
segments.push({
|
|
27788
|
+
type: "literal",
|
|
27789
|
+
value: literal
|
|
27790
|
+
});
|
|
27791
|
+
literal = "";
|
|
27792
|
+
}
|
|
27793
|
+
i += 2;
|
|
27794
|
+
const { expr, consumed } = scanExpression(raw, i);
|
|
27795
|
+
i += consumed;
|
|
27796
|
+
segments.push({
|
|
27797
|
+
type: "expression",
|
|
27798
|
+
value: expr
|
|
27799
|
+
});
|
|
27800
|
+
} else {
|
|
27801
|
+
literal += raw[i];
|
|
27802
|
+
i++;
|
|
27803
|
+
}
|
|
27804
|
+
if (literal.length > 0) segments.push({
|
|
27805
|
+
type: "literal",
|
|
27806
|
+
value: literal
|
|
27807
|
+
});
|
|
27808
|
+
return segments;
|
|
27809
|
+
}
|
|
27810
|
+
function parseTemplateString(ctx, token) {
|
|
27811
|
+
ctx.advance();
|
|
27812
|
+
const sourceCodeInfo = token[2];
|
|
27813
|
+
const segments = splitSegments(token[1].slice(1, -1));
|
|
27814
|
+
if (segments.length === 0) return withSourceCodeInfo([NodeTypes.String, ""], sourceCodeInfo);
|
|
27815
|
+
if (segments.length === 1 && segments[0].type === "literal") return withSourceCodeInfo([NodeTypes.String, segments[0].value], sourceCodeInfo);
|
|
27816
|
+
const segmentNodes = [];
|
|
27817
|
+
for (const segment of segments) if (segment.type === "literal") {
|
|
27818
|
+
if (segment.value.length === 0) continue;
|
|
27819
|
+
segmentNodes.push(withSourceCodeInfo([NodeTypes.String, segment.value], sourceCodeInfo));
|
|
27820
|
+
} else {
|
|
27821
|
+
if (segment.value.trim().length === 0) throw new DvalaError("Empty interpolation in template string", sourceCodeInfo);
|
|
27822
|
+
const minified = minifyTokenStream(tokenize(segment.value, false, sourceCodeInfo?.filePath), { removeWhiteSpace: true });
|
|
27823
|
+
for (const t of minified.tokens) if (t[0] === "Error") throw new DvalaError(`Template string interpolation error: ${t[3]}`, sourceCodeInfo);
|
|
27824
|
+
const expr = parseExpression(createParserContext(minified), 0);
|
|
27825
|
+
segmentNodes.push(expr);
|
|
27826
|
+
}
|
|
27827
|
+
return withSourceCodeInfo([NodeTypes.TemplateString, segmentNodes], sourceCodeInfo);
|
|
27828
|
+
}
|
|
27829
|
+
//#endregion
|
|
27565
27830
|
//#region src/parser/subParsers/parseOperand.ts
|
|
27566
27831
|
function parseOperand(ctx) {
|
|
27567
27832
|
let operand = parseOperandPart(ctx);
|
|
@@ -27616,6 +27881,7 @@ function parseOperandPart(ctx) {
|
|
|
27616
27881
|
case "Number":
|
|
27617
27882
|
case "BasePrefixedNumber": return parseNumber(ctx);
|
|
27618
27883
|
case "string": return parseString(ctx, token);
|
|
27884
|
+
case "TemplateString": return parseTemplateString(ctx, token);
|
|
27619
27885
|
case "Symbol": {
|
|
27620
27886
|
ctx.storePosition();
|
|
27621
27887
|
const lamdaFunction = parseLambdaFunction(ctx);
|
|
@@ -27747,18 +28013,6 @@ function parse(tokenStream) {
|
|
|
27747
28013
|
return nodes;
|
|
27748
28014
|
}
|
|
27749
28015
|
//#endregion
|
|
27750
|
-
//#region src/tokenizer/minifyTokenStream.ts
|
|
27751
|
-
function minifyTokenStream(tokenStream, { removeWhiteSpace }) {
|
|
27752
|
-
const tokens = tokenStream.tokens.filter((token) => {
|
|
27753
|
-
if (isSingleLineCommentToken(token) || isMultiLineCommentToken(token) || isShebangToken(token) || removeWhiteSpace && isWhitespaceToken(token)) return false;
|
|
27754
|
-
return true;
|
|
27755
|
-
});
|
|
27756
|
-
return {
|
|
27757
|
-
...tokenStream,
|
|
27758
|
-
tokens
|
|
27759
|
-
};
|
|
27760
|
-
}
|
|
27761
|
-
//#endregion
|
|
27762
28016
|
//#region src/evaluator/effectTypes.ts
|
|
27763
28017
|
const SUSPENDED_MESSAGE = "Program suspended";
|
|
27764
28018
|
/**
|
|
@@ -28439,9 +28693,33 @@ function stepNode(node, env, k) {
|
|
|
28439
28693
|
};
|
|
28440
28694
|
case NodeTypes.NormalExpression: return stepNormalExpression(node, env, k);
|
|
28441
28695
|
case NodeTypes.SpecialExpression: return stepSpecialExpression(node, env, k);
|
|
28696
|
+
case NodeTypes.TemplateString: return stepTemplateString(node, env, k);
|
|
28442
28697
|
default: throw new DvalaError(`${getNodeTypeName(node[0])}-node cannot be evaluated`, node[2]);
|
|
28443
28698
|
}
|
|
28444
28699
|
}
|
|
28700
|
+
function stepTemplateString(node, env, k) {
|
|
28701
|
+
const segments = node[1];
|
|
28702
|
+
const sourceCodeInfo = node[2];
|
|
28703
|
+
if (segments.length === 0) return {
|
|
28704
|
+
type: "Value",
|
|
28705
|
+
value: "",
|
|
28706
|
+
k
|
|
28707
|
+
};
|
|
28708
|
+
const frame = {
|
|
28709
|
+
type: "TemplateStringBuild",
|
|
28710
|
+
segments,
|
|
28711
|
+
index: 0,
|
|
28712
|
+
result: "",
|
|
28713
|
+
env,
|
|
28714
|
+
sourceCodeInfo
|
|
28715
|
+
};
|
|
28716
|
+
return {
|
|
28717
|
+
type: "Eval",
|
|
28718
|
+
node: segments[0],
|
|
28719
|
+
env,
|
|
28720
|
+
k: [frame, ...k]
|
|
28721
|
+
};
|
|
28722
|
+
}
|
|
28445
28723
|
/**
|
|
28446
28724
|
* Normal expressions: evaluate arguments left-to-right, then dispatch.
|
|
28447
28725
|
* Push EvalArgsFrame + NanCheckFrame, then start evaluating the first arg.
|
|
@@ -29371,6 +29649,7 @@ function applyFrame(frame, value, k) {
|
|
|
29371
29649
|
case "And": return applyAnd(frame, value, k);
|
|
29372
29650
|
case "Or": return applyOr(frame, value, k);
|
|
29373
29651
|
case "Qq": return applyQq(frame, value, k);
|
|
29652
|
+
case "TemplateStringBuild": return applyTemplateStringBuild(frame, value, k);
|
|
29374
29653
|
case "ArrayBuild": return applyArrayBuild(frame, value, k);
|
|
29375
29654
|
case "ObjectBuild": return applyObjectBuild(frame, value, k);
|
|
29376
29655
|
case "LetBind": return applyLetBind(frame, value, k);
|
|
@@ -29657,6 +29936,27 @@ function advanceQq(frame, k) {
|
|
|
29657
29936
|
function skipUndefinedQq(frame, k) {
|
|
29658
29937
|
return advanceQq(frame, k);
|
|
29659
29938
|
}
|
|
29939
|
+
function applyTemplateStringBuild(frame, value, k) {
|
|
29940
|
+
const { segments, env } = frame;
|
|
29941
|
+
const result = frame.result + String(value);
|
|
29942
|
+
const nextIndex = frame.index + 1;
|
|
29943
|
+
if (nextIndex >= segments.length) return {
|
|
29944
|
+
type: "Value",
|
|
29945
|
+
value: result,
|
|
29946
|
+
k
|
|
29947
|
+
};
|
|
29948
|
+
const newFrame = {
|
|
29949
|
+
...frame,
|
|
29950
|
+
index: nextIndex,
|
|
29951
|
+
result
|
|
29952
|
+
};
|
|
29953
|
+
return {
|
|
29954
|
+
type: "Eval",
|
|
29955
|
+
node: segments[nextIndex],
|
|
29956
|
+
env,
|
|
29957
|
+
k: [newFrame, ...k]
|
|
29958
|
+
};
|
|
29959
|
+
}
|
|
29660
29960
|
function applyArrayBuild(frame, value, k) {
|
|
29661
29961
|
const { nodes, result, env, sourceCodeInfo } = frame;
|
|
29662
29962
|
if (frame.isSpread) {
|