diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-02-09 20:22:09 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-04-25 17:49:03 +0000 |
commit | 2683a22364f742e3809b6c48570b0b4aaf37b31f (patch) | |
tree | aff06f7313424ee8481da880168b7129455e6bc9 | |
parent | dad5d1cc82a57a4f657aa3f37ad2f55b69d5b015 (diff) |
Implement support for tagged templates
Get Foo`...` to work as intended by the spec.
Change-Id: If6ccdd7486d3c983c177a3e126e3a661e210a8ae
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 111 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 5 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 24 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 11 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 23 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastfwd_p.h | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 3 |
7 files changed, 164 insertions, 14 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index bf481f351f..fa4772a99b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1279,6 +1279,12 @@ bool Codegen::visit(CallExpression *ast) if (hasError) return false; + handleCall(base, calldata); + return false; +} + +void Codegen::handleCall(Reference &base, Arguments calldata) +{ //### Do we really need all these call instructions? can's we load the callee in a temp? if (base.type == Reference::QmlScopeObject) { Instruction::CallScopeObjectProperty call; @@ -1346,7 +1352,6 @@ bool Codegen::visit(CallExpression *ast) } _expr.setResult(Reference::fromAccumulator(this)); - return false; } Codegen::Arguments Codegen::pushArgs(ArgumentList *args) @@ -1378,6 +1383,30 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args) return { argc, calldata }; } +Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args) +{ + int argc = 0; + for (TemplateLiteral *it = args; it; it = it->next) + ++argc; + + if (!argc) + return { 0, 0 }; + + int calldata = bytecodeGenerator->newRegisterArray(argc); + + argc = 0; + for (TemplateLiteral *it = args; it && it->expression; it = it->next) { + RegisterScope scope(this); + Reference e = expression(it->expression); + if (hasError) + break; + (void) e.storeOnStack(calldata + argc); + ++argc; + } + + return { argc, calldata }; +} + bool Codegen::visit(ConditionalExpression *ast) { if (hasError) @@ -1490,6 +1519,86 @@ bool Codegen::visit(FieldMemberExpression *ast) return false; } +bool Codegen::visit(TaggedTemplate *ast) +{ + if (hasError) + return false; + + RegisterScope scope(this); + + Reference base = expression(ast->base); + if (hasError) + return false; + switch (base.type) { + case Reference::Member: + case Reference::Subscript: + base = base.asLValue(); + break; + case Reference::Name: + break; + default: + base = base.storeOnStack(); + break; + } + + int arrayTemp = createTemplateArray(ast->templateLiteral); + Q_UNUSED(arrayTemp); + auto calldata = pushTemplateArgs(ast->templateLiteral); + if (hasError) + return false; + ++calldata.argc; + Q_ASSERT(calldata.argv == arrayTemp + 1); + --calldata.argv; + + handleCall(base, calldata); + return false; + + + return false; +} + +int Codegen::createTemplateArray(TemplateLiteral *t) +{ + int arrayTemp = bytecodeGenerator->newRegister(); + + RegisterScope scope(this); + + int argc = 0; + int args = -1; + auto push = [this, &argc, &args](const QStringRef &arg) { + int temp = bytecodeGenerator->newRegister(); + if (args == -1) + args = temp; + Instruction::LoadRuntimeString instr; + instr.stringId = registerString(arg.toString()); + bytecodeGenerator->addInstruction(instr); + Instruction::StoreReg store; + store.reg = temp; + bytecodeGenerator->addInstruction(store); + + ++argc; + }; + + for (TemplateLiteral *it = t; it; it = it->next) + push(it->value); + + if (args == -1) { + Q_ASSERT(argc == 0); + args = 0; + } + + Instruction::DefineArray call; + call.argc = argc; + call.args = Moth::StackSlot::createRegister(args); + bytecodeGenerator->addInstruction(call); + + Instruction::StoreReg store; + store.reg = arrayTemp; + bytecodeGenerator->addInstruction(store); + + return arrayTemp; +} + bool Codegen::visit(FunctionExpression *ast) { if (hasError) diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 61029644c3..560dc48a63 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -561,6 +561,7 @@ protected: bool visit(AST::DeleteExpression *ast) override; bool visit(AST::FalseLiteral *ast) override; bool visit(AST::FieldMemberExpression *ast) override; + bool visit(AST::TaggedTemplate *ast) override; bool visit(AST::FunctionExpression *ast) override; bool visit(AST::IdentifierExpression *ast) override; bool visit(AST::NestedExpression *ast) override; @@ -634,6 +635,10 @@ public: Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right); struct Arguments { int argc; int argv; }; Arguments pushArgs(AST::ArgumentList *args); + void handleCall(Reference &base, Arguments calldata); + + Arguments pushTemplateArgs(AST::TemplateLiteral *args); + int createTemplateArray(AST::TemplateLiteral *t); void setUseFastLookups(bool b) { useFastLookups = b; } diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 5313d4d066..ed69e01ba8 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1748,6 +1748,17 @@ case $rule_number: { } break; ./ +CallExpression: CallExpression TemplateLiteral; +/. case $rule_number: ./ + +MemberExpression: MemberExpression TemplateLiteral ; +/. +case $rule_number: { + AST::TaggedTemplate *node = new (pool) AST::TaggedTemplate(sym(1).Expression, sym(2).Template); + sym(1).Node = node; +} break; +./ + MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; /. case $rule_number: { @@ -1759,13 +1770,6 @@ case $rule_number: { } break; ./ -MemberExpression: MemberExpression TemplateLiteral ; -/. -case $rule_number: { - qWarning() << "Template member expression implemented"; -} break; -./ - NewExpression: MemberExpression ; NewExpression: T_NEW NewExpression ; @@ -1817,12 +1821,6 @@ case $rule_number: { } break; ./ -CallExpression: CallExpression TemplateLiteral; -/. case $rule_number: { - qWarning() << "Template calling not implemented"; -} break; -./ - ArgumentListOpt: ; /. case $rule_number: { diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 6fdfd8279c..b29450c1df 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -158,6 +158,8 @@ void StringLiteral::accept0(Visitor *visitor) void TemplateLiteral::accept0(Visitor *visitor) { if (visitor->visit(this)) { + if (next) + accept(next, visitor); } visitor->endVisit(this); @@ -992,6 +994,15 @@ void UiEnumMemberList::accept0(Visitor *visitor) visitor->endVisit(this); } +void TaggedTemplate::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(templateLiteral, visitor); + } + + visitor->endVisit(this); +} + } } // namespace QQmlJS::AST QT_QML_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 5f094ad4f5..b03e15700a 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -189,6 +189,7 @@ public: Kind_StringLiteralPropertyName, Kind_SwitchStatement, Kind_TemplateLiteral, + Kind_TaggedTemplate, Kind_ThisExpression, Kind_ThrowStatement, Kind_TildeExpression, @@ -838,6 +839,28 @@ public: SourceLocation identifierToken; }; +class QML_PARSER_EXPORT TaggedTemplate : public ExpressionNode +{ +public: + QQMLJS_DECLARE_AST_NODE(TaggedTemplate) + + TaggedTemplate(ExpressionNode *b, TemplateLiteral *t) + : base (b), templateLiteral(t) + { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return base->firstSourceLocation(); } + + SourceLocation lastSourceLocation() const override + { return templateLiteral->lastSourceLocation(); } + + // attributes + ExpressionNode *base; + TemplateLiteral *templateLiteral; +}; + class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode { public: diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 3ebef5b128..1aa285697f 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -106,6 +106,7 @@ class StringLiteralPropertyName; class NumericLiteralPropertyName; class ArrayMemberExpression; class FieldMemberExpression; +class TaggedTemplate; class NewMemberExpression; class NewExpression; class CallExpression; diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 5a0767a697..534cc9bd6d 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -173,6 +173,9 @@ public: virtual bool visit(FieldMemberExpression *) { return true; } virtual void endVisit(FieldMemberExpression *) {} + virtual bool visit(TaggedTemplate *) { return true; } + virtual void endVisit(TaggedTemplate *) {} + virtual bool visit(NewMemberExpression *) { return true; } virtual void endVisit(NewMemberExpression *) {} |