Skip to content

Commit

Permalink
[wip]
Browse files Browse the repository at this point in the history
  • Loading branch information
gnidan committed Feb 5, 2024
1 parent 9191985 commit d038781
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 39 deletions.
65 changes: 65 additions & 0 deletions packages/web/spec/pointer/expression.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,106 @@ import SchemaViewer from "@site/src/components/SchemaViewer";

# Expression syntax

Pointer expressions operate on the domain of bytes representing unsigned
integers.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
/>

## Literal values

An expression can be a literal value.

Literal values **must** be represented either as JSON numbers or as
`0x`-prefixed hexadecimal strings. Hexadecimal strings always represent a
literal string of bytes.

For convenience, this schema does not restrict hexadecimal string
representations to those that specify an even-number of digits (i.e., those
that specify complete byte pairs); odd numbers of hexadecimal digits are fine.

Hexadecimal string representations **may** omit leading zeroes; values are
assumed to be left-padded to the bytes width appropriate for the context.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Literal"
/>

## Scalar variables

An expression can be a string value equal to the identifier for a known
scalar variable introduced by some pointer representation.

For an example where scalar variables may appear, see the
[List collection schema](/spec/pointer/collection/list).

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Literal"
/>

## Arithmetic operations

An expression can be an object of the form `{ <op>: [...] }`, where `<op>`
denotes an arithmetic operation.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Arithmetic"
/>

## Lookup region definition

An expression can reference properties defined for a particular region, such as
another region's `"offset"` or `"length"`. Such expressions resolve to the
same value as the expression specified for that corresponding property.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Lookup"
/>

## Reading from the EVM

An expression can be an object of the form `{ "$read": "<region>" }`, where
`<region>` references a particular region defined in some root pointer.

The value of such an expression is the concatenation of bytes present in the
running machine state that correspond to the bytes addressed by the referenced
region.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Read"
/>

## Keccak256 hashes

An expression can be an object of form `{ "$keccak256": [...] }`, indicating
that the value of the expression is a Solidity-style, tightly-packed keccak256
hash of the concatenation of bytes specified by the list.

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Keccak256"
/>

## Region references

Regions can be referenced either by name (which **must** be a defined region),
or by use of the literal string value `"$this"` (which indicates that the
referenced region is the region containing the expression itself).

In cases where an expression is used outside the context of a particular
region definition, the use of `"$this"` is **prohibited**.

