/** * @fileoverview A factory for creating AST nodes * @author Fred K. Schott * @copyright 2014 Fred K. Schott. All rights reserved. * @copyright 2011-2013 Ariya Hidayat * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ var astNodeTypes = require("./ast-node-types"); //------------------------------------------------------------------------------ // Public //------------------------------------------------------------------------------ module.exports = { /** * Create an Array Expression ASTNode out of an array of elements * @param {ASTNode[]} elements An array of ASTNode elements * @returns {ASTNode} An ASTNode representing the entire array expression */ createArrayExpression: function(elements) { return { type: astNodeTypes.ArrayExpression, elements: elements }; }, /** * Create an Arrow Function Expression ASTNode * @param {ASTNode} params The function arguments * @param {ASTNode} body The function body * @param {boolean} expression True if the arrow function is created via an expression. * Always false for declarations, but kept here to be in sync with * FunctionExpression objects. * @returns {ASTNode} An ASTNode representing the entire arrow function expression */ createArrowFunctionExpression: function (params, body, expression) { return { type: astNodeTypes.ArrowFunctionExpression, id: null, params: params, body: body, generator: false, expression: expression }; }, /** * Create an ASTNode representation of an assignment expression * @param {ASTNode} operator The assignment operator * @param {ASTNode} left The left operand * @param {ASTNode} right The right operand * @returns {ASTNode} An ASTNode representing the entire assignment expression */ createAssignmentExpression: function(operator, left, right) { return { type: astNodeTypes.AssignmentExpression, operator: operator, left: left, right: right }; }, /** * Create an ASTNode representation of an assignment pattern (default parameters) * @param {ASTNode} left The left operand * @param {ASTNode} right The right operand * @returns {ASTNode} An ASTNode representing the entire assignment pattern */ createAssignmentPattern: function(left, right) { return { type: astNodeTypes.AssignmentPattern, left: left, right: right }; }, /** * Create an ASTNode representation of a binary expression * @param {ASTNode} operator The assignment operator * @param {ASTNode} left The left operand * @param {ASTNode} right The right operand * @returns {ASTNode} An ASTNode representing the entire binary expression */ createBinaryExpression: function(operator, left, right) { var type = (operator === "||" || operator === "&&") ? astNodeTypes.LogicalExpression : astNodeTypes.BinaryExpression; return { type: type, operator: operator, left: left, right: right }; }, /** * Create an ASTNode representation of a block statement * @param {ASTNode} body The block statement body * @returns {ASTNode} An ASTNode representing the entire block statement */ createBlockStatement: function(body) { return { type: astNodeTypes.BlockStatement, body: body }; }, /** * Create an ASTNode representation of a break statement * @param {ASTNode} label The break statement label * @returns {ASTNode} An ASTNode representing the break statement */ createBreakStatement: function(label) { return { type: astNodeTypes.BreakStatement, label: label }; }, /** * Create an ASTNode representation of a call expression * @param {ASTNode} callee The function being called * @param {ASTNode[]} args An array of ASTNodes representing the function call arguments * @returns {ASTNode} An ASTNode representing the entire call expression */ createCallExpression: function(callee, args) { return { type: astNodeTypes.CallExpression, callee: callee, "arguments": args }; }, /** * Create an ASTNode representation of a catch clause/block * @param {ASTNode} param Any catch clause exeption/conditional parameter information * @param {ASTNode} body The catch block body * @returns {ASTNode} An ASTNode representing the entire catch clause */ createCatchClause: function(param, body) { return { type: astNodeTypes.CatchClause, param: param, body: body }; }, /** * Creates an ASTNode representation of a class body. * @param {ASTNode} body The node representing the body of the class. * @returns {ASTNode} An ASTNode representing the class body. */ createClassBody: function(body) { return { type: astNodeTypes.ClassBody, body: body }; }, createClassExpression: function(id, superClass, body) { return { type: astNodeTypes.ClassExpression, id: id, superClass: superClass, body: body }; }, createClassDeclaration: function(id, superClass, body) { return { type: astNodeTypes.ClassDeclaration, id: id, superClass: superClass, body: body }; }, createMethodDefinition: function(propertyType, kind, key, value, computed) { return { type: astNodeTypes.MethodDefinition, key: key, value: value, kind: kind, "static": propertyType === "static", computed: computed }; }, createMetaProperty: function(meta, property) { return { type: astNodeTypes.MetaProperty, meta: meta, property: property }; }, /** * Create an ASTNode representation of a conditional expression * @param {ASTNode} test The conditional to evaluate * @param {ASTNode} consequent The code to be run if the test returns true * @param {ASTNode} alternate The code to be run if the test returns false * @returns {ASTNode} An ASTNode representing the entire conditional expression */ createConditionalExpression: function(test, consequent, alternate) { return { type: astNodeTypes.ConditionalExpression, test: test, consequent: consequent, alternate: alternate }; }, /** * Create an ASTNode representation of a continue statement * @param {?ASTNode} label The optional continue label (null if not set) * @returns {ASTNode} An ASTNode representing the continue statement */ createContinueStatement: function(label) { return { type: astNodeTypes.ContinueStatement, label: label }; }, /** * Create an ASTNode representation of a debugger statement * @returns {ASTNode} An ASTNode representing the debugger statement */ createDebuggerStatement: function() { return { type: astNodeTypes.DebuggerStatement }; }, /** * Create an ASTNode representation of an empty statement * @returns {ASTNode} An ASTNode representing an empty statement */ createEmptyStatement: function() { return { type: astNodeTypes.EmptyStatement }; }, /** * Create an ASTNode representation of an expression statement * @param {ASTNode} expression The expression * @returns {ASTNode} An ASTNode representing an expression statement */ createExpressionStatement: function(expression) { return { type: astNodeTypes.ExpressionStatement, expression: expression }; }, /** * Create an ASTNode representation of a while statement * @param {ASTNode} test The while conditional * @param {ASTNode} body The while loop body * @returns {ASTNode} An ASTNode representing a while statement */ createWhileStatement: function(test, body) { return { type: astNodeTypes.WhileStatement, test: test, body: body }; }, /** * Create an ASTNode representation of a do..while statement * @param {ASTNode} test The do..while conditional * @param {ASTNode} body The do..while loop body * @returns {ASTNode} An ASTNode representing a do..while statement */ createDoWhileStatement: function(test, body) { return { type: astNodeTypes.DoWhileStatement, body: body, test: test }; }, /** * Create an ASTNode representation of a for statement * @param {ASTNode} init The initialization expression * @param {ASTNode} test The conditional test expression * @param {ASTNode} update The update expression * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for statement */ createForStatement: function(init, test, update, body) { return { type: astNodeTypes.ForStatement, init: init, test: test, update: update, body: body }; }, /** * Create an ASTNode representation of a for..in statement * @param {ASTNode} left The left-side variable for the property name * @param {ASTNode} right The right-side object * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for..in statement */ createForInStatement: function(left, right, body) { return { type: astNodeTypes.ForInStatement, left: left, right: right, body: body, each: false }; }, /** * Create an ASTNode representation of a for..of statement * @param {ASTNode} left The left-side variable for the property value * @param {ASTNode} right The right-side object * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for..of statement */ createForOfStatement: function(left, right, body) { return { type: astNodeTypes.ForOfStatement, left: left, right: right, body: body }; }, /** * Create an ASTNode representation of a function declaration * @param {ASTNode} id The function name * @param {ASTNode} params The function arguments * @param {ASTNode} body The function body * @param {boolean} generator True if the function is a generator, false if not. * @param {boolean} expression True if the function is created via an expression. * Always false for declarations, but kept here to be in sync with * FunctionExpression objects. * @returns {ASTNode} An ASTNode representing a function declaration */ createFunctionDeclaration: function (id, params, body, generator, expression) { return { type: astNodeTypes.FunctionDeclaration, id: id, params: params || [], body: body, generator: !!generator, expression: !!expression }; }, /** * Create an ASTNode representation of a function expression * @param {ASTNode} id The function name * @param {ASTNode} params The function arguments * @param {ASTNode} body The function body * @param {boolean} generator True if the function is a generator, false if not. * @param {boolean} expression True if the function is created via an expression. * @returns {ASTNode} An ASTNode representing a function declaration */ createFunctionExpression: function (id, params, body, generator, expression) { return { type: astNodeTypes.FunctionExpression, id: id, params: params || [], body: body, generator: !!generator, expression: !!expression }; }, /** * Create an ASTNode representation of an identifier * @param {ASTNode} name The identifier name * @returns {ASTNode} An ASTNode representing an identifier */ createIdentifier: function(name) { return { type: astNodeTypes.Identifier, name: name }; }, /** * Create an ASTNode representation of an if statement * @param {ASTNode} test The if conditional expression * @param {ASTNode} consequent The consequent if statement to run * @param {ASTNode} alternate the "else" alternate statement * @returns {ASTNode} An ASTNode representing an if statement */ createIfStatement: function(test, consequent, alternate) { return { type: astNodeTypes.IfStatement, test: test, consequent: consequent, alternate: alternate }; }, /** * Create an ASTNode representation of a labeled statement * @param {ASTNode} label The statement label * @param {ASTNode} body The labeled statement body * @returns {ASTNode} An ASTNode representing a labeled statement */ createLabeledStatement: function(label, body) { return { type: astNodeTypes.LabeledStatement, label: label, body: body }; }, /** * Create an ASTNode literal from the source code * @param {ASTNode} token The ASTNode token * @param {string} source The source code to get the literal from * @returns {ASTNode} An ASTNode representing the new literal */ createLiteralFromSource: function(token, source) { var node = { type: astNodeTypes.Literal, value: token.value, raw: source.slice(token.range[0], token.range[1]) }; // regular expressions have regex properties if (token.regex) { node.regex = token.regex; } return node; }, /** * Create an ASTNode template element * @param {Object} value Data on the element value * @param {string} value.raw The raw template string * @param {string} value.cooked The processed template string * @param {boolean} tail True if this is the final element in a template string * @returns {ASTNode} An ASTNode representing the template string element */ createTemplateElement: function(value, tail) { return { type: astNodeTypes.TemplateElement, value: value, tail: tail }; }, /** * Create an ASTNode template literal * @param {ASTNode[]} quasis An array of the template string elements * @param {ASTNode[]} expressions An array of the template string expressions * @returns {ASTNode} An ASTNode representing the template string */ createTemplateLiteral: function(quasis, expressions) { return { type: astNodeTypes.TemplateLiteral, quasis: quasis, expressions: expressions }; }, /** * Create an ASTNode representation of a spread element * @param {ASTNode} argument The array being spread * @returns {ASTNode} An ASTNode representing a spread element */ createSpreadElement: function(argument) { return { type: astNodeTypes.SpreadElement, argument: argument }; }, /** * Create an ASTNode representation of an experimental rest property * @param {ASTNode} argument The identifier being rested * @returns {ASTNode} An ASTNode representing a rest element */ createExperimentalRestProperty: function(argument) { return { type: astNodeTypes.ExperimentalRestProperty, argument: argument }; }, /** * Create an ASTNode representation of an experimental spread property * @param {ASTNode} argument The identifier being spread * @returns {ASTNode} An ASTNode representing a spread element */ createExperimentalSpreadProperty: function(argument) { return { type: astNodeTypes.ExperimentalSpreadProperty, argument: argument }; }, /** * Create an ASTNode tagged template expression * @param {ASTNode} tag The tag expression * @param {ASTNode} quasi A TemplateLiteral ASTNode representing * the template string itself. * @returns {ASTNode} An ASTNode representing the tagged template */ createTaggedTemplateExpression: function(tag, quasi) { return { type: astNodeTypes.TaggedTemplateExpression, tag: tag, quasi: quasi }; }, /** * Create an ASTNode representation of a member expression * @param {string} accessor The member access method (bracket or period) * @param {ASTNode} object The object being referenced * @param {ASTNode} property The object-property being referenced * @returns {ASTNode} An ASTNode representing a member expression */ createMemberExpression: function(accessor, object, property) { return { type: astNodeTypes.MemberExpression, computed: accessor === "[", object: object, property: property }; }, /** * Create an ASTNode representation of a new expression * @param {ASTNode} callee The constructor for the new object type * @param {ASTNode} args The arguments passed to the constructor * @returns {ASTNode} An ASTNode representing a new expression */ createNewExpression: function(callee, args) { return { type: astNodeTypes.NewExpression, callee: callee, "arguments": args }; }, /** * Create an ASTNode representation of a new object expression * @param {ASTNode[]} properties An array of ASTNodes that represent all object * properties and associated values * @returns {ASTNode} An ASTNode representing a new object expression */ createObjectExpression: function(properties) { return { type: astNodeTypes.ObjectExpression, properties: properties }; }, /** * Create an ASTNode representation of a postfix expression * @param {string} operator The postfix operator ("++", "--", etc.) * @param {ASTNode} argument The operator argument * @returns {ASTNode} An ASTNode representing a postfix expression */ createPostfixExpression: function(operator, argument) { return { type: astNodeTypes.UpdateExpression, operator: operator, argument: argument, prefix: false }; }, /** * Create an ASTNode representation of an entire program * @param {ASTNode} body The program body * @param {string} sourceType Either "module" or "script". * @returns {ASTNode} An ASTNode representing an entire program */ createProgram: function(body, sourceType) { return { type: astNodeTypes.Program, body: body, sourceType: sourceType }; }, /** * Create an ASTNode representation of an object property * @param {string} kind The type of property represented ("get", "set", etc.) * @param {ASTNode} key The property key * @param {ASTNode} value The new property value * @param {boolean} method True if the property is also a method (value is a function) * @param {boolean} shorthand True if the property is shorthand * @param {boolean} computed True if the property value has been computed * @returns {ASTNode} An ASTNode representing an object property */ createProperty: function(kind, key, value, method, shorthand, computed) { return { type: astNodeTypes.Property, key: key, value: value, kind: kind, method: method, shorthand: shorthand, computed: computed }; }, /** * Create an ASTNode representation of a rest element * @param {ASTNode} argument The rest argument * @returns {ASTNode} An ASTNode representing a rest element */ createRestElement: function (argument) { return { type: astNodeTypes.RestElement, argument: argument }; }, /** * Create an ASTNode representation of a return statement * @param {?ASTNode} argument The return argument, null if no argument is provided * @returns {ASTNode} An ASTNode representing a return statement */ createReturnStatement: function(argument) { return { type: astNodeTypes.ReturnStatement, argument: argument }; }, /** * Create an ASTNode representation of a sequence of expressions * @param {ASTNode[]} expressions An array containing each expression, in order * @returns {ASTNode} An ASTNode representing a sequence of expressions */ createSequenceExpression: function(expressions) { return { type: astNodeTypes.SequenceExpression, expressions: expressions }; }, /** * Create an ASTNode representation of super * @returns {ASTNode} An ASTNode representing super */ createSuper: function() { return { type: astNodeTypes.Super }; }, /** * Create an ASTNode representation of a switch case statement * @param {ASTNode} test The case value to test against the switch value * @param {ASTNode} consequent The consequent case statement * @returns {ASTNode} An ASTNode representing a switch case */ createSwitchCase: function(test, consequent) { return { type: astNodeTypes.SwitchCase, test: test, consequent: consequent }; }, /** * Create an ASTNode representation of a switch statement * @param {ASTNode} discriminant An expression to test against each case value * @param {ASTNode[]} cases An array of switch case statements * @returns {ASTNode} An ASTNode representing a switch statement */ createSwitchStatement: function(discriminant, cases) { return { type: astNodeTypes.SwitchStatement, discriminant: discriminant, cases: cases }; }, /** * Create an ASTNode representation of a this statement * @returns {ASTNode} An ASTNode representing a this statement */ createThisExpression: function() { return { type: astNodeTypes.ThisExpression }; }, /** * Create an ASTNode representation of a throw statement * @param {ASTNode} argument The argument to throw * @returns {ASTNode} An ASTNode representing a throw statement */ createThrowStatement: function(argument) { return { type: astNodeTypes.ThrowStatement, argument: argument }; }, /** * Create an ASTNode representation of a try statement * @param {ASTNode} block The try block * @param {ASTNode} handler A catch handler * @param {?ASTNode} finalizer The final code block to run after the try/catch has run * @returns {ASTNode} An ASTNode representing a try statement */ createTryStatement: function(block, handler, finalizer) { return { type: astNodeTypes.TryStatement, block: block, handler: handler, finalizer: finalizer }; }, /** * Create an ASTNode representation of a unary expression * @param {string} operator The unary operator * @param {ASTNode} argument The unary operand * @returns {ASTNode} An ASTNode representing a unary expression */ createUnaryExpression: function(operator, argument) { if (operator === "++" || operator === "--") { return { type: astNodeTypes.UpdateExpression, operator: operator, argument: argument, prefix: true }; } return { type: astNodeTypes.UnaryExpression, operator: operator, argument: argument, prefix: true }; }, /** * Create an ASTNode representation of a variable declaration * @param {ASTNode[]} declarations An array of variable declarations * @param {string} kind The kind of variable created ("var", "let", etc.) * @returns {ASTNode} An ASTNode representing a variable declaration */ createVariableDeclaration: function(declarations, kind) { return { type: astNodeTypes.VariableDeclaration, declarations: declarations, kind: kind }; }, /** * Create an ASTNode representation of a variable declarator * @param {ASTNode} id The variable ID * @param {ASTNode} init The variable's initial value * @returns {ASTNode} An ASTNode representing a variable declarator */ createVariableDeclarator: function(id, init) { return { type: astNodeTypes.VariableDeclarator, id: id, init: init }; }, /** * Create an ASTNode representation of a with statement * @param {ASTNode} object The with statement object expression * @param {ASTNode} body The with statement body * @returns {ASTNode} An ASTNode representing a with statement */ createWithStatement: function(object, body) { return { type: astNodeTypes.WithStatement, object: object, body: body }; }, createYieldExpression: function(argument, delegate) { return { type: astNodeTypes.YieldExpression, argument: argument || null, delegate: delegate }; }, createJSXAttribute: function(name, value) { return { type: astNodeTypes.JSXAttribute, name: name, value: value || null }; }, createJSXSpreadAttribute: function(argument) { return { type: astNodeTypes.JSXSpreadAttribute, argument: argument }; }, createJSXIdentifier: function(name) { return { type: astNodeTypes.JSXIdentifier, name: name }; }, createJSXNamespacedName: function(namespace, name) { return { type: astNodeTypes.JSXNamespacedName, namespace: namespace, name: name }; }, createJSXMemberExpression: function(object, property) { return { type: astNodeTypes.JSXMemberExpression, object: object, property: property }; }, createJSXElement: function(openingElement, closingElement, children) { return { type: astNodeTypes.JSXElement, openingElement: openingElement, closingElement: closingElement, children: children }; }, createJSXEmptyExpression: function() { return { type: astNodeTypes.JSXEmptyExpression }; }, createJSXExpressionContainer: function(expression) { return { type: astNodeTypes.JSXExpressionContainer, expression: expression }; }, createJSXOpeningElement: function(name, attributes, selfClosing) { return { type: astNodeTypes.JSXOpeningElement, name: name, selfClosing: selfClosing, attributes: attributes }; }, createJSXClosingElement: function(name) { return { type: astNodeTypes.JSXClosingElement, name: name }; }, createExportSpecifier: function(local, exported) { return { type: astNodeTypes.ExportSpecifier, exported: exported || local, local: local }; }, createImportDefaultSpecifier: function(local) { return { type: astNodeTypes.ImportDefaultSpecifier, local: local }; }, createImportNamespaceSpecifier: function(local) { return { type: astNodeTypes.ImportNamespaceSpecifier, local: local }; }, createExportNamedDeclaration: function(declaration, specifiers, source) { return { type: astNodeTypes.ExportNamedDeclaration, declaration: declaration, specifiers: specifiers, source: source }; }, createExportDefaultDeclaration: function(declaration) { return { type: astNodeTypes.ExportDefaultDeclaration, declaration: declaration }; }, createExportAllDeclaration: function(source) { return { type: astNodeTypes.ExportAllDeclaration, source: source }; }, createImportSpecifier: function(local, imported) { return { type: astNodeTypes.ImportSpecifier, local: local || imported, imported: imported }; }, createImportDeclaration: function(specifiers, source) { return { type: astNodeTypes.ImportDeclaration, specifiers: specifiers, source: source }; } };