diff options
-rw-r--r-- | src/qml/compiler/qv4bytecodegenerator_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 31 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 2 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler.cpp | 19 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler_p.h | 1 | ||||
-rw-r--r-- | src/qml/jit/qv4jit.cpp | 5 | ||||
-rw-r--r-- | src/qml/jit/qv4jit_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 5 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 63 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 13 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 11 |
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 '-': |