funcity 0.3.0 → 0.4.0

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/index.cjs CHANGED
@@ -302,16 +302,8 @@ const tokenizeIdentity = (context) => {
302
302
  range: { start, end: context.cursor.location("end") }
303
303
  };
304
304
  };
305
- const tokenizeCodeBlock = (context) => {
306
- const openStart = context.cursor.location("start");
307
- context.cursor.skip(2);
308
- const tokens = [
309
- {
310
- kind: "open",
311
- symbol: "{{",
312
- range: { start: openStart, end: context.cursor.location("end") }
313
- }
314
- ];
305
+ const tokenizeCodeTokens = (context, stopOnClose, finalizeUnknownOnEot) => {
306
+ const tokens = [];
315
307
  let unknownStartLocation;
316
308
  const finalizeUnknown = () => {
317
309
  if (unknownStartLocation) {
@@ -327,20 +319,21 @@ const tokenizeCodeBlock = (context) => {
327
319
  }
328
320
  };
329
321
  while (!context.cursor.eot()) {
330
- if (context.cursor.assert("}}")) {
322
+ if (stopOnClose && context.cursor.assert("}}")) {
331
323
  finalizeUnknown();
332
- const location = context.cursor.location("start");
333
- context.cursor.skip(2);
334
- tokens.push({
335
- kind: "close",
336
- symbol: "}}",
337
- range: { start: location, end: context.cursor.location("end") }
338
- });
339
- return tokens;
324
+ return { tokens, closed: true };
340
325
  }
341
326
  const ch = context.cursor.getChar();
342
327
  if (ch === "\\") {
343
328
  const next = context.cursor.getChar(1);
329
+ if (next === "\n") {
330
+ context.cursor.skip(2);
331
+ continue;
332
+ }
333
+ if (next === "\r" && context.cursor.getChar(2) === "\n") {
334
+ context.cursor.skip(3);
335
+ continue;
336
+ }
344
337
  if (next === "{" || next === "}") {
345
338
  context.cursor.skip(2);
346
339
  continue;
@@ -405,12 +398,41 @@ const tokenizeCodeBlock = (context) => {
405
398
  } else if (ch === " ") {
406
399
  finalizeUnknown();
407
400
  context.cursor.skip(1);
408
- } else if (!unknownStartLocation) {
409
- unknownStartLocation = context.cursor.location("start");
401
+ } else {
402
+ if (!unknownStartLocation) {
403
+ unknownStartLocation = context.cursor.location("start");
404
+ }
410
405
  context.cursor.skip(1);
411
406
  }
412
407
  context.cursor.skipChars(" ");
413
408
  }
409
+ if (finalizeUnknownOnEot) {
410
+ finalizeUnknown();
411
+ }
412
+ return { tokens, closed: false };
413
+ };
414
+ const tokenizeCodeBlock = (context) => {
415
+ const openStart = context.cursor.location("start");
416
+ context.cursor.skip(2);
417
+ const tokens = [
418
+ {
419
+ kind: "open",
420
+ symbol: "{{",
421
+ range: { start: openStart, end: context.cursor.location("end") }
422
+ }
423
+ ];
424
+ const result = tokenizeCodeTokens(context, true, false);
425
+ tokens.push(...result.tokens);
426
+ if (result.closed) {
427
+ const location = context.cursor.location("start");
428
+ context.cursor.skip(2);
429
+ tokens.push({
430
+ kind: "close",
431
+ symbol: "}}",
432
+ range: { start: location, end: context.cursor.location("end") }
433
+ });
434
+ return tokens;
435
+ }
414
436
  const causeLocation = context.cursor.location("start");
415
437
  context.errors.push({
416
438
  type: "error",
@@ -435,9 +457,12 @@ const createTokenizerCursor = (script) => {
435
457
  const ch = script[currentIndex];
436
458
  if (ch === "\r") {
437
459
  rawColumn = 0;
438
- } else if (ch === "\n" && lastch !== "\r") {
439
- rawColumn = 0;
440
460
  rawLine++;
461
+ } else if (ch === "\n") {
462
+ rawColumn = 0;
463
+ if (lastch !== "\r") {
464
+ rawLine++;
465
+ }
441
466
  } else {
442
467
  rawColumn++;
443
468
  }
@@ -514,6 +539,14 @@ const createTokenizerCursor = (script) => {
514
539
  location
515
540
  };
516
541
  };
542
+ const runCodeTokenizer = (script, errors) => {
543
+ const context = {
544
+ cursor: createTokenizerCursor(script),
545
+ errors
546
+ };
547
+ const result = tokenizeCodeTokens(context, false, true);
548
+ return result.tokens;
549
+ };
517
550
  const runTokenizer = (script, errors) => {
518
551
  const context = {
519
552
  cursor: createTokenizerCursor(script),
@@ -645,6 +678,9 @@ const parseLambdaExpression = (cursor, errors) => {
645
678
  };
646
679
  const parsePartialExpression = (cursor, errors) => {
647
680
  const token = cursor.peekToken();
681
+ if (!token) {
682
+ return void 0;
683
+ }
648
684
  switch (token.kind) {
649
685
  case "number": {
650
686
  const node = parseNumber(cursor);
@@ -1029,14 +1065,15 @@ const extractParameterArguments = (namesNode, errors) => {
1029
1065
  }
1030
1066
  }
1031
1067
  };
1032
- const parseBlock = (cursor, errors) => {
1068
+ const parseBlockCore = (cursor, errors, mode) => {
1033
1069
  const rootState = {
1034
1070
  kind: "root",
1035
1071
  startRange: emptyRange,
1036
1072
  branch: createBranchState()
1037
1073
  };
1038
1074
  const statementStates = [rootState];
1039
- let isInExpressionBlock = false;
1075
+ const isCodeMode = mode === "code";
1076
+ let isInExpressionBlock = isCodeMode;
1040
1077
  while (true) {
1041
1078
  const token = drainEndOfLineAndPeek(cursor);
1042
1079
  if (!token) {
@@ -1063,14 +1100,16 @@ const parseBlock = (cursor, errors) => {
1063
1100
  case "open": {
1064
1101
  if (token.symbol === "{{") {
1065
1102
  cursor.skipToken();
1066
- if (isInExpressionBlock) {
1067
- errors.push({
1068
- type: "error",
1069
- description: `Already opened expression block`,
1070
- range: token.range
1071
- });
1103
+ if (!isCodeMode) {
1104
+ if (isInExpressionBlock) {
1105
+ errors.push({
1106
+ type: "error",
1107
+ description: `Already opened expression block`,
1108
+ range: token.range
1109
+ });
1110
+ }
1111
+ isInExpressionBlock = true;
1072
1112
  }
1073
- isInExpressionBlock = true;
1074
1113
  } else {
1075
1114
  const node = parseExpression(cursor, errors);
1076
1115
  if (node) {
@@ -1081,6 +1120,10 @@ const parseBlock = (cursor, errors) => {
1081
1120
  }
1082
1121
  case "close": {
1083
1122
  cursor.skipToken();
1123
+ if (token.symbol === "}}" && isCodeMode) {
1124
+ flushCurrentBranch(statementStates);
1125
+ break;
1126
+ }
1084
1127
  if (!isInExpressionBlock) {
1085
1128
  errors.push({
1086
1129
  type: "error",
@@ -1089,6 +1132,14 @@ const parseBlock = (cursor, errors) => {
1089
1132
  });
1090
1133
  break;
1091
1134
  }
1135
+ if (isCodeMode) {
1136
+ errors.push({
1137
+ type: "error",
1138
+ description: `Mismatched close bracket`,
1139
+ range: token.range
1140
+ });
1141
+ break;
1142
+ }
1092
1143
  flushCurrentBranch(statementStates);
1093
1144
  isInExpressionBlock = false;
1094
1145
  break;
@@ -1335,6 +1386,9 @@ const parseBlock = (cursor, errors) => {
1335
1386
  }
1336
1387
  return rootState.branch.blocks;
1337
1388
  };
1389
+ const parseBlock = (cursor, errors) => {
1390
+ return parseBlockCore(cursor, errors, "script");
1391
+ };
1338
1392
  const createParserCursor = (tokens) => {
1339
1393
  let index = 0;
1340
1394
  const peekToken = () => {
@@ -1360,6 +1414,10 @@ const createParserCursor = (tokens) => {
1360
1414
  skipToken
1361
1415
  };
1362
1416
  };
1417
+ const parseExpressions = (tokens, errors) => {
1418
+ const cursor = createParserCursor(tokens);
1419
+ return parseBlockCore(cursor, errors, "code");
1420
+ };
1363
1421
  const runParser = (tokens, errors) => {
1364
1422
  const cursor = createParserCursor(tokens);
1365
1423
  const blockNodes = parseBlock(cursor, errors);
@@ -2137,8 +2195,10 @@ exports.makeFunCityFunction = makeFunCityFunction;
2137
2195
  exports.outputErrors = outputErrors;
2138
2196
  exports.parseBlock = parseBlock;
2139
2197
  exports.parseExpression = parseExpression;
2198
+ exports.parseExpressions = parseExpressions;
2140
2199
  exports.reduceExpressionNode = reduceExpressionNode;
2141
2200
  exports.reduceNode = reduceNode;
2201
+ exports.runCodeTokenizer = runCodeTokenizer;
2142
2202
  exports.runParser = runParser;
2143
2203
  exports.runReducer = runReducer;
2144
2204
  exports.runScriptOnce = runScriptOnce;