Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add { $wordsized: <expression> } expression #93

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/pointers/src/evaluate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
});
});
4 changes: 3 additions & 1 deletion packages/pointers/src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ async function evaluateResize(
): Promise<Data> {
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);
}
Expand Down
50 changes: 38 additions & 12 deletions packages/pointers/src/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,22 +381,48 @@ export namespace Pointer {
export const isKeccak256 =
makeIsOperation<"$keccak256", Keccak256>("$keccak256", isOperands);

export type Resize<N extends number = number> = {
[K in `$sized${N}`]: Expression;
}
export type Resize<N extends number = number> =
| Resize.ToNumber<N>
| Resize.ToWordsize;
export const isResize = <N extends number>(
value: unknown
): value is Resize<N> => {
if (
!value ||
typeof value !== "object" ||
Object.keys(value).length !== 1
) {
return false;
): value is Resize<N> =>
[
Resize.isToWordsize,
Resize.isToNumber,
].some(guard => guard(value));

export namespace Resize {
export type ToNumber<N extends number> = {
[K in `$sized${N}`]: Expression;
};
export const isToNumber = <N extends number>(
value: unknown
): value is ToNumber<N> => {
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);
}
}
}
2 changes: 1 addition & 1 deletion schemas/pointer.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 23 additions & 10 deletions schemas/pointer/expression.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,15 @@ $defs:
Resize:
title: Resize data
description: |
An object of the form `{ "$sized<N>": <expression> }`, where `<N>` is the
smallest decimal representation of an unsigned integer and where
`<expression>` is another expression.

This object's value is evaluated as follows, based on the number
represented by `<N>` and the bytes width of `<expression>`:
A resize operation expression is either an object of the form
`{ "$sized<N>": <expression> }` or an object of the form
`{ "$wordsized": <expression> }`, where `<expression>` is an expression
whose value is to be resized, and, if applicable, where `<N>` 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 `<expression>` evaluates to and based on `<N>` (using the
value of `"$wordsize"` for `<N>` in the case of the latter form above):
- If the width equals `<N>`, this object evalutes to the same value as
`<expression>` (equivalent to the identity function or no-op).
- If the width is less than `<N>`, this object evalutes to the same value
Expand All @@ -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
Expand Down
Loading