Skip to content
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
16 changes: 16 additions & 0 deletions packages/format/src/types/program/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@ testSchemaGuards("ethdebug/format/program/context", [
schema: "schema:ethdebug/format/program/context/frame",
guard: Context.isFrame,
},
{
schema: "schema:ethdebug/format/program/context/function",
guard: Context.Function.isIdentity,
},
{
schema: "schema:ethdebug/format/program/context/function/invoke",
guard: Context.isInvoke,
},
{
schema: "schema:ethdebug/format/program/context/function/return",
guard: Context.isReturn,
},
{
schema: "schema:ethdebug/format/program/context/function/revert",
guard: Context.isRevert,
},
] as const);
172 changes: 168 additions & 4 deletions packages/format/src/types/program/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Materials } from "#types/materials";
import { Type, isType } from "#types/type";
import { Type } from "#types/type";
import { Pointer, isPointer } from "#types/pointer";

export type Context =
Expand All @@ -8,7 +8,10 @@ export type Context =
| Context.Remark
| Context.Pick
| Context.Gather
| Context.Frame;
| Context.Frame
| Context.Invoke
| Context.Return
| Context.Revert;

export const isContext = (value: unknown): value is Context =>
[
Expand All @@ -18,6 +21,9 @@ export const isContext = (value: unknown): value is Context =>
Context.isPick,
Context.isFrame,
Context.isGather,
Context.isInvoke,
Context.isReturn,
Context.isRevert,
].some((guard) => guard(value));

