@lango-project/lango-js 0.1.3 → 0.1.4

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/package.json +1 -1
  2. package/src/compiler.mjs +49 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lango-project/lango-js",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "Apache-2.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/compiler.mjs CHANGED
@@ -557,6 +557,8 @@ class Parser {
557
557
  } else if (/^global (\$?[A-Za-z_]\w*)$/.test(text)) {
558
558
  const [, name] = /^global (\$?[A-Za-z_]\w*)$/.exec(text);
559
559
  body.push({ type: "globalDeclare", name, line: line.number });
560
+ } else if (/^@{1,2}\$?[A-Za-z_]\w*.*\(.*\)$/.test(text) && !text.includes(" = ")) {
561
+ body.push({ type: "expression", value: expr(text, line, this) });
560
562
  } else if (/^context ([A-Za-z_]\w*) = (.+)$/.test(text)) {
561
563
  const [, name, value] = /^context ([A-Za-z_]\w*) = (.+)$/.exec(text);
562
564
  body.push({ type: "contextSet", name, value: expr(value, line, this) });
@@ -944,9 +946,9 @@ class Parser {
944
946
  name,
945
947
  value: { type: "sql", text: sqlText, parts, parameters },
946
948
  });
947
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] = (.+)$/.test(text)) {
949
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] = (.+)$/.test(text)) {
948
950
  const [, receiver, firstIndex, secondIndex, sourceValue] =
949
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] = (.+)$/.exec(text);
951
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] = (.+)$/.exec(text);
950
952
  body.push({
951
953
  type: "indexAssign",
952
954
  receiver,
@@ -954,9 +956,9 @@ class Parser {
954
956
  value: this.expression(sourceValue, line),
955
957
  operator: null,
956
958
  });
957
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.test(text)) {
959
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.test(text)) {
958
960
  const [, receiver, firstIndex, secondIndex, operator, sourceValue] =
959
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.exec(text);
961
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.exec(text);
960
962
  body.push({
961
963
  type: "indexAssign",
962
964
  receiver,
@@ -964,9 +966,9 @@ class Parser {
964
966
  value: this.expression(sourceValue, line),
965
967
  operator,
966
968
  });
967
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\](\+\+|--)$/.test(text)) {
969
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\](\+\+|--)$/.test(text)) {
968
970
  const [, receiver, firstIndex, secondIndex, suffix] =
969
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\](\+\+|--)$/.exec(text);
971
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\]\[([^\]]+)\](\+\+|--)$/.exec(text);
970
972
  body.push({
971
973
  type: "indexAssign",
972
974
  receiver,
@@ -974,9 +976,9 @@ class Parser {
974
976
  value: { type: "raw", value: "1" },
975
977
  operator: suffix === "++" ? "+" : "-",
976
978
  });
977
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] = (.+)$/.test(text)) {
979
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] = (.+)$/.test(text)) {
978
980
  const [, receiver, sourceIndex, sourceValue] =
979
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] = (.+)$/.exec(text);
981
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] = (.+)$/.exec(text);
980
982
  body.push({
981
983
  type: "indexAssign",
982
984
  receiver,
@@ -984,9 +986,9 @@ class Parser {
984
986
  value: this.expression(sourceValue, line),
985
987
  operator: null,
986
988
  });
987
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.test(text)) {
989
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.test(text)) {
988
990
  const [, receiver, sourceIndex, operator, sourceValue] =
989
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.exec(text);
991
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\] (\+|-|\*|\/|%|\*\*)= (.+)$/.exec(text);
990
992
  body.push({
991
993
  type: "indexAssign",
992
994
  receiver,
@@ -994,9 +996,9 @@ class Parser {
994
996
  value: this.expression(sourceValue, line),
995
997
  operator,
996
998
  });
997
- } else if (/^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\](\+\+|--)$/.test(text)) {
999
+ } else if (/^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\](\+\+|--)$/.test(text)) {
998
1000
  const [, receiver, sourceIndex, suffix] =
999
- /^([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\](\+\+|--)$/.exec(text);
1001
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\[([^\]]+)\](\+\+|--)$/.exec(text);
1000
1002
  body.push({
1001
1003
  type: "indexAssign",
1002
1004
  receiver,
@@ -1005,7 +1007,7 @@ class Parser {
1005
1007
  operator: suffix === "++" ? "+" : "-",
1006
1008
  });
1007
1009
  } else {
1008
- const assignment = /^(\$[A-Za-z_]\w*|@{0,2}\$?[A-Za-z_]\w*|[A-Za-z_]\w*(?:\.\$?[A-Za-z_]\w*)+) = (.+)$/.exec(text);
1010
+ const assignment = /^(\$[A-Za-z_]\w*|@{0,2}\$?[A-Za-z_]\w*(?:\.\$?[A-Za-z_]\w*)*) = (.+)$/.exec(text);
1009
1011
  if (!assignment)
1010
1012
  this.fail(line, "LNG1106", `unsupported Faz 2 statement: ${text}`);
1011
1013
  body.push({
@@ -1412,7 +1414,7 @@ function expr(source, line, parser) {
1412
1414
  line: line.number,
1413
1415
  };
1414
1416
  const nestedIndex =
1415
- /^([A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w)*(?:\?\.)?\[.+\])(\?\.)?\[(.+)\]$/.exec(
1417
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w)*(?:\?\.)?\[.+\])(\?\.)?\[(.+)\]$/.exec(
1416
1418
  text,
1417
1419
  );
1418
1420
  if (nestedIndex)
@@ -1423,7 +1425,7 @@ function expr(source, line, parser) {
1423
1425
  index: expr(nestedIndex[3], line, parser),
1424
1426
  };
1425
1427
  const computedIndex =
1426
- /^([A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w)*)(\?\.)?\[([^\]]+)\]$/.exec(
1428
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w)*)(\?\.)?\[([^\]]+)\]$/.exec(
1427
1429
  text,
1428
1430
  );