Individual properties **may not** be defined with any reference to themselves.
Properties also **may not** be defined in terms of mutual reference to each
other. <small>(Don't make this harder than it has to be.)</small>

<SchemaViewer
schema={{ id: "schema:ethdebug/format/pointer/expression" }}
pointer="#/$defs/Reference"
/>
14 changes: 14 additions & 0 deletions packages/web/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export const schemaIndex: SchemaIndex = {
href: "/spec/type/complex/function#parameters-schema"
},

"schema:ethdebug/format/pointer": {
href: "/spec/pointer"
},

"schema:ethdebug/format/pointer/region": {
href: "/spec/pointer/region"
},
Expand Down Expand Up @@ -127,6 +131,11 @@ export const schemaIndex: SchemaIndex = {
href: "/spec/pointer/expression#arithmetic-operations"
},

"schema:ethdebug/format/pointer/expression#/$defs/Lookup": {
title: "Lookup expression schema",
href: "/spec/pointer/expression#lookup-region-definition"
},

"schema:ethdebug/format/pointer/expression#/$defs/Read": {
title: "Read expression schema",
href: "/spec/pointer/expression#reading-from-the-evm"
Expand All @@ -136,4 +145,9 @@ export const schemaIndex: SchemaIndex = {
title: "Keccak256 hash expression schema",
href: "/spec/pointer/expression#keccak256-hashes"
},

"schema:ethdebug/format/pointer/expression#/$defs/Reference": {
title: "Region reference",
href: "/spec/pointer/expression#region-references"
},
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from "react";
import type { JSONSchema } from "json-schema-typed/draft-2020-12";
import CreateNodes from "@theme-original/JSONSchemaViewer/components/CreateNodes";
import CreateNodes from "@theme/JSONSchemaViewer/components/CreateNodes";
import CreateEdge from "@theme-original/JSONSchemaViewer/components/CreateEdge";
import { SchemaHierarchyComponent } from "@theme-original/JSONSchemaViewer/contexts"
import { Collapsible } from "@theme/JSONSchemaViewer/components";
import { GenerateFriendlyName, QualifierMessages } from "@theme/JSONSchemaViewer/utils";
import { internalIdKey } from "@site/src/contexts/SchemaContext";
import { CreateDescription } from "@theme/JSONSchemaViewer/JSONSchemaElements";
import { useJSVOptionsContext } from "@theme/JSONSchemaViewer/contexts"

export interface UnnecessaryComposition {
schemaWithoutUnnecessaryComposition: JSONSchema;
schemaWithoutUnnecessaryComposition: Exclude<JSONSchema, boolean>;
unnecessaryCompositionKeyword: "allOf" | "oneOf" | "anyOf";
unnecessarilyComposedSchema: JSONSchema;
}

Expand All @@ -14,17 +22,17 @@ export function detectUnnecessaryComposition(
return;
}

const redundantKeywords = (["allOf", "oneOf", "anyOf"] as const)
const unnecessaryCompositionKeywords = (["allOf", "oneOf", "anyOf"] as const)
.filter(keyword => keyword in schema && (schema[keyword] || []).length === 1);

if (redundantKeywords.length !== 1) {
if (unnecessaryCompositionKeywords.length !== 1) {
return;
}

const [redundantKeyword] = redundantKeywords;
const [unnecessaryCompositionKeyword] = unnecessaryCompositionKeywords;

const {
[redundantKeyword]: composition,
[unnecessaryCompositionKeyword]: composition,
...schemaWithoutUnnecessaryComposition
} = schema;

Expand All @@ -33,6 +41,7 @@ export function detectUnnecessaryComposition(

return {
unnecessarilyComposedSchema,
unnecessaryCompositionKeyword,
schemaWithoutUnnecessaryComposition
};
}
Expand All @@ -42,29 +51,94 @@ export interface UnnecessaryCompositionSchemaProps extends UnnecessaryCompositio

export default function UnnecessaryCompositionSchema({
schemaWithoutUnnecessaryComposition,
unnecessaryCompositionKeyword,
unnecessarilyComposedSchema
}: UnnecessaryCompositionSchemaProps): JSX.Element {
const unnecessarilyComposedSchemaNecessities = removeDocumentingFields(
unnecessarilyComposedSchema
);
const jsvOptions = useJSVOptionsContext();

// treat the unnecessary composition to represent the extension of a base
// schema, where the unnecessarily composed schema is the base
const baseSchema = unnecessarilyComposedSchema;
const extensionSchema = schemaWithoutUnnecessaryComposition;
const {
documentation,
semantics
} = separateDocumentationFromSemantics(extensionSchema);

if (Object.keys(semantics).length === 0) {
const { description } = documentation;

return <>
<QualifierMessages schema={documentation} options={jsvOptions} />
{description && <CreateDescription description={description} />}
<hr />

<SchemaHierarchyComponent
innerJsonPointer={`/${unnecessaryCompositionKeyword}/0`}
>
<CreateNodes schema={unnecessarilyComposedSchema} />
</SchemaHierarchyComponent>
</>;
}

return (
<>
<span className="badge badge--info">extensions</span>&nbsp;
These extensions apply to the base schema below:
<p>
<CreateNodes schema={extensionSchema} />
</p>

<Collapsible
summary={
<>
<strong><GenerateFriendlyName schema={baseSchema} /></strong>&nbsp;
<span className="badge badge--info">base schema</span>
</>
}
detailsProps={{
open: true
}}
>
<SchemaHierarchyComponent
innerJsonPointer={`/${unnecessaryCompositionKeyword}/0`}
>
<CreateNodes schema={unnecessarilyComposedSchema} />
</SchemaHierarchyComponent>
</Collapsible>

</>
);
}

function removeDocumentingFields(schema: JSONSchema): JSONSchema {
function separateDocumentationFromSemantics(schema: JSONSchema): {
documentation: Exclude<JSONSchema, boolean>,
semantics: JSONSchema
} {
if (typeof schema === "boolean") {
return schema;
return {
documentation: {},
semantics: schema
};
}

const {
title,
description,
examples,
...schemaNecessities
default: default_,
// @ts-ignore
[internalIdKey]: _id,
...semantics
} = schema;

return schemaNecessities;
return {
documentation: {
title,
description,
examples,
default: default_
},
semantics
};
}
2 changes: 1 addition & 1 deletion schemas/pointer/collection/group.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $id: "schema:ethdebug/format/pointer/collection/group"

title: ethdebug/format/pointer/collection/group
description: |
A schema for ...
A composite collection of pointers
type: object
properties:
group:
Expand Down
11 changes: 9 additions & 2 deletions schemas/pointer/collection/list.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ $id: "schema:ethdebug/format/pointer/collection/list"

title: ethdebug/format/pointer/collection/list
description: |
A schema for ...
An ordered list of pointers, indexed starting at zero.
type: object

properties:
list:
type: object
properties:
count:
description: |
The size of the list that this collection represents.
$ref: "schema:ethdebug/format/pointer/expression"
each:
type: string
description: |
An identifier name whose value as an expression resolves to the index
in the list
$ref: "schema:ethdebug/format/pointer/identifier"
is:
description: |
The dynamically-generated pointer repeated as a list
$ref: "schema:ethdebug/format/pointer"
required:
- count
Expand Down
Loading

0 comments on commit d038781

Please sign in to comment.