@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.
Files changed (2) hide show
  1. package/dist/cli/cli.js +314 -14
  2. 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.16";
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mojir/dvala",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "dvala",
5
5
  "author": "Albert Mojir",
6
6
  "license": "MIT",