@cashscript/utils 0.13.0 → 0.13.2

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.
@@ -48,6 +48,11 @@ const PROLOGUE_KINDS = [
48
48
  SourceTagKind.LOCKTIME_GUARD,
49
49
  SourceTagKind.PARAMETER_VALIDATION,
50
50
  ];
51
+ // Compiler-injected epilogue checks: emitted after the function/loop body
52
+ const EPILOGUE_KINDS = [
53
+ SourceTagKind.SCOPE_CLEANUP,
54
+ SourceTagKind.LOOP_CONDITION,
55
+ ];
51
56
  function buildInsertions(locationData, sourceLines, sourceTags) {
52
57
  const tags = (sourceTags ? parseSourceTags(sourceTags) : []);
53
58
  return tags.map((tag) => {
@@ -70,6 +75,14 @@ function deriveAnchor(tag, tags, locationData, sourceLines) {
70
75
  indent: lineIndent(sourceLines, firstBodyLine),
71
76
  };
72
77
  }
78
+ // Scope cleanup and loop-back condition tags always get inserted right before the scope's closing brace.
79
+ if (EPILOGUE_KINDS.includes(tag.kind)) {
80
+ const braceLine = getDisplayLine(locationData[tag.startIndex]);
81
+ return {
82
+ insertAfterLine: braceLine - 1,
83
+ indent: deriveIndent(locationData[tag.startIndex].location.start.line, sourceLines),
84
+ };
85
+ }
73
86
  return {
74
87
  insertAfterLine: getDisplayLine(locationData[Math.max(tag.startIndex - 1, 0)]),
75
88
  indent: deriveIndent(getDisplayLine(locationData[tag.startIndex]), sourceLines),
@@ -113,6 +126,10 @@ function tagDescription(tag, locationData, sourceLines) {
113
126
  const parameter = deriveSourceText(tag, locationData, sourceLines);
114
127
  return `>>> parameter type check${parameter ? ` (${parameter})` : ''}`;
115
128
  }
129
+ case SourceTagKind.SCOPE_CLEANUP:
130
+ return '>>> scope cleanup';
131
+ case SourceTagKind.LOOP_CONDITION:
132
+ return '>>> loop condition check';
116
133
  case SourceTagKind.FOR_UPDATE:
117
134
  default:
118
135
  return `>>> for-loop update (${deriveSourceText(tag, locationData, sourceLines)})`;
package/dist/script.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { encodeDataPush, hexToBin, disassembleBytecodeBch, flattenBinArray, encodeAuthenticationInstructions, decodeAuthenticationInstructions, OpcodesBch, } from '@bitauth/libauth';
2
2
  import OptimisationsEquivFile from './cashproof-optimisations.js';
3
3
  import { optimisationReplacements } from './optimisations.js';
4
- import { PositionHint } from './types.js';
4
+ import { range } from './data.js';
5
+ import { PositionHint, SourceTagKind } from './types.js';
5
6
  export const Op = OpcodesBch;
6
7
  export function scriptToAsm(script) {
7
8
  return bytecodeToAsm(scriptToBytecode(script));
@@ -120,7 +121,24 @@ export function optimiseBytecode(script, locationData, logs, requires, sourceTag
120
121
  requires = newRequires;
121
122
  sourceTags = newSourceTags;
122
123
  }
123
- return { script, locationData, logs, requires, sourceTags };
124
+ return { script, locationData, logs, requires, sourceTags: reconcileScopeCleanupTags(script, sourceTags) };
125
+ }
126
+ const SCOPE_CLEANUP_OPCODES = [Op.OP_DROP, Op.OP_NIP, Op.OP_2DROP];
127
+ // Make sure that scope cleanup tags are only displayed if they did not merge with other tags or drift
128
+ // due to compiler optimisations.
129
+ function reconcileScopeCleanupTags(script, sourceTags) {
130
+ const otherTags = sourceTags.filter((tag) => tag.kind !== SourceTagKind.SCOPE_CLEANUP);
131
+ return sourceTags.filter((tag) => {
132
+ if (tag.kind !== SourceTagKind.SCOPE_CLEANUP)
133
+ return true;
134
+ const isOnlyCleanupOpcodes = range(tag.startIndex, tag.endIndex)
135
+ .every((index) => SCOPE_CLEANUP_OPCODES.includes(script[index]));
136
+ if (!isOnlyCleanupOpcodes)
137
+ return false;
138
+ const overlapsOtherTag = otherTags
139
+ .some((other) => tag.startIndex <= other.endIndex && other.startIndex <= tag.endIndex);
140
+ return !overlapsOtherTag;
141
+ });
124
142
  }
125
143
  export function optimiseBytecodeOld(script, runs = 1000) {
126
144
  const optimisations = OptimisationsEquivFile
package/dist/types.d.ts CHANGED
@@ -54,7 +54,9 @@ export declare enum PositionHint {
54
54
  export declare enum SourceTagKind {
55
55
  FOR_UPDATE = "fu",
56
56
  LOCKTIME_GUARD = "lg",
57
- PARAMETER_VALIDATION = "pv"
57
+ PARAMETER_VALIDATION = "pv",
58
+ SCOPE_CLEANUP = "sc",
59
+ LOOP_CONDITION = "lc"
58
60
  }
59
61
  export interface SourceTagEntry {
60
62
  startIndex: number;
package/dist/types.js CHANGED
@@ -197,5 +197,7 @@ export var SourceTagKind;
197
197
  SourceTagKind["FOR_UPDATE"] = "fu";
198
198
  SourceTagKind["LOCKTIME_GUARD"] = "lg";
199
199
  SourceTagKind["PARAMETER_VALIDATION"] = "pv";
200
+ SourceTagKind["SCOPE_CLEANUP"] = "sc";
201
+ SourceTagKind["LOOP_CONDITION"] = "lc";
200
202
  })(SourceTagKind || (SourceTagKind = {}));
201
203
  //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cashscript/utils",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "CashScript utilities and types",
5
5
  "keywords": [
6
6
  "bitcoin cash",
@@ -48,5 +48,5 @@
48
48
  "typescript": "^5.9.2",
49
49
  "vitest": "^4.0.15"
50
50
  },
51
- "gitHead": "a3461662016a2f3dad36431ba5a2b148bcc4dc75"
51
+ "gitHead": "a4f112abb0d035ecf018ebc694e2b081f25b3409"
52
52
  }