Files
esbuild/scripts/fuzzer/estree-grammar.js
2020-04-22 20:24:05 -07:00

469 lines
11 KiB
JavaScript

// These helper functions are shortcuts to make the rules below cleaner
const oneOf = (...of) => ({ type: 'choice', of })
const nullable = of => oneOf(literal(null), of)
const arrayOf = of => ({ type: 'array', of })
const arrayOfWithTrailing = (of, trailing) => ({ type: 'array', of, trailing })
const nonEmptyArrayOf = of => ({ type: 'array', of, nonEmpty: true })
const literal = literal => ({ type: 'literal', literal })
module.exports = {
Program: {
body: arrayOf(oneOf('Statement', 'Declaration', 'ModuleDeclaration')),
},
$Pattern: {
Identifier: {
name: 'string',
},
ArrayPattern: {
elements: arrayOfWithTrailing(oneOf('Pattern', literal(null)), 'RestElement'),
},
ObjectPattern: {
properties: arrayOf('AssignmentProperty'),
},
AssignmentPattern: {
left: 'NoAssignmentPattern',
right: 'Expression',
},
},
$NoAssignmentPattern: {
Identifier: {
name: 'string',
},
ArrayPattern: {
elements: arrayOfWithTrailing(oneOf('Pattern', literal(null)), 'RestElement'),
},
ObjectPattern: {
properties: arrayOf('AssignmentProperty'),
},
},
AssignmentProperty: {
type: literal('Property'),
key: 'Identifier',
value: 'AssignmentPropertyPattern',
kind: literal('init'),
method: literal(false),
},
$AssignmentPropertyPattern: {
Identifier: {
name: 'string',
},
AssignmentPattern: {
left: 'NoAssignmentPattern',
right: 'Expression',
},
},
RestElement: {
argument: 'NoAssignmentPattern',
},
$Expression: {
ThisExpression: {},
Identifier: {
name: 'string',
},
Literal: {
value: oneOf('boolean', 'string', 'number', 'regexp', literal(null)),
},
ArrayExpression: {
elements: arrayOfWithTrailing(oneOf('Expression', literal(null)), 'SpreadElement'),
},
ObjectExpression: {
properties: arrayOf('Property'),
},
FunctionExpression: {
id: nullable('Identifier'),
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
UnaryExpression: {
operator: oneOf(literal('-'), literal('+'), literal('!'), literal('~'), literal('typeof'), literal('void'), literal('delete')),
prefix: 'boolean',
argument: 'Expression',
},
UpdateExpression: {
operator: oneOf(literal('--'), literal('++')),
argument: 'Expression',
prefix: 'boolean',
},
BinaryExpression: {
operator: oneOf(
literal('=='), literal('!='), literal('==='), literal('!=='),
literal('<'), literal('<='), literal('>'), literal('>='),
literal('<<'), literal('>>'), literal('>>>'),
literal('+'), literal('-'), literal('*'), literal('/'), literal('%'),
literal('|'), literal('^'), literal('&'), literal('in'),
literal('instanceof'), literal('**'),
),
left: 'Expression',
right: 'Expression',
},
AssignmentExpression: {
operator: oneOf(
literal('='), literal('+='), literal('-='), literal('*='), literal('/='), literal('%='),
literal('<<='), literal('>>='), literal('>>>='),
literal('|='), literal('^='), literal('&='), literal('**='),
),
left: oneOf('NoAssignmentPattern', 'Expression'),
right: 'Expression',
},
LogicalExpression: {
operator: oneOf(literal('||'), literal('&&')),
left: 'Expression',
right: 'Expression',
},
$MemberExpression: [
{
object: 'Expression',
property: 'Identifier',
computed: literal(false),
},
{
object: 'Expression',
property: 'Expression',
computed: literal(true),
},
],
ConditionalExpression: {
test: 'Expression',
alternate: 'Expression',
consequent: 'Expression',
},
CallExpression: {
callee: 'Expression',
arguments: arrayOf(oneOf('Expression', 'SpreadElement')),
},
NewExpression: {
callee: 'Expression',
arguments: arrayOf(oneOf('Expression', 'SpreadElement')),
},
SequenceExpression: {
expressions: nonEmptyArrayOf('Expression'),
},
$ArrowFunctionExpression: [
{
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
expression: literal(false),
},
{
async: 'boolean',
params: arrayOf('Pattern'),
body: 'Expression',
expression: literal(true),
},
],
ClassExpression: {
id: nullable('Identifier'),
superClass: nullable('Expression'),
body: 'ClassBody',
},
},
ForStatement: {
init: nullable(oneOf('VariableDeclaration', 'Expression')),
test: nullable('Expression'),
update: nullable('Expression'),
body: 'Statement',
},
$Statement: {
EmptyStatement: {},
DebuggerStatement: {},
WithStatement: {
object: 'Expression',
body: 'Statement',
},
ReturnStatement: {
argument: nullable('Expression'),
},
LabeledStatement: {
label: 'Identifier',
body: 'Statement',
},
BreakStatement: {
label: nullable('Identifier'),
},
ContinueStatement: {
label: nullable('Identifier'),
},
ExpressionStatement: {
expression: 'Expression',
},
BlockStatement: {
body: arrayOf(oneOf('Statement', 'Declaration')),
},
IfStatement: {
test: 'Expression',
consequent: 'Statement',
alternate: nullable('Statement'),
},
SwitchStatement: {
discriminant: 'Expression',
cases: arrayOf('SwitchCase'),
},
ThrowStatement: {
argument: 'Expression',
},
$TryStatement: [
{
block: 'BlockStatement',
handler: 'CatchClause',
finalizer: nullable('BlockStatement'),
},
{
block: 'BlockStatement',
handler: nullable('CatchClause'),
finalizer: 'BlockStatement',
},
],
WhileStatement: {
test: 'Expression',
body: 'Statement',
},
DoWhileStatement: {
body: 'Statement',
test: 'Expression',
},
ForStatement: {
init: nullable(oneOf('VariableDeclaration', 'Expression')),
test: nullable('Expression'),
update: nullable('Expression'),
body: 'Statement',
},
ForInStatement: {
left: oneOf('VariableDeclaration', 'Pattern'),
right: 'Expression',
body: 'Statement',
},
ForOfStatement: {
left: oneOf('VariableDeclaration', 'Pattern'),
right: 'Expression',
body: 'Statement',
},
},
$Declaration: {
VariableDeclaration: {
declarations: nonEmptyArrayOf('VariableDeclarator'),
kind: oneOf(literal('var'), literal('let'), literal('const')),
},
FunctionDeclaration: {
id: 'Identifier',
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
ClassDeclaration: {
id: 'Identifier',
superClass: nullable('Expression'),
body: 'ClassBody',
},
},
VariableDeclaration: {
declarations: nonEmptyArrayOf('VariableDeclarator'),
kind: oneOf(literal('var'), literal('let'), literal('const')),
},
VariableDeclarator: {
id: 'NoAssignmentPattern',
init: nullable('Expression'),
},
FunctionDeclaration: {
id: 'Identifier',
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
ClassDeclaration: {
id: 'Identifier',
superClass: nullable('Expression'),
body: 'ClassBody',
},
AnonymousDefaultExportedFunctionDeclaration: {
type: literal('FunctionDeclaration'),
id: literal(null),
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
AnonymousDefaultExportedClassDeclaration: {
type: literal('ClassDeclaration'),
id: literal(null),
superClass: nullable('Expression'),
body: 'ClassBody',
},
$ModuleDeclaration: {
ImportDeclaration: {
specifiers: arrayOf('ImportSpecifier', 'ImportDefaultSpecifier', 'ImportNamespaceSpecifier'),
source: 'ImportPath',
},
$ExportNamedDeclaration: [
{
declaration: 'Declaration',
source: 'ImportPath',
},
{
specifiers: arrayOf('ExportSpecifier'),
source: 'ImportPath',
},
],
ExportDefaultDeclaration: {
declaration: oneOf(
'AnonymousDefaultExportedFunctionDeclaration',
'AnonymousDefaultExportedClassDeclaration',
'FunctionDeclaration',
'ClassDeclaration',
'Expression',
),
},
ExportAllDeclaration: {
source: 'ImportPath',
},
},
ImportSpecifier: {
local: 'Identifier',
imported: 'Identifier',
},
ExportSpecifier: {
local: 'Identifier',
imported: 'Identifier',
},
ImportDefaultSpecifier: {
local: 'Identifier',
},
ImportNamespaceSpecifier: {
local: 'Identifier',
},
ImportPath: {
type: literal('Literal'),
value: 'string',
},
Identifier: {
name: 'string',
},
SpreadElement: {
argument: 'Expression',
},
CatchClause: {
param: 'NoAssignmentPattern',
body: 'BlockStatement',
},
BlockStatement: {
body: arrayOf(oneOf('Statement', 'Declaration')),
},
SwitchCase: {
test: nullable('Expression'),
consequent: arrayOf(oneOf('Statement', 'Declaration')),
},
FunctionExpression: {
id: nullable('Identifier'),
async: 'boolean',
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
NoAsyncFunctionExpression: {
type: literal('FunctionExpression'),
id: nullable('Identifier'),
params: arrayOf('Pattern'),
body: 'BlockStatement',
},
$Property: [
{
key: 'Identifier',
value: 'Expression',
kind: literal('init'),
},
{
key: 'Identifier',
value: 'NoAsyncFunctionExpression',
kind: oneOf(literal('get'), literal('set')),
},
{
key: 'Identifier',
value: 'FunctionExpression',
kind: literal('init'),
method: literal(true),
},
{
key: 'Expression',
computed: literal(true),
value: 'Expression',
kind: literal('init'),
},
{
key: 'Expression',
computed: literal(true),
value: 'NoAsyncFunctionExpression',
kind: oneOf(literal('get'), literal('set')),
},
{
key: 'Expression',
computed: literal(true),
value: 'FunctionExpression',
kind: literal('init'),
method: literal(true),
},
],
ClassBody: {
body: arrayOf('MethodDefinition'),
},
$MethodDefinition: [
{
key: 'Identifier',
value: 'FunctionExpression',
kind: literal('method'),
computed: literal(false),
static: 'boolean',
},
{
key: 'Identifier',
value: 'NoAsyncFunctionExpression',
kind: oneOf(literal('get'), literal('set')),
computed: literal(false),
static: 'boolean',
},
{
key: 'Expression',
value: 'FunctionExpression',
kind: literal('method'),
computed: literal(true),
static: 'boolean',
},
{
key: 'Expression',
value: 'NoAsyncFunctionExpression',
kind: oneOf(literal('get'), literal('set')),
computed: literal(true),
static: 'boolean',
},
],
}