diff --git a/packages/pointers/src/evaluate.test.ts b/packages/pointers/src/evaluate.test.ts index 16bcf574..ee256b0c 100644 --- a/packages/pointers/src/evaluate.test.ts +++ b/packages/pointers/src/evaluate.test.ts @@ -226,5 +226,11 @@ describe("evaluate", () => { expect(data).toHaveLength(1); expect(data).toEqual(Data.fromNumber(0xcd)); } + + { + const data = await evaluate({ $wordsized: "0xabcd" }, options); + expect(data).toHaveLength(32); + expect(data).toEqual(Data.fromNumber(0xabcd).resizeTo(32)); + } }); }); diff --git a/packages/pointers/src/evaluate.ts b/packages/pointers/src/evaluate.ts index 8c42ead1..b3db2205 100644 --- a/packages/pointers/src/evaluate.ts +++ b/packages/pointers/src/evaluate.ts @@ -227,7 +227,9 @@ async function evaluateResize( ): Promise { const [[operation, subexpression]] = Object.entries(expression); - const newLength = Number(operation.match(/^\$sized([1-9]+[0-9]*)$/)![1]); + const newLength = Pointer.Expression.Resize.isToNumber(expression) + ? Number(operation.match(/^\$sized([1-9]+[0-9]*)$/)![1]) + : 32; return (await evaluate(subexpression, options)).resizeTo(newLength); } diff --git a/packages/pointers/src/pointer.ts b/packages/pointers/src/pointer.ts index 1969ae24..8d37bd53 100644 --- a/packages/pointers/src/pointer.ts +++ b/packages/pointers/src/pointer.ts @@ -381,22 +381,48 @@ export namespace Pointer { export const isKeccak256 = makeIsOperation<"$keccak256", Keccak256>("$keccak256", isOperands); - export type Resize = { - [K in `$sized${N}`]: Expression; - } + export type Resize = + | Resize.ToNumber + | Resize.ToWordsize; export const isResize = ( value: unknown - ): value is Resize => { - if ( - !value || - typeof value !== "object" || - Object.keys(value).length !== 1 - ) { - return false; + ): value is Resize => + [ + Resize.isToWordsize, + Resize.isToNumber, + ].some(guard => guard(value)); + + export namespace Resize { + export type ToNumber = { + [K in `$sized${N}`]: Expression; + }; + export const isToNumber = ( + value: unknown + ): value is ToNumber => { + if ( + !value || + typeof value !== "object" || + Object.keys(value).length !== 1 + ) { + return false; + } + const [key] = Object.keys(value); + + return typeof key === "string" && /^\$sized([1-9]+[0-9]*)$/.test(key); + }; + + export type ToWordsize = { + $wordsized: Expression; } - const [key] = Object.keys(value); + export const isToWordsize = (value: unknown): value is ToWordsize => + !!value && + typeof value === "object" && + Object.keys(value).length === 1 && + "$wordsized" in value && + typeof value.$wordsized !== "undefined" && + isExpression(value.$wordsized); + - return typeof key === "string" && /^\$sized([1-9]+[0-9]*)$/.test(key); } } } diff --git a/schemas/pointer.schema.yaml b/schemas/pointer.schema.yaml index 9db4a26d..789e23d0 100644 --- a/schemas/pointer.schema.yaml +++ b/schemas/pointer.schema.yaml @@ -194,7 +194,7 @@ examples: "start-slot": $keccak256: - - $sized32: "contract-variable-slot" + - $wordsized: "contract-variable-slot" "total-slots": # account for both zero and nonzero slot remainders by adding diff --git a/schemas/pointer/expression.schema.yaml b/schemas/pointer/expression.schema.yaml index 7f79feed..70814822 100644 --- a/schemas/pointer/expression.schema.yaml +++ b/schemas/pointer/expression.schema.yaml @@ -199,12 +199,15 @@ $defs: Resize: title: Resize data description: | - An object of the form `{ "$sized": }`, where `` is the - smallest decimal representation of an unsigned integer and where - `` is another expression. - - This object's value is evaluated as follows, based on the number - represented by `` and the bytes width of ``: + A resize operation expression is either an object of the form + `{ "$sized": }` or an object of the form + `{ "$wordsized": }`, where `` is an expression + whose value is to be resized, and, if applicable, where `` is the + smallest decimal representation of an unsigned integer. + + This object's value is evaluated as follows, based on the bytes width of + the value `` evaluates to and based on `` (using the + value of `"$wordsize"` for `` in the case of the latter form above): - If the width equals ``, this object evalutes to the same value as `` (equivalent to the identity function or no-op). - If the width is less than ``, this object evalutes to the same value @@ -218,15 +221,25 @@ $defs: (These cases match the behavior that Solidity uses for resizing its `bytesN`/`uintN` types.) type: object - additionalProperties: false - patternProperties: - "^\\$sized([1-9]+[0-9]*)$": - $ref: "schema:ethdebug/format/pointer/expression" + oneOf: + - title: Resize to literal number of bytes + type: object + patternProperties: + "^\\$sized([1-9]+[0-9]*)$": + $ref: "schema:ethdebug/format/pointer/expression" + additionalProperties: false + - title: Resize to word-size + type: object + patternProperties: + "^\\$wordsized$": + $ref: "schema:ethdebug/format/pointer/expression" + additionalProperties: false minProperties: 1 maxProperties: 1 examples: - $sized2: "0x00" # 0x0000 - $sized2: "0xffffff" # 0xffff + - $wordsized: "0x00" # 0x0000000000000000000000000000000000000000000000000000000000000000 examples: - 0