Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"lerna-update-wizard": "^0.16.0",
"lint-staged": "^10.4.2",
"nyc": "^13.0.1",
"prettier": "^2.0.5",
"prettier": "^2.2.1",
"prs-merged-since": "^1.1.0"
},
"workspaces": {
Expand Down
10 changes: 10 additions & 0 deletions packages/parse-mapping-lookup/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"overrides": [
{
"files": ["**/*.spec.ts"],
"env": {
"jest": true
}
}
]
}
1 change: 1 addition & 0 deletions packages/parse-mapping-lookup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
13 changes: 13 additions & 0 deletions packages/parse-mapping-lookup/.madgerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"excludeRegExp": [
"\\.\\.",
"test"
],
"fileExtensions": ["ts"],
"detectiveOptions": {
"ts": {
"skipTypeImports": true
}
},
"tsConfig": "./tsconfig.json"
}
9 changes: 9 additions & 0 deletions packages/parse-mapping-lookup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# `@truffle/parse-mapping-lookup`

## Usage

```typescript
import { parse } from "@truffle/parse-mapping-lookup";

parse("ledger.balances[0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e]");
```
84 changes: 84 additions & 0 deletions packages/parse-mapping-lookup/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"name": "@truffle/parse-mapping-lookup",
"version": "0.1.0",
"description": "Parse pointers to mapping/struct innards (e.g. m[0])",
"keywords": [
"smart-contract",
"truffle"
],
"author": "g. nicholas d'andrea <gnidan@trufflesuite.com>",
"homepage": "https://github.com/trufflesuite/truffle#readme",
"license": "MIT",
"main": "dist/src/index.js",
"directories": {
"dist": "dist"
},
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/trufflesuite/truffle.git",
"directory": "packages/parse-mapping-lookup"
},
"scripts": {
"build": "yarn build:dist && yarn build:docs",
"clean": "rm -rf ./dist",
"prepare": "yarn build",
"build:dist": "ttsc",
"build:docs": "typedoc",
"madge": "madge ./src/index.ts",
"test": "jest --verbose --detectOpenHandles --forceExit --passWithNoTests"
},
"devDependencies": {
"@types/jest": "^26.0.20",
"@types/node": "12.12.21",
"jest": "^26.5.2",
"madge": "^3.11.0",
"ts-jest": "^26.4.1",
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"ttypescript": "^1.5.7",
"typedoc": "^0.20.19",
"typescript": "^4.1.4",
"typescript-transform-paths": "^2.1.0"
},
"bugs": {
"url": "https://github.com/trufflesuite/truffle/issues"
},
"dependencies": {
"parjs": "^0.12.7"
},
"jest": {
"moduleFileExtensions": [
"ts",
"js",
"json",
"node"
],
"testEnvironment": "node",
"transform": {
"^.+\\.ts$": "ts-jest"
},
"globals": {
"ts-jest": {
"tsConfig": "<rootDir>/tsconfig.json",
"diagnostics": true
}
},
"moduleNameMapper": {
"^@truffle/parse-mapping-lookup/(.*)": "<rootDir>/src/$1",
"^@truffle/parse-mapping-lookup$": "<rootDir>/src",
"^test/(.*)": "<rootDir>/test/$1"
},
"testMatch": [
"<rootDir>/src/**/test/*\\.(ts|js)",
"<rootDir>/test/**/test/*\\.(ts|js)",
"<rootDir>/src/**/*\\.(spec|test)\\.(ts|js)",
"<rootDir>/test/**/*\\.(spec|test)\\.(ts|js)"
]
}
}
25 changes: 25 additions & 0 deletions packages/parse-mapping-lookup/src/ast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import debugModule from "debug";
const debug = debugModule("parse-mapping-lookup:ast");

import { Forms, definitions } from "./grammar";
import { Node, makeConstructors } from "./meta";

export type Identifier = Node<Forms, "identifier">;
export type String = Node<Forms, "string">;
export type Value = Node<Forms, "value">;
export type IndexAccess = Node<Forms, "indexAccess">;
export type MemberLookup = Node<Forms, "memberLookup">;
export type Pointer = Node<Forms, "pointer">;
export type Expression = Node<Forms, "expression">;

const constructors = makeConstructors<Forms>({ definitions });

export const {
identifier,
string,
value,
indexAccess,
memberLookup,
pointer,
expression
} = constructors;
75 changes: 75 additions & 0 deletions packages/parse-mapping-lookup/src/grammar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { string, regexp, noCharOf } from "parjs";
import { between, map, then, qthen, many, or } from "parjs/combinators";

import { Definitions } from "./meta";

import { solidityString } from "./string";

export type Forms = {
identifier: {
name: { type: string };
};
string: {
contents: { type: string };
};
value: {
contents: { type: string };
};
indexAccess: {
index: { kind: "string" | "value" };
};
memberLookup: {
property: { kind: "identifier" };
};
pointer: {
path: Array<{ kind: "memberLookup" | "indexAccess" }>;
};
expression: {
root: { kind: "identifier" };
pointer: { kind: "pointer" };
};
};

