aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/src/abi_encoder/utils/signature_parser.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils/src/abi_encoder/utils/signature_parser.ts')
-rw-r--r--packages/utils/src/abi_encoder/utils/signature_parser.ts151
1 files changed, 69 insertions, 82 deletions
diff --git a/packages/utils/src/abi_encoder/utils/signature_parser.ts b/packages/utils/src/abi_encoder/utils/signature_parser.ts
index 315784cea..d3996bf8e 100644
--- a/packages/utils/src/abi_encoder/utils/signature_parser.ts
+++ b/packages/utils/src/abi_encoder/utils/signature_parser.ts
@@ -1,101 +1,88 @@
import { DataItem } from 'ethereum-types';
import * as _ from 'lodash';
+interface Node {
+ name: string;
+ value: string;
+ children: Node[];
+ parent?: Node;
+}
+
+function parseNode(node: Node): DataItem {
+ const components: DataItem[] = [];
+ _.each(node.children, (child: Node) => {
+ const component = parseNode(child);
+ components.push(component);
+ });
+ const dataItem: DataItem = {
+ name: node.name,
+ type: node.value,
+ };
+ if (!_.isEmpty(components)) {
+ dataItem.components = components;
+ }
+ return dataItem;
+}
+
/**
- * Returns an array of DataItem's corresponding to the input signature.
- * A signature can be in two forms: '<DataItem.type>' or '(<DataItem1.type>, <DataItem2.type>, ...)
- * An example of the first form would be 'address' or 'uint256'
- * An example of the second form would be '(address, uint256)'
- * Signatures can also include a name field, for example: 'foo address' or '(foo address, bar uint256)'
- * @param signature of input DataItems
- * @return DataItems derived from input signature
+ * Returns a DataItem corresponding to the input signature.
+ * A signature can be in two forms: `type` or `(type_1,type_2,...,type_n)`
+ * An example of the first form would be 'address' or 'uint256[]' or 'bytes[5][]'
+ * An example of the second form would be '(address,uint256)' or '(address,uint256)[]'
+ * @param signature of input DataItem.
+ * @return DataItem derived from input signature.
*/
-export function generateDataItemsFromSignature(signature: string): DataItem[] {
- let trimmedSignature = signature;
- if (signature.startsWith('(')) {
- if (!signature.endsWith(')')) {
- throw new Error(`Failed to generate data item. Must end with ')'`);
- }
- trimmedSignature = signature.substr(1, signature.length - 2);
+export function generateDataItemFromSignature(signature: string): DataItem {
+ // No data item corresponds to an empty signature
+ if (_.isEmpty(signature)) {
+ throw new Error(`Cannot parse data item from empty signature, ''`);
}
- trimmedSignature += ',';
- let isCurrTokenArray = false;
- let currTokenArrayModifier = '';
- let isParsingArrayModifier = false;
- let currToken = '';
- let parenCount = 0;
- let currTokenName = '';
- const dataItems: DataItem[] = [];
- for (const char of trimmedSignature) {
- // Tokenize the type string while keeping track of parentheses.
+ // Create a parse tree for data item
+ let node: Node = {
+ name: '',
+ value: '',
+ children: [],
+ };
+ for (const char of signature) {
switch (char) {
case '(':
- parenCount += 1;
- currToken += char;
+ const child = {
+ name: '',
+ value: '',
+ children: [],
+ parent: node,
+ };
+ node.value = 'tuple';
+ node.children.push(child);
+ node = child;
break;
+
case ')':
- parenCount -= 1;
- currToken += char;
+ node = node.parent as Node;
break;
- case '[':
- if (parenCount === 0) {
- isParsingArrayModifier = true;
- isCurrTokenArray = true;
- currTokenArrayModifier += '[';
- } else {
- currToken += char;
- }
- break;
- case ']':
- if (parenCount === 0) {
- isParsingArrayModifier = false;
- currTokenArrayModifier += ']';
- } else {
- currToken += char;
- }
+
+ case ',':
+ const sibling = {
+ name: '',
+ value: '',
+ children: [],
+ parent: node.parent,
+ };
+ (node.parent as Node).children.push(sibling);
+ node = sibling;
break;
+
case ' ':
- if (parenCount === 0) {
- currTokenName = currToken;
- currToken = '';
- } else {
- currToken += char;
- }
+ node.name = node.value;
+ node.value = '';
break;
- case ',':
- if (parenCount === 0) {
- // Generate new DataItem from token
- const components = currToken.startsWith('(') ? generateDataItemsFromSignature(currToken) : [];
- const isTuple = !_.isEmpty(components);
- const dataItem: DataItem = { name: currTokenName, type: '' };
- if (isTuple) {
- dataItem.type = 'tuple';
- dataItem.components = components;
- } else {
- dataItem.type = currToken;
- }
- if (isCurrTokenArray) {
- dataItem.type += currTokenArrayModifier;
- }
- dataItems.push(dataItem);
- // reset token state
- currTokenName = '';
- currToken = '';
- isCurrTokenArray = false;
- currTokenArrayModifier = '';
- break;
- } else {
- currToken += char;
- break;
- }
+
default:
- if (isParsingArrayModifier) {
- currTokenArrayModifier += char;
- } else {
- currToken += char;
- }
+ node.value += char;
break;
}
}
- return dataItems;
+ // Interpret data item from parse tree
+ const dataItem = parseNode(node);
+ return dataItem;
}