aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-02-10 17:04:32 +0100
committerLars Knoll <lars.knoll@qt.io>2018-04-25 17:49:09 +0000
commitb59b727035c4c1a4d235432cc67e5d89d3a24cd3 (patch)
treeb452f39eab452a8a472dfc5c9b7e89ab4a354c1f /src
parent2683a22364f742e3809b6c48570b0b4aaf37b31f (diff)
ES6: add support for default arguments for function parameters
The parser can also handle rest parameters correctly, this will however require some additional work in the runtime to support it correctly. Change-Id: Ib6f4d27683774966b2d2aac075494d2f5066d2a2 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h6
-rw-r--r--src/qml/compiler/qv4codegen.cpp31
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/jit/qv4assembler.cpp19
-rw-r--r--src/qml/jit/qv4assembler_p.h1
-rw-r--r--src/qml/jit/qv4jit.cpp5
-rw-r--r--src/qml/jit/qv4jit_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp5
-rw-r--r--src/qml/parser/qqmljs.g63
-rw-r--r--src/qml/parser/qqmljsast_p.h13
-rw-r--r--src/qml/parser/qqmljslexer.cpp11
12 files changed, 138 insertions, 23 deletions
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index e69f2cd310..9bd9d82e0d 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -181,6 +181,12 @@ public:
return addJumpInstruction(data);
}
+ Q_REQUIRED_RESULT Jump jumpNotUndefined()
+ {
+ Instruction::JumpNotUndefined data;
+ return addJumpInstruction(data);
+ }
+
void jumpStrictEqual(const StackSlot &lhs, const Label &target)
{
Instruction::CmpStrictEqual cmp;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index fa4772a99b..bc0c62e9be 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2210,12 +2210,20 @@ static bool endsWithReturn(Node *node)
return false;
}
+static bool isSimpleParameterList(AST::FormalParameterList *formals)
+{
+ while (formals) {
+ if (formals->isRest || formals->defaultExpression)
+ return false;
+ formals = formals->next;
+ }
+ return true;
+}
+
int Codegen::defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
AST::SourceElements *body)
{
- Q_UNUSED(formals);
-
enterContext(ast);
if (_context->functionIndex >= 0)
@@ -2316,7 +2324,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
}
}
if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed) {
- if (_context->isStrict) {
+ if (_context->isStrict || !isSimpleParameterList(formals)) {
Instruction::CreateUnmappedArgumentsObject setup;
bytecodeGenerator->addInstruction(setup);
} else {
@@ -2331,6 +2339,23 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bytecodeGenerator->addInstruction(convert);
}
+ while (formals) {
+ if (formals->isRest) {
+ // #### implement me
+ throwSyntaxError(formals->firstSourceLocation(), QString::fromLatin1("Support for rest parameters not implemented!"));
+ }
+ if (formals->defaultExpression) {
+ RegisterScope scope(this);
+ Reference f = referenceForName(formals->name.toString(), true);
+ f.loadInAccumulator();
+ BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
+ expression(formals->defaultExpression).loadInAccumulator();
+ f.storeConsumeAccumulator();
+ jump.link();
+ }
+ formals = formals->next;
+ }
+
beginFunctionBodyHook();
sourceElements(body);
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 450fa50528..362bc40b31 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -473,6 +473,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
+ MOTH_BEGIN_INSTR(JumpNotUndefined)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(JumpNotUndefined)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 7dd639c94c..df9be62672 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -133,6 +133,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
+#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -249,6 +250,7 @@ QT_BEGIN_NAMESPACE
F(Jump) \
F(JumpTrue) \
F(JumpFalse) \
+ F(JumpNotUndefined) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index c3e16c4093..890d9d03a1 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -701,6 +701,12 @@ struct PlatformAssembler64 : PlatformAssemblerCommon
PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();});
}
+ void jumpNotUndefined(int offset)
+ {
+ auto jump = branch64(NotEqual, AccumulatorRegister, TrustedImm64(0));
+ patches.push_back({ jump, offset });
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
@@ -1136,6 +1142,14 @@ struct PlatformAssembler32 : PlatformAssemblerCommon
push(TrustedImm32(v));
}
+ void jumpNotUndefined(int offset)
+ {
+ move(AccumulatorRegisterTag, ScratchRegister);
+ or32(AccumulatorRegisterValue, ScratchRegister);
+ auto jump = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ patches.push_back({ jump, offset });
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32),
@@ -1982,6 +1996,11 @@ void Assembler::jumpFalse(int offset)
});
}
+void Assembler::jumpNotUndefined(int offset)
+{
+ pasm()->jumpNotUndefined(offset);
+}
+
void Assembler::jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
{
pasm()->jumpStrictEqualStackSlotInt(lhs, rhs, offset);
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 37d4232a17..a98761c6ab 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -140,6 +140,7 @@ public:
void jump(int offset);
void jumpTrue(int offset);
void jumpFalse(int offset);
+ void jumpNotUndefined(int offset);
void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset);
void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset);
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp
index bc46c0ca1d..ec446b63ec 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4jit.cpp
@@ -816,6 +816,7 @@ void BaselineJIT::generate_Construct(int func, int argc, int argv)
void BaselineJIT::generate_Jump(int offset) { as->jump(instructionOffset() + offset); }
void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(instructionOffset() + offset); }
void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(instructionOffset() + offset); }
+void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(instructionOffset() + offset); }
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
@@ -1190,6 +1191,10 @@ void BaselineJIT::collectLabelsInBytecode()
addLabel(code - start + offset);
MOTH_END_INSTR(JumpFalse)
+ MOTH_BEGIN_INSTR(JumpNotUndefined)
+ addLabel(code - start + offset);
+ MOTH_END_INSTR(JumpUndefined)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h
index 5aebf78a8d..93fa7e7576 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4jit_p.h
@@ -197,6 +197,7 @@ public:
void generate_Jump(int offset) override;
void generate_JumpTrue(int offset) override;
void generate_JumpFalse(int offset) override;
+ void generate_JumpNotUndefined(int offset) override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index fbb2744c15..88d859eef5 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -1023,6 +1023,11 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject,
}
MOTH_END_INSTR(JumpFalse)
+ MOTH_BEGIN_INSTR(JumpNotUndefined)
+ if (Q_LIKELY(acc != QV4::Encode::undefined()))
+ code += offset;
+ MOTH_END_INSTR(JumpNotUndefined)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index ed69e01ba8..58739bdf1e 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -78,6 +78,7 @@
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
%token T_ENUM "enum"
+%token T_ELLIPSIS "..."
--- template strings
%token T_NO_SUBSTITUTION_TEMPLATE
@@ -1621,7 +1622,7 @@ case $rule_number: {
} break;
./
-PropertyAssignment: T_SET PropertyName T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+PropertyAssignment: T_SET PropertyName T_LPAREN FormalParameters T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
@@ -3071,7 +3072,7 @@ case $rule_number: {
-- declaration.
Function: T_FUNCTION %prec REDUCE_HERE ;
-FunctionDeclaration: Function JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+FunctionDeclaration: Function JsIdentifier T_LPAREN FormalParameters T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
@@ -3085,7 +3086,7 @@ case $rule_number: {
} break;
./
-FunctionExpression: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+FunctionExpression: T_FUNCTION JsIdentifier T_LPAREN FormalParameters T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
@@ -3100,7 +3101,7 @@ case $rule_number: {
} break;
./
-FunctionExpression: T_FUNCTION T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
@@ -3113,39 +3114,67 @@ case $rule_number: {
} break;
./
-FormalParameterList: JsIdentifier ;
+FormalParameters : ;
/.
case $rule_number: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
+ sym(1).Node = 0;
} break;
./
-FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+FormalParameters: FormalParameterList ;
/.
case $rule_number: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
- node->commaToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
+ sym(1).Node = sym(1).FormalParameterList->finish ();
} break;
./
-FormalParameterListOpt: ;
+FormalParameterList: FunctionRestParameter ;
+
+FormalParameterList: FormalsList ;
+
+FormalsList: FormalParameter ;
+
+FormalParameterList: FormalsList T_COMMA FunctionRestParameter ;
+/. case $rule_number: ./
+
+FormalsList: FormalsList T_COMMA FormalParameter ;
/.
case $rule_number: {
- sym(1).Node = 0;
+ sym(1).FormalParameterList = sym(1).FormalParameterList->append(sym(3).FormalParameterList);
} break;
./
-FormalParameterListOpt: FormalParameterList ;
+FunctionRestParameter: BindingRestElement ;
+FormalParameter: BindingElement ;
+
+BindingRestElement: T_ELLIPSIS BindingIdentifier ;
/.
case $rule_number: {
- sym(1).Node = sym(1).FormalParameterList->finish ();
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(2));
+ node->identifierToken = loc(2);
+ node->isRest = true;
+ sym(1).Node = node;
+} break;
+./
+
+BindingElement: SingleNameBinding ;
+-- BindingElement: BindingPattern InitialiserOpt ;
+
+-- BindingPattern: ObjectBindingPattern ;
+-- BindingPattern: ArrayBindingPattern ;
+
+SingleNameBinding: BindingIdentifier InitialiserOpt ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
+ node->identifierToken = loc(1);
+ node->defaultExpression = sym(2).Expression;
+ sym(1).Node = node;
} break;
./
+BindingIdentifier: JsIdentifier;
+
FunctionBodyOpt: ;
/.
case $rule_number: {
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index b03e15700a..61ee89ad2f 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -2081,8 +2081,8 @@ class QML_PARSER_EXPORT FormalParameterList: public Node
public:
QQMLJS_DECLARE_AST_NODE(FormalParameterList)
- FormalParameterList(const QStringRef &n):
- name (n), next (this)
+ FormalParameterList(const QStringRef &n)
+ : name(n), next(this)
{ kind = K; }
FormalParameterList(FormalParameterList *previous, const QStringRef &n):
@@ -2093,6 +2093,12 @@ public:
previous->next = this;
}
+ FormalParameterList *append(FormalParameterList *n) {
+ n->next = next;
+ next = n;
+ return n;
+ }
+
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
@@ -2110,8 +2116,9 @@ public:
// attributes
QStringRef name;
+ bool isRest = false;
+ ExpressionNode *defaultExpression = nullptr;
FormalParameterList *next;
- SourceLocation commaToken;
SourceLocation identifierToken;
};
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index d48766e9a8..0b6033c1df 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -605,6 +605,17 @@ again:
case '.':
if (isDecimalDigit(_char.unicode()))
return scanNumber(ch);
+ if (_char == QLatin1Char('.')) {
+ scanChar();
+ if (_char == QLatin1Char('.')) {
+ scanChar();
+ return T_ELLIPSIS;
+ } else {
+ _errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
+ return T_ERROR;
+ }
+ }
return T_DOT;
case '-':