tools/hermes-parser/js/scripts/genPredicateFunctions.js (179 lines of code) (raw):
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import {
HermesESTreeJSON,
formatAndWriteDistArtifact,
LITERAL_TYPES,
NODES_WITHOUT_TRANSFORM_NODE_TYPES,
} from './utils/scriptUtils';
const predicateFunctions: Array<string> = [];
const NODES_WITH_SPECIAL_HANDLING = new Set([]);
const nodes = HermesESTreeJSON.map(n => n.name).concat('Literal');
for (const node of nodes) {
if (
NODES_WITH_SPECIAL_HANDLING.has(node) ||
NODES_WITHOUT_TRANSFORM_NODE_TYPES.has(node) ||
LITERAL_TYPES.has(node)
) {
continue;
}
predicateFunctions.push(
`
export function is${node}(node: ESNode | Token): boolean %checks {
return node.type === '${node}';
}
`,
);
}
const COMMENTS = ['Line', 'Block'];
for (const comment of COMMENTS) {
predicateFunctions.push(
`
export function is${comment}Comment(node: ESNode | Token): boolean %checks {
return node.type === '${comment}';
}
`,
);
}
// TODO(bradzacher) generate this list from the types maybe?
const TOKENS: $ReadOnlyArray<[string, string, string]> = [
// Both BinaryOperator and UnaryOperator
['Minus', '-', 'Punctuator'],
['Plus', '+', 'Punctuator'],
// UnaryOperator
['LogicalNot', '!', 'Punctuator'],
['UnaryNegation', '~', 'Punctuator'],
['TypeOf', 'typeof', 'Keyword'],
['Void', 'void', 'Keyword'],
['Delete', 'delete', 'Keyword'],
// BinaryOperator
['LooseEqual', '==', 'Punctuator'],
['LooseNotEqual', '!=', 'Punctuator'],
['StrictEqual', '===', 'Punctuator'],
['StrictNotEqual', '!==', 'Punctuator'],
['LessThan', '<', 'Punctuator'],
['LessThanOrEqualTo', '<=', 'Punctuator'],
['GreaterThan', '>', 'Punctuator'],
['GreaterThanOrEqualTo', '>=', 'Punctuator'],
['BitwiseLeftShift', '<<', 'Punctuator'],
['BitwiseRightShift', '>>', 'Punctuator'],
['BitwiseUnsignedRightShift', '>>>', 'Punctuator'],
['Asterix', '*', 'Punctuator'],
['ForwardSlash', '/', 'Punctuator'],
['Percent', '%', 'Punctuator'],
['Exponentiation', '**', 'Punctuator'],
['BitwiseOR', '|', 'Punctuator'],
['BitwiseXOR', '^', 'Punctuator'],
['BitwiseAND', '&', 'Punctuator'],
['In', 'in', 'Keyword'],
['InstanceOf', 'instanceof', 'Keyword'],
// LogicalOperator
['LogicalOR', '||', 'Punctuator'],
['LogicalAND', '&&', 'Punctuator'],
['NullishCoalesce', '??', 'Punctuator'],
// AssignmentOperator
['Equal', '=', 'Punctuator'],
['PlusEqual', '+=', 'Punctuator'],
['MinusEqual', '-=', 'Punctuator'],
['MultiplyEqual', '*=', 'Punctuator'],
['DivideEqual', '/=', 'Punctuator'],
['RemainderEqual', '%=', 'Punctuator'],
['ExponentateEqual', '**=', 'Punctuator'],
['BitwiseLeftShiftEqual', '<<=', 'Punctuator'],
['BitwiseRightShiftEqual', '>>=', 'Punctuator'],
['BitwiseUnsignedRightShiftEqual', '>>>=', 'Punctuator'],
['BitwiseOREqual', '|=', 'Punctuator'],
['BitwiseXOREqual', '^=', 'Punctuator'],
['BitwiseANDEqual', '&=', 'Punctuator'],
['LogicalOREqual', '||=', 'Punctuator'],
['LogicalANDEqual', '&&=', 'Punctuator'],
['NullishCoalesceEqual', '??=', 'Punctuator'],
// UpdateOperator
['Increment', '++', 'Punctuator'],
['Decrement', '--', 'Punctuator'],
// Type Operators
// These are duplicates of BinaryOperators, but here for convenience and clarity
['UnionType', '|', 'Punctuator'],
['IntersectionType', '&', 'Punctuator'],
// Misc other keywords
['Break', 'break', 'Keyword'],
['Case', 'case', 'Keyword'],
['Catch', 'catch', 'Keyword'],
['Class', 'class', 'Keyword'],
['Const', 'const', 'Keyword'],
['Continue', 'continue', 'Keyword'],
['Debugger', 'debugger', 'Keyword'],
['Default', 'default', 'Keyword'],
['Do', 'do', 'Keyword'],
['Else', 'else', 'Keyword'],
['Enum', 'enum', 'Keyword'],
['Export', 'export', 'Keyword'],
['Extends', 'extends', 'Keyword'],
['Finally', 'finally', 'Keyword'],
['For', 'for', 'Keyword'],
['Function', 'function', 'Keyword'],
['If', 'if', 'Keyword'],
['Implements', 'implements', 'Keyword'],
['Import', 'import', 'Keyword'],
['Interface', 'interface', 'Keyword'],
['New', 'new', 'Keyword'],
['Return', 'return', 'Keyword'],
['Static', 'static', 'Keyword'],
['Super', 'super', 'Keyword'],
['Switch', 'switch', 'Keyword'],
['This', 'this', 'Keyword'],
['Throw', 'throw', 'Keyword'],
['Try', 'try', 'Keyword'],
['Var', 'var', 'Keyword'],
['While', 'while', 'Keyword'],
['With', 'with', 'Keyword'],
['Yield', 'yield', 'Keyword'],
// these keywords aren't reported as Keyword tokens by the parser either
// due to syntax ambiguity, or as they are flow-specific keywords
['As', 'as', 'Identifier'],
['Async', 'async', 'Identifier'],
['Await', 'await', 'Identifier'],
['Declare', 'declare', 'Identifier'],
['From', 'from', 'Identifier'],
['Get', 'get', 'Identifier'],
['Let', 'let', 'Identifier'],
['Module', 'module', 'Identifier'],
['Of', 'of', 'Identifier'],
['Set', 'set', 'Identifier'],
['Type', 'type', 'Identifier'],
// Misc other punctuators
['Comma', ',', 'Punctuator'],
['Colon', ':', 'Punctuator'],
['Semicolon', ';', 'Punctuator'],
['Dot', '.', 'Punctuator'],
['DotDotDot', '...', 'Punctuator'],
['OptionalChain', '?.', 'Punctuator'],
['QuestionMark', '?', 'Punctuator'],
// could call these "round brackets" for consistency, but I think more people call them parentheses
['OpeningParenthesis', '(', 'Punctuator'],
['ClosingParenthesis', ')', 'Punctuator'],
// could call these "Braces", but I think more people call them curlies
['OpeningCurlyBracket', '{', 'Punctuator'],
['ClosingCurlyBracket', '}', 'Punctuator'],
// could call these "Chevrons", but I think more people call them angle brackets
['OpeningAngleBracket', '<', 'Punctuator'],
['ClosingAngleBracket', '>', 'Punctuator'],
];
for (const [name, token, type] of TOKENS) {
if (type === 'Identifier') {
// certain keywords may be reported as Identifier depending on the context
predicateFunctions.push(
`
export function is${name}Keyword(node: ESNode | Token): boolean %checks {
return (node.type === 'Identifier' || node.type === 'Keyword') && node.value === '${token}';
}
`,
);
} else {
predicateFunctions.push(
`
export function is${name}Token(node: ESNode | Token): boolean %checks {
return node.type === '${type}' && node.value === '${token}';
}
`,
);
}
}
const fileContents = `\
import type {ESNode, Token} from 'hermes-estree';
${predicateFunctions.join('\n')}
`;
formatAndWriteDistArtifact({
code: fileContents,
package: 'hermes-estree',
filename: 'predicates.js',
subdirSegments: ['generated'],
});
formatAndWriteDistArtifact({
code: fileContents,
package: 'hermes-estree',
filename: 'predicates.js.flow',
flow: 'strict-local',
subdirSegments: ['generated'],
});