aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 '-':