diff --git a/src/qmljsc/purejavascriptgenerator.cpp b/src/qmljsc/purejavascriptgenerator.cpp index ae1fd2e..10708c6 100644 --- a/src/qmljsc/purejavascriptgenerator.cpp +++ b/src/qmljsc/purejavascriptgenerator.cpp @@ -1,439 +1,498 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Jan Marker * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "purejavascriptgenerator.h" #include "utils/error.h" using namespace QQmlJS; PureJavaScriptGenerator::PureJavaScriptGenerator() : m_outputStack() { } QString PureJavaScriptGenerator::getGeneratedCode() { if (m_outputStack.size() > 1) { const QString errorDescription = QString("stack was not reduced correctly, top element is %1").arg(m_outputStack.top()); QmlJSc::Error stackError(QmlJSc::Error::InternalError, errorDescription); throw stackError; } else if (m_outputStack.size() == 0) { return ""; } return m_outputStack.pop(); } bool PureJavaScriptGenerator::visit(AST::BinaryExpression *binaryExpression) { switch(binaryExpression->op) { case QSOperator::Assign: m_outputStack << "="; break; case QSOperator::InplaceAdd: m_outputStack << "+="; break; case QSOperator::InplaceSub: m_outputStack << "-="; break; case QSOperator::InplaceMul: m_outputStack << "*="; break; case QSOperator::InplaceDiv: m_outputStack << "/="; break; case QSOperator::InplaceMod: m_outputStack << "%="; break; case QSOperator::InplaceLeftShift: m_outputStack << "<<="; break; case QSOperator::InplaceRightShift: m_outputStack << ">>="; break; case QSOperator::InplaceURightShift: m_outputStack << ">>>="; break; case QSOperator::InplaceAnd: m_outputStack << "&="; break; case QSOperator::InplaceXor: m_outputStack << "^="; break; case QSOperator::InplaceOr: m_outputStack << "|="; break; case QSOperator::Add: m_outputStack << "+"; break; case QSOperator::Sub: m_outputStack << "-"; break; case QSOperator::Mul: m_outputStack << "*"; break; case QSOperator::Div: m_outputStack << "/"; break; case QSOperator::Mod: m_outputStack << "%"; break; case QSOperator::LShift: m_outputStack << "<<"; break; case QSOperator::RShift: m_outputStack << ">>"; break; case QSOperator::URShift: m_outputStack << ">>>"; break; case QSOperator::BitAnd: m_outputStack << "&"; break; case QSOperator::BitXor: m_outputStack << "^"; break; case QSOperator::BitOr: m_outputStack << "|"; break; case QSOperator::Equal: m_outputStack << "=="; break; case QSOperator::NotEqual: m_outputStack << "!="; break; case QSOperator::StrictEqual: m_outputStack << "==="; break; case QSOperator::StrictNotEqual: m_outputStack << "!=="; break; case QSOperator::Gt: m_outputStack << ">"; break; case QSOperator::Ge: m_outputStack << ">="; break; case QSOperator::Lt: m_outputStack << "<"; break; case QSOperator::Le: m_outputStack << "<="; break; case QSOperator::And: m_outputStack << "&&"; break; case QSOperator::Or: m_outputStack << "||"; break; case QSOperator::In: m_outputStack << " in "; break; case QSOperator::InstanceOf: m_outputStack << " instanceof "; break; default: Q_ASSERT_X(binaryExpression->op, __FILE__, "The operator is not handled yet"); } return true; } bool PureJavaScriptGenerator::visit(AST::BreakStatement *breakStatement) { reduceJumpStatement("break", breakStatement->label); return true; } bool PureJavaScriptGenerator::visit(AST::CaseClause *) { m_outputStack << "case"; return true; } bool PureJavaScriptGenerator::visit(AST::ContinueStatement *continueStatement) { reduceJumpStatement("continue", continueStatement->label); return true; } bool PureJavaScriptGenerator::visit(AST::DefaultClause *) { m_outputStack << "default"; return true; } bool PureJavaScriptGenerator::visit(AST::Elision *currentElision) { QString output; while (currentElision) { output += ','; currentElision = currentElision->next; } m_outputStack << output; return true; } bool PureJavaScriptGenerator::visit(AST::FalseLiteral *) { m_outputStack << "false"; return true; } bool PureJavaScriptGenerator::visit(AST::FormalParameterList *currentParameter) { QString parameterCode; while (currentParameter) { parameterCode += currentParameter->name.toString(); if (currentParameter->next) { parameterCode += ','; } currentParameter = currentParameter->next; } m_outputStack << parameterCode; return true; } bool PureJavaScriptGenerator::visit(AST::IdentifierExpression *identifierExpression) { m_outputStack << identifierExpression->name.toString(); return true; } bool PureJavaScriptGenerator::visit(AST::IdentifierPropertyName *identifierPropertyName) { m_outputStack << identifierPropertyName->id.toString(); return true; } bool PureJavaScriptGenerator::visit(AST::NullExpression *) { m_outputStack << "null"; return true; } bool PureJavaScriptGenerator::visit(AST::NumericLiteral *numericLiteral) { m_outputStack.push(QString::number(numericLiteral->value)); return true; } bool PureJavaScriptGenerator::visit(AST::StringLiteral *stringLiteral) { m_outputStack << '"' + stringLiteral->value.toString() + '"'; return true; } bool PureJavaScriptGenerator::visit(AST::ThisExpression *) { m_outputStack << "this"; return true; } bool PureJavaScriptGenerator::visit(AST::TrueLiteral *) { m_outputStack << "true"; return true; } void PureJavaScriptGenerator::endVisit(AST::ArgumentList *argumentList) { reduceListStack(argumentList, ","); } void PureJavaScriptGenerator::endVisit(AST::ArrayLiteral *arrayLiteral) { const QString elision = (arrayLiteral->elision)?m_outputStack.pop():""; const QString elements = (arrayLiteral->elements)?m_outputStack.pop():""; m_outputStack << '[' + elements + elision + ']'; } void PureJavaScriptGenerator::endVisit(AST::ArrayMemberExpression *) { const QString keyExpression = m_outputStack.pop(); const QString arrayExpression = m_outputStack.pop(); m_outputStack << arrayExpression + '[' + keyExpression + ']'; } void PureJavaScriptGenerator::endVisit(AST::BinaryExpression *) { const QString rightOperand = m_outputStack.pop(); const QString leftOperand = m_outputStack.pop(); const QString operation = m_outputStack.pop(); QString expression = QString("%1%2%3").arg(leftOperand).arg(operation).arg(rightOperand); m_outputStack.push(expression); } void PureJavaScriptGenerator::endVisit(AST::Block *) { const QString blockCode = m_outputStack.pop(); m_outputStack << '{' + blockCode + '}'; } void PureJavaScriptGenerator::endVisit(AST::CallExpression *callExpression) { const QString arguments = (callExpression->arguments)?m_outputStack.pop():""; const QString function = m_outputStack.pop(); m_outputStack << function + '(' + arguments + ')'; } void PureJavaScriptGenerator::endVisit(AST::CaseBlock *caseBlock) { QString clausesRight; if (caseBlock->moreClauses) { clausesRight = m_outputStack.pop(); } QString defaultClause; if (caseBlock->defaultClause) { defaultClause = m_outputStack.pop(); } const QString clausesLeft = m_outputStack.pop(); m_outputStack << '{' + clausesLeft + defaultClause + clausesRight + '}'; } void PureJavaScriptGenerator::endVisit(AST::DoWhileStatement *) { const QString expression = m_outputStack.pop(); const QString statement = m_outputStack.pop(); m_outputStack << "do " + statement + "while" + '(' + expression + ')' + ';'; // space after do: do var i;while(false); is a valid statement and requires a space } void PureJavaScriptGenerator::endVisit(AST::CaseClause *) { const QString statement = m_outputStack.pop(); const QString expression = m_outputStack.pop(); const QString caseKeyword = m_outputStack.pop(); m_outputStack << caseKeyword + ' ' + expression + ':' + statement; } void PureJavaScriptGenerator::endVisit(AST::CaseClauses *caseClauses) { reduceListStack(caseClauses); } +void PureJavaScriptGenerator::endVisit(AST::ConditionalExpression *) { + const QString secondExpression = m_outputStack.pop(); + const QString firstExpression = m_outputStack.pop(); + const QString condition = m_outputStack.pop(); + m_outputStack << condition + '?' + firstExpression + ':' + secondExpression; +} + void PureJavaScriptGenerator::endVisit(AST::DefaultClause *) { const QString statement = m_outputStack.pop(); const QString defaultKeyword = m_outputStack.pop(); m_outputStack << defaultKeyword + ':' + statement; } +void PureJavaScriptGenerator::endVisit(AST::DeleteExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << "delete " + expression; +} + void PureJavaScriptGenerator::endVisit(AST::ElementList *elementList) { QString code; AST::ElementList *currentElement = elementList; QStack::iterator positionOnStack = m_outputStack.end(); for (currentElement = elementList; currentElement; currentElement = currentElement->next) { if (currentElement->elision) { --positionOnStack; } if (currentElement->expression) { --positionOnStack; } } for (currentElement = elementList; currentElement; currentElement = currentElement->next) { if (currentElement->elision) { code += *positionOnStack; positionOnStack = m_outputStack.erase(positionOnStack); } if (currentElement->expression) { code += *positionOnStack + ','; positionOnStack = m_outputStack.erase(positionOnStack); } } m_outputStack << code; } void PureJavaScriptGenerator::endVisit(AST::EmptyStatement *) { m_outputStack << ";"; } void PureJavaScriptGenerator::endVisit(AST::ExpressionStatement *) { m_outputStack << m_outputStack.pop() + ';'; } void PureJavaScriptGenerator::endVisit(AST::FieldMemberExpression *fieldMemberExpression) { const QString objectExpression = m_outputStack.pop(); const QString memberName = fieldMemberExpression->name.toString(); m_outputStack << objectExpression + '.' + memberName; } void PureJavaScriptGenerator::endVisit(AST::ForEachStatement *) { const QString statement = m_outputStack.pop(); const QString objectExpression = m_outputStack.pop(); const QString variableExpression = m_outputStack.pop(); m_outputStack << "for(" + variableExpression + " in " + objectExpression + ')' + statement; } void PureJavaScriptGenerator::endVisit(AST::ForStatement *forStatement) { const QString statement = m_outputStack.pop(); const QString incrementExpression = (forStatement->expression)?m_outputStack.pop():""; const QString condition = (forStatement->condition)?m_outputStack.pop():""; const QString initialisation = (forStatement->initialiser)?m_outputStack.pop():""; m_outputStack << "for(" + initialisation + ';' + condition + ';' + incrementExpression + ')' + statement; } void PureJavaScriptGenerator::endVisit(AST::FunctionBody *) { const QString body = m_outputStack.pop(); m_outputStack << '{' + body + '}'; } void PureJavaScriptGenerator::endVisit(AST::FunctionDeclaration *functionDeclaration) { const QString body = (functionDeclaration->body) ? m_outputStack.pop() : "{}"; const QString parameters = (functionDeclaration->formals) ? m_outputStack.pop() : ""; const QString name = functionDeclaration->name.toString(); m_outputStack << "function " + name + '(' + parameters + ')' + body; } void PureJavaScriptGenerator::endVisit(AST::IdentifierExpression *) { } void PureJavaScriptGenerator::endVisit(AST::IfStatement *ifExpression) { const QString elseStatements = (ifExpression->ko) ? m_outputStack.pop() : ""; const QString ifStatements = m_outputStack.pop(); const QString expression = m_outputStack.pop(); QString code("if(" + expression + ')' + ifStatements); if (ifExpression->ko) { code += "else " + elseStatements; } m_outputStack << code; } void PureJavaScriptGenerator::endVisit(AST::LocalForEachStatement *) { const QString statement = m_outputStack.pop(); const QString objectExpression = m_outputStack.pop(); const QString declaredVariableName = m_outputStack.pop(); m_outputStack << "for(var " + declaredVariableName + " in " + objectExpression + ')' + statement; } void PureJavaScriptGenerator::endVisit(AST::LocalForStatement *localForStatement) { const QString statement = m_outputStack.pop(); const QString incrementExpression = (localForStatement->expression)?m_outputStack.pop():""; const QString condition = (localForStatement->condition)?m_outputStack.pop():""; const QString declaration = (localForStatement->declarations)?m_outputStack.pop():""; m_outputStack << "for(" + declaration + ';' + condition + ';' + incrementExpression + ')' + statement; } +void PureJavaScriptGenerator::endVisit(AST::NewExpression *) { + const QString constructor = m_outputStack.pop(); + m_outputStack << "new " + constructor; +} + +void PureJavaScriptGenerator::endVisit(AST::NewMemberExpression *newMemberExpression) { + const QString arguments = (newMemberExpression->arguments)?m_outputStack.pop():""; + const QString constructor = m_outputStack.pop(); + m_outputStack << "new " + constructor + '(' + arguments + ')'; +} + +void PureJavaScriptGenerator::endVisit(AST::NestedExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << '(' + expression + ')'; +} + +void PureJavaScriptGenerator::endVisit(AST::NotExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << '!' + expression; +} + void PureJavaScriptGenerator::endVisit(AST::NumericLiteral *) { } void PureJavaScriptGenerator::endVisit(AST::ObjectLiteral *) { const QString properties = m_outputStack.pop(); m_outputStack << '{' + properties + '}'; } void PureJavaScriptGenerator::endVisit(AST::PostDecrementExpression *) { const QString expression = m_outputStack.pop(); m_outputStack << expression + "--"; } void PureJavaScriptGenerator::endVisit(AST::PostIncrementExpression *) { const QString expression = m_outputStack.pop(); m_outputStack << expression + "++"; } void PureJavaScriptGenerator::endVisit(AST::PreDecrementExpression *) { const QString expression = m_outputStack.pop(); m_outputStack << "--" + expression; } void PureJavaScriptGenerator::endVisit(AST::PreIncrementExpression *) { const QString expression = m_outputStack.pop(); m_outputStack << "++" + expression; } void PureJavaScriptGenerator::endVisit(AST::PropertyAssignmentList *assignmentList) { reduceListStack(assignmentList, ","); } void PureJavaScriptGenerator::endVisit(AST::PropertyGetterSetter *getterSetter) { const QString functionBody = (getterSetter->functionBody)?m_outputStack.pop():"{}"; const QString parameters = (getterSetter->formals)?m_outputStack.pop():""; const QString propertyName = m_outputStack.pop(); if (getterSetter->type == AST::PropertyGetterSetter::Getter) { m_outputStack << "get " + propertyName + "()" + functionBody; } else { m_outputStack << "set " + propertyName + '(' + parameters + ')' + functionBody; } } void PureJavaScriptGenerator::endVisit(AST::PropertyNameAndValue *) { const QString expression = m_outputStack.pop(); const QString propertyName = m_outputStack.pop(); m_outputStack << propertyName + ':' + expression; } void PureJavaScriptGenerator::endVisit(AST::ReturnStatement *returnStatement) { const QString expression = (returnStatement->expression) ? ' '+m_outputStack.pop() : ""; m_outputStack << "return" + expression + ';'; } void PureJavaScriptGenerator::endVisit(AST::SourceElements *sourceElements) { reduceListStack(sourceElements); } void PureJavaScriptGenerator::endVisit(AST::StatementList *statementList) { reduceListStack(statementList); } void PureJavaScriptGenerator::endVisit(AST::StringLiteral *) { } void PureJavaScriptGenerator::endVisit(AST::SwitchStatement *) { const QString clauseBlock = m_outputStack.pop(); const QString expression = m_outputStack.pop(); m_outputStack << "switch(" + expression + ')' + clauseBlock; } +void PureJavaScriptGenerator::endVisit(AST::TildeExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << '~' + expression; +} + +void PureJavaScriptGenerator::endVisit(AST::TypeOfExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << "typeof " + expression; +} + +void PureJavaScriptGenerator::endVisit(AST::UnaryMinusExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << '-' + expression; +} + +void PureJavaScriptGenerator::endVisit(AST::UnaryPlusExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << '+' + expression; +} + void PureJavaScriptGenerator::endVisit(AST::VariableDeclaration *declaration) { const QString expression = (declaration->expression) ? "="+m_outputStack.pop() : ""; const QString variableName = declaration->name.toString(); m_outputStack << variableName + expression; } void PureJavaScriptGenerator::endVisit(AST::VariableDeclarationList *declarationList) { reduceListStack(declarationList, ","); const QString declarationListCode = m_outputStack.pop(); const QString declarationType = (declarationList->declaration->readOnly) ? "const" : "var"; m_outputStack << declarationType + ' ' + declarationListCode; } void PureJavaScriptGenerator::endVisit(AST::VariableStatement *) { m_outputStack << m_outputStack.pop() + ';'; } +void PureJavaScriptGenerator::endVisit(AST::VoidExpression *) { + const QString expression = m_outputStack.pop(); + m_outputStack << "void " + expression; +} + + void PureJavaScriptGenerator::endVisit(AST::WhileStatement *) { const QString statement = m_outputStack.pop(); const QString expression = m_outputStack.pop(); m_outputStack << "while(" + expression + ')' + statement; } void PureJavaScriptGenerator::reduceJumpStatement(const char *keyword, QStringRef label) { QString labelStatementCode(keyword); if (label.length() > 0) { labelStatementCode.append(' '); labelStatementCode.append(label.toString()); } m_outputStack << labelStatementCode + ';'; } \ No newline at end of file diff --git a/src/qmljsc/purejavascriptgenerator.h b/src/qmljsc/purejavascriptgenerator.h index 35dfa35..ad4635e 100644 --- a/src/qmljsc/purejavascriptgenerator.h +++ b/src/qmljsc/purejavascriptgenerator.h @@ -1,116 +1,127 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Jan Marker * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef QMLWEB_PUREJAVASCRIPTGENERATOR_H #define QMLWEB_PUREJAVASCRIPTGENERATOR_H #include #include class PureJavaScriptGenerator : public QQmlJS::AST::Visitor { public: PureJavaScriptGenerator(); QString getGeneratedCode(); virtual bool visit(QQmlJS::AST::BinaryExpression *) override; virtual bool visit(QQmlJS::AST::BreakStatement *) override; virtual bool visit(QQmlJS::AST::CaseClause *) override; virtual bool visit(QQmlJS::AST::ContinueStatement *) override; virtual bool visit(QQmlJS::AST::DefaultClause *) override; virtual bool visit(QQmlJS::AST::Elision *) override; virtual bool visit(QQmlJS::AST::FalseLiteral *) override; virtual bool visit(QQmlJS::AST::FormalParameterList *) override; virtual bool visit(QQmlJS::AST::IdentifierExpression *) override; virtual bool visit(QQmlJS::AST::IdentifierPropertyName *) override; virtual bool visit(QQmlJS::AST::NullExpression *) override; virtual bool visit(QQmlJS::AST::NumericLiteral *) override; virtual bool visit(QQmlJS::AST::StringLiteral *) override; virtual bool visit(QQmlJS::AST::ThisExpression *) override; virtual bool visit(QQmlJS::AST::TrueLiteral *) override; virtual void endVisit(QQmlJS::AST::ArgumentList *) override; virtual void endVisit(QQmlJS::AST::ArrayLiteral *) override; virtual void endVisit(QQmlJS::AST::ArrayMemberExpression *) override; virtual void endVisit(QQmlJS::AST::BinaryExpression *) override; virtual void endVisit(QQmlJS::AST::Block *) override; virtual void endVisit(QQmlJS::AST::CallExpression *) override; virtual void endVisit(QQmlJS::AST::CaseBlock *) override; virtual void endVisit(QQmlJS::AST::CaseClause *) override; virtual void endVisit(QQmlJS::AST::CaseClauses *) override; + virtual void endVisit(QQmlJS::AST::ConditionalExpression *) override; virtual void endVisit(QQmlJS::AST::DefaultClause *) override; + virtual void endVisit(QQmlJS::AST::DeleteExpression *) override; virtual void endVisit(QQmlJS::AST::DoWhileStatement *) override; virtual void endVisit(QQmlJS::AST::ElementList *) override; virtual void endVisit(QQmlJS::AST::EmptyStatement *) override; virtual void endVisit(QQmlJS::AST::ExpressionStatement *) override; virtual void endVisit(QQmlJS::AST::FieldMemberExpression *) override; virtual void endVisit(QQmlJS::AST::ForEachStatement *) override; virtual void endVisit(QQmlJS::AST::ForStatement *) override; virtual void endVisit(QQmlJS::AST::FunctionBody *) override; virtual void endVisit(QQmlJS::AST::FunctionDeclaration *) override; virtual void endVisit(QQmlJS::AST::IdentifierExpression *) override; virtual void endVisit(QQmlJS::AST::IfStatement *) override; virtual void endVisit(QQmlJS::AST::LocalForEachStatement *) override; virtual void endVisit(QQmlJS::AST::LocalForStatement *) override; + virtual void endVisit(QQmlJS::AST::NewExpression *) override; + virtual void endVisit(QQmlJS::AST::NewMemberExpression *) override; + virtual void endVisit(QQmlJS::AST::NestedExpression *) override; + virtual void endVisit(QQmlJS::AST::NotExpression *) override; virtual void endVisit(QQmlJS::AST::NumericLiteral *) override; virtual void endVisit(QQmlJS::AST::ObjectLiteral *) override; virtual void endVisit(QQmlJS::AST::PostDecrementExpression *) override; virtual void endVisit(QQmlJS::AST::PostIncrementExpression *) override; virtual void endVisit(QQmlJS::AST::PreDecrementExpression *) override; virtual void endVisit(QQmlJS::AST::PreIncrementExpression *) override; virtual void endVisit(QQmlJS::AST::PropertyAssignmentList *) override; virtual void endVisit(QQmlJS::AST::PropertyGetterSetter *) override; virtual void endVisit(QQmlJS::AST::PropertyNameAndValue *) override; virtual void endVisit(QQmlJS::AST::ReturnStatement *) override; virtual void endVisit(QQmlJS::AST::SourceElements *) override; virtual void endVisit(QQmlJS::AST::StringLiteral *) override; virtual void endVisit(QQmlJS::AST::StatementList *) override; virtual void endVisit(QQmlJS::AST::SwitchStatement *) override; + virtual void endVisit(QQmlJS::AST::TildeExpression *) override; + virtual void endVisit(QQmlJS::AST::TypeOfExpression *) override; + virtual void endVisit(QQmlJS::AST::UnaryMinusExpression *) override; + virtual void endVisit(QQmlJS::AST::UnaryPlusExpression *) override; virtual void endVisit(QQmlJS::AST::VariableDeclaration *) override; virtual void endVisit(QQmlJS::AST::VariableDeclarationList *) override; virtual void endVisit(QQmlJS::AST::VariableStatement *) override; + virtual void endVisit(QQmlJS::AST::VoidExpression *) override; virtual void endVisit(QQmlJS::AST::WhileStatement *) override; private: template void reduceListStack(ListType* list, const char* separator = ""); void reduceJumpStatement(const char *keyword, QStringRef label); QStack m_outputStack; friend class TestPureJavaScriptGenerator; }; template void PureJavaScriptGenerator::reduceListStack(ListType* current, const char* separator) { // the list is only iterated to count the elements // current is not processed in any way QString code; while (current) { code.prepend(m_outputStack.pop()); if (current->next) { code.prepend(separator); } current = current->next; } m_outputStack << code; } #endif //QMLWEB_PUREJAVASCRIPTGENERATOR_H diff --git a/tests/auto/data/javascript/expressions.js b/tests/auto/data/javascript/expressions.js index b97808a..3923c92 100644 --- a/tests/auto/data/javascript/expressions.js +++ b/tests/auto/data/javascript/expressions.js @@ -1 +1 @@ -var x;var i;var e=i++;e=++i;e=i--;e=--i; \ No newline at end of file +var x;var i;var e=i++;e=++i;e=i--;e=--i;5*(2+3);true?1:2; \ No newline at end of file diff --git a/tests/auto/data/javascript/lefthandexpressions.compiled.js b/tests/auto/data/javascript/lefthandexpressions.compiled.js new file mode 100644 index 0000000..6a83ce4 --- /dev/null +++ b/tests/auto/data/javascript/lefthandexpressions.compiled.js @@ -0,0 +1 @@ +obj.prop;obj["prop"];obj[0];new great();new greater(1);new greater(1,2);new great; \ No newline at end of file diff --git a/tests/auto/data/javascript/lefthandexpressions.js b/tests/auto/data/javascript/lefthandexpressions.js new file mode 100644 index 0000000..656bd83 --- /dev/null +++ b/tests/auto/data/javascript/lefthandexpressions.js @@ -0,0 +1,7 @@ +obj.prop; +obj["prop"]; +obj[0]; +new great(); +new greater(1); +new greater(1, 2); +new great; \ No newline at end of file diff --git a/tests/auto/data/javascript/propertyaccess.compiled.js b/tests/auto/data/javascript/propertyaccess.compiled.js deleted file mode 100644 index 4a11b7d..0000000 --- a/tests/auto/data/javascript/propertyaccess.compiled.js +++ /dev/null @@ -1 +0,0 @@ -obj.prop;obj["prop"];obj[0]; \ No newline at end of file diff --git a/tests/auto/data/javascript/propertyaccess.js b/tests/auto/data/javascript/propertyaccess.js deleted file mode 100644 index 094b1ed..0000000 --- a/tests/auto/data/javascript/propertyaccess.js +++ /dev/null @@ -1,3 +0,0 @@ -obj.prop; -obj["prop"]; -obj[0]; \ No newline at end of file diff --git a/tests/auto/data/javascript/unaryoperators.js b/tests/auto/data/javascript/unaryoperators.js new file mode 100644 index 0000000..26e391a --- /dev/null +++ b/tests/auto/data/javascript/unaryoperators.js @@ -0,0 +1 @@ +delete v;void 4;typeof o;+5;-5;~4;!false; \ No newline at end of file diff --git a/tests/auto/qmljsc/testpurejavascriptgenerator.cpp b/tests/auto/qmljsc/testpurejavascriptgenerator.cpp index 67573fe..4542e21 100644 --- a/tests/auto/qmljsc/testpurejavascriptgenerator.cpp +++ b/tests/auto/qmljsc/testpurejavascriptgenerator.cpp @@ -1,505 +1,543 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Jan Marker * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include "../../../src/qmljsc/utils/error.h" #include "../../../src/qmljsc/purejavascriptgenerator.h" #define TEST_VISIT_PUTS_ON_STACK(className, testSituation, expectedStackContent, instance) \ void test_visit_ ## className ## _ ## testSituation ## _returnsTrue() { \ QCOMPARE(m_generator->visit(&instance), true); \ } \ void test_ ## visit ## _ ## className ## _ ## testSituation ## _putsOnStack() { \ m_generator->visit(&instance); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack.top(), QStringLiteral(expectedStackContent)); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack.size(), 1); \ } #define TEST_VISIT_BINARYOP_PUTS_ON_STACK(operatorEnumName, character) \ void test_visit_BinaryExpression_ ## operatorEnumName ## _returnsTrue() { \ QQmlJS::AST::BinaryExpression classInstance(nullptr, QSOperator::operatorEnumName, nullptr); \ QCOMPARE(m_generator->visit(&classInstance), true); \ } \ void test_visit_BinaryExpression_ ## operatorEnumName ## _putsOnStack() { \ QQmlJS::AST::BinaryExpression instance(nullptr, QSOperator::operatorEnumName, nullptr); \ QStack expectedStack;\ expectedStack.append(character);\ m_generator->visit(&instance); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack, expectedStack); \ } #define TEST_VISIT_DEFAULT_IMPL_(className, instance) \ void test_visit ## _ ## className ## _defaultImplementation_returns_true() { \ QCOMPARE(m_generator->visit(&instance), true); \ } \ void test_ ## visit ## _ ## className ## _ ## testSituation ## _putsNothingOnStack() { \ m_generator->visit(&instance); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack.count(), 0); \ } #define TEST_ENDVISIT_REDUCES(className, scenarioName, expectedTopOfStack, stackContent, instance) \ void test_endVisit_ ## className ## _ ## scenarioName ## _reducesStack() { \ asPureJSGen(m_generator)->m_outputStack.append(QVectorstackContent); \ m_generator->endVisit(&instance); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack.top(), QStringLiteral(expectedTopOfStack)); \ QCOMPARE(asPureJSGen(m_generator)->m_outputStack.count(), 1); \ } using namespace QQmlJS; class TestPureJavaScriptGenerator : public QObject { Q_OBJECT public: TestPureJavaScriptGenerator() : m_someLabel("ALabel") , m_someLabelStringRef(&m_someLabel) , m_someString("some string") , m_someStringStringRef(&m_someString) , m_someIdentifier("i") , m_someIdentifierStringRef(&m_someIdentifier) , m_anotherIdentifier("e") , m_anotherIdentifierStringRef(&m_anotherIdentifier) , m_propertyIdentifier("property") , m_propertyIdentifierStringRef(&m_propertyIdentifier) /* Expressions */ , m_thisExpression() , m_nullExpression() , m_identifierExpression(m_someIdentifierStringRef) , m_trueLiteral() , m_falseLiteral() , m_numericalExpressionPi(3.14) , m_stringLiteral(m_someStringStringRef) , m_twoElisions() , m_elisionsPart2(&m_twoElisions) , m_arrayElementsExp(nullptr, &m_trueLiteral) , m_arrayElementsExpExp(nullptr, &m_trueLiteral) , m_arrayElementsExpExpPart2(&m_arrayElementsExpExp, nullptr, &m_falseLiteral) , m_arrayElementsElisionExp(&m_twoElisions, &m_falseLiteral) , m_arrayElementsExpElisionExp(nullptr, &m_falseLiteral) , m_arrayLiteralWithElision(&m_arrayElementsExp, &m_twoElisions) , m_arrayLiteralWithoutElision(&m_arrayElementsExp) , m_arrayLiteralOnlyElision(&m_twoElisions) , m_arrayElementsExpElisionExpPart2(&m_arrayElementsExpElisionExp, &m_twoElisions, &m_trueLiteral) , m_identifierPropertyName(m_someIdentifierStringRef) , m_propertyNameAndValue(&m_identifierPropertyName, &m_falseLiteral) , m_propertyGetter(&m_identifierPropertyName, &m_functionBody) , m_propertyGetterEmptyBody(&m_identifierPropertyName, nullptr) , m_propertySetter(&m_identifierPropertyName, &m_twoParameters, &m_functionBody) , m_propertySetterEmptyBody(&m_identifierPropertyName, &m_twoParameters, nullptr) , m_twoProperties(&m_propertyNameAndValue) , m_twoPropertiesPart2(&m_twoProperties, &m_propertyNameAndValue) , m_objectLiteral(&m_twoProperties) , m_equalsBinaryExpression(nullptr, QSOperator::Equal, nullptr) + , m_nestedExpression(nullptr) , m_postDecrementExpression(&m_numericalExpressionPi) , m_postIncrementExpression(&m_numericalExpressionPi) , m_preDecrementExpression(&m_numericalExpressionPi) , m_preIncrementExpression(&m_numericalExpressionPi) , m_block(nullptr) , m_fieldMemberExpression(&m_identifierExpression, m_propertyIdentifierStringRef) , m_arrayMemberExpression(nullptr, nullptr) , m_argumentListOneArgument(&m_trueLiteral) , m_argumentListTwoArguments(&m_trueLiteral) , m_argumentListTwoArgumentsPart2(&m_argumentListTwoArguments, &m_trueLiteral) , m_callExpressionWithArguments(&m_identifierExpression, &m_argumentListTwoArguments) , m_callExpressionWithoutArguments(&m_identifierExpression, nullptr) + , m_newMemberExpressionArguments(&m_identifierExpression, &m_argumentListOneArgument) + , m_newMemberExpressionNoArguments(&m_identifierExpression, nullptr) + , m_newExpression(&m_identifierExpression) + , m_tildeExpression(&m_identifierExpression) + , m_notExpression(&m_identifierExpression) + , m_unaryPlusExpression(&m_identifierExpression) + , m_unaryMinusExpression(&m_identifierExpression) + , m_deleteExpression(&m_identifierExpression) + , m_typeOfExpression(&m_identifierExpression) + , m_voidExpression(&m_identifierExpression) + , m_conditionalExpression(&m_trueLiteral, &m_numericalExpressionPi, &m_numericalExpressionPi) /* Variable Declarations */ , m_constDeclaration1(m_someIdentifierStringRef, nullptr) , m_constDeclaration2(m_anotherIdentifierStringRef, nullptr) , m_variableDeclarationWithAssignment(m_someIdentifierStringRef, &m_trueLiteral) , m_variableDeclarationWithoutAssignment(m_someIdentifierStringRef, nullptr) , m_twoConstDeclarations(&m_constDeclaration1) , m_twoConstDeclarationsPart2(&m_twoConstDeclarations, &m_constDeclaration2) , m_twoVarDeclarations(&m_variableDeclarationWithAssignment) , m_twoVarDeclarationsPart2(&m_twoVarDeclarations, &m_variableDeclarationWithoutAssignment) /* Statements */ , m_breakStatementWithLabel(m_someLabelStringRef) , m_breakStatementWithoutLabel(nullptr) , m_continueStatementWithLabel(m_someLabelStringRef) , m_continueStatementWithoutLabel(nullptr) , m_emptyStatement() , m_statement1() , m_statement2() , m_statement3() , m_expressionStatement(nullptr) , m_ifStatementWithoutElse(&m_trueLiteral, &m_statement1) , m_ifStatementWithElse(&m_trueLiteral, &m_statement1, &m_statement2) , m_returnStatementWithoutValue(nullptr) , m_returnStatementWithValue(&m_trueLiteral) , m_variableStatement(&m_twoVarDeclarations) , m_threeStatementsList(&m_statement1) , m_statementListPart2(&m_threeStatementsList, &m_statement2) , m_statementListPart3(&m_statementListPart2, &m_statement3) , m_sourceElement1(nullptr) , m_sourceElement2(nullptr) , m_sourceElement3(nullptr) , m_threeSourceElementsList(&m_sourceElement1) , m_sourceElementsListPart2(&m_threeSourceElementsList, &m_sourceElement2) , m_sourceElementsListPart3(&m_sourceElementsListPart2, &m_sourceElement3) /* Function declaration */ , m_twoParameters(m_someIdentifierStringRef) , m_parameterListPart2(&m_twoParameters, m_anotherIdentifierStringRef) , m_functionBody(nullptr) , m_functionDeclarationWithoutParameters(m_someIdentifierStringRef, nullptr, &m_functionBody) , m_functionDeclarationWithParameters(m_someIdentifierStringRef, &m_twoParameters , &m_functionBody) , m_functionDeclarationWithoutBody(m_someIdentifierStringRef, &m_twoParameters, nullptr) /* Switch */ , m_caseClause1(&m_trueLiteral, &m_threeStatementsList) , m_caseClause2(&m_trueLiteral, &m_threeStatementsList) , m_twoCaseClauses(&m_caseClause1) , m_twoCaseClausesPart2(&m_twoCaseClauses, &m_caseClause2) , m_defaultClause(&m_threeStatementsList) , m_caseBlock(&m_twoCaseClauses, &m_defaultClause, &m_twoCaseClauses) , m_caseBlockOnlyCases(&m_twoCaseClauses) , m_caseBlockCasesAndDefault(&m_twoCaseClauses, &m_defaultClause) , m_caseBlockCasesDefaultCases(&m_twoCaseClauses, &m_defaultClause, &m_twoCaseClauses) , m_caseClause(&m_trueLiteral, &m_threeStatementsList) , m_switchStatement(&m_trueLiteral, &m_caseBlock) , m_whileStatement(nullptr, nullptr) , m_doWhileStatement(nullptr, nullptr) , m_forStatementAllParts(&m_trueLiteral, &m_falseLiteral, &m_trueLiteral, &m_block) , m_forStatementNoPart(nullptr, nullptr, nullptr, &m_block) , m_localForStatementAllParts(&m_twoVarDeclarations, &m_falseLiteral, &m_trueLiteral, &m_block) , m_localForStatementNoPart(nullptr, nullptr, nullptr, &m_block) , m_forEachStatement(&m_trueLiteral, &m_trueLiteral, &m_block) , m_localForEachStatement(&m_variableDeclarationWithoutAssignment, &m_trueLiteral, &m_block) { m_elisionsPart2.finish(); m_arrayElementsExp.finish(); m_arrayElementsExpExpPart2.finish(); m_arrayElementsElisionExp.finish(); m_arrayElementsExpElisionExpPart2.finish(); m_twoPropertiesPart2.finish(); m_argumentListOneArgument.finish(); m_argumentListTwoArgumentsPart2.finish(); m_statementListPart3.finish(); m_sourceElementsListPart3.finish(); m_parameterListPart2.finish(); m_twoConstDeclarationsPart2.finish(true); m_twoVarDeclarationsPart2.finish(false); m_twoCaseClausesPart2.finish(); } private: PureJavaScriptGenerator* asPureJSGen(QQmlJS::AST::Visitor* generator) { return static_cast(generator); } QQmlJS::AST::Visitor *m_generator; const QString m_someLabel; const QStringRef m_someLabelStringRef; const QString m_someString; const QStringRef m_someStringStringRef; const QString m_someIdentifier; const QStringRef m_someIdentifierStringRef; const QString m_anotherIdentifier; const QStringRef m_anotherIdentifierStringRef; const QString m_propertyIdentifier; const QStringRef m_propertyIdentifierStringRef; /* Expressions */ AST::ThisExpression m_thisExpression; AST::NullExpression m_nullExpression; AST::IdentifierExpression m_identifierExpression; AST::TrueLiteral m_trueLiteral; AST::FalseLiteral m_falseLiteral; AST::NumericLiteral m_numericalExpressionPi; AST::StringLiteral m_stringLiteral; AST::Elision m_twoElisions; AST::Elision m_elisionsPart2; AST::ElementList m_arrayElementsExp; AST::ElementList m_arrayElementsExpExp; AST::ElementList m_arrayElementsExpExpPart2; AST::ElementList m_arrayElementsElisionExp; AST::ElementList m_arrayElementsExpElisionExp; AST::ElementList m_arrayElementsExpElisionExpPart2; AST::ArrayLiteral m_arrayLiteralWithElision; AST::ArrayLiteral m_arrayLiteralWithoutElision; AST::ArrayLiteral m_arrayLiteralOnlyElision; AST::IdentifierPropertyName m_identifierPropertyName; AST::PropertyNameAndValue m_propertyNameAndValue; AST::PropertyGetterSetter m_propertyGetter; AST::PropertyGetterSetter m_propertyGetterEmptyBody; AST::PropertyGetterSetter m_propertySetter; AST::PropertyGetterSetter m_propertySetterEmptyBody; AST::PropertyAssignmentList m_twoProperties; AST::PropertyAssignmentList m_twoPropertiesPart2; AST::ObjectLiteral m_objectLiteral; AST::BinaryExpression m_equalsBinaryExpression; + AST::NestedExpression m_nestedExpression; AST::PostDecrementExpression m_postDecrementExpression; AST::PostIncrementExpression m_postIncrementExpression; AST::PreDecrementExpression m_preDecrementExpression; AST::PreIncrementExpression m_preIncrementExpression; AST::FieldMemberExpression m_fieldMemberExpression; AST::ArrayMemberExpression m_arrayMemberExpression; AST::ArgumentList m_argumentListOneArgument; AST::ArgumentList m_argumentListTwoArguments; AST::ArgumentList m_argumentListTwoArgumentsPart2; AST::CallExpression m_callExpressionWithArguments; AST::CallExpression m_callExpressionWithoutArguments; + AST::NewMemberExpression m_newMemberExpressionNoArguments; + AST::NewMemberExpression m_newMemberExpressionArguments; + AST::NewExpression m_newExpression; + + AST::TildeExpression m_tildeExpression; + AST::NotExpression m_notExpression; + AST::UnaryPlusExpression m_unaryPlusExpression; + AST::UnaryMinusExpression m_unaryMinusExpression; + AST::DeleteExpression m_deleteExpression; + AST::TypeOfExpression m_typeOfExpression; + AST::VoidExpression m_voidExpression; + + AST::ConditionalExpression m_conditionalExpression; /* Variable Declarations */ AST::VariableDeclaration m_constDeclaration1; AST::VariableDeclaration m_constDeclaration2; AST::VariableDeclaration m_variableDeclarationWithAssignment; AST::VariableDeclaration m_variableDeclarationWithoutAssignment; AST::VariableDeclarationList m_twoConstDeclarations; AST::VariableDeclarationList m_twoConstDeclarationsPart2; AST::VariableDeclarationList m_twoVarDeclarations; AST::VariableDeclarationList m_twoVarDeclarationsPart2; /* Statements */ AST::BreakStatement m_breakStatementWithLabel; AST::BreakStatement m_breakStatementWithoutLabel; AST::ContinueStatement m_continueStatementWithLabel; AST::ContinueStatement m_continueStatementWithoutLabel; AST::EmptyStatement m_emptyStatement; AST::EmptyStatement m_statement1; AST::EmptyStatement m_statement2; AST::EmptyStatement m_statement3; AST::ExpressionStatement m_expressionStatement; AST::IfStatement m_ifStatementWithoutElse; AST::IfStatement m_ifStatementWithElse; AST::ReturnStatement m_returnStatementWithoutValue; AST::ReturnStatement m_returnStatementWithValue; AST::VariableStatement m_variableStatement; AST::Block m_block; AST::StatementList m_threeStatementsList; AST::StatementList m_statementListPart2; AST::StatementList m_statementListPart3; AST::StatementSourceElement m_sourceElement1; AST::StatementSourceElement m_sourceElement2; AST::StatementSourceElement m_sourceElement3; AST::SourceElements m_threeSourceElementsList; AST::SourceElements m_sourceElementsListPart2; AST::SourceElements m_sourceElementsListPart3; /* Function declarations */ AST::FormalParameterList m_twoParameters; AST::FormalParameterList m_parameterListPart2; AST::FunctionBody m_functionBody; AST::FunctionDeclaration m_functionDeclarationWithoutParameters; AST::FunctionDeclaration m_functionDeclarationWithParameters; AST::FunctionDeclaration m_functionDeclarationWithoutBody; /* Switch */ AST::CaseClause m_caseClause1; AST::CaseClause m_caseClause2; AST::CaseClauses m_twoCaseClauses; AST::CaseClauses m_twoCaseClausesPart2; AST::DefaultClause m_defaultClause; AST::CaseBlock m_caseBlock; AST::CaseBlock m_caseBlockOnlyCases; AST::CaseBlock m_caseBlockCasesAndDefault; AST::CaseBlock m_caseBlockCasesDefaultCases; AST::CaseClause m_caseClause; AST::SwitchStatement m_switchStatement; /* Loops */ AST::WhileStatement m_whileStatement; AST::DoWhileStatement m_doWhileStatement; AST::ForStatement m_forStatementAllParts; AST::ForStatement m_forStatementNoPart; AST::LocalForStatement m_localForStatementAllParts; AST::LocalForStatement m_localForStatementNoPart; AST::ForEachStatement m_forEachStatement; AST::LocalForEachStatement m_localForEachStatement; private slots: void init() { m_generator = new PureJavaScriptGenerator(); }; void cleanup() { delete m_generator; } void testGeneratedCodeIsInitiallyEmpty() { QCOMPARE(asPureJSGen(m_generator)->getGeneratedCode(), QStringLiteral("")); } void test_getGeneratedCode_getsTopOfStack() { // Prepare asPureJSGen(m_generator)->m_outputStack << "1"; // Verify QCOMPARE(asPureJSGen(m_generator)->getGeneratedCode(), QStringLiteral("1")); } void test_getGeneratedCode_throwsError_OnStackSizeGreaterThanOne() { // Prepare asPureJSGen(m_generator)->m_outputStack << "1" << "2"; // Verify QVERIFY_EXCEPTION_THROWN(asPureJSGen(m_generator)->getGeneratedCode(), QmlJSc::Error); } TEST_VISIT_DEFAULT_IMPL_(Block , m_block) TEST_VISIT_PUTS_ON_STACK(BreakStatement , WithLabel , "break ALabel;" , m_breakStatementWithLabel) TEST_VISIT_PUTS_ON_STACK(BreakStatement , WithoutLabel , "break;" , m_breakStatementWithoutLabel) TEST_VISIT_DEFAULT_IMPL_(CaseBlock , m_caseBlock) TEST_VISIT_PUTS_ON_STACK(CaseClause , AnyCase , "case" , m_caseClause1) TEST_VISIT_DEFAULT_IMPL_(CaseClauses , m_twoCaseClauses) TEST_VISIT_PUTS_ON_STACK(DefaultClause , Default , "default" , m_defaultClause) TEST_VISIT_PUTS_ON_STACK(ContinueStatement , WithLabel , "continue ALabel;", m_continueStatementWithLabel) TEST_VISIT_PUTS_ON_STACK(ContinueStatement , WithoutLabel , "continue;" , m_continueStatementWithoutLabel) TEST_VISIT_PUTS_ON_STACK(Elision , AnyCase , ",," , m_twoElisions) TEST_VISIT_DEFAULT_IMPL_(EmptyStatement , m_emptyStatement) TEST_VISIT_DEFAULT_IMPL_(ExpressionStatement , m_expressionStatement) TEST_VISIT_PUTS_ON_STACK(FormalParameterList , OneParameter , "e" , m_parameterListPart2) TEST_VISIT_PUTS_ON_STACK(FormalParameterList , TwoParameters , "i,e" , m_twoParameters) TEST_VISIT_PUTS_ON_STACK(FalseLiteral , AnyCase , "false" , m_falseLiteral) TEST_VISIT_DEFAULT_IMPL_(FunctionBody , m_functionBody) TEST_VISIT_DEFAULT_IMPL_(FunctionDeclaration , m_functionDeclarationWithParameters) TEST_VISIT_PUTS_ON_STACK(IdentifierExpression , AnyCase , "i" , m_identifierExpression) TEST_VISIT_PUTS_ON_STACK(IdentifierPropertyName , AnyCase , "i" , m_identifierPropertyName) TEST_VISIT_DEFAULT_IMPL_(IfStatement , m_ifStatementWithoutElse) TEST_VISIT_PUTS_ON_STACK(NullExpression , AnyCase , "null" , m_nullExpression) TEST_VISIT_PUTS_ON_STACK(NumericLiteral , Pi , "3.14" , m_numericalExpressionPi) TEST_VISIT_DEFAULT_IMPL_(PostDecrementExpression , m_postDecrementExpression) TEST_VISIT_DEFAULT_IMPL_(PostIncrementExpression , m_postIncrementExpression) TEST_VISIT_DEFAULT_IMPL_(PreDecrementExpression , m_preDecrementExpression) TEST_VISIT_DEFAULT_IMPL_(PreIncrementExpression , m_preIncrementExpression) TEST_VISIT_DEFAULT_IMPL_(ReturnStatement , m_returnStatementWithoutValue) TEST_VISIT_DEFAULT_IMPL_(SourceElements , m_threeSourceElementsList) TEST_VISIT_DEFAULT_IMPL_(StatementList , m_threeStatementsList) TEST_VISIT_PUTS_ON_STACK(StringLiteral , AnyCase , "\"some string\"" , m_stringLiteral) TEST_VISIT_DEFAULT_IMPL_(SwitchStatement , m_switchStatement) TEST_VISIT_PUTS_ON_STACK(ThisExpression , AnyCase , "this" , m_thisExpression) TEST_VISIT_PUTS_ON_STACK(TrueLiteral , AnyCase , "true" , m_trueLiteral) TEST_VISIT_DEFAULT_IMPL_(VariableDeclaration , m_variableDeclarationWithoutAssignment) TEST_VISIT_DEFAULT_IMPL_(VariableDeclarationList , m_twoConstDeclarations) TEST_VISIT_DEFAULT_IMPL_(VariableStatement , m_variableStatement) TEST_ENDVISIT_REDUCES(ArgumentList , OneArgument , "1" , ({"1"}) , m_argumentListOneArgument) TEST_ENDVISIT_REDUCES(ArgumentList , TwoArguments , "1,2" , ({"1", "2"}) , m_argumentListTwoArguments) TEST_ENDVISIT_REDUCES(ArrayLiteral , OnlyElision , "[,,,]" , ({",,,"}) , m_arrayLiteralOnlyElision) TEST_ENDVISIT_REDUCES(ArrayLiteral , WithElision , "[5,,,]" , ({"5", ",,,"}) , m_arrayLiteralWithElision) TEST_ENDVISIT_REDUCES(ArrayLiteral , WithoutElision , "[5]" , ({"5"}) , m_arrayLiteralWithoutElision) TEST_ENDVISIT_REDUCES(ArrayMemberExpression , AnyCase , "i[2]" , ({"i", "2"}) , m_arrayMemberExpression) TEST_ENDVISIT_REDUCES(BinaryExpression , TwoOperands , "2==4" , ({"==", "2", "4"}) , m_equalsBinaryExpression) TEST_ENDVISIT_REDUCES(Block , AnyCase , "{content}" , ({"content"}) , m_block) TEST_ENDVISIT_REDUCES(CallExpression , WithArguments , "func(args)" , ({"func", "args"}) , m_callExpressionWithArguments) TEST_ENDVISIT_REDUCES(CallExpression , WithoutArguments , "func()" , ({"func"}) , m_callExpressionWithoutArguments) TEST_ENDVISIT_REDUCES(CaseBlock , OnlyCases , "{cases;}" , ({"cases;"}) , m_caseBlockOnlyCases) TEST_ENDVISIT_REDUCES(CaseBlock , CasesAndDefault , "{cases;default;}", ({"cases;", "default;"}) , m_caseBlockCasesAndDefault) TEST_ENDVISIT_REDUCES(CaseBlock , CasesDefaultCases , "{cases;default;cases;}", ({"cases;", "default;", "cases;"}), m_caseBlockCasesDefaultCases) TEST_ENDVISIT_REDUCES(CaseClause , CaseWithStatement , "case exp:stm;" , ({"case", "exp", "stm;"}) , m_caseClause) TEST_ENDVISIT_REDUCES(CaseClauses , TwoClauses , "case e:s;case e2:s2;", ({"case e:s;", "case e2:s2;"}), m_twoCaseClauses) + TEST_ENDVISIT_REDUCES(ConditionalExpression , AnyCase , "condition?e1:e2" , ({"condition", "e1", "e2"}) , m_conditionalExpression) TEST_ENDVISIT_REDUCES(DefaultClause , AnyCase , "default:stm" , ({"default", "stm"}) , m_defaultClause) - TEST_ENDVISIT_REDUCES(DoWhileStatement , AnyCase , "do stm;while(e);", ({"stm;", "e"}) , m_doWhileStatement) + TEST_ENDVISIT_REDUCES(DeleteExpression , AnyCase , "delete v" , ({"v"}) , m_deleteExpression) + TEST_ENDVISIT_REDUCES(DoWhileStatement , AnyCase , "do stm;while(e);", ({"stm;", "e"}) , m_doWhileStatement) TEST_ENDVISIT_REDUCES(ElementList , Expression , "expr," , ({"expr"}) , m_arrayElementsExp) TEST_ENDVISIT_REDUCES(ElementList , TwoExpressions , "expr,expr," , ({"expr", "expr"}) , m_arrayElementsExpExp) TEST_ENDVISIT_REDUCES(ElementList , ElisionExpression , "elisionexpr," , ({"elision", "expr"}) , m_arrayElementsElisionExp) TEST_ENDVISIT_REDUCES(ElementList , ExprElisionExpr , "expr,eliexpr," , ({"expr", "eli", "expr"}) , m_arrayElementsExpElisionExp) TEST_ENDVISIT_REDUCES(EmptyStatement , DefaultScenario , ";" , ({}) , m_emptyStatement) TEST_ENDVISIT_REDUCES(ExpressionStatement , AnyCase , "expression;" , ({"expression"}) , m_expressionStatement) TEST_ENDVISIT_REDUCES(FieldMemberExpression , AnyCase , "obj.property" , ({"obj"}) , m_fieldMemberExpression) TEST_ENDVISIT_REDUCES(FormalParameterList , AnyCase , "i" , ({"i"}) , m_twoParameters) // does nothing TEST_ENDVISIT_REDUCES(ForEachStatement , AnyCase , "for(i in o)stm;" , ({"i", "o", "stm;"}) , m_forEachStatement) TEST_ENDVISIT_REDUCES(ForStatement , AllParts , "for(i;c;++)stm;" , ({"i", "c", "++", "stm;"}) , m_forStatementAllParts) TEST_ENDVISIT_REDUCES(ForStatement , NoPart , "for(;;)stm;" , ({"stm;"}) , m_forStatementNoPart) TEST_ENDVISIT_REDUCES(FunctionBody , ClosesCorrectly , "{func}" , ({"func"}) , m_functionBody) TEST_ENDVISIT_REDUCES(FunctionDeclaration , BodyNoParameters , "function i(){body}" , ({"{body}"}) , m_functionDeclarationWithoutParameters) TEST_ENDVISIT_REDUCES(FunctionDeclaration , BodyParameters , "function i(para){body}", ({"para", "{body}"}) , m_functionDeclarationWithParameters) TEST_ENDVISIT_REDUCES(FunctionDeclaration , WithoutBody , "function i(para){}" , ({"para"}) , m_functionDeclarationWithoutBody) TEST_ENDVISIT_REDUCES(IdentifierExpression , AnyCase , "abc" , ({"abc"}) , m_identifierExpression) TEST_ENDVISIT_REDUCES(IfStatement , OnlyIf , "if(exp)stm;" , ({"exp", "stm;"}) , m_ifStatementWithoutElse) TEST_ENDVISIT_REDUCES(IfStatement , IfElse , "if(exp)s;else s;", ({"exp", "s;", "s;"}) , m_ifStatementWithElse) TEST_ENDVISIT_REDUCES(LocalForEachStatement , AnyCase , "for(var i in o)stm;", ({"i", "o", "stm;"}) , m_localForEachStatement) TEST_ENDVISIT_REDUCES(LocalForStatement , AllParts , "for(var i;c;++)stm;", ({"var i", "c", "++", "stm;"}), m_localForStatementAllParts) TEST_ENDVISIT_REDUCES(LocalForStatement , NoPart , "for(;;)stm;" , ({"stm;"}) , m_localForStatementNoPart) + TEST_ENDVISIT_REDUCES(NestedExpression , AnyCase , "(expression)" , ({"expression"}) , m_nestedExpression) + TEST_ENDVISIT_REDUCES(NewExpression , AnyCase , "new constr" , ({"constr"}) , m_newExpression) + TEST_ENDVISIT_REDUCES(NewMemberExpression , NoArguments , "new constr()" , ({"constr"}) , m_newMemberExpressionNoArguments) + TEST_ENDVISIT_REDUCES(NewMemberExpression , Arguments , "new constr(arg)" , ({"constr", "arg"}) , m_newMemberExpressionArguments) + TEST_ENDVISIT_REDUCES(NotExpression , AnyCase , "!5" , ({"5"}) , m_notExpression) TEST_ENDVISIT_REDUCES(NumericLiteral , AnyCase , "2.7" , ({"2.7"}) , m_numericalExpressionPi) TEST_ENDVISIT_REDUCES(ObjectLiteral , AnyCase , "{properties}" , ({"properties"}) , m_objectLiteral) TEST_ENDVISIT_REDUCES(PostDecrementExpression , AnyCase , "2.7--" , ({"2.7"}) , m_postDecrementExpression) TEST_ENDVISIT_REDUCES(PostIncrementExpression , AnyCase , "2.7++" , ({"2.7"}) , m_postIncrementExpression) TEST_ENDVISIT_REDUCES(PreDecrementExpression , AnyCase , "--2.7" , ({"2.7"}) , m_preDecrementExpression) TEST_ENDVISIT_REDUCES(PreIncrementExpression , AnyCase , "++2.7" , ({"2.7"}) , m_preIncrementExpression) TEST_ENDVISIT_REDUCES(PropertyAssignmentList , TwoProperties , "prop1,prop2" , ({"prop1", "prop2"}) , m_twoProperties) TEST_ENDVISIT_REDUCES(PropertyGetterSetter , Getter , "get i(){body}" , ({"i", "{body}"}) , m_propertyGetter) TEST_ENDVISIT_REDUCES(PropertyGetterSetter , GetterEmptyBody , "get i(){}" , ({"i"}) , m_propertyGetterEmptyBody) TEST_ENDVISIT_REDUCES(PropertyGetterSetter , Setter , "set i(param){body}", ({"i", "param", "{body}"}) , m_propertySetter) TEST_ENDVISIT_REDUCES(PropertyGetterSetter , SetterEmptyBody , "set i(param){}" , ({"i", "param"}) , m_propertySetterEmptyBody) TEST_ENDVISIT_REDUCES(PropertyNameAndValue , AnyCase , "prop:expr" , ({"prop", "expr"}) , m_propertyNameAndValue) TEST_ENDVISIT_REDUCES(ReturnStatement , WithoutReturnValue, "return;" , ({}) , m_returnStatementWithoutValue) TEST_ENDVISIT_REDUCES(ReturnStatement , WithReturnValue , "return true;" , ({"true"}) , m_returnStatementWithValue) TEST_ENDVISIT_REDUCES(SourceElements , ThreeSrcElements , "sEl1sEl2sEl3" , ({"sEl1", "sEl2", "sEl3"}) , m_threeSourceElementsList) TEST_ENDVISIT_REDUCES(SourceElements , ThreeStatements , "st1st2st3" , ({"st1", "st2", "st3"}) , m_threeStatementsList) TEST_ENDVISIT_REDUCES(StringLiteral , AnyCase , "another string" , ({"another string"}) , m_stringLiteral) TEST_ENDVISIT_REDUCES(SwitchStatement , AnyCase , "switch(e){blk}" , ({"e", "{blk}"}) , m_switchStatement) + TEST_ENDVISIT_REDUCES(TildeExpression , AnyCase , "~5" , ({"5"}) , m_tildeExpression) + TEST_ENDVISIT_REDUCES(TypeOfExpression , AnyCase , "typeof v" , ({"v"}) , m_typeOfExpression) + TEST_ENDVISIT_REDUCES(UnaryMinusExpression , AnyCase , "-5" , ({"5"}) , m_unaryMinusExpression) + TEST_ENDVISIT_REDUCES(UnaryPlusExpression , AnyCase , "+5" , ({"5"}) , m_unaryPlusExpression) TEST_ENDVISIT_REDUCES(VariableDeclaration , WithAssignment , "i=5" , ({"5"}) , m_variableDeclarationWithAssignment) TEST_ENDVISIT_REDUCES(VariableDeclaration , WithoutAssignment , "i" , ({}) , m_variableDeclarationWithoutAssignment) TEST_ENDVISIT_REDUCES(VariableDeclarationList , TwoDeclarations , "var i,e=5" , ({"i", "e=5"}) , m_twoVarDeclarations) TEST_ENDVISIT_REDUCES(VariableDeclarationList , OneDeclaration , "var e=5" , ({"e=5"}) , m_twoVarDeclarationsPart2) TEST_ENDVISIT_REDUCES(VariableDeclarationList , ConstDeclaration , "const e=5" , ({"e=5"}) , m_twoConstDeclarationsPart2) TEST_ENDVISIT_REDUCES(VariableStatement , AnyCase , "x;" , ({"x"}) , m_variableStatement) + TEST_ENDVISIT_REDUCES(VoidExpression , AnyCase , "void v" , ({"v"}) , m_voidExpression) TEST_ENDVISIT_REDUCES(WhileStatement , AnyCase , "while(e)stm" , ({"e", "stm"}) , m_whileStatement) TEST_VISIT_BINARYOP_PUTS_ON_STACK(Assign, "=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceAdd, "+=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceSub, "-=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceMul, "*=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceDiv, "/=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceMod, "%=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceLeftShift, "<<=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceRightShift, ">>=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceURightShift, ">>>=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceAnd, "&=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceXor, "^=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InplaceOr, "|=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Add, "+") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Sub, "-") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Mul, "*") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Div, "/") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Mod, "%") TEST_VISIT_BINARYOP_PUTS_ON_STACK(LShift, "<<") TEST_VISIT_BINARYOP_PUTS_ON_STACK(RShift, ">>") TEST_VISIT_BINARYOP_PUTS_ON_STACK(URShift, ">>>") TEST_VISIT_BINARYOP_PUTS_ON_STACK(BitAnd, "&") TEST_VISIT_BINARYOP_PUTS_ON_STACK(BitXor, "^") TEST_VISIT_BINARYOP_PUTS_ON_STACK(BitOr, "|") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Equal, "==") TEST_VISIT_BINARYOP_PUTS_ON_STACK(NotEqual, "!=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(StrictEqual, "===") TEST_VISIT_BINARYOP_PUTS_ON_STACK(StrictNotEqual, "!==") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Gt, ">") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Ge, ">=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Lt, "<") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Le, "<=") TEST_VISIT_BINARYOP_PUTS_ON_STACK(And, "&&") TEST_VISIT_BINARYOP_PUTS_ON_STACK(Or, "||") TEST_VISIT_BINARYOP_PUTS_ON_STACK(In, " in ") TEST_VISIT_BINARYOP_PUTS_ON_STACK(InstanceOf, " instanceof ") }; QTEST_MAIN(TestPureJavaScriptGenerator) #include "testpurejavascriptgenerator.moc" diff --git a/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp b/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp index 9ec3227..606e556 100644 --- a/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp +++ b/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp @@ -1,117 +1,118 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Jan Marker * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "../../../src/qmljsc/purejavascriptgenerator.h" #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QQmlJS::AST::Node*) class TestPureJavaScriptGeneratorIntegration : public QObject { Q_OBJECT private: QQmlJS::AST::Node* astForFile(QString fileName) { QString input = fileContent(fileName); QQmlJS::Engine* engine = new QQmlJS::Engine(); QQmlJS::Lexer* lexer = new QQmlJS::Lexer(engine); lexer->setCode(input, 1, true); QQmlJS::Parser* parser = new QQmlJS::Parser(engine); if (!parser->parseProgram()) { qDebug() << parser->errorMessage(); } return parser->rootNode(); } QString fileContent(QString fileName) { QFile inputFile(fileName); Q_ASSERT_X(inputFile.open(QFile::ReadOnly), __FILE__, "File could not be opened. Is it added as resource in the CMakeLists.txt?"); return QString(inputFile.readAll()); } void addRowForFile(QString fileName) { addRowForFileWithCompiled(fileName, fileName); } void addRowForFileWithCompiled(QString sourceFileName, QString compiledFileName) { const QString folder(":/test/%1.js"); QTest::newRow(sourceFileName.toLocal8Bit()) << astForFile(folder.arg(sourceFileName)) << fileContent(folder.arg(compiledFileName)); } void addRowForFileWithCompiled(QString fileName) { addRowForFileWithCompiled(fileName, QString("%1.compiled").arg(fileName)); } private slots: void test_compileJavaScriptFile_data() { QTest::addColumn("ast"); QTest::addColumn("expectedOutput"); addRowForFileWithCompiled("declarations"); addRowForFile("expressions"); addRowForFileWithCompiled("functions"); + addRowForFile("unaryoperators"); addRowForFileWithCompiled("binaryoperations"); addRowForFileWithCompiled("otherstatements"); addRowForFileWithCompiled("ifstatements"); addRowForFileWithCompiled("switchstatements"); addRowForFileWithCompiled("literals"); addRowForFileWithCompiled("arrayliterals"); addRowForFileWithCompiled("objectliterals"); - addRowForFileWithCompiled("propertyaccess"); + addRowForFileWithCompiled("lefthandexpressions"); addRowForFileWithCompiled("functioncalls"); addRowForFileWithCompiled("loops"); } void test_compileJavaScriptFile() { // Prepare QFETCH(QQmlJS::AST::Node*, ast); QFETCH(QString, expectedOutput); PureJavaScriptGenerator generator; // Do ast->accept(&generator); // Verify QCOMPARE(generator.getGeneratedCode(), expectedOutput); } }; QTEST_MAIN(TestPureJavaScriptGeneratorIntegration) #include "testpurejavascriptgenerator_integration.moc"