esvisit
Version:
Expression/Statement visitor for ECMAScript5 Mozilla ASTs
575 lines (505 loc) • 11.9 kB
JavaScript
/////////////
// Helpers //
/////////////
function identifier (name) { return { type: "Identifier", name: name } }
function block (stmts) { return { type: "BlockStatement", body: stmts } }
function member (object, property) {
var computed = typeof property !== "string"
return {
type: "MemberExpression",
object: object,
computed: computed,
property: computed ? property : identifier(property)
}
}
function declarator (idname, init) {
return {
type: "VariableDeclarator",
id: identifier(idname),
init: init
}
}
function declaration (declarators) {
return {
type: "VariableDeclaration",
declarations: declarators,
kind: "var"
}
}
function literal (value) {
return {
type: "Literal",
value: value
}
}
////////////////
// Statements //
////////////////
var statements = {}
statements.Empty = function () {
return {
$type: "Empty",
type: "EmptyStatement"
}
}
statements.Strict = function () {
return {
$type: "Strict",
type: "ExpressionStatement",
expression: {
type: "Literal",
value: "use strict"
}
}
}
statements.Block = function (body) {
return {
$type: "Block",
type: "BlockStatement",
body: body
}
}
statements.Expression = function (expression) {
return {
$type: "Expression",
type: "ExpressionStatement",
expression: expression
}
}
statements.If = function (test, consequent, alternate) {
return {
$type: "If",
type: "IfStatement",
test: test,
consequent: consequent,
alternate: alternate || null
}
}
statements.Label = function (labelname, body) {
return {
$type: "Label",
type: "LabeledStatement",
label: identifier(labelname),
body: body
}
}
statements.Break = function (labelname) {
return {
$type: "Break",
type: "BreakStatement",
label: labelname ? identifier(labelname) : null
}
}
statements.Continue = function (labelname) {
return {
$type: "Continue",
type: "ContinueStatement",
label: label ? identifier(labelname) : null
}
}
statements.With = function (object, body) {
return {
$type: "With",
type: "WithStatement",
object: object,
body: body
}
}
statements.Switch = function (discriminant, cases) {
return {
$type: "Switch",
discriminant: discriminant,
cases: cases,
lexical: false
}
}
statements.Return = function (argument) {
return {
$type: "Return",
type: "ReturnStatement",
argument: argument || null
}
}
statements.Throw = function (argument) {
return {
$type: "Throw",
type: "ThrowStatement",
argument: argument
}
}
statements.Try = function (trystmts, catchparam, catchstmts, finallystmts) {
return {
$type: "Try",
type: "TryStatement",
block: block(trystmts),
guardedHandlers: [],
handlers: catchparam ? [{type:"CatchClause", param:identifier(catchparam), guard:null, body:block(catchstmts)}] : [],
finalizer: finallystmts ? block(finallystmts) : null
}
}
statements.While = function (test, body) {
return {
$type: "While",
type: "WhileStatement",
test: test,
body: body
}
}
statements.DoWhile = function (test, body) {
return {
$type: "DoWhile",
type: "DoWhileStatement",
test: test,
body: body
}
}
statements.DeclarationFor = function (initdeclarators, test, update, body) {
return {
$type: "DeclarationFor",
type: "ForStatement",
init: declaration(initdeclarators),
test: test || null,
update: update || null,
body: body
}
}
statements.For = function (init, test, update, body) {
return {
$type: "For",
type: "ForStatement",
init: init || null,
test: test || null ,
update: update || null,
body: body
}
}
statements.IdentifierForIn = function (leftname, right, body) {
return {
$type: "IdentifierForIn",
type: "ForInStatement",
left: identifier(leftname),
right: right,
body: body
}
}
statements.MemberForIn = function (leftobject, leftproperty, right, body) {
return {
$type: "MemberForIn",
type: "ForInStatement",
left: member(leftobject, leftproperty),
right: right,
body: body
}
}
statements.DeclarationForIn = function (leftname, leftinit, right, body) {
return {
$type: "DeclarationForIn",
type: "ForInStatement",
left: declaration([declarator(leftname, leftinit)]),
right: right,
body: body
}
}
statements.Definition = function (idname, paramnames, bodystmts) {
return {
$type: "Definition",
type: "FunctionDeclaration",
id: identifier(idname),
params: paramnames.map(identifier),
defaults: [],
body: block(bodystmts),
generator: false,
expression: false
}
}
statements.Declaration = function (declarators) {
return {
$type: "Declaration",
type: "VariableDeclaration",
kind: "var",
declarations: declarators
}
}
exports.statements = statements
////////////////
// Expression //
////////////////
var expressions = {}
expressions.This = function () {
return {
$type: "This",
type: "ThisExpression"
}
}
expressions.Array = function (elements) {
return {
$type: "Array",
type: "ArrayExpression",
elements: elements.map(function (e) { return e || null })
}
}
expressions.Object = function (properties) {
return {
$type: "Object",
type: "ObjectExpression",
properties: properties
}
}
expressions.Function = function (idname, paramnames, bodystmts) {
return {
$type: "Function",
type: "FunctionExpression",
id: idname ? identifier(idname) : null,
params: paramnames.map(identifier),
defaults: [],
generator: false,
expression: false,
body: block(bodystmts),
}
}
expressions.HoistedFunction = function (idname, paramnames, variables, bodystmts) {
var seen = {}
paramnames.forEach(function (name) { seen[name] = true })
variables = variables.filter(function (name) { return seen[name] ? false : (seen[name]=true) })
var declarators = variables.map(function (name) { return { type:"VariableDeclarator", id:identifier(name), init:null} })
bodystmts.unshift(declarators.length
? {type:"VariableDeclaration", kind:"var", declarations:declarators}
: {type:"EmptyStatement"})
return {
$type: "HoistedFunction",
type: "FunctionExpression",
id: idname ? identifier(idname) : null,
params: paramnames.map(identifier),
defaults: [],
generator: false,
expression: false,
body: block(bodystmts)
}
}
expressions.Sequence = function (expressions) {
return {
$type: "Sequence",
type: "SequenceExpression",
expressions: expressions
}
}
expressions.IdentifierTypeof = function (argumentname) {
return {
$type: "IdentifierTypeof",
type: "UnaryExpression",
operator: "typeof",
prefix: true,
argument: identifier(argumentname)
}
}
expressions.IdentifierDelete = function (argumentname) {
return {
$type: "IdentifierDelete",
type: "UnaryExpression",
operator: "delete",
prefix: true,
argument: identifier(argumentname)
}
}
expressions.MemberDelete = function (argumentobject, argumentproperty) {
return {
$type: "IdentifierDelete",
type: "UnaryExpression",
operator: "delete",
prefix: true,
argument: member(argumentobject, argumentproperty)
}
}
expressions.Unary = function (operator, argument) {
return {
$type: "Unary",
type: "UnaryExpression",
operator: operator,
argument: argument
}
}
expressions.Binary = function (operator, left, right) {
return {
$type: "Binary",
type: "BinaryExpression",
operator: operator,
left: left,
right: right
}
}
expressions.IdentifierAssignment = function (leftname, right) {
return {
$type: "IdentifierAssignment",
type: "AssignmentExpression",
operator: "=",
left: identifier(leftname),
right: right
}
}
expressions.IdentifierBinaryAssignment = function (operator, leftname, right) {
return {
$type: "IdentifierBinaryAssignment",
type: "AssignmentExpression",
operator: operator,
left: identifier(leftname),
right: right
}
}
expressions.MemberAssignment = function (leftobject, leftproperty, right) {
return {
$type: "MemberAssignment",
type: "AssignmentExpression",
operator: "=",
left: member(leftobject, leftproperty),
right: right
}
}
expressions.MemberBinaryAssignment = function (operator, leftobject, leftproperty, right) {
return {
$type: "MemberBinaryAssignment",
type: "AssignmentExpression",
operator: operator,
left: member(leftobject, leftproperty),
right: right
}
}
expressions.IdentifierUpdate = function (operator, prefix, argumentname) {
return {
$type: "IdentifierUpdate",
type: "UpdateExpression",
operator: operator,
prefix: prefix,
argument: identifier(argumentname)
}
}
expressions.MemberUpdate = function (operator, prefix, argumentobject, argumentproperty) {
return {
$type: "MemberUpdate",
type: "UpdateExpression",
operator: operator,
prefix: prefix,
argument: member(argumentobject, argumentproperty)
}
}
expressions.Logical = function (operator, left, right) {
return {
$type: "Logical",
type: "LogicalExpression",
operator: operator,
left: left,
right: right
}
}
expressions.Conditional = function (test, consequent, alternate) {
return {
$type: "Conditional",
type: "ConditionalExpression",
test: test,
consequent: consequent,
alternate: alternate
}
}
expressions.New = function (callee, args) {
return {
$type: "New",
type: "NewExpression",
callee: callee,
arguments: args
}
}
expressions.MemberCall = function (calleeobject, calleeproperty, arguments) {
return {
$type: "MemberCall",
type: "CallExpression",
callee: member(calleeobject, calleeproperty),
arguments: arguments
}
}
expressions.EvalCall = function (arguments) {
return {
$type: "EvalCall",
type: "CallExpression",
callee: identifier("eval"),
arguments: arguments
}
}
expressions.Call = function (callee, arguments) {
return {
$type: "Call",
type: "CallExpression",
callee: callee,
arguments: arguments
}
}
expressions.Member = function (object, property) {
computed = typeof property !== "string"
return {
$type: "Member",
type: "MemberExpression",
computed: computed,
object: object,
property: computed ? property : identifier(property)
}
}
expressions.Identifier = function (name) {
return {
$type: "Identifier",
type: "Identifier",
name: name
}
}
expressions.Literal = function (value) {
return {
$type: "Literal",
type: "Literal",
value: value
}
}
exports.expressions = expressions
/////////////////////////
// Additional Builders //
/////////////////////////
exports.Program = function (bodystmts) {
return {
type: "Program",
body: bodystmts
}
}
exports.Declarator = function (name, init) {
return {
type: "VariableDeclarator",
id: identifier(name),
init: init || null
}
}
exports.InitProperty = function (keyvalue, value) {
return {
type: "Property",
kind: "init",
key: literal(keyvalue),
value: value
}
}
exports.GetProperty = function (keyvalue, bodystmts) {
return {
type: "Property",
kind: "get",
key: literal(keyvalue),
value: { type: "Function", params: [], body: block(bodystmts) }
}
}
exports.SetProperty = function (keyvalue, paramname, bodystmts) {
return {
type: "Property",
kind: "set",
key: literal(keyvalue),
value: { type: "Function", params: [identifier(paramname)], body: block(bodystmts) }
}
}
exports.SwitchCase = function (test, consequent) {
return {
type: "SwitchCase",
test: test||null,
consequent: consequent
}
}