@solvprotocol/upgrade-safe-transpiler
Version:
Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.
58 lines (54 loc) • 1.93 kB
text/typescript
import assert from 'assert';
// Type Identifiers in the AST are for some reason encoded so that they don't
// contain parentheses or commas, which have been substituted as follows:
// ( -> $_
// ) -> _$
// , -> _$_
// This is particularly hard to decode because it is not a prefix-free code.
// Thus, the following regex has to perform a lookahead to make sure it gets
// the substitution right.
export function decodeTypeIdentifier(typeIdentifier: string): string {
return typeIdentifier.replace(/(\$_|_\$_|_\$)(?=(\$_|_\$_|_\$)*([^_$]|$))/g, m => {
switch (m) {
case '$_':
return '(';
case '_$':
return ')';
case '_$_':
return ',';
default:
throw new Error('Unreachable');
}
});
}
// Some Type Identifiers contain a _storage_ptr suffix, but the _ptr part
// appears in some places and not others. We remove it to get consistent type
// ids from the different places in the AST.
export function normalizeTypeIdentifier(typeIdentifier: string): string {
return decodeTypeIdentifier(typeIdentifier).replace(/_storage_ptr\b/g, '_storage');
}
// Type Identifiers contain AST id numbers, which makes them sensitive to
// unrelated changes in the source code. This function stabilizes a type
// identifier by removing all AST ids.
export function stabilizeTypeIdentifier(typeIdentifier: string): string {
let decoded = decodeTypeIdentifier(typeIdentifier);
const re = /(t_struct|t_enum|t_contract)\(/g;
let match;
while ((match = re.exec(decoded))) {
let i;
let d = 1;
for (i = match.index + match[0].length; d !== 0; i++) {
assert(i < decoded.length, 'index out of bounds');
const c = decoded[i];
if (c === '(') {
d += 1;
} else if (c === ')') {
d -= 1;
}
}
const re2 = /\d+_?/y;
re2.lastIndex = i;
decoded = decoded.replace(re2, '');
}
return decoded;
}