diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index 90dd7ff2c68b56a5de05dd51d47ecf8916c31a45..9e33605992d90cb4183e8ea18ec12a20bba6a74a 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 1c6f0022a76f4dedfab7b15aeb9d13e7f47fc929..e9369fa834ee8c9dde7810fe20acd2308fef023d 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 c835e99e5ed2f3b1c06c231de62bb1c27a7c0a01..bbc5ce11ba7252a4f8ed00004097f845f0b31ea2 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 696521f1887da45376ff38bcfe1baf3a1ac91e21..f88131722cacb6005a76c9830308f3fbb2e03446 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 70be5ce9a70b62060ee50a843eb4bf1fcdc7fb26..6bb538234cb2bebe0af5c51f9e57beb3bee41270 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 c6fa686fd9c64178b70f37d1627e1d02a21e7e69..a284a72bc691b40bdf068fbc5981f8fd7078698a 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 4069401e8f750f057d99b57851c04cb61006fa36..2af60124e61f1d4c31b9ee1ff6393401235df49b 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 19fd7d0a72afbec85bf91e16e139f7c37c39b7cd..c45530efbe3c6d965c1551ec9183f2b59b6e5b5e 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 aaf29adb9004263fba0b21d380e6a6254b36d301..0e1514a8a0af7134ad33542e16b4470270748c2f 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 0000000000000000000000000000000000000000..cda2d57567f00304a14218b44b23795a02a1d24d --- /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 0000000000000000000000000000000000000000..805b407964f4729f41742868e381e7bdfbe23bb4 --- /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 0000000000000000000000000000000000000000..c38dc29bc62eec1df1200246263343d15a1ecc24 --- /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 0000000000000000000000000000000000000000..95a1914f2a5c4a28a625133b33a778a8c1ad343e --- /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 0000000000000000000000000000000000000000..a53c7f64929ef3f96861024be9862ccb44f5459a --- /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 0000000000000000000000000000000000000000..45d163165b2de01991ead5af307936e0ef7cc5a8 --- /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 0000000000000000000000000000000000000000..0f0859a4aa2ef4515f2f627a5c51af64c7426bc4 --- /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 0000000000000000000000000000000000000000..d440cac693568a1aeb43c449eef0b05bd7339dba --- /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 0000000000000000000000000000000000000000..453f7a994c4a2fa64c5629ac701c770528fdab01 --- /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 0000000000000000000000000000000000000000..ebaa563fdbe4757dcfaf6beb141e75b54de4c819 --- /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 0000000000000000000000000000000000000000..6565cc7a6526e95d920e194e4413baa4ee9a27d9 --- /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 0000000000000000000000000000000000000000..442fad971345bf32d23a53a25ba9ac7289a906db --- /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 0000000000000000000000000000000000000000..df76adeac5bd985beaa5641d2b61415861a49d4a --- /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 0000000000000000000000000000000000000000..3714b5ddbf96954a58b19df773c06ddbeea09ce8 --- /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 0000000000000000000000000000000000000000..741aa1119718aeef6486ffc9f783792dfede5924 --- /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 0000000000000000000000000000000000000000..a61abb4c64ca0ae5f1794ad709e8c91e004c0609 --- /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 0000000000000000000000000000000000000000..015a6b4ab98ce0dfe2a05286e11e8779527cd03d --- /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 0000000000000000000000000000000000000000..637c27662b28fc9551c1f629200cf0ad2b1b7748 --- /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 0000000000000000000000000000000000000000..80b0902093bfb278a33c66afe4c4fb4d0f969bf7 --- /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 0000000000000000000000000000000000000000..2f55230006d65a5de37cb0ef7c57754069c2c704 --- /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 0000000000000000000000000000000000000000..c07b60b0478655e0679659434ee83fc5f5dbcb22 --- /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 0000000000000000000000000000000000000000..8f33d4799b34aa5de0a09faf44d30b0773a4574a --- /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 9f508dd6ed75079122f5dc804e80ff37bb318335..960f59890f11d6e5c596c5384f782e95a3dfb05b 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 0000000000000000000000000000000000000000..d6959c30ed36e677d6db6dc487c31bbc53b40941 --- /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 0000000000000000000000000000000000000000..52fa2eda7fa0318fab3dbcd740430b5ec702beb2 --- /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