summaryrefslogtreecommitdiff
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.cpp127
1 files changed, 114 insertions, 13 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 9c00d660b0..e88f01fdca 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -545,6 +545,23 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
}
}
+Codegen::Reference Codegen::referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name)
+{
+ AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
+ Reference property;
+ if (cname) {
+ Reference computedName = expression(cname->expression);
+ if (hasError)
+ return Reference();
+ computedName = computedName.storeOnStack();
+ property = Reference::fromSubscript(object, computedName).asLValue();
+ } else {
+ QString propertyName = name->asString();
+ property = Reference::fromMember(object, propertyName);
+ }
+ return property;
+}
+
void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternPropertyList *bindingList)
{
RegisterScope scope(this);
@@ -552,18 +569,9 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP
for (PatternPropertyList *it = bindingList; it; it = it->next) {
PatternProperty *p = it->property;
RegisterScope scope(this);
- AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
- Reference property;
- if (cname) {
- Reference computedName = expression(cname->expression);
- if (hasError)
- return;
- computedName = computedName.storeOnStack();
- property = Reference::fromSubscript(object, computedName).asLValue();
- } else {
- QString propertyName = p->name->asString();
- property = Reference::fromMember(object, propertyName);
- }
+ Reference property = referenceForPropertyName(object, p->name);
+ if (hasError)
+ return;
initializeAndDestructureBindingElement(p, property);
if (hasError)
return;
@@ -812,7 +820,100 @@ bool Codegen::visit(VariableDeclarationList *)
bool Codegen::visit(ClassExpression *ast)
{
- throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Support for 'class' is unimplemented."));
+ Compiler::Class jsClass;
+ jsClass.name = ast->name.toString();
+ registerString(jsClass.name);
+
+ Reference outerVar = referenceForName(ast->name.toString(), true);
+
+ ClassElementList *constructor = nullptr;
+ int nComputedNames = 0;
+ int nStaticComputedNames = 0;
+
+ RegisterScope scope(this);
+ ControlFlowBlock controlFlow(this, ast);
+
+ for (auto *member = ast->elements; member; member = member->next) {
+ PatternProperty *p = member->property;
+ FunctionExpression *f = p->initializer->asFunctionDefinition();
+ Q_ASSERT(f);
+ AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
+ if (cname) {
+ ++nComputedNames;
+ if (member->isStatic)
+ ++nStaticComputedNames;
+ }
+ QString name = p->name->asString();
+ Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
+ if (p->type == PatternProperty::Getter)
+ type = Compiler::Class::Method::Getter;
+ else if (p->type == PatternProperty::Setter)
+ type = Compiler::Class::Method::Setter;
+ Compiler::Class::Method m{ name, type, defineFunction(name, f, f->formals, f->body)};
+
+ if (!member->isStatic && name == QStringLiteral("constructor")) {
+ if (constructor) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Cannot declare a multiple constructors in a class."));
+ return false;
+ }
+ if (m.type != Compiler::Class::Method::Regular) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Cannot declare a getter or setter named 'constructor'."));
+ return false;
+ }
+ constructor = member;
+ jsClass.constructorIndex = m.functionIndex;
+ continue;
+ }
+
+ if (member->isStatic)
+ jsClass.staticMethods << m;
+ else
+ jsClass.methods << m;
+ }
+
+ int classIndex = _module->classes.size();
+ _module->classes.append(jsClass);
+
+ Reference heritage = Reference::fromStackSlot(this);
+ if (ast->heritage) {
+ bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
+ Reference r = expression(ast->heritage);
+ if (hasError)
+ return false;
+ r.storeOnStack(heritage.stackSlot());
+ } else {
+ Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()).loadInAccumulator();
+ heritage.storeConsumeAccumulator();
+ }
+
+ int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
+ int currentStaticName = computedNames;
+ int currentNonStaticName = computedNames + nStaticComputedNames;
+
+ for (auto *member = ast->elements; member; member = member->next) {
+ AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
+ if (!cname)
+ continue;
+ RegisterScope scope(this);
+ bytecodeGenerator->setLocation(cname->firstSourceLocation());
+ Reference computedName = expression(cname->expression);
+ if (hasError)
+ return false;
+ computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
+ }
+
+ Instruction::CreateClass createClass;
+ createClass.classIndex = classIndex;
+ createClass.heritage = heritage.stackSlot();
+ createClass.computedNames = computedNames;
+
+ bytecodeGenerator->addInstruction(createClass);
+
+ Reference ctor = referenceForName(ast->name.toString(), true);
+ (void) ctor.storeRetainAccumulator();
+ (void) outerVar.storeRetainAccumulator();
+
+ _expr.setResult(Reference::fromAccumulator(this));
return false;
}