Add test for remaining JavaScript constructs

This commit is contained in:
Alexey Andreev 2015-09-23 14:22:24 +03:00
parent ccfddb19a4
commit 792294296d
2 changed files with 152 additions and 45 deletions

View File

@ -162,7 +162,7 @@ public class AstWriter {
print((ArrayComprehension) node); print((ArrayComprehension) node);
break; break;
case Token.GETPROP: case Token.GETPROP:
print((PropertyGet) node, precedence); print((PropertyGet) node);
break; break;
case Token.GENEXPR: case Token.GENEXPR:
print((GeneratorExpression) node); print((GeneratorExpression) node);
@ -208,7 +208,7 @@ public class AstWriter {
print((ConditionalExpression) node, precedence); print((ConditionalExpression) node, precedence);
break; break;
case Token.GETELEM: case Token.GETELEM:
print((ElementGet) node, precedence); print((ElementGet) node);
break; break;
case Token.LETEXPR: case Token.LETEXPR:
print((LetNode) node); print((LetNode) node);
@ -425,6 +425,7 @@ public class AstWriter {
print(cc.getCatchCondition()); print(cc.getCatchCondition());
} }
writer.append(')'); writer.append(')');
print(cc.getBody());
} }
if (node.getFinallyBlock() != null) { if (node.getFinallyBlock() != null) {
writer.ws().append("finally "); writer.ws().append("finally ");
@ -469,48 +470,40 @@ public class AstWriter {
writer.append(';'); writer.append(';');
} }
private void print(ElementGet node, int precedence) throws IOException { private void print(ElementGet node) throws IOException {
if (precedence < PRECEDENCE_MEMBER) {
writer.append('(');
}
print(node.getTarget(), PRECEDENCE_MEMBER); print(node.getTarget(), PRECEDENCE_MEMBER);
if (precedence < PRECEDENCE_MEMBER) {
writer.append(')');
}
writer.append('['); writer.append('[');
print(node.getElement()); print(node.getElement());
writer.append(']'); writer.append(']');
} }
private void print(PropertyGet node, int precedence) throws IOException { private void print(PropertyGet node) throws IOException {
if (precedence < PRECEDENCE_MEMBER) { print(node.getLeft(), PRECEDENCE_MEMBER);
writer.append('(');
}
print(node.getLeft());
if (precedence < PRECEDENCE_MEMBER) {
writer.append(')');
}
writer.ws().append('.').ws(); writer.ws().append('.').ws();
print(node.getRight()); print(node.getRight());
} }
private void print(FunctionCall node, int precedence) throws IOException { private void print(FunctionCall node, int precedence) throws IOException {
if (node instanceof NewExpression) {
writer.append("new ");
}
if (precedence < PRECEDENCE_FUNCTION) { if (precedence < PRECEDENCE_FUNCTION) {
writer.append('('); writer.append('(');
} }
print(node.getTarget(), PRECEDENCE_FUNCTION); int innerPrecedence = node instanceof NewExpression ? PRECEDENCE_FUNCTION - 1 : PRECEDENCE_FUNCTION;
if (precedence < PRECEDENCE_FUNCTION) { if (node instanceof NewExpression) {
writer.append(')'); writer.append("new ");
} }
print(node.getTarget(), innerPrecedence);
writer.append('('); writer.append('(');
printList(node.getArguments()); printList(node.getArguments());
writer.append(')'); writer.append(')');
if (node instanceof NewExpression) { if (node instanceof NewExpression) {
writer.ws(); writer.ws();
print(((NewExpression) node).getInitializer()); NewExpression newExpr = (NewExpression) node;
if (newExpr.getInitializer() != null) {
print(newExpr.getInitializer());
}
}
if (precedence < PRECEDENCE_FUNCTION) {
writer.append(')');
} }
} }
@ -526,7 +519,6 @@ public class AstWriter {
if (precedence < PRECEDENCE_COND) { if (precedence < PRECEDENCE_COND) {
writer.append(')'); writer.append(')');
} }
print(node.getTestExpression(), precedence);
} }
private void printList(List<? extends AstNode> nodes) throws IOException { private void printList(List<? extends AstNode> nodes) throws IOException {
@ -613,19 +605,19 @@ public class AstWriter {
print(node.getElements().get(i)); print(node.getElements().get(i));
} }
} }
printList(node.getElements());
writer.append('}'); writer.append('}');
} }
private void print(ObjectProperty node) throws IOException { private void print(ObjectProperty node) throws IOException {
StringBuilder sb = new StringBuilder();
if (node.isGetterMethod()) { if (node.isGetterMethod()) {
sb.append("get "); writer.append("get ");
} else if (node.isSetterMethod()) { } else if (node.isSetterMethod()) {
sb.append("set "); writer.append("set ");
} }
print(node.getLeft()); print(node.getLeft());
if (!node.isMethod()) {
writer.ws().append(':').ws(); writer.ws().append(':').ws();
}
print(node.getRight()); print(node.getRight());
} }
@ -633,7 +625,7 @@ public class AstWriter {
if (!node.isMethod()) { if (!node.isMethod()) {
writer.append("function"); writer.append("function");
} }
if (node.getFunctionName().getString() != null) { if (node.getFunctionName() != null) {
writer.append(' '); writer.append(' ');
print(node.getFunctionName()); print(node.getFunctionName());
} }
@ -671,6 +663,11 @@ public class AstWriter {
private void printUnary(UnaryExpression node, int precedence) throws IOException { private void printUnary(UnaryExpression node, int precedence) throws IOException {
int innerPrecedence = node.isPostfix() ? PRECEDENCE_POSTFIX : PRECEDENCE_PREFIX; int innerPrecedence = node.isPostfix() ? PRECEDENCE_POSTFIX : PRECEDENCE_PREFIX;
if (innerPrecedence > precedence) {
writer.append('(');
}
if (!node.isPostfix()) { if (!node.isPostfix()) {
writer.append(AstNode.operatorToString(node.getType())); writer.append(AstNode.operatorToString(node.getType()));
if (requiresWhitespaces(node.getType())) { if (requiresWhitespaces(node.getType())) {
@ -678,19 +675,15 @@ public class AstWriter {
} }
} }
if (innerPrecedence > precedence) {
writer.append('(');
}
print(node.getOperand(), innerPrecedence); print(node.getOperand(), innerPrecedence);
if (innerPrecedence > precedence) {
writer.append(')');
}
if (node.isPostfix()) { if (node.isPostfix()) {
writer.append(AstNode.operatorToString(node.getType())); writer.append(AstNode.operatorToString(node.getType()));
} }
if (innerPrecedence > precedence) {
writer.append(')');
}
} }
private void printInfix(InfixExpression node, int precedence) throws IOException { private void printInfix(InfixExpression node, int precedence) throws IOException {
@ -760,7 +753,7 @@ public class AstWriter {
print(node.getRight(), rightPrecedence); print(node.getRight(), rightPrecedence);
if (innerPrecedence > precedence) { if (innerPrecedence > precedence) {
writer.append('('); writer.append(')');
} }
} }

View File

@ -20,8 +20,8 @@ import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.theories.suppliers.TestedOn;
import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.CompilerEnvirons;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.AstRoot;
import org.teavm.codegen.SourceWriter; import org.teavm.codegen.SourceWriter;
import org.teavm.codegen.SourceWriterBuilder; import org.teavm.codegen.SourceWriterBuilder;
@ -94,10 +94,16 @@ public class AstWriterTest {
assertThat(transform("{ foo(); bar(); }"), is("{foo();bar();}")); assertThat(transform("{ foo(); bar(); }"), is("{foo();bar();}"));
} }
@Test
public void writesTryCatch() throws IOException {
assertThat(transform("try { foo(); } catch (e) { alert(e); }"), is("try {foo();}catch(e){alert(e);}"));
assertThat(transform("try { foo(); } finally { close(); }"), is("try {foo();}finally {close();}"));
}
@Test @Test
public void writesFor() throws IOException { public void writesFor() throws IOException {
assertThat(transform("for (var i = 0; i < array.length; ++i) foo(array[i]);"), assertThat(transform("for (var i = 0; i < array.length; ++i,++j) foo(array[i]);"),
is("for(var i=0;i<array.length;++i)foo(array[i]);")); is("for(var i=0;i<array.length;++i,++j)foo(array[i]);"));
} }
@Test @Test
@ -135,16 +141,124 @@ public class AstWriterTest {
@Test @Test
public void writesSwitch() throws IOException { public void writesSwitch() throws IOException {
assertThat(transform("switch (c) { " assertThat(transform("switch (c) { "
+ "case '?': matchAny(); break; " + "case '.': case '?': matchAny(); break; "
+ "case '*': matchSequence(); break;" + "case '*': matchSequence(); break;"
+ "default: matchChar(c); break; } "), + "default: matchChar(c); break; } "),
is("switch(c){case '?':matchAny();break;case '*':matchSequence();break;" is("switch(c){case '.':case '?':matchAny();break;case '*':matchSequence();break;"
+ "default:matchChar(c);break;}")); + "default:matchChar(c);break;}"));
} }
@Test
public void writesLet() throws IOException {
assertThat(transform("let x = 1; alert(x);"), is("let x=1;alert(x);"));
assertThat(transform("let x = 1, y; alert(x,y);"), is("let x=1,y;alert(x,y);"));
}
@Test
public void writesConst() throws IOException {
assertThat(transform("const x = 1,y = 2; alert(x,y);"), is("const x=1,y=2;alert(x,y);"));
}
@Test
public void writesElementGet() throws IOException {
assertThat(transform("return array[i];"), is("return array[i];"));
assertThat(transform("return array[i][j];"), is("return array[i][j];"));
assertThat(transform("return (array[i])[j];"), is("return array[i][j];"));
assertThat(transform("return (a + b)[i];"), is("return (a+b)[i];"));
assertThat(transform("return a + b[i];"), is("return a+b[i];"));
}
@Test
public void writesPropertyGet() throws IOException {
assertThat(transform("return array.length;"), is("return array.length;"));
assertThat(transform("return (array).length;"), is("return array.length;"));
assertThat(transform("return (x + y).toString();"), is("return (x+y).toString();"));
}
@Test
public void writesFunctionCall() throws IOException {
assertThat(transform("return f(x);"), is("return f(x);"));
assertThat(transform("return (f)(x);"), is("return f(x);"));
assertThat(transform("return (f + g)(x);"), is("return (f+g)(x);"));
}
@Test
public void writesConstructorCall() throws IOException {
assertThat(transform("return new (f + g)(x);"), is("return new (f+g)(x);"));
assertThat(transform("return new f + g(x);"), is("return new f()+g(x);"));
assertThat(transform("return new f()(x);"), is("return new f()(x);"));
assertThat(transform("return (new f())(x);"), is("return new f()(x);"));
assertThat(transform("return new (f())(x);"), is("return new (f())(x);"));
assertThat(transform("return new f[0](x);"), is("return new f[0](x);"));
assertThat(transform("return (new f[0](x));"), is("return new f[0](x);"));
}
@Test
public void writesConditionalExpr() throws IOException {
assertThat(transform("return cond ? 1 : 0;"), is("return cond?1:0;"));
assertThat(transform("return a < b ? -1 : a > b ? 1 : 0;"), is("return a<b?-1:a>b?1:0;"));
assertThat(transform("return a < b ? -1 : (a > b ? 1 : 0);"), is("return a<b?-1:a>b?1:0;"));
assertThat(transform("return (a < b ? x == y : x != y) ? 1 : 0;"), is("return (a<b?x==y:x!=y)?1:0;"));
assertThat(transform("return a < b ? (x > y ? x : y) : z"), is("return a<b?(x>y?x:y):z;"));
}
@Test
public void writesRegExp() throws IOException {
assertThat(transform("return /[a-z]+/.match(text);"), is("return /[a-z]+/.match(text);"));
assertThat(transform("return /[a-z]+/ig.match(text);"), is("return /[a-z]+/ig.match(text);"));
}
@Test
public void writesArrayLiteral() throws IOException {
assertThat(transform("return [];"), is("return [];"));
assertThat(transform("return [a, b + c];"), is("return [a,b+c];"));
}
@Test
public void writesObjectLiteral() throws IOException {
assertThat(transform("return {};"), is("return {};"));
assertThat(transform("return { foo : bar };"), is("return {foo:bar};"));
assertThat(transform("return { foo : bar };"), is("return {foo:bar};"));
assertThat(transform("return { _foo : bar, get foo() { return this._foo; } };"),
is("return {_foo:bar,get foo(){return this._foo;}};"));
}
@Test
public void writesFunction() throws IOException {
assertThat(transform("return function f(x, y) { return x + y; };"),
is("return function f(x,y){return x+y;};"));
}
@Test
public void writesUnary() throws IOException {
assertThat(transform("return -a;"), is("return -a;"));
assertThat(transform("return -(a + b);"), is("return -(a+b);"));
assertThat(transform("return -a + b;"), is("return -a+b;"));
assertThat(transform("return (-a) + b;"), is("return -a+b;"));
assertThat(transform("return (-f)(x);"), is("return (-f)(x);"));
assertThat(transform("return typeof a;"), is("return typeof a;"));
}
@Test
public void writesPostfix() throws IOException {
assertThat(transform("return a++;"), is("return a++;"));
}
@Test
public void respectsPrecedence() throws IOException {
assertThat(transform("return a + b + c;"), is("return a+b+c;"));
assertThat(transform("return (a + b) + c;"), is("return a+b+c;"));
assertThat(transform("return a + (b + c);"), is("return a+b+c;"));
assertThat(transform("return a - b + c;"), is("return a-b+c;"));
assertThat(transform("return (a - b) + c;"), is("return a-b+c;"));
assertThat(transform("return a - (b + c);"), is("return a-(b+c);"));
}
private String transform(String text) throws IOException { private String transform(String text) throws IOException {
sb.setLength(0);
CompilerEnvirons env = new CompilerEnvirons(); CompilerEnvirons env = new CompilerEnvirons();
env.setRecoverFromErrors(true); env.setRecoverFromErrors(true);
env.setLanguageVersion(Context.VERSION_1_8);
JSParser factory = new JSParser(env); JSParser factory = new JSParser(env);
factory.enterFunction(); factory.enterFunction();
AstRoot rootNode = factory.parse(new StringReader(text), null, 0); AstRoot rootNode = factory.parse(new StringReader(text), null, 0);