| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.royale.compiler.internal.codegen.js.royale; |
| |
| import org.apache.royale.compiler.driver.IBackend; |
| import org.apache.royale.compiler.internal.codegen.js.goog.TestGoogStatements; |
| import org.apache.royale.compiler.internal.driver.js.royale.RoyaleBackend; |
| import org.apache.royale.compiler.internal.projects.RoyaleJSProject; |
| import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode; |
| import org.apache.royale.compiler.tree.as.IFileNode; |
| import org.apache.royale.compiler.tree.as.IForLoopNode; |
| import org.apache.royale.compiler.tree.as.IIfNode; |
| import org.apache.royale.compiler.tree.as.IImportNode; |
| import org.apache.royale.compiler.tree.as.ILiteralNode; |
| import org.apache.royale.compiler.tree.as.INamespaceNode; |
| import org.apache.royale.compiler.tree.as.ISwitchNode; |
| import org.apache.royale.compiler.tree.as.ITryNode; |
| import org.apache.royale.compiler.tree.as.IVariableNode; |
| import org.apache.royale.compiler.tree.as.IWhileLoopNode; |
| import org.apache.royale.compiler.tree.as.IWithNode; |
| import org.junit.Test; |
| |
| /** |
| * @author Erik de Bruin |
| */ |
| public class TestRoyaleStatements extends TestGoogStatements |
| { |
| @Override |
| public void setUp() |
| { |
| backend = createBackend(); |
| project = new RoyaleJSProject(workspace, backend); |
| super.setUp(); |
| } |
| |
| @Test |
| public void testNamespaceStatement() |
| { |
| INamespaceNode node = (INamespaceNode) getNode("public namespace foo;", |
| INamespaceNode.class, WRAP_LEVEL_NONE); |
| asBlockWalker.visitNamespace(node); |
| assertOut("foo = new Namespace('foo');"); |
| } |
| |
| @Test |
| public void testNamespaceStatementWithURI() |
| { |
| INamespaceNode node = (INamespaceNode) getNode("public namespace foo = 'bar';", |
| INamespaceNode.class, WRAP_LEVEL_NONE); |
| asBlockWalker.visitNamespace(node); |
| assertOut("foo = new Namespace('bar');"); |
| } |
| |
| @Test |
| public void testObjectListeral_withPropertyNameMatchingConst() |
| { |
| ILiteralNode node = (ILiteralNode) getNode("static const myConst:int; function royaleTest_a():Object { return { myConst : myConst } }", |
| ILiteralNode.class, WRAP_LEVEL_CLASS); |
| asBlockWalker.visitLiteral(node); |
| assertOut("{myConst:RoyaleTest_A.myConst}"); |
| } |
| |
| @Test |
| public void testVarDeclaration_withTypeAssignedStringWithNewLine() |
| { |
| IVariableNode node = (IVariableNode) getNode("var a:String = \"\\n\"", |
| IVariableNode.class); |
| asBlockWalker.visitVariable(node); |
| assertOut("var /** @type {string} */ a = \"\\n\""); |
| } |
| |
| @Override |
| @Test |
| public void testVarDeclaration_withType() |
| { |
| IVariableNode node = (IVariableNode) getNode("var a:int;", |
| IVariableNode.class); |
| asBlockWalker.visitVariable(node); |
| assertOut("var /** @type {number} */ a = 0"); |
| } |
| |
| //---------------------------------- |
| // const declaration |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testConstDeclaration() |
| { |
| IVariableNode node = (IVariableNode) getNode("const a = 42;", |
| IVariableNode.class); |
| asBlockWalker.visitVariable(node); |
| assertOut("\n/**\n * @const\n * @type {*}\n */\nvar a = 42"); |
| } |
| |
| @Override |
| @Test |
| public void testConstDeclaration_withType() |
| { |
| IVariableNode node = (IVariableNode) getNode("const a:int = 42;", |
| IVariableNode.class); |
| asBlockWalker.visitVariable(node); |
| assertOut("\n/**\n * @const\n * @type {number}\n */\nvar a = 42"); |
| } |
| |
| @Override |
| @Test |
| public void testConstDeclaration_withList() |
| { |
| IVariableNode node = (IVariableNode) getNode( |
| "const a:int = 4, b:int = 11, c:int = 42;", IVariableNode.class); |
| asBlockWalker.visitVariable(node); |
| assertOut("\n/**\n * @const\n * @type {number}\n */\nvar a = 4, \n/**\n * @const\n * @type {number}\n */\nb = 11, \n/**\n * @const\n * @type {number}\n */\nc = 42"); |
| } |
| |
| //---------------------------------- |
| // for () { } |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitFor_1a() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "var len:int;for (var i:int = 0; i < len; i++) { break; }", |
| IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (var /** @type {number} */ i = 0; i < len; i++) {\n break;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitFor_1b() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "var len:int;for (var i:int = 0; i < len; i++) break;", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (var /** @type {number} */ i = 0; i < len; i++)\n break;"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitFor_1c() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for (var i:int = 0, len:int = 10; i < len; i++) break;", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (var /** @type {number} */ i = 0, /** @type {number} */ len = 10; i < len; i++)\n break;"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitForIn_1() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for (var i:int in obj) { break; }", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (var /** @type {number} */ i in obj) {\n break;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitForIn_1a() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for (var i:int in obj) break; ", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (var /** @type {number} */ i in obj)\n break;"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitForEach_1() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for each(var i:int in obj) { break; }", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("var foreachiter0_target = obj;\nfor (var foreachiter0 in foreachiter0_target) \n{\nvar i = foreachiter0_target[foreachiter0];\n{\n break;\n}}\n"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitForEach_1a() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for each(var i:int in obj) break; ", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("var foreachiter0_target = obj;\nfor (var foreachiter0 in foreachiter0_target) \n{\nvar i = foreachiter0_target[foreachiter0];\n\n break;}\n"); |
| } |
| |
| @Test |
| public void testVisitForEach_2() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "for each(var i:int in obj.foo()) { break; }", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("var foreachiter0_target = obj.foo();\nfor (var foreachiter0 in foreachiter0_target) \n{\nvar i = foreachiter0_target[foreachiter0];\n{\n break;\n}}\n"); |
| } |
| |
| @Test |
| public void testVisitForEach_HoistedVar() |
| { |
| IForLoopNode node = (IForLoopNode) getNode( |
| "var i:int; for each(i in obj) break; ", IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("var foreachiter0_target = obj;\nfor (var foreachiter0 in foreachiter0_target) \n{\ni = foreachiter0_target[foreachiter0];\n\n break;}\n"); |
| } |
| |
| //---------------------------------- |
| // try {} catch () {} finally {} |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitTry_Catch() |
| { |
| ITryNode node = (ITryNode) getNode("try { a; } catch (e:Error) { b; }", |
| ITryNode.class); |
| asBlockWalker.visitTry(node); |
| assertOut("try {\n a;\n} catch (e) {\n b;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitTry_Catch_Finally() |
| { |
| ITryNode node = (ITryNode) getNode( |
| "try { a; } catch (e:Error) { b; } finally { c; }", |
| ITryNode.class); |
| asBlockWalker.visitTry(node); |
| assertOut("try {\n a;\n} catch (e) {\n b;\n} finally {\n c;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitTry_Catch_Catch_Finally() |
| { |
| // TODO (erikdebruin) handle multiple 'catch' statements (FW in Wiki) |
| ITryNode node = (ITryNode) getNode( |
| "try { a; } catch (e:Error) { b; } catch (f:Error) { c; } finally { d; }", |
| ITryNode.class); |
| asBlockWalker.visitTry(node); |
| assertOut("try {\n a;\n} catch (e) {\n b;\n} catch (f) {\n c;\n} finally {\n d;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitTry_CatchEmpty_FinallyEmpty_() |
| { |
| ITryNode node = (ITryNode) getNode( |
| "try { a; } catch (e:Error) { } finally { }", ITryNode.class); |
| asBlockWalker.visitTry(node); |
| assertOut("try {\n a;\n} catch (e) {\n} finally {\n}"); |
| } |
| |
| //---------------------------------- |
| // switch {} |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitSwitch_1() |
| { |
| ISwitchNode node = (ISwitchNode) getNode("switch(i){case 1: break;}", |
| ISwitchNode.class); |
| asBlockWalker.visitSwitch(node); |
| assertOut("switch (i) {\n case 1:\n break;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitSwitch_1a() |
| { |
| ISwitchNode node = (ISwitchNode) getNode( |
| "switch(i){case 1: { break; }}", ISwitchNode.class); |
| asBlockWalker.visitSwitch(node); |
| // (erikdebruin) the code is valid without the extra braces, |
| // i.e. we're good, we "don't care" |
| assertOut("switch (i) {\n case 1:\n break;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitSwitch_2() |
| { |
| ISwitchNode node = (ISwitchNode) getNode( |
| "switch(i){case 1: break; default: return;}", ISwitchNode.class); |
| asBlockWalker.visitSwitch(node); |
| assertOut("switch (i) {\n case 1:\n break;\n default:\n return;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitSwitch_3() |
| { |
| ISwitchNode node = (ISwitchNode) getNode( |
| "switch(i){case 1: { var x:int = 42; break; }; case 2: { var y:int = 66; break; }}", ISwitchNode.class); |
| asBlockWalker.visitSwitch(node); |
| assertOut("switch (i) {\n case 1:\n var /** @type {number} */ x = 42;\n break;\n case 2:\n var /** @type {number} */ y = 66;\n break;\n}"); |
| } |
| |
| //---------------------------------- |
| // if () |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitIf_1() |
| { |
| IIfNode node = (IIfNode) getNode("if (a) b++;", IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a)\n b++;"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitIf_2() |
| { |
| IIfNode node = (IIfNode) getNode("if (a) b++; else c++;", IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a)\n b++;\nelse\n c++;"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitIf_4() |
| { |
| IIfNode node = (IIfNode) getNode( |
| "if (a) b++; else if (c) d++; else if(e) --f;", IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a)\n b++;\nelse if (c)\n d++;\nelse if (e)\n --f;"); |
| } |
| |
| //---------------------------------- |
| // if () { } |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitIf_1a() |
| { |
| IIfNode node = (IIfNode) getNode("if (a) { b++; }", IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a) {\n b++;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitIf_1b() |
| { |
| IIfNode node = (IIfNode) getNode("if (a) { b++; } else { c++; }", |
| IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a) {\n b++;\n} else {\n c++;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitIf_1c() |
| { |
| IIfNode node = (IIfNode) getNode( |
| "if (a) { b++; } else if (b) { c++; } else { d++; }", |
| IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a) {\n b++;\n} else if (b) {\n c++;\n} else {\n d++;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitIf_3() |
| { |
| IIfNode node = (IIfNode) getNode( |
| "if (a) b++; else if (c) d++; else --e;", IIfNode.class); |
| asBlockWalker.visitIf(node); |
| assertOut("if (a)\n b++;\nelse if (c)\n d++;\nelse\n --e;"); |
| } |
| |
| //---------------------------------- |
| // label : for () {} |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitFor_2() |
| { |
| IForLoopNode node = (IForLoopNode) getNode("for (;;) { break; }", |
| IForLoopNode.class); |
| asBlockWalker.visitForLoop(node); |
| assertOut("for (;;) {\n break;\n}"); |
| } |
| |
| //---------------------------------- |
| // while () { } |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitWhileLoop_1() |
| { |
| IWhileLoopNode node = (IWhileLoopNode) getNode( |
| "while(a > b){a++;--b;}", IWhileLoopNode.class); |
| asBlockWalker.visitWhileLoop(node); |
| assertOut("while (a > b) {\n a++;\n --b;\n}"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitWhileLoop_1a() |
| { |
| IWhileLoopNode node = (IWhileLoopNode) getNode("while(a > b) a++;", |
| IWhileLoopNode.class); |
| asBlockWalker.visitWhileLoop(node); |
| assertOut("while (a > b)\n a++;"); |
| } |
| |
| //---------------------------------- |
| // do {} while () |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitWhileLoop_Do_1() |
| { |
| IWhileLoopNode node = (IWhileLoopNode) getNode( |
| "do {a++;--b;} while(a > b);", IWhileLoopNode.class); |
| asBlockWalker.visitWhileLoop(node); |
| assertOut("do {\n a++;\n --b;\n} while (a > b);"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitWhileLoop_Do_1a() |
| { |
| IWhileLoopNode node = (IWhileLoopNode) getNode("do a++; while(a > b);", |
| IWhileLoopNode.class); |
| asBlockWalker.visitWhileLoop(node); |
| assertOut("do\n a++;\nwhile (a > b);"); |
| } |
| |
| //---------------------------------- |
| // label : for () {} |
| //---------------------------------- |
| |
| @Override |
| @Test |
| public void testVisitLabel_1() |
| { |
| LabeledStatementNode node = (LabeledStatementNode) getNode( |
| "foo: for each(var i:int in obj) { break foo; }", |
| LabeledStatementNode.class); |
| asBlockWalker.visitLabeledStatement(node); |
| assertOut("var foreachiter0_target = obj;\nfoo : for (var foreachiter0 in foreachiter0_target) \n{\nvar i = foreachiter0_target[foreachiter0];\n{\n break foo;\n}}\n"); |
| } |
| |
| @Override |
| @Test |
| public void testVisitLabel_1a() |
| { |
| // TODO (mschmalle) LabelStatement messes up in finally{} block, something is wrong there |
| LabeledStatementNode node = (LabeledStatementNode) getNode( |
| "foo: for each(var i:int in obj) break foo;", |
| LabeledStatementNode.class); |
| asBlockWalker.visitLabeledStatement(node); |
| assertOut("var foreachiter0_target = obj;\nfoo : for (var foreachiter0 in foreachiter0_target) \n{\nvar i = foreachiter0_target[foreachiter0];\n\n break foo;}\n"); |
| } |
| |
| //---------------------------------- |
| // with () {} |
| //---------------------------------- |
| |
| @Test |
| public void testVisitWith() |
| { |
| IWithNode node = (IWithNode) getNode("with (a) { b; }", IWithNode.class); |
| asBlockWalker.visitWith(node); |
| assertOut("with (a) {\n b;\n}"); |
| } |
| |
| @Test |
| public void testVisitWith_1a() |
| { |
| IWithNode node = (IWithNode) getNode("with (a) b;", IWithNode.class); |
| asBlockWalker.visitWith(node); |
| assertOut("with (a)\n b;"); |
| } |
| |
| //---------------------------------- |
| // import a.b.C |
| //---------------------------------- |
| |
| @Test |
| public void testVisitImport() |
| { |
| IImportNode node = (IImportNode) getNode("import custom.TestImplementation;", IImportNode.class); |
| asBlockWalker.visitImport(node); |
| assertOut(""); |
| } |
| |
| @Override |
| @Test |
| public void testVisit() |
| { |
| IFileNode node = (IFileNode) getNode( |
| "try { a; } catch (e:Error) { if (a) { if (b) { if (c) b; else if (f) a; else e; }} } finally { }" |
| + "if (d) { var len:int; for (var i:int = 0; i < len; i++) break; }" |
| + "if (a) { with (ab) { c(); } " |
| + "do {a++;do a++; while(a > b);} while(c > d); }" |
| + "if (b) { try { a; throw new Error('foo'); } catch (e:Error) { " |
| + " switch(i){case 1: break; default: return;}" |
| + " } finally { " |
| + " d; var a:Object = function(foo:int, bar:String = 'goo'):int{return -1;};" |
| + " eee.dd; eee.dd; eee.dd; eee.dd;} }" |
| + "foo: for each(var i:int in obj) break foo;", |
| IFileNode.class); |
| asBlockWalker.visitFile(node); |
| assertOutWithMetadata("/**\n" + |
| " * RoyaleTest_A\n" + |
| " *\n" + |
| " * @fileoverview\n" + |
| " *\n" + |
| " * @suppress {checkTypes|accessControls}\n" + |
| " */\n" + |
| "\n" + |
| "goog.provide('RoyaleTest_A');\n" + |
| "\n\n\n" + |
| "/**\n" + |
| " * @constructor\n" + |
| " */\n" + |
| "RoyaleTest_A = function() {\n" + |
| "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n" + |
| "RoyaleTest_A.prototype.royaleTest_a = function() {\n" + |
| " var self = this;\n" + |
| " var /** @type {Function} */ __localFn0__ = function(foo, bar) {\n" + |
| " bar = typeof bar !== 'undefined' ? bar : 'goo';\n" + |
| " return -1;\n" + |
| " }\n" + |
| " try {\n" + |
| " a;\n" + |
| " } catch (e) {\n" + |
| " if (a) {\n" + |
| " if (b) {\n" + |
| " if (c)\n" + |
| " b;\n" + |
| " else if (f)\n" + |
| " a;\n" + |
| " else\n" + |
| " e;\n" + |
| " }\n" + |
| " }\n" + |
| " } finally {\n" + |
| " }\n" + |
| " if (d) {\n" + |
| " var /** @type {number} */ len = 0;\n" + |
| " for (var /** @type {number} */ i = 0; i < len; i++)\n" + |
| " break;\n" + |
| " }\n" + |
| " if (a) {\n" + |
| " with (ab) {\n" + |
| " c();\n" + |
| " }\n" + |
| " do {\n" + |
| " a++;\n" + |
| " do\n" + |
| " a++;\n" + |
| " while (a > b);\n" + |
| " } while (c > d);\n" + |
| " }\n" + |
| " if (b) {\n" + |
| " try {\n" + |
| " a;\n" + |
| " throw new Error('foo');\n" + |
| " } catch (e) {\n" + |
| " switch (i) {\n" + |
| " case 1:\n" + |
| " break;\n" + |
| " default:\n" + |
| " return;\n" + |
| " }\n" + |
| " } finally {\n" + |
| " d;\n" + |
| " var /** @type {Object} */ a = __localFn0__;\n" + |
| " eee.dd;\n" + |
| " eee.dd;\n" + |
| " eee.dd;\n" + |
| " eee.dd;\n" + |
| " }\n" + |
| " }\n" + |
| " var foreachiter0_target = obj;\n" + |
| " foo : for (var foreachiter0 in foreachiter0_target) \n" + |
| " {\n" + |
| " var i = foreachiter0_target[foreachiter0];\n" + |
| " \n" + |
| " break foo;}\n" + |
| " ;\n};\n\n\n" + |
| "/**\n * Metadata\n" + |
| " *\n" + |
| " * @type {Object.<string, Array.<Object>>}\n" + |
| " */\n" + |
| "RoyaleTest_A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'RoyaleTest_A', qName: 'RoyaleTest_A', kind: 'class' }] };\n" + |
| "\n" + |
| "\n" + |
| "\n" + |
| "/**\n" + |
| " * Reflection\n" + |
| " *\n" + |
| " * @return {Object.<string, Function>}\n" + |
| " */\n" + |
| "RoyaleTest_A.prototype.ROYALE_REFLECTION_INFO = function () {\n" + |
| "return {\n" + |
| " variables: function () {return {};},\n" + |
| " accessors: function () {return {};},\n" + |
| " methods: function () {return {};}\n" + |
| "};\n" + |
| "};\n"); |
| } |
| |
| @Override |
| protected IBackend createBackend() |
| { |
| return new RoyaleBackend(); |
| } |
| |
| } |