aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-02-09 20:22:09 +0100
committerLars Knoll <lars.knoll@qt.io>2018-04-25 17:49:03 +0000
commit2683a22364f742e3809b6c48570b0b4aaf37b31f (patch)
treeaff06f7313424ee8481da880168b7129455e6bc9 /src
parentdad5d1cc82a57a4f657aa3f37ad2f55b69d5b015 (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>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp111
-rw-r--r--src/qml/compiler/qv4codegen_p.h5
-rw-r--r--src/qml/parser/qqmljs.g24
-rw-r--r--src/qml/parser/qqmljsast.cpp11
-rw-r--r--src/qml/parser/qqmljsast_p.h23
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h1
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h3
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 *) {}