1429
1431
  if (
@@ -1437,7 +1439,7 @@ function expr(source, line, parser) {
1437
1439
  index: expr(computedIndex[3], line, parser),
1438
1440
  };
1439
1441
  const indexedProperty =
1440
- /^([A-Za-z_]\w*.*\])(\?\.|\.)(\$?[A-Za-z_]\w*)$/.exec(text);
1442
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\])(\?\.|\.)(\$?[A-Za-z_]\w*)$/.exec(text);
1441
1443
  if (
1442
1444
  indexedProperty &&
1443
1445
  !/^[A-Za-z_]\w*\?\.\[(?:\d+|[A-Za-z_]\w*|['"][^'"]*['"])\]$/.test(
@@ -1451,7 +1453,7 @@ function expr(source, line, parser) {
1451
1453
  name: indexedProperty[3],
1452
1454
  };
1453
1455
  const indexedMethodCall =
1454
- /^([A-Za-z_]\w*.*\])(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(text);
1456
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\])(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(text);
1455
1457
  if (indexedMethodCall)
1456
1458
  return {
1457
1459
  type: "methodCall",
@@ -1464,7 +1466,7 @@ function expr(source, line, parser) {
1464
1466
  line: line.number,
1465
1467
  };
1466
1468
  const nestedCallResultIndex =
1467
- /^([A-Za-z_]\w*.*\)\?\.\[.+\])(\?\.)?\[(.+)\]$/.exec(text);
1469
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\)\?\.\[.+\])(\?\.)?\[(.+)\]$/.exec(text);
1468
1470
  if (nestedCallResultIndex)
1469
1471
  return {
1470
1472
  type: "index",
@@ -1473,7 +1475,7 @@ function expr(source, line, parser) {
1473
1475
  index: expr(nestedCallResultIndex[3], line, parser),
1474
1476
  };
1475
1477
  const callResultIndex =
1476
- /^([A-Za-z_]\w*.*\))(\?\.)?\[(.+)\]$/.exec(text);
1478
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\))(\?\.)?\[(.+)\]$/.exec(text);
1477
1479
  if (callResultIndex)
