@markw65/monkeyc-optimizer 1.0.42 → 1.0.44

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.
@@ -4731,7 +4731,13 @@ function withLoc(node, start, end) {
4731
4731
  node.end = start.end;
4732
4732
  node.loc = { ...(node.loc || start.loc), start: start.loc.start };
4733
4733
  }
4734
- if (end && end.loc) {
4734
+ if (end === false) {
4735
+ if (node.loc) {
4736
+ node.loc.end = node.loc.start;
4737
+ node.end = node.start;
4738
+ }
4739
+ }
4740
+ else if (end && end.loc) {
4735
4741
  node.end = end.end;
4736
4742
  node.loc = { ...(node.loc || end.loc), end: end.loc.end };
4737
4743
  }
@@ -4783,7 +4789,9 @@ function getNodeValue(node) {
4783
4789
  return [node, "Long"];
4784
4790
  }
4785
4791
  if (type === "string") {
4786
- return [node, "String"];
4792
+ return node.raw.startsWith("'")
4793
+ ? [node, "Char"]
4794
+ : [node, "String"];
4787
4795
  }
4788
4796
  if (type === "boolean") {
4789
4797
  return [node, "Boolean"];
@@ -5092,6 +5100,12 @@ function getArgSafety(state, func, args, requireAll) {
5092
5100
  let allSafe = true;
5093
5101
  if (!args.every((arg, i) => {
5094
5102
  switch (arg.type) {
5103
+ case "UnaryExpression":
5104
+ if (arg.operator === ":") {
5105
+ safeArgs.push(true);
5106
+ return true;
5107
+ }
5108
+ break;
5095
5109
  case "Literal":
5096
5110
  safeArgs.push(true);
5097
5111
  return true;
@@ -5671,7 +5685,16 @@ function inlineWithArgs(state, func, call, context) {
5671
5685
  withLocDeep(body, context, context, true);
5672
5686
  return body;
5673
5687
  }
5674
- function inlineFunction(state, func, call, context) {
5688
+ function isTypecheckArg(node, arg) {
5689
+ return (node.type === "CallExpression" &&
5690
+ node.callee.type === "Identifier" &&
5691
+ node.callee.name === ":typecheck" &&
5692
+ (arg === null ||
5693
+ (node.arguments.length === 1 &&
5694
+ node.arguments[0].type === "Literal" &&
5695
+ node.arguments[0].value === arg)));
5696
+ }
5697
+ function inlineFunctionHelper(state, func, call, context) {
5675
5698
  if (context) {
5676
5699
  return inlineWithArgs(state, func, call, context);
5677
5700
  }
@@ -5682,6 +5705,33 @@ function inlineFunction(state, func, call, context) {
5682
5705
  state.localsStack[state.localsStack.length - 1].map = map;
5683
5706
  return ret && withLocDeep(ret, call, call, true);
5684
5707
  }
5708
+ function inlineFunction(state, func, call, context) {
5709
+ const ret = inlineFunctionHelper(state, func, call, context);
5710
+ if (!ret)
5711
+ return ret;
5712
+ const typecheckFalse = func.node.attrs?.attributes?.elements.find((attr) => isTypecheckArg(attr, false));
5713
+ if (!typecheckFalse) {
5714
+ return ret;
5715
+ }
5716
+ const callerSn = state.stack.find((sn) => sn.type === "FunctionDeclaration");
5717
+ if (!callerSn) {
5718
+ return ret;
5719
+ }
5720
+ const caller = callerSn.node;
5721
+ if (!caller.attrs) {
5722
+ caller.attrs = withLoc({
5723
+ type: "AttributeList",
5724
+ }, caller, false);
5725
+ }
5726
+ if (!caller.attrs.attributes) {
5727
+ caller.attrs.attributes = withLoc({ type: "Attributes", elements: [] }, caller.attrs, false);
5728
+ }
5729
+ if (caller.attrs.attributes.elements.find((attr) => isTypecheckArg(attr, null))) {
5730
+ return ret;
5731
+ }
5732
+ caller.attrs.attributes.elements.unshift(withLocDeep({ ...typecheckFalse }, caller.attrs, false));
5733
+ return ret;
5734
+ }
5685
5735
  function applyTypeIfNeeded(node) {
5686
5736
  if ("enumType" in node && node.enumType) {
5687
5737
  node = {
@@ -5837,7 +5887,7 @@ function pragmaChecker(state, ast, diagnostics) {
5837
5887
  if (quote == '"') {
5838
5888
  return haystack.includes(needle);
5839
5889
  }
5840
- const re = new RegExp(needle.replace(/@([\d\w]+)/g, "(pre_)?$1(_\\d+)?"));
5890
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/[".]/g, "_")}(?:_\\d+)?)`));
5841
5891
  return re.test(haystack);
5842
5892
  };
5843
5893
  next();
@@ -7784,7 +7834,7 @@ function getLiteralNode(node) {
7784
7834
  case "-": {
7785
7835
  const [arg, type] = getNodeValue(node.argument);
7786
7836
  if (type === "Number" || type === "Long") {
7787
- return replacementLiteral(arg, -arg.value, type);
7837
+ return replacementLiteral(node, -arg.value, type);
7788
7838
  }
7789
7839
  }
7790
7840
  }
@@ -7834,8 +7884,14 @@ function isBooleanExpression(state, node) {
7834
7884
  }
7835
7885
  return false;
7836
7886
  }
7887
+ function roundToFloat(value) {
7888
+ return new Float32Array([value])[0];
7889
+ }
7837
7890
  function replacementLiteral(arg, value, type) {
7838
- if (typeof value === "boolean") {
7891
+ if (value === null) {
7892
+ type = "Null";
7893
+ }
7894
+ else if (typeof value === "boolean") {
7839
7895
  type = "Boolean";
7840
7896
  }
7841
7897
  else if (type === "Number") {
@@ -7844,32 +7900,189 @@ function replacementLiteral(arg, value, type) {
7844
7900
  else if (type === "Long") {
7845
7901
  value = BigInt.asIntN(64, BigInt(value));
7846
7902
  }
7903
+ else if (type === "Float") {
7904
+ value = roundToFloat(Number(value));
7905
+ }
7906
+ let raw = type === "String"
7907
+ ? JSON.stringify(value)
7908
+ : type === "Char"
7909
+ ? value === "'"
7910
+ ? "'\\''"
7911
+ : "'" + JSON.stringify(value).slice(1, -1) + "'"
7912
+ : value == null
7913
+ ? "null"
7914
+ : value.toString();
7915
+ if (type === "Long") {
7916
+ raw += "l";
7917
+ }
7918
+ else if (type === "Double") {
7919
+ raw += "d";
7920
+ }
7921
+ else if (type === "Float" && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
7922
+ raw += "f";
7923
+ }
7924
+ const { start, end, loc } = arg;
7847
7925
  return {
7848
- ...arg,
7926
+ type: "Literal",
7849
7927
  value,
7850
- raw: value.toString() + (type === "Long" ? "l" : ""),
7928
+ raw,
7929
+ start,
7930
+ end,
7931
+ loc,
7851
7932
  };
7852
7933
  }
7934
+ function classify(arg) {
7935
+ switch (arg) {
7936
+ case "Number":
7937
+ return { big: false, int: true };
7938
+ case "Long":
7939
+ return { big: true, int: true };
7940
+ case "Float":
7941
+ return { big: false, int: false };
7942
+ case "Double":
7943
+ return { big: true, int: false };
7944
+ }
7945
+ return null;
7946
+ }
7947
+ function common_arith_types(left, right) {
7948
+ const l = classify(left);
7949
+ if (!l)
7950
+ return null;
7951
+ const r = classify(right);
7952
+ if (!r)
7953
+ return null;
7954
+ if (l.big || r.big) {
7955
+ return l.int && r.int
7956
+ ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
7957
+ : ["Double", (v) => Number(v)];
7958
+ }
7959
+ else {
7960
+ return l.int && r.int
7961
+ ? ["Number", (v) => BigInt.asIntN(32, BigInt(v))]
7962
+ : ["Float", (v) => roundToFloat(Number(v))];
7963
+ }
7964
+ }
7965
+ function common_bitwise_types(left, right) {
7966
+ if (left === "Boolean" && right === "Boolean") {
7967
+ return ["Boolean", (v) => (v ? true : false)];
7968
+ }
7969
+ const l = classify(left);
7970
+ if (!l)
7971
+ return null;
7972
+ const r = classify(right);
7973
+ if (!r)
7974
+ return null;
7975
+ if (!l.int || !r.int)
7976
+ return null;
7977
+ return l.big || r.big
7978
+ ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
7979
+ : ["Number", (v) => Number(BigInt.asIntN(32, BigInt(v)))];
7980
+ }
7981
+ function plus_types(left, right) {
7982
+ if (left === "String" || right === "String") {
7983
+ // Boolean + String is an error, and
7984
+ // Float/Double + String is legal, but its hard to predict
7985
+ // the way the float will be formatted (and it won't match
7986
+ // what javascript would do by default)
7987
+ if (/Float|Double|Boolean/.test(left + right)) {
7988
+ return null;
7989
+ }
7990
+ return ["String", String];
7991
+ }
7992
+ if (left === "Char" || right === "Char") {
7993
+ if (left === right) {
7994
+ // adding two chars produces a string
7995
+ return ["String", String];
7996
+ }
7997
+ if (/Number|Long/.test(left + right)) {
7998
+ return ["Char", (v) => v];
7999
+ }
8000
+ }
8001
+ return common_arith_types(left, right);
8002
+ }
8003
+ function shift_mod_types(left, right) {
8004
+ const result = common_bitwise_types(left, right);
8005
+ if (result && result[0] === "Boolean") {
8006
+ return null;
8007
+ }
8008
+ return result;
8009
+ }
7853
8010
  const operators = {
7854
- "+": (left, right) => left + right,
7855
- "-": (left, right) => left - right,
7856
- "*": (left, right) => left * right,
7857
- "/": (left, right) => left / right,
7858
- "%": (left, right) => left % right,
7859
- "&": (left, right) => left & right,
7860
- "|": (left, right) => left | right,
7861
- "^": (left, right) => left ^ right,
7862
- "<<": (left, right) => left << (right & 127n),
7863
- ">>": (left, right) => left >> (right & 127n),
7864
- "==": (left, right) =>
7865
- // two string literals will compare unequal, becuase string
7866
- // equality is object equality.
7867
- typeof left === "string" ? false : left === right,
7868
- "!=": (left, right) => typeof left === "string" ? true : left !== right,
7869
- "<=": (left, right) => left <= right,
7870
- ">=": (left, right) => left >= right,
7871
- "<": (left, right) => left < right,
7872
- ">": (left, right) => left > right,
8011
+ "+": {
8012
+ typeFn: plus_types,
8013
+ valueFn: (left, right) => typeof left === "string" && typeof right !== "string"
8014
+ ? String.fromCharCode(left.charCodeAt(0) + Number(right))
8015
+ : typeof left !== "string" && typeof right === "string"
8016
+ ? String.fromCharCode(right.charCodeAt(0) + Number(left))
8017
+ : left + right,
8018
+ },
8019
+ "-": {
8020
+ typeFn: common_arith_types,
8021
+ valueFn: (left, right) => left - right,
8022
+ },
8023
+ "*": {
8024
+ typeFn: common_arith_types,
8025
+ valueFn: (left, right) => left * right,
8026
+ },
8027
+ "/": {
8028
+ typeFn: common_arith_types,
8029
+ valueFn: (left, right) => left / right,
8030
+ },
8031
+ "%": {
8032
+ typeFn: shift_mod_types,
8033
+ valueFn: (left, right) => left % right,
8034
+ },
8035
+ "&": {
8036
+ typeFn: common_bitwise_types,
8037
+ valueFn: (left, right) => left & right,
8038
+ },
8039
+ "|": {
8040
+ typeFn: common_bitwise_types,
8041
+ valueFn: (left, right) => left | right,
8042
+ },
8043
+ "^": {
8044
+ typeFn: common_bitwise_types,
8045
+ valueFn: (left, right) => left ^ right,
8046
+ },
8047
+ "<<": {
8048
+ typeFn: shift_mod_types,
8049
+ valueFn: (left, right) => typeof right === "bigint"
8050
+ ? left << right
8051
+ : left << right,
8052
+ },
8053
+ ">>": {
8054
+ typeFn: shift_mod_types,
8055
+ valueFn: (left, right) => typeof right === "bigint"
8056
+ ? left >> right
8057
+ : left >> right,
8058
+ },
8059
+ "==": {
8060
+ typeFn: () => ["Boolean", (v) => v],
8061
+ valueFn: (left, right) =>
8062
+ // two string literals will compare unequal, becuase string
8063
+ // equality is object equality.
8064
+ typeof left === "string" ? false : left === right,
8065
+ },
8066
+ "!=": {
8067
+ typeFn: () => ["Boolean", (v) => v],
8068
+ valueFn: (left, right) => typeof left === "string" ? true : left !== right,
8069
+ },
8070
+ "<=": {
8071
+ typeFn: common_arith_types,
8072
+ valueFn: (left, right) => left <= right,
8073
+ },
8074
+ ">=": {
8075
+ typeFn: common_arith_types,
8076
+ valueFn: (left, right) => left >= right,
8077
+ },
8078
+ "<": {
8079
+ typeFn: common_arith_types,
8080
+ valueFn: (left, right) => left < right,
8081
+ },
8082
+ ">": {
8083
+ typeFn: common_arith_types,
8084
+ valueFn: (left, right) => left > right,
8085
+ },
7873
8086
  as: null,
7874
8087
  instanceof: null,
7875
8088
  has: null,
@@ -7882,23 +8095,31 @@ function optimizeNode(state, node) {
7882
8095
  break;
7883
8096
  switch (node.operator) {
7884
8097
  case "+":
7885
- if (type === "Number" || type === "Long") {
8098
+ if (type === "Number" ||
8099
+ type === "Long" ||
8100
+ type === "Float" ||
8101
+ type === "Double" ||
8102
+ type === "Char" ||
8103
+ type === "String") {
7886
8104
  return arg;
7887
8105
  }
7888
8106
  break;
7889
8107
  case "-":
7890
- if (type === "Number" || type === "Long") {
7891
- return replacementLiteral(arg, -arg.value, type);
8108
+ if (type === "Number" ||
8109
+ type === "Long" ||
8110
+ type === "Float" ||
8111
+ type === "Double") {
8112
+ return replacementLiteral(node, -arg.value, type);
7892
8113
  }
7893
8114
  break;
7894
8115
  case "!":
7895
8116
  case "~":
7896
8117
  {
7897
8118
  if (type === "Number" || type === "Long") {
7898
- return replacementLiteral(arg, ~BigInt(arg.value), type);
8119
+ return replacementLiteral(node, ~BigInt(arg.value), type);
7899
8120
  }
7900
8121
  if (type === "Boolean" && node.operator == "!") {
7901
- return replacementLiteral(arg, !arg.value, type);
8122
+ return replacementLiteral(node, !arg.value, type);
7902
8123
  }
7903
8124
  }
7904
8125
  break;
@@ -7912,23 +8133,13 @@ function optimizeNode(state, node) {
7912
8133
  const [right, right_type] = getNodeValue(node.right);
7913
8134
  if (!left || !right)
7914
8135
  break;
7915
- let value = null;
7916
- let type;
7917
- if ((left_type != "Number" && left_type != "Long") ||
7918
- left_type != right_type) {
7919
- if (node.operator !== "==" && node.operator !== "!=") {
7920
- break;
7921
- }
7922
- value = operators[node.operator](left.value, right.value);
7923
- type = "Boolean";
7924
- }
7925
- else {
7926
- type = left_type;
7927
- value = op(BigInt(left.value), BigInt(right.value));
7928
- }
8136
+ const type = op.typeFn(left_type, right_type);
8137
+ if (!type)
8138
+ break;
8139
+ const value = op.valueFn(type[1](left.value), type[1](right.value));
7929
8140
  if (value === null)
7930
8141
  break;
7931
- return replacementLiteral(left, value, type);
8142
+ return replacementLiteral(node, value, type[0]);
7932
8143
  }
7933
8144
  break;
7934
8145
  }
@@ -9218,7 +9429,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9218
9429
  // the oldest optimized file, we don't need to regenerate
9219
9430
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
9220
9431
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
9221
- if (source_time < opt_time && 1670349312602 < opt_time) {
9432
+ if (source_time < opt_time && 1670782882733 < opt_time) {
9222
9433
  return { hasTests, diagnostics: prevDiagnostics };
9223
9434
  }
9224
9435
  }
@@ -9245,7 +9456,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9245
9456
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
9246
9457
  hasTests,
9247
9458
  diagnostics,
9248
- optimizerVersion: "1.0.42",
9459
+ optimizerVersion: "1.0.44",
9249
9460
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
9250
9461
  }))
9251
9462
  .then(() => ({ hasTests, diagnostics }));