export const definitions: Definitions<Forms> = {
identifier: ({ construct }) =>
regexp(/[a-zA-Z_$][a-zA-Z0-9_$]*/).pipe(
map(([name]) => construct({ name }))
),

string: ({ construct }) =>
solidityString.pipe(map(contents => construct({ contents }))),

value: ({ construct }) =>
noCharOf("]").pipe(
then(noCharOf("]").pipe(many())),
map(([first, rest]) => construct({ contents: [first, ...rest].join("") }))
),

indexAccess: ({ construct, tie }) =>
tie("string").pipe(
or(tie("value")),
between(string("["), string("]")),
map(index => construct({ index }))
),

memberLookup: ({ construct, tie }) =>
string(".").pipe(
qthen(tie("identifier")),
map(property => construct({ property }))
),

pointer: ({ construct, tie }) => {
const stepP = tie("memberLookup").pipe(or(tie("indexAccess")));

return stepP.pipe(
then(stepP.pipe(many())),
map(([first, rest]) => construct({ path: [first, ...rest] }))
);
},

expression: ({ construct, tie }) =>
tie("identifier").pipe(
then(tie("pointer")),
map(([root, pointer]) => construct({ root, pointer }))
)
};
7 changes: 7 additions & 0 deletions packages/parse-mapping-lookup/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import debugModule from "debug";
const debug = debugModule("parse-mapping-lookup");

export { parseExpression } from "./parser";

import * as Ast from "./ast";
export { Ast };
36 changes: 36 additions & 0 deletions packages/parse-mapping-lookup/src/meta/constructors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Forms, FormKind, Node } from "./forms";

export type Constructors<F extends Forms> = {
[K in FormKind<F>]: Constructor<F, K>;
};

export type Constructor<F extends Forms, K extends FormKind<F>> = (
fields: Omit<Node<F, K>, "kind">
) => Node<F, K>;

export type MakeConstructorOptions<F extends Forms, K extends FormKind<F>> = {
kind: K;
};

const makeConstructor = <F extends Forms, K extends FormKind<F>>(
options: MakeConstructorOptions<F, K>
): Constructor<F, K> => {
const { kind } = options;
return fields => ({ kind, ...fields } as Node<F, K>);
};

export type Definition<F extends Forms, _K extends FormKind<F>> = any;
export type MakeConstructorsOptions<F extends Forms> = {
definitions: {
[K in FormKind<F>]: Definition<F, K>;
};
};

export const makeConstructors = <F extends Forms>(
options: MakeConstructorsOptions<F>
): Constructors<F> => {
const { definitions } = options;
return Object.keys(definitions)
.map(kind => ({ [kind]: makeConstructor({ kind }) }))
.reduce((a, b) => ({ ...a, ...b }), {}) as Constructors<F>;
};
47 changes: 47 additions & 0 deletions packages/parse-mapping-lookup/src/meta/forms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export type Forms = {
[kind: string]: {
[name: string]: { kind: string } | { kind: string }[] | { type: any };
};
};

export type FormKind<F extends Forms> = string & keyof F;
export type Form<F extends Forms, K extends FormKind<F>> = F[K];

export type FormFields<F extends Forms, K extends FormKind<F>> = Form<F, K>;

export type FormFieldName<F extends Forms, K extends FormKind<F>> = string &
keyof FormFields<F, K>;

export type FormField<
F extends Forms,
K extends FormKind<F>,
N extends FormFieldName<F, K>
> = FormFields<F, K>[N];

export type FormFieldKind<
F extends Forms,
K extends FormKind<F>,
_N extends FormFieldName<F, K>,
T extends any
> = "kind" extends keyof T ? Node<F, T["kind"] & FormKind<F>> : never;

type _FormFieldNode<
F extends Forms,
K extends FormKind<F>,
N extends FormFieldName<F, K>,
T extends any
> = T extends (infer I)[]
? _FormFieldNode<F, K, N, I>[]
: "type" extends keyof T
? T["type"]
: FormFieldKind<F, K, N, T>;

export type FormFieldNode<
F extends Forms,
K extends FormKind<F>,
N extends FormFieldName<F, K>
> = _FormFieldNode<F, K, N, FormField<F, K, N>>;

export type Node<F extends Forms, K extends FormKind<F>> = { kind: K } & {
[N in FormFieldName<F, K>]: FormFieldNode<F, K, N>;
};
19 changes: 19 additions & 0 deletions packages/parse-mapping-lookup/src/meta/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Node, Forms, FormKind } from "./forms";
export { Node };

import type * as Constructors from "./constructors";
import { makeConstructors } from "./constructors";
export { makeConstructors };

import type * as Parsers from "./parsers";
import { makeParsers } from "./parsers";
export { makeParsers };

export type Definition<
F extends Forms,
K extends FormKind<F>
> = Constructors.Definition<F, K> & Parsers.Definition<F, K>;

export type Definitions<F extends Forms> = {
[K in FormKind<F>]: Definition<F, K>;
};
Loading