1478
1480
  return {
1479
1481
  type: "index",
@@ -1482,7 +1484,7 @@ function expr(source, line, parser) {
1482
1484
  index: expr(callResultIndex[3], line, parser),
1483
1485
  };
1484
1486
  const callResultProperty =
1485
- /^([A-Za-z_]\w*.*\))(\?\.|\.)(\$?[A-Za-z_]\w*)$/.exec(text);
1487
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\))(\?\.|\.)(\$?[A-Za-z_]\w*)$/.exec(text);
1486
1488
  if (callResultProperty)
1487
1489
  return {
1488
1490
  type: "property",
@@ -1491,7 +1493,7 @@ function expr(source, line, parser) {
1491
1493
  name: callResultProperty[3],
1492
1494
  };
1493
1495
  const callResultMethod =
1494
- /^([A-Za-z_]\w*.*\))(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(text);
1496
+ /^(@{0,2}\$?[A-Za-z_]\w*.*\))(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(text);
1495
1497
  if (callResultMethod)
1496
1498
  return {
1497
1499
  type: "methodCall",
@@ -1515,7 +1517,7 @@ function expr(source, line, parser) {
1515
1517
  line: line.number,
1516
1518
  };
1517
1519
  const methodCall =
1518
- /^([A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w*)*?)(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(
1520
+ /^(@{0,2}\$?[A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w*)*?)(\?\.|\.)([A-Za-z_]\w*)\((.*)\)$/.exec(
1519
1521
  text,
1520
1522
  );
1521
1523
  const namespaceMethodCall =
@@ -1569,15 +1571,15 @@ function expr(source, line, parser) {
1569
1571
  return { type: "raw", value: text };
1570
1572
  }
1571
1573
  if (/^(true|false|null)$/.test(text)) return { type: "raw", value: text };
1572
- if (/^[A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w*)*(?:\.|\?\.)_[A-Za-z_]\w*$/.test(text))
1574
+ if (/^@{0,2}\$?[A-Za-z_]\w*(?:(?:\.|\?\.)[A-Za-z_]\w*)*(?:\.|\?\.)_[A-Za-z_]\w*$/.test(text))
1573
1575
  parser.fail(
1574
1576
  line,
1575
1577
  "LNG1115",
1576
1578
  "protected properties are not accessible outside a class",
1577
1579
  );
1578
- if (/^[A-Za-z_]\w*(?:(?:\.|\?\.)\$?[A-Za-z_]\w*|(?:\?\.)?\[(?:\d+|[A-Za-z_]\w*|['"][^'"]*['"])\])+$/.test(text))
1580
+ if (/^@{0,2}\$?[A-Za-z_]\w*(?:(?:\.|\?\.)\$?[A-Za-z_]\w*|(?:\?\.)?\[(?:\d+|[A-Za-z_]\w*|['"][^'"]*['"])\])+$/.test(text))
1579
1581
  return { type: "raw", value: text };
1580
- if (/^[A-Za-z_]\w*\[(?:\d+|[A-Za-z_]\w*|['"][^'"]*['"])\]$/.test(text))
1582
+ if (/^@{0,2}\$?[A-Za-z_]\w*\[(?:\d+|[A-Za-z_]\w*|['"][^'"]*['"])\]$/.test(text))
1581
1583
  return { type: "raw", value: text };
1582
1584
  if (/^(?:\$[A-Za-z_]\w*|@{0,2}\$?[A-Za-z_]\w*)$/.test(text)) return { type: "raw", value: text };
1583
1585
  parser.fail(line, "LNG1108", `unsupported Faz 2 expression: ${text}`);
@@ -3754,15 +3756,10 @@ function emitStatement(node, depth, declared, flags) {
3754
3756
  }
3755
3757
  if (node.type === "assign") {
3756
3758
  const decimalBinding = node.name.startsWith("$") || /^@{1,2}\$/.test(node.name);
3757
- const property = node.name.slice(node.name.startsWith("@@") ? 2 : 1);
3758
3759
  const target = /^[A-Za-z_]\w*(?:\.\$?[A-Za-z_]\w*)+$/.test(node.name)
3759
- ? node.name
3760
- : node.name.startsWith("@@")
3761
- ? `${flags.className}.${property}`
3760
+ ? emitReceiverName(node.name, flags)
3762
3761
  : node.name.startsWith("@")
3763
- ? flags.publicProperties?.has(property)
3764
- ? `this.${property}`
3765
- : `this.#${property}`
3762
+ ? emitReceiverName(node.name, flags)
3766
3763
  : flags.className && node.name.startsWith("_")
3767
3764
  ? `this.${node.name}`
3768
3765
  : node.name;
@@ -3789,7 +3786,7 @@ function emitStatement(node, depth, declared, flags) {
3789
3786
  return `${pad}${prefix}${target} = ${decimalBinding && node.value.type !== "binary" && !decimalLiteral ? `__decimal(${decimalInput})` : value};\n`;
3790
3787
  }
3791
3788
  if (node.type === "indexAssign") {
3792
- const target = `${node.receiver}${(node.indexes ?? [node.index]).map((index) => `[${emitExpr(index, flags)}]`).join("")}`;
3789
+ const target = `${emitReceiverName(node.receiver, flags)}${(node.indexes ?? [node.index]).map((index) => `[${emitExpr(index, flags)}]`).join("")}`;
3793
3790
  const value = emitExpr(node.value, flags);
3794
3791
  if (node.operator) flags.finite = true;
3795
3792
  return `${pad}${target} = ${node.operator ? `__finite(${target} ${node.operator} ${value})` : value};\n`;
@@ -3967,6 +3964,18 @@ function emitBoundaryChecks(parameters, depth, flags) {
3967
3964
  .join("");
3968
3965
  }
3969
3966
  function emitReceiverName(name, flags) {
3967
+ const member = /^(@{1,2})(\$?[A-Za-z_]\w*)(.*)$/.exec(name);
3968
+ if (member) {
3969
+ const [, scope, property, suffix] = member;
3970
+ const owner = scope === "@@" ? flags.className : "this";
3971
+ const visibility = scope === "@@" || flags.publicProperties?.has(property) ? "" : "#";
3972
+ return `${owner}.${visibility}${property}${suffix}`;
3973
+ }
3974
+ const base = /^([A-Za-z_]\w*)([.\[].*)$/.exec(name);
3975
+ if (base && flags.contextNames?.has(base[1])) {
3976
+ flags.context = true;
3977
+ return `__contextGet(${JSON.stringify(base[1])})${base[2]}`;
3978
+ }
3970
3979
  if (!flags.contextNames?.has(name)) return name;
3971
3980
  flags.context = true;
3972
3981
  return `__contextGet(${JSON.stringify(name)})`;
@@ -3985,11 +3994,18 @@ function emitExpr(node, flags) {
3985
3994
  flags.normalize = true;
3986
3995
  return `__normalize(${value})`;
3987
3996
  };
3997
+ if (node.type === "raw")
3998
+ if (/^@{1,2}\$?[A-Za-z_]\w*[.\[?]/.test(node.value))
3999
+ return normalize(emitReceiverName(node.value, flags));
3988
4000
  if (node.type === "raw")
3989
4001
  if (flags.contextNames?.has(node.value)) {
3990
4002
  flags.context = true;
3991
4003
  return `__contextGet(${JSON.stringify(node.value)})`;
3992
4004
  }
4005
+ if (node.type === "raw")
4006
+ if (/^[A-Za-z_]\w*[.\[]/.test(node.value) && flags.contextNames?.has(node.value.split(/[.\[]/)[0])) {
4007
+ return normalize(emitReceiverName(node.value, flags));
4008
+ }
3993
4009
  if (node.type === "raw")
3994
4010
  if (/^DB\.(Active|RollbackOnly|Failed)$/.test(node.value)) {
3995
4011
  flags.databaseEnum = true;