From db093f34b9edd7f8c77ef778b1fc52d86576d3d4 Mon Sep 17 00:00:00 2001 From: ctw-ian Date: Wed, 28 Dec 2022 11:47:14 +0800 Subject: [PATCH] Implementation of TaskPool Issue:I69P2C Signed-off-by: ctw-ian Change-Id: Ide49a8c718de3adf0e8b17f5e9494fdd03deb045 --- es2panda/BUILD.gn | 1 + es2panda/binder/binder.cpp | 4 + es2panda/binder/declaration.h | 5 + es2panda/binder/scope.cpp | 13 +- es2panda/binder/scope.h | 7 +- es2panda/compiler/core/function.cpp | 3 +- es2panda/compiler/core/pandagen.cpp | 6 + es2panda/ir/astNode.h | 3 +- es2panda/ir/base/scriptFunction.h | 10 ++ ...lid-concurrent-arrow-function-expected.txt | 2 + .../invalid-concurrent-arrow-function.js | 20 ++++ ...ncurrent-async-arrow-function-expected.txt | 2 + ...invalid-concurrent-async-arrow-function.js | 20 ++++ ...lid-concurrent-async-function-expected.txt | 2 + .../invalid-concurrent-async-function.js | 20 ++++ ...rent-async-generator-function-expected.txt | 2 + ...lid-concurrent-async-generator-function.js | 20 ++++ ...concurrent-generator-function-expected.txt | 2 + .../invalid-concurrent-generator-function.js | 20 ++++ ...sing-const-lexical-variable-4-expected.txt | 2 + .../using-const-lexical-variable-4.js | 22 ++++ ...ng-mutable-lexical-variable-1-expected.txt | 2 + .../using-mutable-lexical-variable-1.js | 22 ++++ ...ng-mutable-lexical-variable-2-expected.txt | 2 + .../using-mutable-lexical-variable-2.js | 22 ++++ ...ng-mutable-lexical-variable-3-expected.txt | 2 + .../using-mutable-lexical-variable-3.js | 22 ++++ ...ng-mutable-lexical-variable-4-expected.txt | 2 + .../using-mutable-lexical-variable-4.js | 24 ++++ ...ng-mutable-lexical-variable-5-expected.txt | 2 + .../using-mutable-lexical-variable-5.js | 22 ++++ es2panda/test/runner.py | 1 + es2panda/util/concurrent.cpp | 113 ++++++++++++++++++ es2panda/util/concurrent.h | 61 ++++++++++ 34 files changed, 475 insertions(+), 8 deletions(-) create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-arrow-function-expected.txt create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-arrow-function.js create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function-expected.txt create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function.js create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-function-expected.txt create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-function.js create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function-expected.txt create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function.js create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-generator-function-expected.txt create mode 100644 es2panda/test/parser/concurrent/invalid-concurrent-generator-function.js create mode 100644 es2panda/test/parser/concurrent/using-const-lexical-variable-4-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-const-lexical-variable-4.js create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-1-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-1.js create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-2-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-2.js create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-3-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-3.js create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-4-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-4.js create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-5-expected.txt create mode 100644 es2panda/test/parser/concurrent/using-mutable-lexical-variable-5.js create mode 100644 es2panda/util/concurrent.cpp create mode 100644 es2panda/util/concurrent.h diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index 90dd7ff2c6..9e33605992 100644 --- a/es2panda/BUILD.gn +++ b/es2panda/BUILD.gn @@ -246,6 +246,7 @@ es2panda_src = [ "typescript/types/voidType.cpp", "util/base64.cpp", "util/bitset.cpp", + "util/concurrent.cpp", "util/dumper.cpp", "util/helpers.cpp", "util/hotfix.cpp", diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 1c6f0022a7..e9369fa834 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include namespace panda::es2panda::binder { void Binder::InitTopScope() @@ -194,6 +196,7 @@ void Binder::LookupIdentReference(ir::Identifier *ident) if (res.level != 0) { ASSERT(res.variable); + util::Concurrent::VerifyImportVarForConcurrentFunction(Program()->GetLineIndex(), ident, res); res.variable->SetLexical(res.scope, program_->HotfixHelper()); } @@ -469,6 +472,7 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) } case ir::AstNodeType::SCRIPT_FUNCTION: { auto *scriptFunc = childNode->AsScriptFunction(); + util::Concurrent::SetConcurrent(const_cast(scriptFunc), Program()->GetLineIndex()); auto *funcScope = scriptFunc->Scope(); auto *outerScope = scope_; diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index c835e99e5e..bbc5ce11ba 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -98,6 +98,11 @@ public: return (flags_ & flag) != 0; } + bool IsImportDecl() const + { + return HasFlag(DeclarationFlags::IMPORT); + } + bool IsImportOrExportDecl() const { return HasFlag(DeclarationFlags::IMPORT | DeclarationFlags::EXPORT); diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 696521f188..f88131722c 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -21,12 +21,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -91,12 +93,13 @@ ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions uint32_t level = 0; uint32_t lexLevel = 0; const auto *iter = this; + bool crossConcurrent = false; if (iter->IsFunctionParamScope()) { Variable *v = iter->FindLocal(name, options); if (v != nullptr) { - return {name, const_cast(iter), level, lexLevel, v}; + return {name, const_cast(iter), level, lexLevel, v, crossConcurrent}; } level++; @@ -114,12 +117,16 @@ ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions Variable *v = iter->FindLocal(name, options); if (v != nullptr) { - return {name, const_cast(iter), level, lexLevel, v}; + return {name, const_cast(iter), level, lexLevel, v, crossConcurrent}; } if (iter->IsVariableScope()) { level++; + if (iter->IsFunctionScope() && !crossConcurrent) { + crossConcurrent = iter->Node()->AsScriptFunction()->IsConcurrent() ? true : false; + } + if (iter->AsVariableScope()->NeedLexEnv()) { lexLevel++; } @@ -128,7 +135,7 @@ ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions iter = iter->Parent(); } - return {name, nullptr, 0, 0, nullptr}; + return {name, nullptr, 0, 0, nullptr, crossConcurrent}; } Decl *Scope::FindDecl(const util::StringView &name) const diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index 70be5ce9a7..6bb538234c 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -140,10 +140,10 @@ private: class ScopeFindResult { public: ScopeFindResult() = default; - ScopeFindResult(util::StringView n, Scope *s, uint32_t l, Variable *v) : ScopeFindResult(n, s, l, l, v) {} + ScopeFindResult(util::StringView n, Scope *s, uint32_t l, Variable *v) : ScopeFindResult(n, s, l, l, v, false) {} ScopeFindResult(Scope *s, uint32_t l, uint32_t ll, Variable *v) : scope(s), level(l), lexLevel(ll), variable(v) {} - ScopeFindResult(util::StringView n, Scope *s, uint32_t l, uint32_t ll, Variable *v) - : name(n), scope(s), level(l), lexLevel(ll), variable(v) + ScopeFindResult(util::StringView n, Scope *s, uint32_t l, uint32_t ll, Variable *v, bool c) + : name(n), scope(s), level(l), lexLevel(ll), variable(v), crossConcurrent(c) { } @@ -152,6 +152,7 @@ public: uint32_t level {}; uint32_t lexLevel {}; Variable *variable {}; + bool crossConcurrent {false}; }; class Scope { diff --git a/es2panda/compiler/core/function.cpp b/es2panda/compiler/core/function.cpp index c6fa686fd9..a284a72bc6 100644 --- a/es2panda/compiler/core/function.cpp +++ b/es2panda/compiler/core/function.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace panda::es2panda::compiler { @@ -163,8 +164,8 @@ static void CompileFunction(PandaGen *pg) pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION); pg->FunctionEnter(); pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION); - CompileFunctionParameterDeclaration(pg, decl); const ir::AstNode *body = decl->Body(); + CompileFunctionParameterDeclaration(pg, decl); if (body->IsExpression()) { body->Compile(pg); diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index 4069401e8f..2af60124e6 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -16,6 +16,7 @@ #include "pandagen.h" #include +#include #include #include #include @@ -56,6 +57,11 @@ void PandaGen::SetFunctionKind() } auto *func = rootNode_->AsScriptFunction(); + if (func->IsConcurrent()) { + funcKind_ = panda::panda_file::FunctionKind::CONCURRENT_FUNCTION; + return; + } + if (func->IsMethod()) { return; } diff --git a/es2panda/ir/astNode.h b/es2panda/ir/astNode.h index 19fd7d0a72..c45530efbe 100644 --- a/es2panda/ir/astNode.h +++ b/es2panda/ir/astNode.h @@ -87,7 +87,8 @@ enum class ScriptFunctionFlags { EXPRESSION = 1 << 3, OVERLOAD = 1 << 4, CONSTRUCTOR = 1 << 5, - METHOD = 1 << 6 + METHOD = 1 << 6, + CONCURRENT = 1 << 7 }; DEFINE_BITOPS(ScriptFunctionFlags) diff --git a/es2panda/ir/base/scriptFunction.h b/es2panda/ir/base/scriptFunction.h index aaf29adb90..0e1514a8a0 100644 --- a/es2panda/ir/base/scriptFunction.h +++ b/es2panda/ir/base/scriptFunction.h @@ -167,6 +167,16 @@ public: return scope_; } + bool IsConcurrent() const + { + return (flags_ & ir::ScriptFunctionFlags::CONCURRENT) != 0; + } + + bool CanBeConcurrent() const + { + return !(IsGenerator() || IsAsync() || IsArrow() || IsConstructor() || IsMethod()); + } + void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function-expected.txt b/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function-expected.txt new file mode 100644 index 0000000000..cda2d57567 --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only be function declaration [invalid-concurrent-arrow-function.js:18:4] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function.js b/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function.js new file mode 100644 index 0000000000..805b407964 --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-arrow-function.js @@ -0,0 +1,20 @@ +/* + * 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. + */ + +"use strict"; + +() => { + "use concurrent"; +} diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function-expected.txt b/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function-expected.txt new file mode 100644 index 0000000000..c38dc29bc6 --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only be function declaration [invalid-concurrent-async-arrow-function.js:18:4] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function.js b/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function.js new file mode 100644 index 0000000000..95a1914f2a --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-arrow-function.js @@ -0,0 +1,20 @@ +/* + * 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. + */ + +"use strict"; + +async () => { + "use concurrent"; +} \ No newline at end of file diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-function-expected.txt b/es2panda/test/parser/concurrent/invalid-concurrent-async-function-expected.txt new file mode 100644 index 0000000000..a53c7f6492 --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-function-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only be function declaration [invalid-concurrent-async-function.js:18:4] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-function.js b/es2panda/test/parser/concurrent/invalid-concurrent-async-function.js new file mode 100644 index 0000000000..45d163165b --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-function.js @@ -0,0 +1,20 @@ +/* + * 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. + */ + +"use strict"; + +async function a() { + "use concurrent"; +} \ No newline at end of file diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function-expected.txt b/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function-expected.txt new file mode 100644 index 0000000000..0f0859a4aa --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only be function declaration [invalid-concurrent-async-generator-function.js:18:4] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function.js b/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function.js new file mode 100644 index 0000000000..d440cac693 --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-async-generator-function.js @@ -0,0 +1,20 @@ +/* + * 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. + */ + +"use strict"; + +async function *a() { + "use concurrent"; +} diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-generator-function-expected.txt b/es2panda/test/parser/concurrent/invalid-concurrent-generator-function-expected.txt new file mode 100644 index 0000000000..453f7a994c --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-generator-function-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only be function declaration [invalid-concurrent-generator-function.js:18:4] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/invalid-concurrent-generator-function.js b/es2panda/test/parser/concurrent/invalid-concurrent-generator-function.js new file mode 100644 index 0000000000..ebaa563fdb --- /dev/null +++ b/es2panda/test/parser/concurrent/invalid-concurrent-generator-function.js @@ -0,0 +1,20 @@ +/* + * 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. + */ + +"use strict"; + +function *a() { + "use concurrent"; +} \ No newline at end of file diff --git a/es2panda/test/parser/concurrent/using-const-lexical-variable-4-expected.txt b/es2panda/test/parser/concurrent/using-const-lexical-variable-4-expected.txt new file mode 100644 index 0000000000..6565cc7a65 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-const-lexical-variable-4-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-const-lexical-variable-4.js:20:11] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-const-lexical-variable-4.js b/es2panda/test/parser/concurrent/using-const-lexical-variable-4.js new file mode 100644 index 0000000000..442fad9713 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-const-lexical-variable-4.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +"use strict"; +const a = 1; + +function b() { + "use concurrent"; + return a; +} diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1-expected.txt b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1-expected.txt new file mode 100644 index 0000000000..df76adeac5 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-mutable-lexical-variable-1.js:20:11] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1.js b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1.js new file mode 100644 index 0000000000..3714b5ddbf --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-1.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +"use strict"; +let a = 1; + +function b() { + "use concurrent"; + return a; +} diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2-expected.txt b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2-expected.txt new file mode 100644 index 0000000000..741aa11197 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-mutable-lexical-variable-2.js:20:11] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2.js b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2.js new file mode 100644 index 0000000000..a61abb4c64 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-2.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +"use strict"; +var a = 1; + +function b() { + "use concurrent"; + return a; +} diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3-expected.txt b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3-expected.txt new file mode 100644 index 0000000000..015a6b4ab9 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-mutable-lexical-variable-3.js:20:11] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3.js b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3.js new file mode 100644 index 0000000000..637c27662b --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-3.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +"use strict"; +class a {} + +function b() { + "use concurrent"; + return a; +} diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4-expected.txt b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4-expected.txt new file mode 100644 index 0000000000..80b0902093 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-mutable-lexical-variable-4.js:21:15] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4.js b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4.js new file mode 100644 index 0000000000..2f55230006 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-4.js @@ -0,0 +1,24 @@ +/* + * 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. + */ + +"use strict"; +let a = 1; + +function b() { + function c() { + "use concurrent"; + return a; + } +} diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5-expected.txt b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5-expected.txt new file mode 100644 index 0000000000..c07b60b047 --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5-expected.txt @@ -0,0 +1,2 @@ +Error: Concurrent function should only use import variable or local variable [using-mutable-lexical-variable-5.js:20:11] +the size of programs is expected to be 1, but is 0 diff --git a/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5.js b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5.js new file mode 100644 index 0000000000..8f33d4799b --- /dev/null +++ b/es2panda/test/parser/concurrent/using-mutable-lexical-variable-5.js @@ -0,0 +1,22 @@ +/* + * 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. + */ + +"use strict"; +export let a = 1; + +function b() { + "use concurrent"; + return a; +} diff --git a/es2panda/test/runner.py b/es2panda/test/runner.py index 9f508dd6ed..960f59890f 100755 --- a/es2panda/test/runner.py +++ b/es2panda/test/runner.py @@ -839,6 +839,7 @@ def main(): if args.regression: runner = RegressionRunner(args) + runner.add_directory("parser/concurrent", "js", ["--module"]) runner.add_directory("parser/js", "js", ["--parse-only"]) runner.add_directory("parser/ts", "ts", ["--parse-only", "--module", "--extension=ts"]) diff --git a/es2panda/util/concurrent.cpp b/es2panda/util/concurrent.cpp new file mode 100644 index 0000000000..d6959c30ed --- /dev/null +++ b/es2panda/util/concurrent.cpp @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#include "concurrent.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace panda::es2panda::util { + +void Concurrent::SetConcurrent(ir::ScriptFunction *func, const lexer::LineIndex &lineIndex) +{ + auto *body = func->Body(); + if (!body) { + return; + } + + if (body->IsExpression()) { + return; + } + + auto &statements = body->AsBlockStatement()->Statements(); + if (statements.empty()) { + return; + } + + /** + * verify the firstStmt + * if IsExpressionStatement(firstStmt) == false + * return; + * else + * if (firstStmt->IsStringLiteral() && strVal == "use concurrent") + * [fall through] + * else + * return + */ + const auto *stmt = statements.front(); + if (!stmt->IsExpressionStatement()) { + return; + } + + auto *expr = stmt->AsExpressionStatement()->GetExpression(); + if (!expr->IsStringLiteral()) { + return; + } + + if (!expr->AsStringLiteral()->Str().Is(USE_CONCURRENT)) { + return; + } + + // concurrent function should only be function declaration + if (!func->CanBeConcurrent()) { + ThrowInvalidConcurrentFunction(lineIndex, stmt, ConcurrentInvalidFlag::NOT_ORDINARY_FUNCTION); + } + + func->AddFlag(ir::ScriptFunctionFlags::CONCURRENT); +} + +void Concurrent::ThrowInvalidConcurrentFunction(const lexer::LineIndex &lineIndex, const ir::AstNode *expr, + ConcurrentInvalidFlag errFlag) +{ + auto line = expr->Range().start.line; + auto column = (const_cast(lineIndex)).GetLocation(expr->Range().start).col - 1; + switch (errFlag) { + case ConcurrentInvalidFlag::NOT_ORDINARY_FUNCTION: { + throw Error {ErrorType::GENERIC, "Concurrent function should only be function declaration", line, + column}; + break; + } + case ConcurrentInvalidFlag::NOT_IMPORT_VARIABLE: { + throw Error {ErrorType::GENERIC, "Concurrent function should only use import variable or local variable", + line, column}; + break; + } + default: + break; + } +} + +void Concurrent::VerifyImportVarForConcurrentFunction(const lexer::LineIndex &lineIndex, const ir::AstNode *node, + const binder::ScopeFindResult &result) +{ + if (!result.crossConcurrent) { + return; + } + + if (result.variable->IsModuleVariable() && result.variable->Declaration()->IsImportDecl()) { + return; + } + + ThrowInvalidConcurrentFunction(lineIndex, node, ConcurrentInvalidFlag::NOT_IMPORT_VARIABLE); +} + +} // namespace panda::es2panda::util \ No newline at end of file diff --git a/es2panda/util/concurrent.h b/es2panda/util/concurrent.h new file mode 100644 index 0000000000..52fa2eda7f --- /dev/null +++ b/es2panda/util/concurrent.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#ifndef ES2PANDA_UTIL_CONCURRENT_H +#define ES2PANDA_UTIL_CONCURRENT_H + +#include + +namespace panda::es2panda::compiler { +class PandaGen; +} // namespace panda::es2panda::compiler + +namespace panda::es2panda::ir { +class AstNode; +class BlockStatement; +class ScriptFunction; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class ScopeFindResult; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::lexer { +class LineIndex; +} + +namespace panda::es2panda::util { + +enum class ConcurrentInvalidFlag { + NOT_ORDINARY_FUNCTION = 1, + NOT_IMPORT_VARIABLE = 2 +}; + +class Concurrent { +public: + Concurrent() = delete; + + static void SetConcurrent(ir::ScriptFunction *func, const lexer::LineIndex &lineIndex); + static void ThrowInvalidConcurrentFunction(const lexer::LineIndex &lineIndex, const ir::AstNode *expr, + ConcurrentInvalidFlag errFlag); + static void VerifyImportVarForConcurrentFunction(const lexer::LineIndex &lineIndex, const ir::AstNode *node, + const binder::ScopeFindResult &result); + + static constexpr std::string_view USE_CONCURRENT = "use concurrent"; +}; + +} // namespace panda::es2panda::util + +#endif \ No newline at end of file -- Gitee