export namespace Context {
Expand Down Expand Up @@ -47,7 +53,7 @@ export namespace Context {
export interface Variable {
identifier?: string;
declaration?: Materials.SourceRange;
type?: Type;
type?: Type.Specifier;
pointer?: Pointer;
}

Expand All @@ -66,7 +72,7 @@ export namespace Context {
(!("identifier" in value) || typeof value.identifier === "string") &&
(!("declaration" in value) ||
Materials.isSourceRange(value.declaration)) &&
(!("type" in value) || isType(value.type)) &&
(!("type" in value) || Type.isSpecifier(value.type)) &&
(!("pointer" in value) || isPointer(value.pointer));
}

Expand Down Expand Up @@ -111,4 +117,162 @@ export namespace Context {
!!value &&
"frame" in value &&
typeof value.frame === "string";

export namespace Function {
export interface Identity {
identifier?: string;
declaration?: Materials.SourceRange;
type?: Type.Specifier;
}

export const isIdentity = (value: unknown): value is Identity =>
typeof value === "object" &&
!!value &&
(!("identifier" in value) || typeof value.identifier === "string") &&
(!("declaration" in value) ||
Materials.isSourceRange(value.declaration)) &&
(!("type" in value) || Type.isSpecifier(value.type));

export interface PointerRef {
pointer: Pointer;
}

export const isPointerRef = (value: unknown): value is PointerRef =>
typeof value === "object" &&
!!value &&
"pointer" in value &&
isPointer(value.pointer);
}

export interface Invoke {
invoke: Invoke.Invocation;
}

export const isInvoke = (value: unknown): value is Invoke =>
typeof value === "object" &&
!!value &&
"invoke" in value &&
Invoke.isInvocation(value.invoke);

export namespace Invoke {
export type Invocation = Function.Identity &
(
| Invocation.InternalCall
| Invocation.ExternalCall
| Invocation.ContractCreation
);

export const isInvocation = (value: unknown): value is Invocation =>
Function.isIdentity(value) &&
(Invocation.isInternalCall(value) ||
Invocation.isExternalCall(value) ||
Invocation.isContractCreation(value));

export namespace Invocation {
export interface InternalCall extends Function.Identity {
jump: true;
target: Function.PointerRef;
arguments?: Function.PointerRef;
}

export const isInternalCall = (value: unknown): value is InternalCall =>
typeof value === "object" &&
!!value &&
"jump" in value &&
value.jump === true &&
"target" in value &&
Function.isPointerRef(value.target) &&
(!("arguments" in value) || Function.isPointerRef(value.arguments));

export interface ExternalCall extends Function.Identity {
message: true;
target: Function.PointerRef;
gas?: Function.PointerRef;
value?: Function.PointerRef;
input?: Function.PointerRef;
delegate?: true;
static?: true;
}

export const isExternalCall = (value: unknown): value is ExternalCall =>
typeof value === "object" &&
!!value &&
"message" in value &&
value.message === true &&
"target" in value &&
Function.isPointerRef(value.target) &&
(!("gas" in value) || Function.isPointerRef(value.gas)) &&
(!("value" in value) || Function.isPointerRef(value.value)) &&
(!("input" in value) || Function.isPointerRef(value.input)) &&
(!("delegate" in value) || value.delegate === true) &&
(!("static" in value) || value.static === true);

export interface ContractCreation extends Function.Identity {
create: true;
value?: Function.PointerRef;
salt?: Function.PointerRef;
input?: Function.PointerRef;
}

export const isContractCreation = (
value: unknown,
): value is ContractCreation =>
typeof value === "object" &&
!!value &&
"create" in value &&
value.create === true &&
(!("value" in value) || Function.isPointerRef(value.value)) &&
(!("salt" in value) || Function.isPointerRef(value.salt)) &&
(!("input" in value) || Function.isPointerRef(value.input));
}
}

export interface Return {
return: Return.Info;
}

export const isReturn = (value: unknown): value is Return =>
typeof value === "object" &&
!!value &&
"return" in value &&
Return.isInfo(value.return);

export namespace Return {
export interface Info extends Function.Identity {
data: Function.PointerRef;
success?: Function.PointerRef;
}

export const isInfo = (value: unknown): value is Info =>
Function.isIdentity(value) &&
typeof value === "object" &&
!!value &&
"data" in value &&
Function.isPointerRef(value.data) &&
(!("success" in value) || Function.isPointerRef(value.success));
}

export interface Revert {
revert: Revert.Info;
}

export const isRevert = (value: unknown): value is Revert =>
typeof value === "object" &&
!!value &&
"revert" in value &&
Revert.isInfo(value.revert);

export namespace Revert {
export interface Info extends Function.Identity {
reason?: Function.PointerRef;
panic?: number;
}

export const isInfo = (value: unknown): value is Info =>
Function.isIdentity(value) &&
typeof value === "object" &&
!!value &&
(!("reason" in value) || Function.isPointerRef(value.reason)) &&
(!("panic" in value) || typeof value.panic === "number");
}
}
15 changes: 15 additions & 0 deletions packages/format/src/types/type/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,19 @@ testSchemaGuards("ethdebug/format/type", [
schema: "schema:ethdebug/format/type/complex/struct",
guard: Type.Complex.isStruct,
},

// type reference and specifier

{
schema: "schema:ethdebug/format/type/reference",
guard: Type.isReference,
},
{
schema: "schema:ethdebug/format/type/specifier",
guard: Type.isSpecifier,
},
{
schema: "schema:ethdebug/format/type/wrapper",
guard: Type.isWrapper,
},
] as const);
20 changes: 17 additions & 3 deletions packages/format/src/types/type/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,30 @@ export namespace Type {
(typeof value.contains === "object" &&
Object.values(value.contains).every(Type.isWrapper)));

export interface Reference {
id: string | number;
}

export const isReference = (value: unknown): value is Reference =>
typeof value === "object" &&
!!value &&
"id" in value &&
(typeof value.id === "string" || typeof value.id === "number");

export type Specifier = Type | Reference;

export const isSpecifier = (value: unknown): value is Specifier =>
isType(value) || isReference(value);

export interface Wrapper {
type: Type | { id: any };
type: Specifier;
}

export const isWrapper = (value: unknown): value is Wrapper =>
typeof value === "object" &&
!!value &&
"type" in value &&
(isType(value.type) ||
(typeof value.type === "object" && !!value.type && "id" in value.type));
isSpecifier(value.type);

export type Elementary =
| Elementary.Uint
Expand Down
Loading