This is an automated email from the ASF dual-hosted git repository. davisp pushed a commit to reference refs/pull/133/head in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git
commit 037de229942ae16d185587bf551c0e911c7686eb Author: Kyle Simpson <[email protected]> AuthorDate: Sun Sep 22 14:23:45 2013 -0500 adding support for 'extras' (leading and trailing whitespace, single-line comments, multiline comments) to be tracked on (and thus outputted from) all AST-Node types (identifiers, expressions, statements, etc --- escodegen.js | 95 +++++++++++++++ test/ast.js | 384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 479 insertions(+) diff --git a/escodegen.js b/escodegen.js index 6f32f66..c9c814b 100644 --- a/escodegen.js +++ b/escodegen.js @@ -81,6 +81,7 @@ DoWhileStatement: 'DoWhileStatement', DebuggerStatement: 'DebuggerStatement', EmptyStatement: 'EmptyStatement', + EmptyExpression: 'EmptyExpression', ExpressionStatement: 'ExpressionStatement', ForStatement: 'ForStatement', ForInStatement: 'ForInStatement', @@ -304,6 +305,10 @@ return ch === '\r' || ch === '\n'; } + function startsWithLineTerminator(str) { + return isLineTerminator(str.charAt(0)); + } + function updateDeeply(target, override) { var key, val; @@ -769,6 +774,78 @@ return result; } + function addExtrasToNode(node, result) { + + function addExtras(extras, result) { + var i, len, extra; + + for (i = 0, len = extras.length; i < len; i += 1) { + // was previous extra a line-comment? + if (previousLineComment) { + // need to insert a new-line to delimit previous line-comment? + if (!startsWithLineTerminator(extras[i].value)) { + result.push('\n'); + } + } + + extra = extras[i]; + + if (extra.type === 'Whitespace') { + result.push(extra.value); + previousLineComment = false; + } + else if (extra.type === 'LineComment') { + result.push((extra.marker || '//') + extra.value); + previousLineComment = true; + } + else if (extra.type === 'MultilineComment') { + result.push('/*' + extra.value + '*/'); + previousLineComment = false; + } + } + + return result; + } + + var save, previousLineComment = false; + + if (node && node.extras) { + if (node.extras.leading && node.extras.leading.length > 0) { + save = result; + result = []; + + result = addExtras(node.extras.leading, result); + + // was last extra a line-comment? + if (previousLineComment) { + // need to insert a new-line to delimit previous line-comment? + if (!startsWithLineTerminator(toSourceNode(save).toString() || '')) { + result.push('\n'); + previousLineComment = false; + } + } + + result.push(save); + } + + if (node.extras.trailing && node.extras.trailing.length > 0) { + // if result is not yet an array, make it one so we can add to it + if (!Array.isArray(result)) { + result = [result]; + } + result = addExtras(node.extras.trailing, result); + + // was last extra a line-comment? + if (previousLineComment) { + // insert a new-line to delimit previous line-comment + result.push('\n'); + } + } + } + + return result; + } + function parenthesize(text, current, should) { if (current < should) { return ['(', text, ')']; @@ -890,6 +967,15 @@ } switch (type) { + + case Syntax.EmptyExpression: + // 'EmptyExpression' is just a placeholder node for where only + // extras are present. + // Example: comment or whitespace extras in an otherwise empty + // arguments list of a call expression + result = []; + break; + case Syntax.SequenceExpression: result = []; allowIn |= (Precedence.Sequence < precedence); @@ -1488,6 +1574,10 @@ throw new Error('Unknown expression type: ' + expr.type); } + if (expr.extras) { + result = addExtrasToNode(expr, result); + } + return toSourceNode(result, expr); } @@ -1957,6 +2047,10 @@ result = toSourceNode(result).replaceRight(/\s+$/, ''); } + if (stmt.extras) { + result = addExtrasToNode(stmt, result); + } + return toSourceNode(result, stmt); } @@ -2052,6 +2146,7 @@ case Syntax.BinaryExpression: case Syntax.CallExpression: case Syntax.ConditionalExpression: + case Syntax.EmptyExpression: case Syntax.FunctionExpression: case Syntax.Identifier: case Syntax.Literal: diff --git a/test/ast.js b/test/ast.js index 8fc648a..997fceb 100644 --- a/test/ast.js +++ b/test/ast.js @@ -148,6 +148,390 @@ data = { }], expected: '/(?:)/i;' } + ], + 'AST-Node "extras"': [ + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'Identifier', + name: 'foo' + }, + }], + extras: { + leading: [ + { + type: 'Whitespace', + value: '\t' + } + ], + }, + expected: '\tfoo;' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'Identifier', + name: 'foo' + }, + }], + extras: { + trailing: [ + { + type: 'Whitespace', + value: '\t' + } + ], + }, + expected: 'foo;\t' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'Identifier', + name: 'foo' + }, + extras: { + leading: [ + { + type: 'Whitespace', + value: '\t' + } + ], + trailing: [ + { + type: 'Whitespace', + value: '\t' + } + ], + }, + }], + expected: '\tfoo;\t' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'Identifier', + name: 'foo', + extras: { + leading: [ + { + type: 'Whitespace', + value: '\t' + } + ], + trailing: [ + { + type: 'Whitespace', + value: '\t' + } + ], + }, + }, + }], + expected: '\tfoo\t;' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo' + }, + arguments: [ + { + type: 'EmptyExpression', + value: '', + extras: { + leading: [ + { + type: 'Whitespace', + value: '\t' + } + ], + trailing: [ + { + type: 'Whitespace', + value: '\t' + } + ], + }, + } + ], + }, + }], + expected: 'foo(\t\t);' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '2' + }, + ], + } + }, + arguments: [ + { + type: 'EmptyExpression', + value: '', + extras: { + leading: [ + { + type: 'MultilineComment', + value: '3' + }, + ], + }, + } + ], + extras: { + leading: [ + { + type: 'MultilineComment', + value: '1' + }, + ], + trailing: [ + { + type: 'MultilineComment', + value: '4' + }, + ], + } + }, + }], + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '5' + }, + ], + }, + expected: '/*1*/foo/*2*/(/*3*/)/*4*/;/*5*/' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '2' + }, + ], + } + }, + arguments: [ + { + type: 'EmptyExpression', + value: '', + extras: { + leading: [ + { + type: 'LineComment', + value: '3' + } + ], + trailing: [ + { + type: 'MultilineComment', + value: '4' + }, + ], + }, + } + ], + extras: { + leading: [ + { + type: 'MultilineComment', + value: '1' + }, + ], + trailing: [ + { + type: 'MultilineComment', + value: '5' + }, + ] + } + }, + }], + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '6' + }, + ], + }, + expected: '/*1*/foo/*2*/(//3\n/*4*/)/*5*/;/*6*/' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '2' + }, + ], + } + }, + arguments: [ + { + type: 'Literal', + value: 4, + raw: '4', + extras: { + leading: [ + { + type: 'LineComment', + value: '3' + } + ], + trailing: [ + { + type: 'MultilineComment', + value: '5' + }, + ], + }, + } + ], + extras: { + leading: [ + { + type: 'MultilineComment', + value: '1' + }, + ], + trailing: [ + { + type: 'MultilineComment', + value: '6' + }, + ] + } + }, + }], + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '7' + }, + ], + }, + expected: '/*1*/foo/*2*/(//3\n4/*5*/)/*6*/;/*7*/' + }, + { + type: 'Program', + body: [{ + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '2' + }, + ], + } + }, + arguments: [ + { + type: 'Literal', + value: 4, + raw: '4', + extras: { + leading: [ + { + type: 'LineComment', + value: '3' + } + ], + trailing: [ + { + type: 'MultilineComment', + value: '5' + }, + // NOTE: testing custom line-comment markers, + // in support of HTML-style line-comment markers + // Ref: http://javascript.spec.whatwg.org/#comment-syntax + { + type: 'LineComment', + value: '6', + marker: '<!--' + } + ], + }, + } + ], + extras: { + leading: [ + { + type: 'MultilineComment', + value: '1' + }, + ], + trailing: [ + { + type: 'MultilineComment', + value: '7' + }, + ] + } + }, + }], + extras: { + trailing: [ + { + type: 'MultilineComment', + value: '8' + }, + ], + }, + expected: '/*1*/foo/*2*/(//3\n4/*5*/<!--6\n)/*7*/;/*8*/' + }, ] };
