| Index: compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java
|
| diff --git a/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java b/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java
|
| deleted file mode 100644
|
| index ed0666c9d97fcc37f303f4d5370e3a774a89c210..0000000000000000000000000000000000000000
|
| --- a/compiler/java/com/google/dart/compiler/backend/js/JsToStringGenerationVisitor.java
|
| +++ /dev/null
|
| @@ -1,1354 +0,0 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -package com.google.dart.compiler.backend.js;
|
| -
|
| -import com.google.common.collect.Lists;
|
| -import com.google.dart.compiler.backend.js.ast.HasName;
|
| -import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
|
| -import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
| -import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
| -import com.google.dart.compiler.backend.js.ast.JsBlock;
|
| -import com.google.dart.compiler.backend.js.ast.JsBooleanLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsBreak;
|
| -import com.google.dart.compiler.backend.js.ast.JsCase;
|
| -import com.google.dart.compiler.backend.js.ast.JsCatch;
|
| -import com.google.dart.compiler.backend.js.ast.JsConditional;
|
| -import com.google.dart.compiler.backend.js.ast.JsContext;
|
| -import com.google.dart.compiler.backend.js.ast.JsContinue;
|
| -import com.google.dart.compiler.backend.js.ast.JsDebugger;
|
| -import com.google.dart.compiler.backend.js.ast.JsDefault;
|
| -import com.google.dart.compiler.backend.js.ast.JsDoWhile;
|
| -import com.google.dart.compiler.backend.js.ast.JsEmpty;
|
| -import com.google.dart.compiler.backend.js.ast.JsExprStmt;
|
| -import com.google.dart.compiler.backend.js.ast.JsExpression;
|
| -import com.google.dart.compiler.backend.js.ast.JsFor;
|
| -import com.google.dart.compiler.backend.js.ast.JsForIn;
|
| -import com.google.dart.compiler.backend.js.ast.JsFunction;
|
| -import com.google.dart.compiler.backend.js.ast.JsIf;
|
| -import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
| -import com.google.dart.compiler.backend.js.ast.JsLabel;
|
| -import com.google.dart.compiler.backend.js.ast.JsName;
|
| -import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
| -import com.google.dart.compiler.backend.js.ast.JsNew;
|
| -import com.google.dart.compiler.backend.js.ast.JsNullLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsNumberLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsObjectLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsOperator;
|
| -import com.google.dart.compiler.backend.js.ast.JsParameter;
|
| -import com.google.dart.compiler.backend.js.ast.JsPostfixOperation;
|
| -import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
|
| -import com.google.dart.compiler.backend.js.ast.JsProgram;
|
| -import com.google.dart.compiler.backend.js.ast.JsProgramFragment;
|
| -import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
| -import com.google.dart.compiler.backend.js.ast.JsRegExp;
|
| -import com.google.dart.compiler.backend.js.ast.JsReturn;
|
| -import com.google.dart.compiler.backend.js.ast.JsStatement;
|
| -import com.google.dart.compiler.backend.js.ast.JsStringLiteral;
|
| -import com.google.dart.compiler.backend.js.ast.JsSwitch;
|
| -import com.google.dart.compiler.backend.js.ast.JsThisRef;
|
| -import com.google.dart.compiler.backend.js.ast.JsThrow;
|
| -import com.google.dart.compiler.backend.js.ast.JsTry;
|
| -import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
|
| -import com.google.dart.compiler.backend.js.ast.JsVars;
|
| -import com.google.dart.compiler.backend.js.ast.JsVisitable;
|
| -import com.google.dart.compiler.backend.js.ast.JsVisitor;
|
| -import com.google.dart.compiler.backend.js.ast.JsWhile;
|
| -import com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
|
| -import com.google.dart.compiler.common.HasSourceInfo;
|
| -import com.google.dart.compiler.util.TextOutput;
|
| -
|
| -import java.io.IOException;
|
| -import java.util.ArrayList;
|
| -import java.util.HashSet;
|
| -import java.util.Iterator;
|
| -import java.util.List;
|
| -import java.util.Set;
|
| -import java.util.regex.Pattern;
|
| -
|
| -/**
|
| - * Produces text output from a JavaScript AST.
|
| - */
|
| -public class JsToStringGenerationVisitor extends JsVisitor {
|
| -
|
| - private static final char[] CHARS_BREAK = "break".toCharArray();
|
| - private static final char[] CHARS_CASE = "case".toCharArray();
|
| - private static final char[] CHARS_CATCH = "catch".toCharArray();
|
| - private static final char[] CHARS_CONTINUE = "continue".toCharArray();
|
| - private static final char[] CHARS_DEBUGGER = "debugger".toCharArray();
|
| - private static final char[] CHARS_DEFAULT = "default".toCharArray();
|
| - private static final char[] CHARS_DO = "do".toCharArray();
|
| - private static final char[] CHARS_ELSE = "else".toCharArray();
|
| - private static final char[] CHARS_FALSE = "false".toCharArray();
|
| - private static final char[] CHARS_FINALLY = "finally".toCharArray();
|
| - private static final char[] CHARS_FOR = "for".toCharArray();
|
| - private static final char[] CHARS_FUNCTION = "function".toCharArray();
|
| - private static final char[] CHARS_IF = "if".toCharArray();
|
| - private static final char[] CHARS_IN = "in".toCharArray();
|
| - private static final char[] CHARS_NEW = "new".toCharArray();
|
| - private static final char[] CHARS_NULL = "null".toCharArray();
|
| - private static final char[] CHARS_RETURN = "return".toCharArray();
|
| - private static final char[] CHARS_SWITCH = "switch".toCharArray();
|
| - private static final char[] CHARS_THIS = "this".toCharArray();
|
| - private static final char[] CHARS_THROW = "throw".toCharArray();
|
| - private static final char[] CHARS_TRUE = "true".toCharArray();
|
| - private static final char[] CHARS_TRY = "try".toCharArray();
|
| - private static final char[] CHARS_VAR = "var".toCharArray();
|
| - private static final char[] CHARS_WHILE = "while".toCharArray();
|
| - private static final char[] HEX_DIGITS = {
|
| - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
| -
|
| - /**
|
| - * How many lines of code to print inside of a JsBlock when printing terse.
|
| - */
|
| - private static final int JSBLOCK_LINES_TO_PRINT = 3;
|
| -
|
| - /**
|
| - * A variable name is valid if it contains only letters, numbers, _, $ and
|
| - * does not begin with a number. There are actually other valid variable
|
| - * names, such as ones that contain escaped Unicode characters, but we
|
| - * surround those names with quotes in property initializers to be safe.
|
| - */
|
| - private static final Pattern VALID_NAME_PATTERN = Pattern.compile("[a-zA-Z_$][\\w$]*");
|
| -
|
| - public static String javaScriptString(String value) {
|
| - return javaScriptString(value, false);
|
| - }
|
| -
|
| - /**
|
| - * Generate JavaScript code that evaluates to the supplied string. Adapted
|
| - * from {@link ScriptRuntime#escapeString(String)}
|
| - * . The difference is that we quote with either " or ' depending on
|
| - * which one is used less inside the string.
|
| - */
|
| - public static String javaScriptString(String value, boolean forceDoubleQuote) {
|
| - char[] chars = value.toCharArray();
|
| - final int n = chars.length;
|
| - int quoteCount = 0;
|
| - int aposCount = 0;
|
| - for (int i = 0; i < n; ++i) {
|
| - switch (chars[i]) {
|
| - case '"':
|
| - ++quoteCount;
|
| - break;
|
| - case '\'':
|
| - ++aposCount;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - StringBuffer result = new StringBuffer(value.length() + 16);
|
| -
|
| - char quoteChar = (quoteCount < aposCount || forceDoubleQuote) ? '"' : '\'';
|
| - result.append(quoteChar);
|
| -
|
| - for (int i = 0; i < n; ++i) {
|
| - char c = chars[i];
|
| -
|
| - if (' ' <= c && c <= '~' && c != quoteChar && c != '\\') {
|
| - // an ordinary print character (like C isprint())
|
| - result.append(c);
|
| - continue;
|
| - }
|
| -
|
| - int escape = -1;
|
| - switch (c) {
|
| - case '\b':
|
| - escape = 'b';
|
| - break;
|
| - case '\f':
|
| - escape = 'f';
|
| - break;
|
| - case '\n':
|
| - escape = 'n';
|
| - break;
|
| - case '\r':
|
| - escape = 'r';
|
| - break;
|
| - case '\t':
|
| - escape = 't';
|
| - break;
|
| - case '"':
|
| - escape = '"';
|
| - break; // only reach here if == quoteChar
|
| - case '\'':
|
| - escape = '\'';
|
| - break; // only reach here if == quoteChar
|
| - case '\\':
|
| - escape = '\\';
|
| - break;
|
| - }
|
| -
|
| - if (escape >= 0) {
|
| - // an \escaped sort of character
|
| - result.append('\\');
|
| - result.append((char) escape);
|
| - } else {
|
| - /*
|
| - * Emit characters from 0 to 31 that don't have a single character
|
| - * escape sequence in octal where possible. This saves one or two
|
| - * characters compared to the hexadecimal format '\xXX'.
|
| - *
|
| - * These short octal sequences may only be used at the end of the string
|
| - * or where the following character is a non-digit. Otherwise, the
|
| - * following character would be incorrectly interpreted as belonging to
|
| - * the sequence.
|
| - */
|
| - if (c < ' ' && (i == n - 1 || chars[i + 1] < '0' || chars[i + 1] > '9')) {
|
| - result.append('\\');
|
| - if (c > 0x7) {
|
| - result.append((char) ('0' + (0x7 & (c >> 3))));
|
| - }
|
| - result.append((char) ('0' + (0x7 & c)));
|
| - } else {
|
| - int hexSize;
|
| - if (c < 256) {
|
| - // 2-digit hex
|
| - result.append("\\x");
|
| - hexSize = 2;
|
| - } else {
|
| - // Unicode.
|
| - result.append("\\u");
|
| - hexSize = 4;
|
| - }
|
| - // append hexadecimal form of ch left-padded with 0
|
| - for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
|
| - int digit = 0xf & (c >> shift);
|
| - result.append(HEX_DIGITS[digit]);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - result.append(quoteChar);
|
| - escapeClosingTags(result);
|
| - String resultString = result.toString();
|
| - return resultString;
|
| - }
|
| -
|
| - /**
|
| - * Escapes any closing XML tags embedded in <code>str</code>, which could
|
| - * potentially cause a parse failure in a browser, for example, embedding a
|
| - * closing <code><script></code> tag.
|
| - *
|
| - * @param str an unescaped literal; May be null
|
| - */
|
| - private static void escapeClosingTags(StringBuffer str) {
|
| - if (str == null) {
|
| - return;
|
| - }
|
| -
|
| - int index = 0;
|
| -
|
| - while ((index = str.indexOf("</", index)) != -1) {
|
| - str.insert(index + 1, '\\');
|
| - }
|
| - }
|
| -
|
| - protected boolean needSemi = true;
|
| -
|
| - /**
|
| - * "Global" blocks are either the global block of a fragment, or a block
|
| - * nested directly within some other global block. This definition matters
|
| - * because the statements designated by statementEnds and statementStarts are
|
| - * those that appear directly within these global blocks.
|
| - */
|
| - private Set<JsBlock> globalBlocks = new HashSet<JsBlock>();
|
| - private final TextOutput p;
|
| - private ArrayList<Integer> statementEnds = new ArrayList<Integer>();
|
| - private ArrayList<Integer> statementStarts = new ArrayList<Integer>();
|
| -
|
| - public JsToStringGenerationVisitor(TextOutput out) {
|
| - this.p = out;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsArrayAccess x, JsContext ctx) {
|
| - JsExpression arrayExpr = x.getArrayExpr();
|
| - _parenPush(x, arrayExpr, false);
|
| - accept(arrayExpr);
|
| - _parenPop(x, arrayExpr, false);
|
| - _lsquare();
|
| - accept(x.getIndexExpr());
|
| - _rsquare();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsArrayLiteral x, JsContext ctx) {
|
| - _lsquare();
|
| - boolean sep = false;
|
| - for (Object element : x.getExpressions()) {
|
| - JsExpression arg = (JsExpression) element;
|
| - sep = _sepCommaOptSpace(sep);
|
| - _parenPushIfCommaExpr(arg);
|
| - accept(arg);
|
| - _parenPopIfCommaExpr(arg);
|
| - }
|
| - _rsquare();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsBinaryOperation x, JsContext ctx) {
|
| - JsBinaryOperator op = x.getOperator();
|
| - JsExpression arg1 = x.getArg1();
|
| - _parenPush(x, arg1, !op.isLeftAssociative());
|
| - accept(arg1);
|
| - if (op.isKeyword()) {
|
| - _parenPopOrSpace(x, arg1, !op.isLeftAssociative());
|
| - } else {
|
| - _parenPop(x, arg1, !op.isLeftAssociative());
|
| - _spaceOpt();
|
| - }
|
| - p.print(op.getSymbol());
|
| - JsExpression arg2 = x.getArg2();
|
| - if (_spaceCalc(op, arg2)) {
|
| - _parenPushOrSpace(x, arg2, op.isLeftAssociative());
|
| - } else {
|
| - _spaceOpt();
|
| - _parenPush(x, arg2, op.isLeftAssociative());
|
| - }
|
| - accept(arg2);
|
| - _parenPop(x, arg2, op.isLeftAssociative());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsBlock x, JsContext ctx) {
|
| - printJsBlock(x, true, true);
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsBooleanLiteral x, JsContext ctx) {
|
| - if (x.getValue()) {
|
| - _true();
|
| - } else {
|
| - _false();
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsBreak x, JsContext ctx) {
|
| - _break();
|
| -
|
| - JsNameRef label = x.getLabel();
|
| - if (label != null) {
|
| - _space();
|
| - _nameRef(label);
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsCase x, JsContext ctx) {
|
| - _case();
|
| - _space();
|
| - accept(x.getCaseExpr());
|
| - _colon();
|
| - _newlineOpt();
|
| -
|
| - indent();
|
| - for (Object element : x.getStmts()) {
|
| - JsStatement stmt = (JsStatement) element;
|
| - needSemi = true;
|
| - accept(stmt);
|
| - if (needSemi) {
|
| - _semi();
|
| - }
|
| - _newlineOpt();
|
| - }
|
| - outdent();
|
| - needSemi = false;
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsCatch x, JsContext ctx) {
|
| - _spaceOpt();
|
| - _catch();
|
| - _spaceOpt();
|
| - _lparen();
|
| - _nameDef(x.getParameter().getName());
|
| -
|
| - // Optional catch condition.
|
| - //
|
| - JsExpression catchCond = x.getCondition();
|
| - if (catchCond != null) {
|
| - _space();
|
| - _if();
|
| - _space();
|
| - accept(catchCond);
|
| - }
|
| -
|
| - _rparen();
|
| - _spaceOpt();
|
| - accept(x.getBody());
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsConditional x, JsContext ctx) {
|
| - // Associativity: for the then and else branches, it is safe to insert
|
| - // another
|
| - // ternary expression, but if the test expression is a ternary, it should
|
| - // get parentheses around it.
|
| - {
|
| - JsExpression testExpression = x.getTestExpression();
|
| - _parenPush(x, testExpression, true);
|
| - accept(testExpression);
|
| - _parenPop(x, testExpression, true);
|
| - }
|
| - _questionMark();
|
| - {
|
| - JsExpression thenExpression = x.getThenExpression();
|
| - _parenPush(x, thenExpression, false);
|
| - accept(thenExpression);
|
| - _parenPop(x, thenExpression, false);
|
| - }
|
| - _colon();
|
| - {
|
| - JsExpression elseExpression = x.getElseExpression();
|
| - _parenPush(x, elseExpression, false);
|
| - accept(elseExpression);
|
| - _parenPop(x, elseExpression, false);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsContinue x, JsContext ctx) {
|
| - _continue();
|
| -
|
| - JsNameRef label = x.getLabel();
|
| - if (label != null) {
|
| - _space();
|
| - _nameRef(label);
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsDebugger x, JsContext ctx) {
|
| - _debugger();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsDefault x, JsContext ctx) {
|
| - _default();
|
| - _colon();
|
| -
|
| - indent();
|
| - for (Object element : x.getStmts()) {
|
| - JsStatement stmt = (JsStatement) element;
|
| - needSemi = true;
|
| - accept(stmt);
|
| - if (needSemi) {
|
| - _semi();
|
| - }
|
| - _newlineOpt();
|
| - }
|
| - outdent();
|
| - needSemi = false;
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsDoWhile x, JsContext ctx) {
|
| - _do();
|
| - _nestedPush(x.getBody(), true);
|
| - accept(x.getBody());
|
| - _nestedPop(x.getBody());
|
| - if (needSemi) {
|
| - _semi();
|
| - _newlineOpt();
|
| - } else {
|
| - _spaceOpt();
|
| - needSemi = true;
|
| - }
|
| - _while();
|
| - _spaceOpt();
|
| - _lparen();
|
| - accept(x.getCondition());
|
| - _rparen();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsEmpty x, JsContext ctx) {
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsExprStmt x, JsContext ctx) {
|
| - boolean surroundWithParentheses = JsFirstExpressionVisitor.exec(x);
|
| - if (surroundWithParentheses) {
|
| - _lparen();
|
| - }
|
| - JsExpression expr = x.getExpression();
|
| - accept(expr);
|
| - if (surroundWithParentheses) {
|
| - _rparen();
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsFor x, JsContext ctx) {
|
| - _for();
|
| - _spaceOpt();
|
| - _lparen();
|
| -
|
| - // The init expressions or var decl.
|
| - //
|
| - if (x.getInitExpr() != null) {
|
| - accept(x.getInitExpr());
|
| - } else if (x.getInitVars() != null) {
|
| - accept(x.getInitVars());
|
| - }
|
| -
|
| - _semi();
|
| -
|
| - // The loop test.
|
| - //
|
| - if (x.getCondition() != null) {
|
| - _spaceOpt();
|
| - accept(x.getCondition());
|
| - }
|
| -
|
| - _semi();
|
| -
|
| - // The incr expression.
|
| - //
|
| - if (x.getIncrExpr() != null) {
|
| - _spaceOpt();
|
| - accept(x.getIncrExpr());
|
| - }
|
| -
|
| - _rparen();
|
| - _nestedPush(x.getBody(), false);
|
| - accept(x.getBody());
|
| - _nestedPop(x.getBody());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsForIn x, JsContext ctx) {
|
| - _for();
|
| - _spaceOpt();
|
| - _lparen();
|
| -
|
| - if (x.getIterVarName() != null) {
|
| - _var();
|
| - _space();
|
| - _nameDef(x.getIterVarName());
|
| -
|
| - if (x.getIterExpr() != null) {
|
| - _spaceOpt();
|
| - _assignment();
|
| - _spaceOpt();
|
| - accept(x.getIterExpr());
|
| - }
|
| - } else {
|
| - // Just a name ref.
|
| - //
|
| - accept(x.getIterExpr());
|
| - }
|
| -
|
| - _space();
|
| - _in();
|
| - _space();
|
| - accept(x.getObjExpr());
|
| -
|
| - _rparen();
|
| - _nestedPush(x.getBody(), false);
|
| - accept(x.getBody());
|
| - _nestedPop(x.getBody());
|
| - return false;
|
| - }
|
| -
|
| - // function foo(a, b) {
|
| - // stmts...
|
| - // }
|
| - //
|
| - @Override
|
| - public boolean visit(JsFunction x, JsContext ctx) {
|
| - _function();
|
| -
|
| - // Functions can be anonymous.
|
| - //
|
| - if (x.getName() != null) {
|
| - _space();
|
| - _nameOf(x);
|
| - }
|
| -
|
| - _lparen();
|
| - boolean sep = false;
|
| - for (Object element : x.getParameters()) {
|
| - JsParameter param = (JsParameter) element;
|
| - sep = _sepCommaOptSpace(sep);
|
| - accept(param);
|
| - }
|
| - _rparen();
|
| -
|
| - accept(x.getBody());
|
| - needSemi = true;
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsIf x, JsContext ctx) {
|
| - _if();
|
| - _spaceOpt();
|
| - _lparen();
|
| - accept(x.getIfExpr());
|
| - _rparen();
|
| - JsStatement thenStmt = x.getThenStmt();
|
| - _nestedPush(thenStmt, false);
|
| - accept(thenStmt);
|
| - _nestedPop(thenStmt);
|
| - JsStatement elseStmt = x.getElseStmt();
|
| - if (elseStmt != null) {
|
| - if (needSemi) {
|
| - _semi();
|
| - _newlineOpt();
|
| - } else {
|
| - _spaceOpt();
|
| - needSemi = true;
|
| - }
|
| - _else();
|
| - boolean elseIf = elseStmt instanceof JsIf;
|
| - if (!elseIf) {
|
| - _nestedPush(elseStmt, true);
|
| - } else {
|
| - _space();
|
| - }
|
| - accept(elseStmt);
|
| - if (!elseIf) {
|
| - _nestedPop(elseStmt);
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsInvocation x, JsContext ctx) {
|
| - JsExpression qualifier = x.getQualifier();
|
| - _parenPush(x, qualifier, false);
|
| - accept(qualifier);
|
| - _parenPop(x, qualifier, false);
|
| -
|
| - _lparen();
|
| - boolean sep = false;
|
| - for (Object element : x.getArguments()) {
|
| - JsExpression arg = (JsExpression) element;
|
| - sep = _sepCommaOptSpace(sep);
|
| - _parenPushIfCommaExpr(arg);
|
| - accept(arg);
|
| - _parenPopIfCommaExpr(arg);
|
| - }
|
| - _rparen();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsLabel x, JsContext ctx) {
|
| - _nameOf(x);
|
| - _colon();
|
| - _spaceOpt();
|
| - accept(x.getStmt());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsNameRef x, JsContext ctx) {
|
| - JsExpression q = x.getQualifier();
|
| - if (q != null) {
|
| - _parenPush(x, q, false);
|
| - if (q instanceof JsNumberLiteral) {
|
| - /**
|
| - * Fix for Issue #3796. "42.foo" is not allowed, but "(42).foo" is.
|
| - */
|
| - _lparen();
|
| - }
|
| - accept(q);
|
| - if (q instanceof JsNumberLiteral) {
|
| - _rparen();
|
| - }
|
| - _parenPop(x, q, false);
|
| - _dot();
|
| - }
|
| - _nameRef(x);
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsNew x, JsContext ctx) {
|
| - _new();
|
| - _space();
|
| -
|
| - JsExpression ctorExpr = x.getConstructorExpression();
|
| - boolean needsParens = JsConstructExpressionVisitor.exec(ctorExpr);
|
| - if (needsParens) {
|
| - _lparen();
|
| - }
|
| - accept(ctorExpr);
|
| - if (needsParens) {
|
| - _rparen();
|
| - }
|
| -
|
| - /*
|
| - * If a constructor call has no arguments, it may simply be replaced with
|
| - * "new Constructor" with no parentheses.
|
| - */
|
| - List<JsExpression> args = x.getArguments();
|
| - if (args.size() > 0) {
|
| - _lparen();
|
| - boolean sep = false;
|
| - for (JsExpression arg : args) {
|
| - sep = _sepCommaOptSpace(sep);
|
| - _parenPushIfCommaExpr(arg);
|
| - accept(arg);
|
| - _parenPopIfCommaExpr(arg);
|
| - }
|
| - _rparen();
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsNullLiteral x, JsContext ctx) {
|
| - _null();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsNumberLiteral x, JsContext ctx) {
|
| - double dvalue = x.getValue();
|
| - long lvalue = (long) dvalue;
|
| - if (lvalue == dvalue) {
|
| - p.print(Long.toString(lvalue));
|
| - } else {
|
| - p.print(Double.toString(dvalue));
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsObjectLiteral x, JsContext ctx) {
|
| - _lbrace();
|
| - boolean sep = false;
|
| - for (Object element : x.getPropertyInitializers()) {
|
| - sep = _sepCommaOptSpace(sep);
|
| - JsPropertyInitializer propInit = (JsPropertyInitializer) element;
|
| - printLabel : {
|
| - JsExpression labelExpr = propInit.getLabelExpr();
|
| - // labels can be either string, integral, or decimal literals
|
| - if (labelExpr instanceof JsStringLiteral) {
|
| - String propName = ((JsStringLiteral) labelExpr).getValue();
|
| - if (VALID_NAME_PATTERN.matcher(propName).matches()
|
| - && !JsReservedIdentifiers.isKeyword(propName)) {
|
| - p.print(propName);
|
| - break printLabel;
|
| - }
|
| - }
|
| - accept(labelExpr);
|
| - }
|
| - _colon();
|
| - JsExpression valueExpr = propInit.getValueExpr();
|
| - _parenPushIfCommaExpr(valueExpr);
|
| - accept(valueExpr);
|
| - _parenPopIfCommaExpr(valueExpr);
|
| - }
|
| - _rbrace();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsParameter x, JsContext ctx) {
|
| - _nameOf(x);
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsPostfixOperation x, JsContext ctx) {
|
| - JsUnaryOperator op = x.getOperator();
|
| - JsExpression arg = x.getArg();
|
| - // unary operators always associate correctly (I think)
|
| - _parenPush(x, arg, false);
|
| - accept(arg);
|
| - _parenPop(x, arg, false);
|
| - p.print(op.getSymbol());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsPrefixOperation x, JsContext ctx) {
|
| - JsUnaryOperator op = x.getOperator();
|
| - p.print(op.getSymbol());
|
| - JsExpression arg = x.getArg();
|
| - if (_spaceCalc(op, arg)) {
|
| - _space();
|
| - }
|
| - // unary operators always associate correctly (I think)
|
| - _parenPush(x, arg, false);
|
| - accept(arg);
|
| - _parenPop(x, arg, false);
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsProgram x, JsContext ctx) {
|
| - p.print("<JsProgram>");
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsProgramFragment x, JsContext ctx) {
|
| - p.print("<JsProgramFragment>");
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsPropertyInitializer x, JsContext ctx) {
|
| - // Since there are separators, we actually print the property init
|
| - // in visit(JsObjectLiteral).
|
| - //
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsRegExp x, JsContext ctx) {
|
| - _slash();
|
| - p.print(x.getPattern());
|
| - _slash();
|
| - String flags = x.getFlags();
|
| - if (flags != null) {
|
| - p.print(flags);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsReturn x, JsContext ctx) {
|
| - _return();
|
| - JsExpression expr = x.getExpr();
|
| - if (expr != null) {
|
| - _space();
|
| - accept(expr);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsStringLiteral x, JsContext ctx) {
|
| - printStringLiteral(x.getValue());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsSwitch x, JsContext ctx) {
|
| - _switch();
|
| - _spaceOpt();
|
| - _lparen();
|
| - accept(x.getExpr());
|
| - _rparen();
|
| - _spaceOpt();
|
| - _blockOpen();
|
| - acceptList(x.getCases());
|
| - _blockClose();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsThisRef x, JsContext ctx) {
|
| - _this();
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsThrow x, JsContext ctx) {
|
| - _throw();
|
| - _space();
|
| - accept(x.getExpr());
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsTry x, JsContext ctx) {
|
| - _try();
|
| - _spaceOpt();
|
| - accept(x.getTryBlock());
|
| -
|
| - acceptList(x.getCatches());
|
| -
|
| - JsBlock finallyBlock = x.getFinallyBlock();
|
| - if (finallyBlock != null) {
|
| - _spaceOpt();
|
| - _finally();
|
| - _spaceOpt();
|
| - accept(finallyBlock);
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsVar x, JsContext ctx) {
|
| - _nameOf(x);
|
| - JsExpression initExpr = x.getInitExpr();
|
| - if (initExpr != null) {
|
| - _spaceOpt();
|
| - _assignment();
|
| - _spaceOpt();
|
| - _parenPushIfCommaExpr(initExpr);
|
| - accept(initExpr);
|
| - _parenPopIfCommaExpr(initExpr);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsVars x, JsContext ctx) {
|
| - _var();
|
| - _space();
|
| - boolean sep = false;
|
| - for (JsVar var : x) {
|
| - sep = _sepCommaOptSpace(sep);
|
| - accept(var);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - public boolean visit(JsWhile x, JsContext ctx) {
|
| - _while();
|
| - _spaceOpt();
|
| - _lparen();
|
| - accept(x.getCondition());
|
| - _rparen();
|
| - _nestedPush(x.getBody(), false);
|
| - accept(x.getBody());
|
| - _nestedPop(x.getBody());
|
| - return false;
|
| - }
|
| -
|
| - // CHECKSTYLE_NAMING_OFF
|
| - protected void _newline() {
|
| - p.newline();
|
| - }
|
| -
|
| - protected void _newlineOpt() {
|
| - p.newlineOpt();
|
| - }
|
| -
|
| - protected void printJsBlock(JsBlock x, boolean truncate, boolean finalNewline) {
|
| - boolean needBraces = !x.isGlobalBlock();
|
| -
|
| - if (needBraces) {
|
| - // Open braces.
|
| - //
|
| - _blockOpen();
|
| - }
|
| -
|
| - int count = 0;
|
| - for (Iterator<JsStatement> iter = x.getStatements().iterator(); iter.hasNext(); ++count) {
|
| - boolean isGlobal = x.isGlobalBlock() || globalBlocks.contains(x);
|
| -
|
| - if (truncate && count > JSBLOCK_LINES_TO_PRINT) {
|
| - p.print("[...]");
|
| - _newlineOpt();
|
| - break;
|
| - }
|
| - JsStatement stmt = iter.next();
|
| - needSemi = true;
|
| - boolean shouldRecordPositions = isGlobal && !(stmt instanceof JsBlock);
|
| - boolean stmtIsGlobalBlock = false;
|
| - if (isGlobal) {
|
| - if (stmt instanceof JsBlock) {
|
| - // A block inside a global block is still considered global
|
| - stmtIsGlobalBlock = true;
|
| - globalBlocks.add((JsBlock) stmt);
|
| - }
|
| - }
|
| - if (shouldRecordPositions) {
|
| - statementStarts.add(p.getPosition());
|
| - }
|
| - accept(stmt);
|
| - if (stmtIsGlobalBlock) {
|
| - globalBlocks.remove(stmt);
|
| - }
|
| - if (needSemi) {
|
| - /*
|
| - * Special treatment of function decls: If they are the only item in a
|
| - * statement (i.e. not part of an assignment operation), just give them
|
| - * a newline instead of a semi.
|
| - */
|
| - boolean functionStmt =
|
| - stmt instanceof JsExprStmt && ((JsExprStmt) stmt).getExpression() instanceof JsFunction;
|
| - /*
|
| - * Special treatment of the last statement in a block: only a few
|
| - * statements at the end of a block require semicolons.
|
| - */
|
| - boolean lastStatement = !iter.hasNext() && needBraces && !JsRequiresSemiVisitor.exec(stmt);
|
| - if (functionStmt) {
|
| - if (lastStatement) {
|
| - _newlineOpt();
|
| - } else {
|
| - _newline();
|
| - }
|
| - } else {
|
| - if (lastStatement) {
|
| - _semiOpt();
|
| - } else {
|
| - _semi();
|
| - }
|
| - _newlineOpt();
|
| - }
|
| - }
|
| - if (shouldRecordPositions) {
|
| - assert (statementStarts.size() == statementEnds.size() + 1);
|
| - statementEnds.add(p.getPosition());
|
| - }
|
| - }
|
| -
|
| - if (needBraces) {
|
| - // _blockClose() modified
|
| - p.indentOut();
|
| - p.print('}');
|
| - if (finalNewline) {
|
| - _newlineOpt();
|
| - }
|
| - }
|
| - needSemi = false;
|
| - }
|
| -
|
| - private void _assignment() {
|
| - p.print('=');
|
| - }
|
| -
|
| - private void _blockClose() {
|
| - p.indentOut();
|
| - p.print('}');
|
| - _newlineOpt();
|
| - }
|
| -
|
| - private void _blockOpen() {
|
| - p.print('{');
|
| - p.indentIn();
|
| - _newlineOpt();
|
| - }
|
| -
|
| - private void _break() {
|
| - p.print(CHARS_BREAK);
|
| - }
|
| -
|
| - private void _case() {
|
| - p.print(CHARS_CASE);
|
| - }
|
| -
|
| - private void _catch() {
|
| - p.print(CHARS_CATCH);
|
| - }
|
| -
|
| - private void _colon() {
|
| - p.print(':');
|
| - }
|
| -
|
| - private void _continue() {
|
| - p.print(CHARS_CONTINUE);
|
| - }
|
| -
|
| - private void _debugger() {
|
| - p.print(CHARS_DEBUGGER);
|
| - }
|
| -
|
| - private void _default() {
|
| - p.print(CHARS_DEFAULT);
|
| - }
|
| -
|
| - private void _do() {
|
| - p.print(CHARS_DO);
|
| - }
|
| -
|
| - private void _dot() {
|
| - p.print('.');
|
| - }
|
| -
|
| - private void _else() {
|
| - p.print(CHARS_ELSE);
|
| - }
|
| -
|
| - private void _false() {
|
| - p.print(CHARS_FALSE);
|
| - }
|
| -
|
| - private void _finally() {
|
| - p.print(CHARS_FINALLY);
|
| - }
|
| -
|
| - private void _for() {
|
| - p.print(CHARS_FOR);
|
| - }
|
| -
|
| - private void _function() {
|
| - p.print(CHARS_FUNCTION);
|
| - }
|
| -
|
| - private void _if() {
|
| - p.print(CHARS_IF);
|
| - }
|
| -
|
| - private void _in() {
|
| - p.print(CHARS_IN);
|
| - }
|
| -
|
| - private void _lbrace() {
|
| - p.print('{');
|
| - }
|
| -
|
| - private void _lparen() {
|
| - p.print('(');
|
| - }
|
| -
|
| - private void _lsquare() {
|
| - p.print('[');
|
| - }
|
| -
|
| - private void _nameDef(JsName name) {
|
| - p.print(name.getShortIdent());
|
| - }
|
| -
|
| - private void _nameOf(HasName hasName) {
|
| - _nameDef(hasName.getName());
|
| - }
|
| -
|
| - private void _nameRef(JsNameRef nameRef) {
|
| - p.print(nameRef.getShortIdent());
|
| - }
|
| -
|
| - private boolean _nestedPop(JsStatement statement) {
|
| - boolean pop = !(statement instanceof JsBlock);
|
| - if (pop) {
|
| - p.indentOut();
|
| - }
|
| - return pop;
|
| - }
|
| -
|
| - private boolean _nestedPush(JsStatement statement, boolean needSpace) {
|
| - boolean push = !(statement instanceof JsBlock);
|
| - if (push) {
|
| - if (needSpace) {
|
| - _space();
|
| - }
|
| - p.indentIn();
|
| - _newlineOpt();
|
| - } else {
|
| - _spaceOpt();
|
| - }
|
| - return push;
|
| - }
|
| -
|
| - private void _new() {
|
| - p.print(CHARS_NEW);
|
| - }
|
| -
|
| - private void _null() {
|
| - p.print(CHARS_NULL);
|
| - }
|
| -
|
| - private boolean _parenCalc(JsExpression parent, JsExpression child, boolean wrongAssoc) {
|
| - int parentPrec = JsPrecedenceVisitor.exec(parent);
|
| - int childPrec = JsPrecedenceVisitor.exec(child);
|
| - return (parentPrec > childPrec || (parentPrec == childPrec && wrongAssoc));
|
| - }
|
| -
|
| - private boolean _parenPop(JsExpression parent, JsExpression child, boolean wrongAssoc) {
|
| - boolean doPop = _parenCalc(parent, child, wrongAssoc);
|
| - if (doPop) {
|
| - _rparen();
|
| - }
|
| - return doPop;
|
| - }
|
| -
|
| - private boolean _parenPopIfCommaExpr(JsExpression x) {
|
| - boolean doPop =
|
| - x instanceof JsBinaryOperation
|
| - && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA;
|
| - if (doPop) {
|
| - _rparen();
|
| - }
|
| - return doPop;
|
| - }
|
| -
|
| - private boolean _parenPopOrSpace(JsExpression parent, JsExpression child, boolean wrongAssoc) {
|
| - boolean doPop = _parenCalc(parent, child, wrongAssoc);
|
| - if (doPop) {
|
| - _rparen();
|
| - } else {
|
| - _space();
|
| - }
|
| - return doPop;
|
| - }
|
| -
|
| - private boolean _parenPush(JsExpression parent, JsExpression child, boolean wrongAssoc) {
|
| - boolean doPush = _parenCalc(parent, child, wrongAssoc);
|
| - if (doPush) {
|
| - _lparen();
|
| - }
|
| - return doPush;
|
| - }
|
| -
|
| - private boolean _parenPushIfCommaExpr(JsExpression x) {
|
| - boolean doPush =
|
| - x instanceof JsBinaryOperation
|
| - && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA;
|
| - if (doPush) {
|
| - _lparen();
|
| - }
|
| - return doPush;
|
| - }
|
| -
|
| - private boolean _parenPushOrSpace(JsExpression parent, JsExpression child, boolean wrongAssoc) {
|
| - boolean doPush = _parenCalc(parent, child, wrongAssoc);
|
| - if (doPush) {
|
| - _lparen();
|
| - } else {
|
| - _space();
|
| - }
|
| - return doPush;
|
| - }
|
| -
|
| - private void _questionMark() {
|
| - p.print('?');
|
| - }
|
| -
|
| - private void _rbrace() {
|
| - p.print('}');
|
| - }
|
| -
|
| - private void _return() {
|
| - p.print(CHARS_RETURN);
|
| - }
|
| -
|
| - private void _rparen() {
|
| - p.print(')');
|
| - }
|
| -
|
| - private void _rsquare() {
|
| - p.print(']');
|
| - }
|
| -
|
| - private void _semi() {
|
| - p.print(';');
|
| - }
|
| -
|
| - private void _semiOpt() {
|
| - p.printOpt(';');
|
| - }
|
| -
|
| - private boolean _sepCommaOptSpace(boolean sep) {
|
| - if (sep) {
|
| - p.print(',');
|
| - _spaceOpt();
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - private void _slash() {
|
| - p.print('/');
|
| - }
|
| -
|
| - private void _space() {
|
| - p.print(' ');
|
| - }
|
| -
|
| - /**
|
| - * Decide whether, if <code>op</code> is printed followed by <code>arg</code>,
|
| - * there needs to be a space between the operator and expression.
|
| - *
|
| - * @return <code>true</code> if a space needs to be printed
|
| - */
|
| - private boolean _spaceCalc(JsOperator op, JsExpression arg) {
|
| - if (op.isKeyword()) {
|
| - return true;
|
| - }
|
| - if (arg instanceof JsBinaryOperation) {
|
| - JsBinaryOperation binary = (JsBinaryOperation) arg;
|
| - /*
|
| - * If the binary operation has a higher precedence than op, then it won't
|
| - * be parenthesized, so check the first argument of the binary operation.
|
| - */
|
| - if (binary.getOperator().getPrecedence() > op.getPrecedence()) {
|
| - return _spaceCalc(op, binary.getArg1());
|
| - }
|
| - return false;
|
| - }
|
| - if (arg instanceof JsPrefixOperation) {
|
| - JsOperator op2 = ((JsPrefixOperation) arg).getOperator();
|
| - return (op == JsBinaryOperator.SUB || op == JsUnaryOperator.NEG)
|
| - && (op2 == JsUnaryOperator.DEC || op2 == JsUnaryOperator.NEG)
|
| - || (op == JsBinaryOperator.ADD && op2 == JsUnaryOperator.INC);
|
| - }
|
| - if (arg instanceof JsNumberLiteral) {
|
| - JsNumberLiteral literal = (JsNumberLiteral) arg;
|
| - return (op == JsBinaryOperator.SUB || op == JsUnaryOperator.NEG) && (literal.getValue() < 0);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private void _spaceOpt() {
|
| - p.printOpt(' ');
|
| - }
|
| -
|
| - private void _switch() {
|
| - p.print(CHARS_SWITCH);
|
| - }
|
| -
|
| - private void _this() {
|
| - p.print(CHARS_THIS);
|
| - }
|
| -
|
| - private void _throw() {
|
| - p.print(CHARS_THROW);
|
| - }
|
| -
|
| - private void _true() {
|
| - p.print(CHARS_TRUE);
|
| - }
|
| -
|
| - private void _try() {
|
| - p.print(CHARS_TRY);
|
| - }
|
| -
|
| - private void _var() {
|
| - p.print(CHARS_VAR);
|
| - }
|
| -
|
| - private void _while() {
|
| - p.print(CHARS_WHILE);
|
| - }
|
| -
|
| - // CHECKSTYLE_NAMING_ON
|
| -
|
| - private void indent() {
|
| - p.indentIn();
|
| - }
|
| -
|
| - private void outdent() {
|
| - p.indentOut();
|
| - }
|
| -
|
| - private void printStringLiteral(String value) {
|
| - String resultString = javaScriptString(value);
|
| - p.print(resultString);
|
| - }
|
| -}
|
|
|