diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index 7375e895306a4e02a8e03769fa7f79bb5cbc3806..70be5ce9a70b62060ee50a843eb4bf1fcdc7fb26 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -508,6 +508,11 @@ public: bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; + void RemoveThisParam() + { + params_.erase(params_.begin()); + } + friend class FunctionScope; template friend class ScopeWithParamScope; diff --git a/es2panda/ir/base/scriptFunction.cpp b/es2panda/ir/base/scriptFunction.cpp index 52a766ed10d2635603071a600c1fb4a8b4501181..3716b630ccd0a4289ef3e5ce4910719aefa2dc28 100644 --- a/es2panda/ir/base/scriptFunction.cpp +++ b/es2panda/ir/base/scriptFunction.cpp @@ -60,6 +60,10 @@ void ScriptFunction::Iterate(const NodeTraverser &cb) const cb(id_); } + if (thisParam_) { + cb(thisParam_); + } + if (typeParams_) { cb(typeParams_); } @@ -106,6 +110,10 @@ void ScriptFunction::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder) auto paramScopeCtx = binder::LexicalScope::Enter(binder, scope_->ParamScope()); + if (thisParam_) { + thisParam_ = std::get(cb(thisParam_))->AsExpression(); + } + if (typeParams_) { typeParams_ = std::get(cb(typeParams_))->AsTSTypeParameterDeclaration(); } diff --git a/es2panda/ir/base/scriptFunction.h b/es2panda/ir/base/scriptFunction.h index 5a0db1202e379a1952decebbd95e10df1f5ebef1..aaf29adb9004263fba0b21d380e6a6254b36d301 100644 --- a/es2panda/ir/base/scriptFunction.h +++ b/es2panda/ir/base/scriptFunction.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H #include +#include #include namespace panda::es2panda::compiler { @@ -40,7 +41,7 @@ class ScriptFunction : public AstNode { public: explicit ScriptFunction(binder::FunctionScope *scope, ArenaVector &¶ms, TSTypeParameterDeclaration *typeParams, AstNode *body, Expression *returnTypeAnnotation, - ir::ScriptFunctionFlags flags, bool declare) + ir::ScriptFunctionFlags flags, bool declare, bool isTsFunction) : AstNode(AstNodeType::SCRIPT_FUNCTION), scope_(scope), id_(nullptr), @@ -52,6 +53,15 @@ public: declare_(declare), exportDefault_(false) { + thisParam_ = nullptr; + if (isTsFunction && !params_.empty()) { + auto *firstParam = params_.front(); + if (firstParam->IsIdentifier() && firstParam->AsIdentifier()->Name().Is(THIS_PARAM)) { + thisParam_ = firstParam; + params_.erase(params_.begin()); + scope_->ParamScope()->RemoveThisParam(); + } + } } const Identifier *Id() const @@ -164,8 +174,11 @@ public: void UpdateSelf(const NodeUpdater &cb, binder::Binder *binder) override; private: + static constexpr std::string_view THIS_PARAM = "this"; + binder::FunctionScope *scope_; Identifier *id_; + Expression *thisParam_; ArenaVector params_; TSTypeParameterDeclaration *typeParams_; AstNode *body_; diff --git a/es2panda/parser/commonjs.cpp b/es2panda/parser/commonjs.cpp index cd28c9d1988c320138047ce5b9ca5f9f8e659817..d60656615b95bf49b6f43eec8744637e115fa6b9 100644 --- a/es2panda/parser/commonjs.cpp +++ b/es2panda/parser/commonjs.cpp @@ -74,7 +74,7 @@ void ParserImpl::ParseCommonjs() auto *funcNode = AllocNode(functionScope, std::move(params), nullptr, program_.Ast(), nullptr, - functionContext.Flags(), false); + functionContext.Flags(), false, Extension() == ScriptExtension::TS); functionScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); diff --git a/es2panda/parser/expressionParser.cpp b/es2panda/parser/expressionParser.cpp index 56bbe33c8d7ca8acb512965934f4df6a38621cf4..0c3b41399037a0f0a179493843d609bb460b9f0a 100644 --- a/es2panda/parser/expressionParser.cpp +++ b/es2panda/parser/expressionParser.cpp @@ -396,7 +396,8 @@ ir::ArrowFunctionExpression *ParserImpl::ParseArrowFunctionExpressionBody(ArrowF } funcNode = AllocNode(functionScope, std::move(desc->params), typeParamDecl, body, - returnTypeAnnotation, arrowFunctionContext->Flags(), false); + returnTypeAnnotation, arrowFunctionContext->Flags(), false, + Extension() == ScriptExtension::TS); funcNode->SetRange({desc->startLoc, endLoc}); functionScope->BindNode(funcNode); desc->paramScope->BindNode(funcNode); diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index dd1b69eb3375549d650bf4843fb3a2e47c90af12..4d6fc72bfae8fb6d7a53a4efbd69865340c4feda 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -2555,7 +2555,8 @@ ir::MethodDefinition *ParserImpl::CreateImplicitConstructor(bool hasSuperClass, auto *body = AllocNode(scope, std::move(statements)); auto *func = AllocNode(scope, std::move(params), nullptr, isDeclare ? nullptr : body, nullptr, - ir::ScriptFunctionFlags::CONSTRUCTOR, isDeclare); + ir::ScriptFunctionFlags::CONSTRUCTOR, isDeclare, + Extension() == ScriptExtension::TS); scope->BindNode(func); paramScope->BindNode(func); scope->BindParamScope(paramScope); @@ -3248,7 +3249,8 @@ ir::ScriptFunction *ParserImpl::ParseFunction(ParserStatus newStatus, bool isDec auto *funcNode = AllocNode(functionScope, std::move(params), typeParamDecl, body, returnTypeAnnotation, - functionContext.Flags(), isDeclare && letDeclare); + functionContext.Flags(), isDeclare && letDeclare, + Extension() == ScriptExtension::TS); functionScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); funcNode->SetRange({startLoc, endLoc}); diff --git a/es2panda/parser/transformer/transformer.cpp b/es2panda/parser/transformer/transformer.cpp index 19afc1c9fd9da78d4f923cde9a47868cb2adb3a7..7802fc5c7509e14e88da2b8980c436cf59391a94 100644 --- a/es2panda/parser/transformer/transformer.cpp +++ b/es2panda/parser/transformer/transformer.cpp @@ -438,7 +438,7 @@ ir::CallExpression *Transformer::CreateCallExpressionForTsModule(ir::TSModuleDec } funcNode = AllocNode(funcScope, std::move(params), nullptr, blockNode, nullptr, - ir::ScriptFunctionFlags::NONE, false); + ir::ScriptFunctionFlags::NONE, false, Extension() == ScriptExtension::TS); funcScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); diff --git a/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1-expected.txt b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..0009a01dfd9f139c5f07e65c991e82527a3868d1 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1-expected.txt @@ -0,0 +1 @@ +test-ts-function-1 diff --git a/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1.ts b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..08cd39ef0c7156620ec05ef8e86877815f8456b8 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-1.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +function f(this, a : string) { + print(a); +} + +f("test-ts-function-1"); diff --git a/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2-expected.txt b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..f897285b33d06a1a7b9f9bfc573ef805707b4130 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2-expected.txt @@ -0,0 +1,3 @@ +test-ts-function-2 +1 +true diff --git a/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2.ts b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2.ts new file mode 100644 index 0000000000000000000000000000000000000000..54fc1712146c0613e267d54bf4b1950776b88436 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/functions/test-ts-function-2.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +function f(this, a : string) +function f(this, a : number) +function f(this, a : boolean) +function f(this, a: string | number | boolean) { + print(a); +} + +f("test-ts-function-2"); +f(1); +f(true);