aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r--src/qml/compiler/qv4codegen.cpp149
1 files changed, 81 insertions, 68 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 1e98d1167b..5b7a7f9050 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -128,7 +128,7 @@ static inline bool isSimpleExpr(IR::Expr *e)
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
- , _env(0)
+ , _variableEnvironment(0)
, _allowFuncDecls(true)
, defaultProgramMode(defaultProgramMode)
{
@@ -142,17 +142,17 @@ void Codegen::ScanFunctions::operator()(Node *node)
void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Environment *e = _cg->newEnvironment(node, _env, compilationMode);
+ Environment *e = _cg->newEnvironment(node, _variableEnvironment, compilationMode);
if (!e->isStrict)
e->isStrict = _cg->_strictMode;
_envStack.append(e);
- _env = e;
+ _variableEnvironment = e;
}
void Codegen::ScanFunctions::leaveEnvironment()
{
_envStack.pop();
- _env = _envStack.isEmpty() ? 0 : _envStack.top();
+ _variableEnvironment = _envStack.isEmpty() ? 0 : _envStack.top();
}
void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
@@ -168,7 +168,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
continue;
QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
if (str == QLatin1String("use strict")) {
- _env->isStrict = true;
+ _variableEnvironment->isStrict = true;
} else {
// TODO: give a warning.
}
@@ -183,7 +183,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
if (name == QLatin1String("implements")
|| name == QLatin1String("interface")
|| name == QLatin1String("let")
@@ -201,7 +201,7 @@ void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *paramet
{
while (parameters) {
if (parameters->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
parameters = parameters->next;
}
}
@@ -220,19 +220,19 @@ void Codegen::ScanFunctions::endVisit(Program *)
bool Codegen::ScanFunctions::visit(CallExpression *ast)
{
- if (! _env->hasDirectEval) {
+ if (! _variableEnvironment->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
- _env->hasDirectEval = true;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ _variableEnvironment->hasDirectEval = true;
}
}
}
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -241,7 +241,7 @@ bool Codegen::ScanFunctions::visit(NewMemberExpression *ast)
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -257,26 +257,38 @@ bool Codegen::ScanFunctions::visit(ArrayLiteral *ast)
for (Elision *elision = ast->elision->next; elision; elision = elision->next)
++index;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, index);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, index);
return true;
}
bool Codegen::ScanFunctions::visit(VariableDeclaration *ast)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
checkName(ast->name, ast->identifierToken);
if (ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration);
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ if (ast->scope == AST::VariableDeclaration::VariableScope::ReadOnlyBlockScope && !ast->expression) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
+ return false;
+ }
+ QString name = ast->name.toString();
+ const Environment::Member *m = 0;
+ if (_variableEnvironment->memberInfo(name, &m)) {
+ if (m->isLexicallyScoped() || ast->isLexicallyScoped()) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
+ }
+ }
+ _variableEnvironment->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration, ast->scope);
return true;
}
bool Codegen::ScanFunctions::visit(IdentifierExpression *ast)
{
checkName(ast->name, ast->identifierToken);
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
return true;
}
@@ -308,7 +320,7 @@ bool Codegen::ScanFunctions::visit(FunctionExpression *ast)
void Codegen::ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName, bool isExpression)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression);
}
@@ -329,7 +341,7 @@ bool Codegen::ScanFunctions::visit(ObjectLiteral *ast)
if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
++argc;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
Node::accept(ast->properties, this);
@@ -361,7 +373,7 @@ void Codegen::ScanFunctions::endVisit(FunctionDeclaration *)
bool Codegen::ScanFunctions::visit(WithStatement *ast)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
_cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
return false;
}
@@ -371,7 +383,7 @@ bool Codegen::ScanFunctions::visit(WithStatement *ast)
bool Codegen::ScanFunctions::visit(DoWhileStatement *ast) {
{
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
}
Node::accept(ast->expression, this);
@@ -383,7 +395,7 @@ bool Codegen::ScanFunctions::visit(ForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -394,7 +406,7 @@ bool Codegen::ScanFunctions::visit(LocalForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -404,7 +416,7 @@ bool Codegen::ScanFunctions::visit(ForEachStatement *ast) {
Node::accept(ast->initialiser, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -414,7 +426,7 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
Node::accept(ast->declaration, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -422,12 +434,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
bool Codegen::ScanFunctions::visit(ThisExpression *)
{
- _env->usesThis = true;
+ _variableEnvironment->usesThis = true;
return false;
}
bool Codegen::ScanFunctions::visit(Block *ast) {
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _variableEnvironment->isStrict ? false : _allowFuncDecls);
Node::accept(ast->statements, this);
return false;
}
@@ -435,26 +447,26 @@ bool Codegen::ScanFunctions::visit(Block *ast) {
void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression)
{
bool wasStrict = false;
- if (_env) {
- _env->hasNestedFunctions = true;
+ if (_variableEnvironment) {
+ _variableEnvironment->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
if (expr)
- _env->enter(name, Environment::FunctionDefinition, expr);
+ _variableEnvironment->enter(name, Environment::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
if (name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- wasStrict = _env->isStrict;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ wasStrict = _variableEnvironment->isStrict;
}
enterEnvironment(ast, FunctionCode);
checkForArguments(formals);
- _env->isNamedFunctionExpression = isExpression && !name.isEmpty();
- _env->formals = formals;
+ _variableEnvironment->isNamedFunctionExpression = isExpression && !name.isEmpty();
+ _variableEnvironment->formals = formals;
if (body)
checkDirectivePrologue(body->elements);
- if (wasStrict || _env->isStrict) {
+ if (wasStrict || _variableEnvironment->isStrict) {
QStringList args;
for (FormalParameterList *it = formals; it; it = it->next) {
QString arg = it->name.toString();
@@ -478,7 +490,7 @@ Codegen::Codegen(bool strict)
, _block(0)
, _exitBlock(0)
, _returnAddress(0)
- , _env(0)
+ , _variableEnvironment(0)
, _loop(0)
, _labelledStatement(0)
, _scopeAndFinally(0)
@@ -498,7 +510,7 @@ void Codegen::generateFromProgram(const QString &fileName,
Q_ASSERT(node);
_module = module;
- _env = 0;
+ _variableEnvironment = 0;
_module->setFileName(fileName);
@@ -517,7 +529,7 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
{
_module = module;
_module->setFileName(fileName);
- _env = 0;
+ _variableEnvironment = 0;
ScanFunctions scan(this, sourceCode, GlobalCode);
// fake a global environment
@@ -534,14 +546,14 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
void Codegen::enterEnvironment(Node *node)
{
- _env = _envMap.value(node);
- Q_ASSERT(_env);
+ _variableEnvironment = _envMap.value(node);
+ Q_ASSERT(_variableEnvironment);
}
void Codegen::leaveEnvironment()
{
- Q_ASSERT(_env);
- _env = _env->parent;
+ Q_ASSERT(_variableEnvironment);
+ _variableEnvironment = _variableEnvironment->parent;
}
void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock)
@@ -1443,7 +1455,7 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
// Temporaries cannot be deleted
IR::ArgLocal *al = expr->asArgLocal();
- if (al && al->index < static_cast<unsigned>(_env->members.size())) {
+ if (al && al->index < static_cast<unsigned>(_variableEnvironment->members.size())) {
// Trying to delete a function argument might throw.
if (_function->isStrict) {
throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
@@ -1472,7 +1484,7 @@ bool Codegen::visit(DeleteExpression *ast)
}
if (expr->asTemp() ||
(expr->asArgLocal() &&
- expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) {
+ expr->asArgLocal()->index >= static_cast<unsigned>(_variableEnvironment->members.size()))) {
_expr.code = _block->CONST(IR::BoolType, 1);
return false;
}
@@ -1525,7 +1537,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
return 0;
uint scope = 0;
- Environment *e = _env;
+ Environment *e = _variableEnvironment;
IR::Function *f = _function;
while (f && e->parent) {
@@ -1556,7 +1568,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
if (IR::Expr *fallback = fallbackNameLookup(name, line, col))
return fallback;
- if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
+ if (!e->parent && (!f || !f->insideWithOrCatch) && _variableEnvironment->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
// global context or with. Lookup by name
@@ -2072,7 +2084,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
TempScope scope(_function);
- if (_env->compilationMode == QmlBinding)
+ if (_variableEnvironment->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
return false;
@@ -2096,26 +2108,26 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::BasicBlock *entryBlock = function->newBasicBlock(0);
IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock);
- function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode
+ function->hasDirectEval = _variableEnvironment->hasDirectEval || _variableEnvironment->compilationMode == EvalCode
|| _module->debugMode; // Conditional breakpoints are like eval in the function
- function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
- function->usesThis = _env->usesThis;
- function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
- function->isStrict = _env->isStrict;
- function->isNamedExpression = _env->isNamedFunctionExpression;
- function->isQmlBinding = _env->compilationMode == QmlBinding;
+ function->usesArgumentsObject = _variableEnvironment->parent && (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+ function->usesThis = _variableEnvironment->usesThis;
+ function->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
+ function->isStrict = _variableEnvironment->isStrict;
+ function->isNamedExpression = _variableEnvironment->isNamedFunctionExpression;
+ function->isQmlBinding = _variableEnvironment->compilationMode == QmlBinding;
AST::SourceLocation loc = ast->firstSourceLocation();
function->line = loc.startLine;
function->column = loc.startColumn;
if (function->usesArgumentsObject)
- _env->enter(QStringLiteral("arguments"), Environment::VariableDeclaration);
+ _variableEnvironment->enter(QStringLiteral("arguments"), Environment::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
// variables in global code are properties of the global context object, not locals as with other functions.
- if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == FunctionCode || _variableEnvironment->compilationMode == QmlBinding) {
unsigned t = 0;
- for (Environment::MemberMap::iterator it = _env->members.begin(), end = _env->members.end(); it != end; ++it) {
+ for (Environment::MemberMap::iterator it = _variableEnvironment->members.begin(), end = _variableEnvironment->members.end(); it != end; ++it) {
const QString &local = it.key();
function->LOCAL(local);
(*it).index = t;
@@ -2123,18 +2135,19 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
++t;
}
} else {
- if (!_env->isStrict) {
+ if (!_variableEnvironment->isStrict) {
for (const QString &inheritedLocal : qAsConst(inheritedLocals)) {
function->LOCAL(inheritedLocal);
unsigned tempIndex = entryBlock->newTemp();
Environment::Member member = { Environment::UndefinedMember,
- static_cast<int>(tempIndex), 0 };
- _env->members.insert(inheritedLocal, member);
+ static_cast<int>(tempIndex), 0,
+ AST::VariableDeclaration::VariableScope::FunctionScope };
+ _variableEnvironment->members.insert(inheritedLocal, member);
}
}
IR::ExprList *args = 0;
- for (Environment::MemberMap::const_iterator it = _env->members.constBegin(), cend = _env->members.constEnd(); it != cend; ++it) {
+ for (Environment::MemberMap::const_iterator it = _variableEnvironment->members.constBegin(), cend = _variableEnvironment->members.constEnd(); it != cend; ++it) {
const QString &local = it.key();
IR::ExprList *next = function->New<IR::ExprList>();
next->expr = entryBlock->NAME(local, 0, 0);
@@ -2166,11 +2179,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- for (const Environment::Member &member : qAsConst(_env->members)) {
+ for (const Environment::Member &member : qAsConst(_variableEnvironment->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
- if (! _env->parent) {
+ if (! _variableEnvironment->parent) {
move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
_block->CLOSURE(function));
} else {
@@ -2356,7 +2369,7 @@ bool Codegen::visit(ExpressionStatement *ast)
TempScope scope(_function);
- if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == EvalCode || _variableEnvironment->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
move(_block->TEMP(_returnAddress), *e);
@@ -2604,7 +2617,7 @@ bool Codegen::visit(ReturnStatement *ast)
if (hasError)
return true;
- if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding) {
+ if (_variableEnvironment->compilationMode != FunctionCode && _variableEnvironment->compilationMode != QmlBinding) {
throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
return false;
}
@@ -2992,7 +3005,7 @@ bool Codegen::visit(UiSourceElement *)
bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, const SourceLocation& loc)
{
- if (!_env->isStrict)
+ if (!_variableEnvironment->isStrict)
return false;
if (IR::Name *n = expr->asName()) {
if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments"))