From 37160b8d913d6bdc76b0d06b63bc07529ed53f47 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Mon, 21 Feb 2022 19:59:21 -0500 Subject: [PATCH 01/20] give anonymous_ name for struct/class/interface --- src/MapleFE/astopt/include/ast_info.h | 1 + src/MapleFE/astopt/src/ast_info.cpp | 16 +++++++++++++++- src/MapleFE/scripts/maplefe-autogen.py | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/astopt/include/ast_info.h b/src/MapleFE/astopt/include/ast_info.h index 4753f50dac..de56fcf645 100644 --- a/src/MapleFE/astopt/include/ast_info.h +++ b/src/MapleFE/astopt/include/ast_info.h @@ -77,6 +77,7 @@ class AST_INFO { TypeAliasNode *CreateTypeAliasNode(TreeNode *to, TreeNode *from); StructNode *CreateStructFromStructLiteral(StructLiteralNode *node); + unsigned GetAnonymousName(); TreeNode *GetAnonymousStruct(TreeNode *node); bool IsInterface(TreeNode *node); diff --git a/src/MapleFE/astopt/src/ast_info.cpp b/src/MapleFE/astopt/src/ast_info.cpp index e841e0d65a..4764c9657b 100644 --- a/src/MapleFE/astopt/src/ast_info.cpp +++ b/src/MapleFE/astopt/src/ast_info.cpp @@ -490,10 +490,15 @@ StructNode *AST_INFO::CreateStructFromStructLiteral(StructLiteralNode *node) { return newnode; } -TreeNode *AST_INFO::GetAnonymousStruct(TreeNode *node) { +unsigned AST_INFO::GetAnonymousName() { std::string str("AnonymousStruct_"); str += std::to_string(mNum++); unsigned stridx = gStringPool.GetStrIdx(str); + return stridx; +} + +TreeNode *AST_INFO::GetAnonymousStruct(TreeNode *node) { + unsigned stridx = GetAnonymousName(); TreeNode *newnode = node; if (newnode->IsStructLiteral()) { StructLiteralNode *sl = static_cast(node); @@ -793,6 +798,9 @@ StructNode *ClassStructVisitor::VisitStructNode(StructNode *node) { if (id && node->GetStrIdx() == 0) { node->SetStrIdx(id->GetStrIdx()); } + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { if (TreeNode *t = node->GetField(i)) { @@ -823,6 +831,9 @@ ClassNode *ClassStructVisitor::VisitClassNode(ClassNode *node) { mInfo->SetTypeId(node, TY_Class); (void) AstVisitor::VisitClassNode(node); if (mInfo->GetPass() == 0) { + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } gTypeTable.AddType(node); mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { @@ -854,6 +865,9 @@ InterfaceNode *ClassStructVisitor::VisitInterfaceNode(InterfaceNode *node) { mInfo->SetTypeId(node, TY_Class); (void) AstVisitor::VisitInterfaceNode(node); if (mInfo->GetPass() == 0) { + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } gTypeTable.AddType(node); mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { diff --git a/src/MapleFE/scripts/maplefe-autogen.py b/src/MapleFE/scripts/maplefe-autogen.py index 1dd330b317..f0ffce0cf1 100755 --- a/src/MapleFE/scripts/maplefe-autogen.py +++ b/src/MapleFE/scripts/maplefe-autogen.py @@ -818,7 +818,7 @@ bool PutNode(TreeNode *n) {{ case NK_UserType: *mOs << EnumVal(UserTypeNode, UT_Type, Type); break; case NK_XXportAsPair: *mOs << (static_cast(n)->IsDefault() ? "default" : ""); *mOs << (static_cast(n)->IsRef() ? " ref" : " copy"); break; - case NK_Struct: *mOs << EnumVal(StructNode, StructProp, Prop); break; + case NK_Struct: *mOs << EnumVal(StructNode, StructProp, Prop); *mOs << "\\\\n" << n->GetName(); break; }} if(n->IsStmt()) *mOs << "\\",penwidth=2,color=\\"tomato"; -- Gitee From f4ea7cb7856bca60791cc2bc0e032539a75cac42 Mon Sep 17 00:00:00 2001 From: eching Date: Tue, 22 Feb 2022 02:45:57 -0800 Subject: [PATCH 02/20] Handle duplicate global var declarations. Updated testcase. --- src/MapleFE/ast2cpp/include/cpp_declaration.h | 1 + src/MapleFE/ast2cpp/src/cpp_declaration.cpp | 18 ++++++++++++++++++ .../test/typescript/unit_tests/var-dup.ts | 4 +++- .../typescript/unit_tests/var-dup.ts.result | 13 +++++++++++-- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/MapleFE/ast2cpp/include/cpp_declaration.h b/src/MapleFE/ast2cpp/include/cpp_declaration.h index fcf6b61c32..9745b249e4 100644 --- a/src/MapleFE/ast2cpp/include/cpp_declaration.h +++ b/src/MapleFE/ast2cpp/include/cpp_declaration.h @@ -19,6 +19,7 @@ #include #include "ast_handler.h" #include "cpp_emitter.h" +#include namespace maplefe { diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index 96a1e654b0..c909a0f5b2 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -300,9 +300,27 @@ class CollectDecls : public AstVisitor { return node; } + unsigned GetModuleNodeId(TreeNode* node) { + while (node->GetParent() && !node->GetParent()->IsModule()) + node = node->GetParent(); + return node == nullptr? 0: node->GetParent()->GetNodeId(); + } + DeclNode *VisitDeclNode(DeclNode *node) { std::string def = mCppDecl->EmitTreeNode(node); std::string var = mCppDecl->EmitTreeNode(node->GetVar()); + + // Handle duplicate TS global var decls (legal in TS) + static std::unordered_map*>globVars; // map module id to its globalvar list + unsigned modId = GetModuleNodeId(node); + std::unordered_map*>::iterator mit = globVars.find(modId); + if (mit == globVars.end()) // create globalvar list for module + globVars[modId] = new std::list; + std::list::iterator it = std::find(globVars[modId]->begin(), globVars[modId]->end(), var); + if (it != globVars[modId]->end()) // skip C++ decl emit for duplciate TS globVar + return node; + globVars[modId]->push_back(var); + std::string ns = mCppDecl->GetNamespace(node); std::string ext = "extern "s + def.substr(0, def.find('=')) + ";\n"s; if (ns.empty()) diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts b/src/MapleFE/test/typescript/unit_tests/var-dup.ts index 9356416213..d393b8a8ec 100644 --- a/src/MapleFE/test/typescript/unit_tests/var-dup.ts +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts @@ -1,3 +1,4 @@ +var name:string = "abc"; function foo(a: number) { var sum = 0; for (var i = 0; i < a; i++) { @@ -10,5 +11,6 @@ function foo(a: number) { return sum; } - +var name:string = "xyz"; console.log(foo(10)); +console.log(name); diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result index 8eb5ad8a69..525911174d 100644 --- a/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result @@ -1,7 +1,12 @@ -Matched 63 tokens. -Matched 73 tokens. +Matched 7 tokens. +Matched 70 tokens. +Matched 77 tokens. +Matched 87 tokens. +Matched 94 tokens. ============= Module =========== == Sub Tree == +js_var Decl: name="abc" +== Sub Tree == func foo(a) throws: js_var Decl: sum=0 for ( ) @@ -13,5 +18,9 @@ func foo(a) throws: return sum +== Sub Tree == +js_var Decl: name="xyz" == Sub Tree == console.log(foo(10)) +== Sub Tree == +console.log(name) -- Gitee From 011701bc764890b9bc4c29fa986317d79fbb2427 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Tue, 22 Feb 2022 11:35:46 -0500 Subject: [PATCH 03/20] add option to find decl in curreenty scope only --- src/MapleFE/shared/include/ast_scope.h | 2 +- src/MapleFE/shared/src/ast_scope.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MapleFE/shared/include/ast_scope.h b/src/MapleFE/shared/include/ast_scope.h index 32131f660c..088072c362 100644 --- a/src/MapleFE/shared/include/ast_scope.h +++ b/src/MapleFE/shared/include/ast_scope.h @@ -83,7 +83,7 @@ public: TreeNode* GetExportedDecl(unsigned i) {return mExportedDecls.ValueAtIndex(i);} TreeNode* GetType(unsigned i) {return mTypes.ValueAtIndex(i);} - TreeNode* FindDeclOf(unsigned stridx); + TreeNode* FindDeclOf(unsigned stridx, bool deep = true); TreeNode* FindExportedDeclOf(unsigned stridx); TreeNode* FindTypeOf(unsigned stridx); diff --git a/src/MapleFE/shared/src/ast_scope.cpp b/src/MapleFE/shared/src/ast_scope.cpp index 7441ddac5e..f1e5505be6 100644 --- a/src/MapleFE/shared/src/ast_scope.cpp +++ b/src/MapleFE/shared/src/ast_scope.cpp @@ -31,7 +31,7 @@ void ASTScope::AddChild(ASTScope *s) { // This is to find the decl having the name as stridx // starting from local scope -TreeNode* ASTScope::FindDeclOf(unsigned stridx) { +TreeNode* ASTScope::FindDeclOf(unsigned stridx, bool deep) { ASTScope *scope = this; while (scope) { for (unsigned i = 0; i < scope->GetDeclNum(); i++) { @@ -46,8 +46,8 @@ TreeNode* ASTScope::FindDeclOf(unsigned stridx) { return tree; } } - // search parent scope - scope = scope->mParent; + // search parent scope if deep is set + scope = deep ? scope->mParent : NULL; } return NULL; } -- Gitee From 532f929581631a1b62042ae6e2907bdae698aa6c Mon Sep 17 00:00:00 2001 From: Wen HU Date: Tue, 22 Feb 2022 11:46:46 -0500 Subject: [PATCH 04/20] duplicated var decl is replaced by assignment if with init --- src/MapleFE/astopt/src/ast_scp.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 9179704ab7..4462adb4b4 100644 --- a/src/MapleFE/astopt/src/ast_scp.cpp +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -428,6 +428,7 @@ NamespaceNode *BuildScopeVisitor::VisitNamespaceNode(NamespaceNode *node) { DeclNode *BuildScopeVisitor::VisitDeclNode(DeclNode *node) { BuildScopeBaseVisitor::VisitDeclNode(node); ASTScope *scope = NULL; + bool deep = true; if (node->GetProp() == JS_Var) { // promote to use function or module scope scope = mUserScopeStack.top(); @@ -438,10 +439,33 @@ DeclNode *BuildScopeVisitor::VisitDeclNode(DeclNode *node) { node->GetVar()->SetScope(scope); } } else { - // use current scope + // restrict to current scope scope = mScopeStack.top(); + deep = false; + } + // check if it is already a decl in the scope + unsigned stridx = node->GetStrIdx(); + TreeNode *decl = scope->FindDeclOf(stridx, deep); + if (decl) { + if (decl != node) { + // replace with an assignment if apply + if (node->GetInit()) { + BinOperatorNode *bop = mHandler->NewTreeNode(); + bop->SetOprId(OPR_Assign); + IdentifierNode *id = mHandler->NewTreeNode(); + id->SetStrIdx(stridx); + id->SetScope(scope); + + bop->SetOpndA(id); + bop->SetOpndB(node->GetInit()); + node = (DeclNode *)bop; + } else { + node = NULL; + } + } + } else { + AddDecl(scope, node); } - AddDecl(scope, node); return node; } -- Gitee From 2b884c1fbd6c195da1f7fa7d3ac0295327bf8b81 Mon Sep 17 00:00:00 2001 From: yehandong Date: Wed, 23 Feb 2022 10:16:22 +0800 Subject: [PATCH 05/20] remove the git config username from setup. --- tools/setup_tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/setup_tools.sh b/tools/setup_tools.sh index 8b320e302c..a8672855b9 100755 --- a/tools/setup_tools.sh +++ b/tools/setup_tools.sh @@ -31,7 +31,7 @@ ANDROID_SRCDIR=$MAPLE_ROOT/../android/$ANDROID_VERSION ANDROID_DIR=$MAPLE_ROOT/android -USR_EMAIL=`git config user.email` +#USR_EMAIL=`git config user.email` if [ "$android_env" == "android" ]; then if [ ! -f $TOOLS/android-ndk-r21/ndk-build ]; then -- Gitee From fc62f33d9ec47e578a6e3364c7858119504fd9a5 Mon Sep 17 00:00:00 2001 From: yehandong Date: Wed, 23 Feb 2022 10:17:54 +0800 Subject: [PATCH 06/20] add a section to show how to build a small case from .ts to a.out --- src/MapleFE/docs/readme | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/MapleFE/docs/readme b/src/MapleFE/docs/readme index 732f9f3725..9ff4bbefc7 100644 --- a/src/MapleFE/docs/readme +++ b/src/MapleFE/docs/readme @@ -47,10 +47,19 @@ alias gounit='cd $unit' - For graphic view of JavaScript object inheritance relations: o cd $MFE/docs/util; node proto.js | ./viewdot.sh -3. TypeScript/JavaScript inheritance modeling in C++ +3. Run a single case from .ts + 1) ~/OpenArkCompiler/src/MapleFE/output/typescript/bin/ts2ast while-stmt.ts + This creates while-stmt.ts.ast at the same directory + 2) ~/OpenArkCompiler/src/MapleFE/output/typescript/bin/ast2cpp while-stmt.ts.ast + This generates the while-stmt.cpp + 3) g++ -g -o run -I/home/ubuntu/OpenArkCompiler/src/MapleFE/ast2cpp/runtime/include -I/home/ubuntu/OpenArkCompiler/src/MapleFE/astopt/include -std=c++17 while-stmt.cpp /home/ubuntu/OpenArkCompiler/src/MapleFE/ast2cpp/runtime/src/*.cpp + This generates the executable run. + 4) ./run to test the result. + +4. TypeScript/JavaScript inheritance modeling in C++ ==================================================== -3.1 JavaScript Object Properties +4.1 JavaScript Object Properties JavaScript objects have both instance properties and inherited properties. Instance properties are held in the object's own property @@ -67,7 +76,7 @@ In Javascript, object property lookup order is: - then lookup inherited property (from property list of object pointed to by chain of __proto__ starting from __proto__ of current object -3.2 TypeScript/JavaScript inheritance modeling in C++ +4.2 TypeScript/JavaScript inheritance modeling in C++ The inheritance relationship of TS/JS objects is mapped to C++ as classes derived hierarchically along the __proto__ chain. This allows @@ -100,7 +109,7 @@ instead of a prototype object, there is still only a single copy of inheited properties, because in JavaScript, there is only 1 single instance of each function constructor. -3.3 Property inheritance with __proto__ chain +4.3 Property inheritance with __proto__ chain See environment section in readme for instruction to view graphic display of JavaScript object inheritance relationship. The following -- Gitee From 1e24c6f93b129b28288fc01df5608f1a4ab61977 Mon Sep 17 00:00:00 2001 From: yehandong Date: Wed, 23 Feb 2022 10:18:49 +0800 Subject: [PATCH 07/20] add one new separator, triple slash --- src/MapleFE/shared/include/supported_separators.def | 1 + src/MapleFE/shared/src/parser.cpp | 8 -------- src/MapleFE/typescript/separator.spec | 3 ++- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/MapleFE/shared/include/supported_separators.def b/src/MapleFE/shared/include/supported_separators.def index 40298b4bb0..9257ed97ba 100644 --- a/src/MapleFE/shared/include/supported_separators.def +++ b/src/MapleFE/shared/include/supported_separators.def @@ -34,3 +34,4 @@ SEPARATOR(Whitespace) SEPARATOR(Tab) // Horizontal Tab, 0x09 SEPARATOR(ArrowFunction) // first coming from JS, => SEPARATOR(Optional) // first coming from JS, ?. +SEPARATOR(TripleSlash) // first coming from TS, ///, used in triple-slash-directive diff --git a/src/MapleFE/shared/src/parser.cpp b/src/MapleFE/shared/src/parser.cpp index 12e8d953dc..3a5a118062 100644 --- a/src/MapleFE/shared/src/parser.cpp +++ b/src/MapleFE/shared/src/parser.cpp @@ -576,14 +576,6 @@ ParseStatus Parser::ParseStmt() { mRootNode = mAppealNodePool.NewAppealNode(); mAppealNodes.push_back(mRootNode); - // mActiveTokens contain some un-matched tokens from last time of TraverseStmt(), - // because at the end of every TraverseStmt() when it finishes its matching it always - // MoveCurToken() which in turn calls LexOneLine() to read new tokens of a new line. - // - // This means in LexOneLine() we also need check if there are already tokens pending. - // - // [TODO] Later on, we will move thoes pending tokens to a separate data structure. - unsigned token_num = LexOneLine(); // No more token, end of file if (!token_num) diff --git a/src/MapleFE/typescript/separator.spec b/src/MapleFE/typescript/separator.spec index b06a949337..9804f9b97f 100644 --- a/src/MapleFE/typescript/separator.spec +++ b/src/MapleFE/typescript/separator.spec @@ -42,4 +42,5 @@ STRUCT Separator : ((" ", Whitespace), ("?.",Optional), ("@", At), ("#", Pound), - ("\t", Tab)) + ("\t", Tab), + ("///", TripleSlash)) -- Gitee From ea666fa8c4624c4500d92601e732c83e81cb1773 Mon Sep 17 00:00:00 2001 From: yehandong Date: Wed, 23 Feb 2022 10:22:44 +0800 Subject: [PATCH 08/20] Update the .gitignore to ignore more tools and libs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f71bf2703f..dcf0dec08f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ third_party/aosp_10.0.0_r35* third_party/aosp_modified* third_party/ctorture* third_party/llvm_modified* +third_party/llvm-* +tools/lib tools/bin* tools/android* tools/aosp* -- Gitee From d12509b26cd323de68b8b240b79f4cd3af434c80 Mon Sep 17 00:00:00 2001 From: yehandong Date: Wed, 23 Feb 2022 15:16:16 +0800 Subject: [PATCH 09/20] Added virtual function Lexer::FindTripleSlash() --- src/MapleFE/autogen/reserved.spec | 6 ++---- src/MapleFE/shared/include/lexer.h | 2 ++ src/MapleFE/shared/src/lexer.cpp | 3 +++ src/MapleFE/typescript/include/lang_spec.h | 1 + src/MapleFE/typescript/src/lang_spec.cpp | 20 ++++++++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/MapleFE/autogen/reserved.spec b/src/MapleFE/autogen/reserved.spec index 445cc388cc..1832b7c5dc 100644 --- a/src/MapleFE/autogen/reserved.spec +++ b/src/MapleFE/autogen/reserved.spec @@ -34,10 +34,8 @@ rule HEXDIGIT : ONEOF(DIGIT, 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', ' # irregular char like \n, \, DEL, etc. will be handled in lexer.cpp if some language allows them in string literal. rule IRREGULAR_CHAR : "this_is_for_fake_rule" -# We will catch any utf-8 char in lexer in a short-cut. -rule UTF8 : "this_is_for_fake_rule" - -# Below are special rules handled in lexer source code. Since it'll be in lexer code, it means +# Below are special rules handled in lexer.cpp. Since it'll be in lexer code, it means # it's a shared rule of all languages. It has to be in reserved.spec. +rule UTF8 : "this_is_for_fake_rule" rule TemplateLiteral : "this_is_for_fake_rule" rule RegularExpression : "this_is_for_fake_rule" diff --git a/src/MapleFE/shared/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 151f55b258..00a3f70862 100644 --- a/src/MapleFE/shared/include/lexer.h +++ b/src/MapleFE/shared/include/lexer.h @@ -135,6 +135,8 @@ public: virtual bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end) {return false;} virtual bool FindNextTLPlaceHolder(unsigned start, std::string& s, unsigned& end) {return false;} + virtual bool FindTripleSlash() {return false;} + // replace keyword/opr/sep... with tokens //void PlantTokens(); //void PlantTraverseRuleTable(RuleTable*); diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index ccd8a5a255..7fc85f25fb 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -541,6 +541,9 @@ LitData Lexer::GetLiteral() { // // Return true if a comment is read. The contents are ignore. bool Lexer::GetComment() { + if (FindTripleSlash()) + return false; + if (line[curidx] == '/' && line[curidx+1] == '/') { curidx = current_line_size; return true; diff --git a/src/MapleFE/typescript/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h index 929de87c24..96aef8bf12 100644 --- a/src/MapleFE/typescript/include/lang_spec.h +++ b/src/MapleFE/typescript/include/lang_spec.h @@ -49,6 +49,7 @@ public: TempLitData* GetTempLit(); bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end); bool FindNextTLPlaceHolder(unsigned start, std::string& s, unsigned& end); + bool FindTripleSlash(); }; //////////////////////////////////////////////////////////////////////////////////// diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index b2022817b9..0c0af20afa 100644 --- a/src/MapleFE/typescript/src/lang_spec.cpp +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -394,6 +394,26 @@ bool TypescriptLexer::FindNextTLPlaceHolder(unsigned start_idx, std::string& str return true; } +// This is to catch TS triple-slash directives : /// Date: Wed, 23 Feb 2022 02:30:23 -0800 Subject: [PATCH 10/20] Revert "Handle duplicate global var declarations. Updated testcase." This reverts commit f4ea7cb7856bca60791cc2bc0e032539a75cac42. Duplicate global var is handled in AST by commit 532f9295 instead. --- src/MapleFE/ast2cpp/include/cpp_declaration.h | 1 - src/MapleFE/ast2cpp/src/cpp_declaration.cpp | 18 ------------------ .../test/typescript/unit_tests/var-dup.ts | 4 +--- .../typescript/unit_tests/var-dup.ts.result | 13 ++----------- 4 files changed, 3 insertions(+), 33 deletions(-) diff --git a/src/MapleFE/ast2cpp/include/cpp_declaration.h b/src/MapleFE/ast2cpp/include/cpp_declaration.h index 9745b249e4..fcf6b61c32 100644 --- a/src/MapleFE/ast2cpp/include/cpp_declaration.h +++ b/src/MapleFE/ast2cpp/include/cpp_declaration.h @@ -19,7 +19,6 @@ #include #include "ast_handler.h" #include "cpp_emitter.h" -#include namespace maplefe { diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index c909a0f5b2..96a1e654b0 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -300,27 +300,9 @@ class CollectDecls : public AstVisitor { return node; } - unsigned GetModuleNodeId(TreeNode* node) { - while (node->GetParent() && !node->GetParent()->IsModule()) - node = node->GetParent(); - return node == nullptr? 0: node->GetParent()->GetNodeId(); - } - DeclNode *VisitDeclNode(DeclNode *node) { std::string def = mCppDecl->EmitTreeNode(node); std::string var = mCppDecl->EmitTreeNode(node->GetVar()); - - // Handle duplicate TS global var decls (legal in TS) - static std::unordered_map*>globVars; // map module id to its globalvar list - unsigned modId = GetModuleNodeId(node); - std::unordered_map*>::iterator mit = globVars.find(modId); - if (mit == globVars.end()) // create globalvar list for module - globVars[modId] = new std::list; - std::list::iterator it = std::find(globVars[modId]->begin(), globVars[modId]->end(), var); - if (it != globVars[modId]->end()) // skip C++ decl emit for duplciate TS globVar - return node; - globVars[modId]->push_back(var); - std::string ns = mCppDecl->GetNamespace(node); std::string ext = "extern "s + def.substr(0, def.find('=')) + ";\n"s; if (ns.empty()) diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts b/src/MapleFE/test/typescript/unit_tests/var-dup.ts index d393b8a8ec..9356416213 100644 --- a/src/MapleFE/test/typescript/unit_tests/var-dup.ts +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts @@ -1,4 +1,3 @@ -var name:string = "abc"; function foo(a: number) { var sum = 0; for (var i = 0; i < a; i++) { @@ -11,6 +10,5 @@ function foo(a: number) { return sum; } -var name:string = "xyz"; + console.log(foo(10)); -console.log(name); diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result index 525911174d..8eb5ad8a69 100644 --- a/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result @@ -1,12 +1,7 @@ -Matched 7 tokens. -Matched 70 tokens. -Matched 77 tokens. -Matched 87 tokens. -Matched 94 tokens. +Matched 63 tokens. +Matched 73 tokens. ============= Module =========== == Sub Tree == -js_var Decl: name="abc" -== Sub Tree == func foo(a) throws: js_var Decl: sum=0 for ( ) @@ -18,9 +13,5 @@ func foo(a) throws: return sum -== Sub Tree == -js_var Decl: name="xyz" == Sub Tree == console.log(foo(10)) -== Sub Tree == -console.log(name) -- Gitee From dfaac6440163f55a1ea2a57f6b587056187d7092 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Wed, 23 Feb 2022 11:52:57 -0500 Subject: [PATCH 11/20] for body of function use function scope instead of body scope --- src/MapleFE/astopt/src/ast_scp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 4462adb4b4..3f260170ac 100644 --- a/src/MapleFE/astopt/src/ast_scp.cpp +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -439,8 +439,16 @@ DeclNode *BuildScopeVisitor::VisitDeclNode(DeclNode *node) { node->GetVar()->SetScope(scope); } } else { - // restrict to current scope scope = mScopeStack.top(); + // for body of function use function scope instead of body scope + TreeNode *b = node->GetParent(); + if (b && b->IsBlock()) { + TreeNode *f = b->GetParent(); + if (f && f->IsFunction()) { + scope = mUserScopeStack.top(); + } + } + // restrict to current scope deep = false; } // check if it is already a decl in the scope -- Gitee From ff7e275c6ce42fe7f7a65acf4ca40ebb3a7112d2 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Wed, 23 Feb 2022 13:13:38 -0500 Subject: [PATCH 12/20] avoid dumplicated entries in typetable; set typeid TY_String for String class etc --- src/MapleFE/astopt/src/ast_info.cpp | 19 +++++++++++++++---- src/MapleFE/shared/include/typetable.h | 2 +- src/MapleFE/shared/src/typetable.cpp | 6 +++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/MapleFE/astopt/src/ast_info.cpp b/src/MapleFE/astopt/src/ast_info.cpp index 4764c9657b..5bf7c23895 100644 --- a/src/MapleFE/astopt/src/ast_info.cpp +++ b/src/MapleFE/astopt/src/ast_info.cpp @@ -70,12 +70,24 @@ void AST_INFO::CollectInfo() { } void AST_INFO::AddBuiltInTypes() { + unsigned size = gTypeTable.size(); + for (unsigned idx = 1; idx < size; idx++) { + TreeNode *node = gTypeTable.GetTypeFromTypeIdx(idx); + if (node->IsUserType()) { + mStrIdx2TypeIdxMap[node->GetStrIdx()] = node->GetTypeIdx(); + } + } + // add language builtin types TreeNode *node = NULL; + unsigned stridx = 0; #define BUILTIN(T) \ - node = gTypeTable.CreateBuiltinType(#T, TY_Class);\ - gTypeTable.AddType(node);\ - mStrIdx2TypeIdxMap[node->GetStrIdx()] = node->GetTypeIdx(); + stridx = gStringPool.GetStrIdx(#T);\ + if (mStrIdx2TypeIdxMap.find(stridx) == mStrIdx2TypeIdxMap.end()) {\ + node = gTypeTable.CreateBuiltinType(#T, TY_Class, TY_Class);\ + gTypeTable.AddType(node);\ + mStrIdx2TypeIdxMap[stridx] = node->GetTypeIdx();\ + } #include "lang_builtin.def" } @@ -744,7 +756,6 @@ UserTypeNode *FillNodeInfoVisitor::VisitUserTypeNode(UserTypeNode *node) { if (id) { unsigned tidx = mInfo->GetBuiltInTypeIdx(id); if (tidx) { - mInfo->SetTypeId(id, TY_Class); mInfo->SetTypeIdx(id, tidx); } if (!id->IsTypeIdNone()) { diff --git a/src/MapleFE/shared/include/typetable.h b/src/MapleFE/shared/include/typetable.h index 2817fadd4e..10930c5ade 100644 --- a/src/MapleFE/shared/include/typetable.h +++ b/src/MapleFE/shared/include/typetable.h @@ -62,7 +62,7 @@ public: unsigned GetPreBuildSize() { return mPreBuildSize; } unsigned GetPrimSize() { return mPrimSize; } TreeNode *CreatePrimType(std::string name, TypeId tid); - TreeNode *CreateBuiltinType(std::string name, TypeId tid); + TreeNode *CreateBuiltinType(std::string name, TypeId tid, TypeId uttid); void AddPrimAndBuiltinTypes(); bool AddType(TreeNode *node); TypeEntry *GetTypeEntryFromTypeIdx(unsigned tidx); diff --git a/src/MapleFE/shared/src/typetable.cpp b/src/MapleFE/shared/src/typetable.cpp index ad58543fd8..13adfe4df1 100644 --- a/src/MapleFE/shared/src/typetable.cpp +++ b/src/MapleFE/shared/src/typetable.cpp @@ -65,7 +65,7 @@ TreeNode *TypeTable::CreatePrimType(std::string name, TypeId tid) { return ptype; } -TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid) { +TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid, TypeId uttid) { unsigned stridx = gStringPool.GetStrIdx(name); IdentifierNode *id = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); new (id) IdentifierNode(stridx); @@ -74,7 +74,7 @@ TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid) { UserTypeNode *utype = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); new (utype) UserTypeNode(id); utype->SetStrIdx(stridx); - utype->SetTypeId(TY_Class); + utype->SetTypeId(uttid); id->SetParent(utype); mTypeId2TypeMap[tid] = utype; @@ -117,7 +117,7 @@ void TypeTable::AddPrimAndBuiltinTypes() { mPrimSize = size(); -#define TYPE(T) node = CreateBuiltinType(#T, TY_##T); AddType(node); +#define TYPE(T) node = CreateBuiltinType(#T, TY_##T, TY_##T); AddType(node); #define PRIMTYPE(T) // additional usertype Boolean TYPE(Boolean); -- Gitee From cc529a3252cb406c6a5cca1b09101f46bac13342 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Wed, 23 Feb 2022 14:42:29 -0500 Subject: [PATCH 13/20] adjust merge typeid for class; use mId in user type as decl --- src/MapleFE/astopt/src/ast_info.cpp | 10 +++++----- src/MapleFE/astopt/src/ast_scp.cpp | 9 ++++++--- src/MapleFE/astopt/src/ast_ti.cpp | 12 ++++++++---- src/MapleFE/shared/include/typetable.h | 2 +- src/MapleFE/shared/src/typetable.cpp | 9 ++++++--- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/MapleFE/astopt/src/ast_info.cpp b/src/MapleFE/astopt/src/ast_info.cpp index 5bf7c23895..14b560d3a4 100644 --- a/src/MapleFE/astopt/src/ast_info.cpp +++ b/src/MapleFE/astopt/src/ast_info.cpp @@ -84,7 +84,7 @@ void AST_INFO::AddBuiltInTypes() { #define BUILTIN(T) \ stridx = gStringPool.GetStrIdx(#T);\ if (mStrIdx2TypeIdxMap.find(stridx) == mStrIdx2TypeIdxMap.end()) {\ - node = gTypeTable.CreateBuiltinType(#T, TY_Class, TY_Class);\ + node = gTypeTable.CreateBuiltinType(#T, TY_Class);\ gTypeTable.AddType(node);\ mStrIdx2TypeIdxMap[stridx] = node->GetTypeIdx();\ } @@ -257,16 +257,16 @@ bool AST_INFO::IsTypeCompatible(TreeNode *node1, TreeNode *node2) { if ((!node1 && node2) || (node1 && !node2)) { return false; } + // not same kind + if (node1->GetKind() != node2->GetKind()) { + return false; + } // at least one is prim if (node1->IsPrimType() || node2->IsPrimType()) { TypeId tid_field = GetTypeId(node2); TypeId tid_target = GetTypeId(node1); return (tid_field == tid_target); } - // not same kind - if (node1->GetKind() != node2->GetKind()) { - return false; - } bool result = false; // same kind NodeKind nk = node1->GetKind(); diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 3f260170ac..7a87e6f256 100644 --- a/src/MapleFE/astopt/src/ast_scp.cpp +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -128,9 +128,12 @@ void BuildScopeVisitor::InitInternalTypes() { TreeNode *node = gTypeTable.GetTypeFromTypeIdx(i); node->SetScope(scope); if (node->IsUserType()) { - static_cast(node)->GetId()->SetScope(scope); - AddType(scope, node); - AddDecl(scope, node); + UserTypeNode *ut = static_cast(node); + TreeNode *id = ut->GetId(); + id->SetScope(scope); + AddType(scope, ut); + // id as a decl + AddDecl(scope, id); } else { AddType(scope, node); } diff --git a/src/MapleFE/astopt/src/ast_ti.cpp b/src/MapleFE/astopt/src/ast_ti.cpp index 22706289ed..4ca2aed22d 100644 --- a/src/MapleFE/astopt/src/ast_ti.cpp +++ b/src/MapleFE/astopt/src/ast_ti.cpp @@ -226,6 +226,7 @@ TypeId TypeInferVisitor::MergeTypeId(TypeId tia, TypeId tib) { switch (tia) { case TY_None: result = tib; break; + case TY_Class: case TY_Object: case TY_User: result = tia; break; @@ -233,7 +234,6 @@ TypeId TypeInferVisitor::MergeTypeId(TypeId tia, TypeId tib) { case TY_Undefined: case TY_String: case TY_Function: - case TY_Class: case TY_Array: result = TY_Merge; break; case TY_Boolean: { @@ -1533,8 +1533,12 @@ IdentifierNode *TypeInferVisitor::VisitIdentifierNode(IdentifierNode *node) { } } if (node->GetInit()) { - UpdateTypeId(node, node->GetInit()->GetTypeId()); - UpdateTypeIdx(node, node->GetInit()->GetTypeIdx()); + if (node->GetTypeId() == TY_None) { + SetTypeId(node, node->GetInit()->GetTypeId()); + } + if (node->GetTypeIdx() == 0) { + SetTypeIdx(node, node->GetInit()->GetTypeIdx()); + } SetUpdated(); return node; } @@ -1819,7 +1823,7 @@ UserTypeNode *TypeInferVisitor::VisitUserTypeNode(UserTypeNode *node) { SetTypeId(node, TY_Array); SetTypeIdx(node, TY_Array); } else if (node->GetId()) { - UpdateTypeId(node, node->GetId()); + SetTypeId(node, TY_Class); UpdateTypeIdx(node, node->GetId()); } TreeNode *parent = node->GetParent(); diff --git a/src/MapleFE/shared/include/typetable.h b/src/MapleFE/shared/include/typetable.h index 10930c5ade..2817fadd4e 100644 --- a/src/MapleFE/shared/include/typetable.h +++ b/src/MapleFE/shared/include/typetable.h @@ -62,7 +62,7 @@ public: unsigned GetPreBuildSize() { return mPreBuildSize; } unsigned GetPrimSize() { return mPrimSize; } TreeNode *CreatePrimType(std::string name, TypeId tid); - TreeNode *CreateBuiltinType(std::string name, TypeId tid, TypeId uttid); + TreeNode *CreateBuiltinType(std::string name, TypeId tid); void AddPrimAndBuiltinTypes(); bool AddType(TreeNode *node); TypeEntry *GetTypeEntryFromTypeIdx(unsigned tidx); diff --git a/src/MapleFE/shared/src/typetable.cpp b/src/MapleFE/shared/src/typetable.cpp index 13adfe4df1..c528450f35 100644 --- a/src/MapleFE/shared/src/typetable.cpp +++ b/src/MapleFE/shared/src/typetable.cpp @@ -65,7 +65,7 @@ TreeNode *TypeTable::CreatePrimType(std::string name, TypeId tid) { return ptype; } -TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid, TypeId uttid) { +TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid) { unsigned stridx = gStringPool.GetStrIdx(name); IdentifierNode *id = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); new (id) IdentifierNode(stridx); @@ -74,7 +74,7 @@ TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid, TypeId utti UserTypeNode *utype = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); new (utype) UserTypeNode(id); utype->SetStrIdx(stridx); - utype->SetTypeId(uttid); + utype->SetTypeId(TY_Class); id->SetParent(utype); mTypeId2TypeMap[tid] = utype; @@ -89,6 +89,9 @@ bool TypeTable::AddType(TreeNode *node) { unsigned tid = mTypeTable.size(); mNodeId2TypeIdxMap[id] = tid; node->SetTypeIdx(tid); + if (node->IsUserType()) { + static_cast(node)->GetId()->SetTypeIdx(tid); + } TypeEntry *entry = new TypeEntry(node); mTypeTable.push_back(entry); return true; @@ -117,7 +120,7 @@ void TypeTable::AddPrimAndBuiltinTypes() { mPrimSize = size(); -#define TYPE(T) node = CreateBuiltinType(#T, TY_##T, TY_##T); AddType(node); +#define TYPE(T) node = CreateBuiltinType(#T, TY_##T); AddType(node); #define PRIMTYPE(T) // additional usertype Boolean TYPE(Boolean); -- Gitee From 93635ab5306d031eff871697793cfd711895d090 Mon Sep 17 00:00:00 2001 From: eching Date: Wed, 23 Feb 2022 14:05:44 -0800 Subject: [PATCH 14/20] Document handling of builtin constructors String/Number/Boolean and primitve/literal types string/number/boolean. --- src/MapleFE/docs/builtin-constructors.md | 31 +++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/MapleFE/docs/builtin-constructors.md b/src/MapleFE/docs/builtin-constructors.md index b38060c8ad..d5936b12a4 100644 --- a/src/MapleFE/docs/builtin-constructors.md +++ b/src/MapleFE/docs/builtin-constructors.md @@ -25,7 +25,7 @@ Not all built-in objects work as object constructors. The following is a list of JavaScript built-in objects that works as object constructors to create objects of corresponding built-in type: -## List of JavaScript built-in object constructors +### 1. List of JavaScript built-in object constructors ``` 1 AggregateError 2 Array @@ -73,6 +73,35 @@ of corresponding built-in type: 44 WeakSet ``` +### 2. JavaScript builtin String/Number/Boolean object constructor and string/number/boolean primitive +https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_primitives_and_string_objects + +"Note that JavaScript distinguishes between String objects and primitive string values. (The same is true of Boolean and Numbers.) + +String literals (denoted by double or single quotes) and strings returned from String calls in a non-constructor context (that is, called without using the new keyword) are primitive strings. JavaScript automatically converts primitives to String objects, so that it's possible to use String object methods for primitive strings. In contexts where a method is to be invoked on a primitive string or a property lookup occurs, JavaScript will automatically wrap the string primitive and call the method or perform the property lookup." +``` + 1 var s1 : string = "test"; // string literal + 2 var s2 : String = "test"; // string literal + 3 var s3 : string = String("test"); // string literal + 4 var s4 : String = String("test"); // string literal + 5 var s5 : String = new String("test"); // String object + 6 console.log(typeof(s1)); // string + 7 console.log(s1.slice(1,2)); // string literal s1 wrapped/converted to String object for call + 8 console.log(typeof(s2)); // string + 9 console.log(typeof(s3)); // string + 10 console.log(typeof(s4)); // string + 11 console.log(typeof(s5)); // object +``` + +For TypeScript to C++ mapping, string primitive maps to std::string, and String objects maples to builtin String object t2crt::String (same for Booelan and Numbers). + +The type returned by JavaScript/TypeScript String/Number/Boolean builtin/constructor function depends on the usage: +- when used as a function, it is a type converter (convert between literal typeis), returns primitve/literal type string/number/boolean +- when used with new op(), it is a constructor and returns an object +- A variable declared as primitve type string/number/boolean will be wrapped/converted to a String/Number/Boolean object if any object property/method is referenced + For TypeScript to C++, this conversion can be done by the runtime, but there is opportunity for optimization if it can be determined at compile time whether a primitive will be used as an object, in which case the primitve literal can be generated as object intead. + + ## TypeScript types Additionally these TypeScript types will be treated as built-in object types too: -- Gitee From 76498d81d8c6d01e441b9e59bf908c4fdf123737 Mon Sep 17 00:00:00 2001 From: yehandong Date: Thu, 24 Feb 2022 15:45:35 +0800 Subject: [PATCH 15/20] Support TS triple slash directives. --- src/MapleFE/ast2mpl/src/mpl_processor.cpp | 4 ++ src/MapleFE/shared/include/ast.h | 30 ++++++++++++ src/MapleFE/shared/include/ast_nk.def | 2 + src/MapleFE/shared/include/parser.h | 2 + .../shared/include/supported_actions.def | 2 + .../shared/include/supported_operators.def | 1 + .../shared/include/supported_separators.def | 1 - src/MapleFE/shared/src/ast.cpp | 26 ++++++++++ src/MapleFE/shared/src/ast_builder.cpp | 44 +++++++++++++++++ src/MapleFE/shared/src/lexer.cpp | 4 +- src/MapleFE/shared/src/parser.cpp | 47 +++++++++++++++++-- src/MapleFE/shared/src/vfy.cpp | 4 ++ .../import-ambient-module.ts.result | 7 ++- .../unit_tests/triple-slash-dir.d.ts.result | 6 +++ src/MapleFE/typescript/identifier.spec | 3 +- src/MapleFE/typescript/operator.spec | 3 ++ src/MapleFE/typescript/separator.spec | 3 +- src/MapleFE/typescript/src/lang_spec.cpp | 14 +++--- src/MapleFE/typescript/stmt.spec | 9 +++- 19 files changed, 194 insertions(+), 18 deletions(-) diff --git a/src/MapleFE/ast2mpl/src/mpl_processor.cpp b/src/MapleFE/ast2mpl/src/mpl_processor.cpp index e66c75643e..a943ae29b8 100644 --- a/src/MapleFE/ast2mpl/src/mpl_processor.cpp +++ b/src/MapleFE/ast2mpl/src/mpl_processor.cpp @@ -609,6 +609,10 @@ maple::BaseNode *Ast2MplBuilder::ProcessInfer(StmtExprKind skind, TreeNode *tnod return nullptr; } +maple::BaseNode *Ast2MplBuilder::ProcessTripleSlash(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + maple::BaseNode *Ast2MplBuilder::ProcessBlockDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { BlockNode *ast_block = static_cast(tnode); for (int i = 0; i < ast_block->GetChildrenNum(); i++) { diff --git a/src/MapleFE/shared/include/ast.h b/src/MapleFE/shared/include/ast.h index 58d327ce4f..4ef9361c73 100644 --- a/src/MapleFE/shared/include/ast.h +++ b/src/MapleFE/shared/include/ast.h @@ -2388,5 +2388,35 @@ public: void Dump(unsigned); }; +////////////////////////////////////////////////////// +// Triple Slash Directive +////////////////////////////////////////////////////// + +enum TripleSlashProp { + TSP_Path, + TSP_Types, + TSP_Lib, + TSP_NoDefaultLib, + TSP_NA +}; + +class TripleSlashNode : public TreeNode { +private: + TripleSlashProp mProp; + TreeNode *mValue; +public: + TripleSlashNode() : TreeNode(NK_TripleSlash) {mValue = NULL; mProp = TSP_NA;} + ~TripleSlashNode() {} + + TreeNode* GetValue() {return mValue;} + void SetValue(TreeNode *n) {mValue = n; SETPARENT(n);} + + TripleSlashProp GetProp() {return mProp;} + void SetProp(TripleSlashProp p) {mProp = p;} + + void Dump(unsigned); +}; + + } #endif diff --git a/src/MapleFE/shared/include/ast_nk.def b/src/MapleFE/shared/include/ast_nk.def index df99869326..e6c720c140 100644 --- a/src/MapleFE/shared/include/ast_nk.def +++ b/src/MapleFE/shared/include/ast_nk.def @@ -88,6 +88,8 @@ NODEKIND(In) NODEKIND(Is) NODEKIND(Infer) +NODEKIND(TripleSlash) // TS triple-slash directive + NODEKIND(Block) NODEKIND(Function) NODEKIND(Class) diff --git a/src/MapleFE/shared/include/parser.h b/src/MapleFE/shared/include/parser.h index a747c23656..26d4f73af7 100644 --- a/src/MapleFE/shared/include/parser.h +++ b/src/MapleFE/shared/include/parser.h @@ -43,6 +43,7 @@ class TreeNode; typedef enum AppealStatus { FailWasFailed, FailNotRightToken, + FailNotRightString, FailNotIdentifier, FailNotLiteral, FailNotRegExpr, @@ -302,6 +303,7 @@ public: // 1. If the target is a token, we just need compare mCurToken with it. // 2. If the target is a special rule table, like literal, identifier, we just // need check the type of mCurToken. + bool TraverseStringSucc(Token*, AppealNode*, AppealNode *&); bool TraverseToken(Token*, AppealNode*, AppealNode *&); bool TraverseLiteral(RuleTable*, AppealNode*); bool TraverseIdentifier(RuleTable*, AppealNode*); diff --git a/src/MapleFE/shared/include/supported_actions.def b/src/MapleFE/shared/include/supported_actions.def index 1b3f48505e..ef4710d386 100644 --- a/src/MapleFE/shared/include/supported_actions.def +++ b/src/MapleFE/shared/include/supported_actions.def @@ -237,5 +237,7 @@ ACTION(AddTypeParameterExtends) ACTION(BuildNameTypePair) +ACTION(BuildTripleSlash) // TS triple-slash directive. + // This is a special action to pass a child to parent ACTION(PassChild) diff --git a/src/MapleFE/shared/include/supported_operators.def b/src/MapleFE/shared/include/supported_operators.def index b09021d0b2..2ffa34dd44 100644 --- a/src/MapleFE/shared/include/supported_operators.def +++ b/src/MapleFE/shared/include/supported_operators.def @@ -81,4 +81,5 @@ OPERATOR(StNe, Binary) OPERATOR(ArrowFunction, Binary) OPERATOR(NullCoalesce, Binary) OPERATOR(NullAssign, Binary) +OPERATOR(TripleSlash, Binary) // triple slash directive diff --git a/src/MapleFE/shared/include/supported_separators.def b/src/MapleFE/shared/include/supported_separators.def index 9257ed97ba..40298b4bb0 100644 --- a/src/MapleFE/shared/include/supported_separators.def +++ b/src/MapleFE/shared/include/supported_separators.def @@ -34,4 +34,3 @@ SEPARATOR(Whitespace) SEPARATOR(Tab) // Horizontal Tab, 0x09 SEPARATOR(ArrowFunction) // first coming from JS, => SEPARATOR(Optional) // first coming from JS, ?. -SEPARATOR(TripleSlash) // first coming from TS, ///, used in triple-slash-directive diff --git a/src/MapleFE/shared/src/ast.cpp b/src/MapleFE/shared/src/ast.cpp index d0772ef409..937d6431c5 100644 --- a/src/MapleFE/shared/src/ast.cpp +++ b/src/MapleFE/shared/src/ast.cpp @@ -2153,4 +2153,30 @@ void InterfaceNode::Dump(unsigned indent) { } } +void TripleSlashNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("trip-slash reference "); + + switch(mProp) { + case TSP_Path: + DUMP0_NORETURN("path = "); + break; + case TSP_Types: + DUMP0_NORETURN("types = "); + break; + case TSP_NoDefaultLib: + DUMP0_NORETURN("no-default-lib = "); + break; + case TSP_Lib: + DUMP0_NORETURN("lib = "); + break; + case TSP_NA: + default: + DUMP0_NORETURN("NA = "); + break; + } + + mValue->Dump(0); +} + } diff --git a/src/MapleFE/shared/src/ast_builder.cpp b/src/MapleFE/shared/src/ast_builder.cpp index 8657146ac7..e715baa5a1 100644 --- a/src/MapleFE/shared/src/ast_builder.cpp +++ b/src/MapleFE/shared/src/ast_builder.cpp @@ -4256,6 +4256,50 @@ TreeNode* ASTBuilder::BuildInfer() { return mLastTreeNode; } +//////////////////////////////////////////////////////////////////////////////// +// Triple Slash Directive of TypeScript +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildTripleSlash() { + if (mTrace) + std::cout << "In BuildTripleSlash" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *left = l_param.mData.mTreeNode; + + Param r_param = mParams[1]; + MASSERT(!r_param.mIsEmpty); + MASSERT(r_param.mIsTreeNode); + TreeNode *right = r_param.mData.mTreeNode; + + TripleSlashNode *tsnode = (TripleSlashNode*)gTreePool.NewTreeNode(sizeof(TripleSlashNode)); + new (tsnode) TripleSlashNode(); + + TripleSlashProp prop = TSP_NA; + if (left->IsIdentifier()) { + // no-default-lib + if ((strlen(left->GetName()) == 14) && !strncmp(left->GetName(), "no-default-lib", 14)) + prop = TSP_NoDefaultLib; + // lib + if ((strlen(left->GetName()) == 3) && !strncmp(left->GetName(), "lib", 3)) + prop = TSP_Lib; + // types + if ((strlen(left->GetName()) == 5) && !strncmp(left->GetName(), "types", 5)) + prop = TSP_Types; + // path + if ((strlen(left->GetName()) == 4) && !strncmp(left->GetName(), "path", 4)) + prop = TSP_Path; + } + tsnode->SetProp(prop); + + tsnode->SetValue(right); + + mLastTreeNode = tsnode; + return mLastTreeNode; +} + //////////////////////////////////////////////////////////////////////////////// // Await //////////////////////////////////////////////////////////////////////////////// diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index 7fc85f25fb..694f86a8ed 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -657,7 +657,9 @@ bool Lexer::TraverseTableData(TableData *data) { // Need to make sure the following text is a separator curidx += strlen(data->mData.mString); if (mCheckSeparator || special_need_check) { - if ((TraverseSepTable() != SEP_NA) || (TraverseOprTable() != OPR_NA)) { + if ((TraverseSepTable() != SEP_NA) || + (TraverseOprTable() != OPR_NA) || + EndOfLine()) { // TraverseSepTable() moves 'curidx', need restore it curidx = old_pos + strlen(data->mData.mString); // Put into gStringPool diff --git a/src/MapleFE/shared/src/parser.cpp b/src/MapleFE/shared/src/parser.cpp index 3a5a118062..ea109fc5f0 100644 --- a/src/MapleFE/shared/src/parser.cpp +++ b/src/MapleFE/shared/src/parser.cpp @@ -798,6 +798,8 @@ void Parser::DumpExitTable(const char *table_name, unsigned indent, std::cout << " fail@WasFailed" << "}" << std::endl; else if (reason == FailNotRightToken) std::cout << " fail@NotRightToken" << "}" << std::endl; + else if (reason == FailNotRightString) + std::cout << " fail@NotRightString" << "}" << std::endl; else if (reason == FailNotIdentifier) std::cout << " fail@NotIdentifer" << "}" << std::endl; else if (reason == FailNotLiteral) @@ -1252,6 +1254,41 @@ bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) } } +// Returns 1. true if succ. +// 2. child_node which represents 'token'. +bool Parser::TraverseStringSucc(Token *token, AppealNode *parent, AppealNode *&child_node) { + AppealNode *appeal = NULL; + mIndentation += 2; + + if (mTraceTable) { + std::string name = "string:"; + name += token->GetName(); + name += " curr_token matches"; + DumpEnterTable(name.c_str(), mIndentation); + } + + appeal = mAppealNodePool.NewAppealNode(); + child_node = appeal; + mAppealNodes.push_back(appeal); + appeal->SetToken(token); + appeal->SetStartIndex(mCurToken); + appeal->SetParent(parent); + parent->AddChild(appeal); + appeal->mResult = Succ; + appeal->AddMatch(mCurToken); + MoveCurToken(); + + if (mTraceTable) { + std::string name; + name = "string:"; + name += token->GetName(); + DumpExitTable(name.c_str(), mIndentation, appeal); + } + + mIndentation -= 2; + return true; +} + // Returns 1. true if succ. // 2. child_node which represents 'token'. bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_node) { @@ -1798,10 +1835,14 @@ bool Parser::TraverseTableData(TableData *data, AppealNode *appeal, AppealNode * switch (data->mType) { case DT_Char: + MASSERT(0 && "Hit Char in TableData during matching!"); + break; case DT_String: - //MASSERT(0 && "Hit Char/String in TableData during matching!"); - //TODO: Need compare literal. But so far looks like it's impossible to - // have a literal token able to match a string/char in rules. + if (curr_token->IsIdentifier() && + !strncmp(curr_token->GetName(), data->mData.mString, strlen(data->mData.mString)) && + strlen(curr_token->GetName()) == strlen(data->mData.mString) ){ + found = TraverseStringSucc(curr_token, appeal, child_node); + } break; // separator, operator, keywords are generated as DT_Token. // just need check the pointer of token diff --git a/src/MapleFE/shared/src/vfy.cpp b/src/MapleFE/shared/src/vfy.cpp index cb03fb5439..02a87ff57b 100644 --- a/src/MapleFE/shared/src/vfy.cpp +++ b/src/MapleFE/shared/src/vfy.cpp @@ -568,4 +568,8 @@ void Verifier::VerifyArrayType(ArrayTypeNode *tree){ return; } +void Verifier::VerifyTripleSlash(TripleSlashNode *tree){ + return; +} + } diff --git a/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result index 42db4d50cd..c71e900f9a 100644 --- a/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result +++ b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result @@ -1,7 +1,10 @@ -Matched 7 tokens. -Matched 14 tokens. +Matched 8 tokens. +Matched 15 tokens. +Matched 22 tokens. ============= Module =========== == Sub Tree == +trip-slash reference path = "import-in-module.ts" +== Sub Tree == import {X} "M1" == Sub Tree == import {NS} "M2" diff --git a/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result index f9052bd4b2..0e74c743cd 100644 --- a/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result +++ b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result @@ -1 +1,7 @@ +Matched 8 tokens. +Matched 16 tokens. ============= Module =========== +== Sub Tree == +trip-slash reference no-default-lib = "true" +== Sub Tree == +trip-slash reference lib = "es5" diff --git a/src/MapleFE/typescript/identifier.spec b/src/MapleFE/typescript/identifier.spec index 6cfe3baf6e..5723b480b3 100644 --- a/src/MapleFE/typescript/identifier.spec +++ b/src/MapleFE/typescript/identifier.spec @@ -16,4 +16,5 @@ # rule JavaChar : ONEOF(CHAR, '_' , '$') rule CharOrDigit : ONEOF(JavaChar, DIGIT) -rule Identifier : JavaChar + ZEROORMORE(CharOrDigit) +rule Identifier : ONEOF("no-default-lib", + JavaChar + ZEROORMORE(CharOrDigit)) diff --git a/src/MapleFE/typescript/operator.spec b/src/MapleFE/typescript/operator.spec index 48d5037f5a..d09db223d3 100644 --- a/src/MapleFE/typescript/operator.spec +++ b/src/MapleFE/typescript/operator.spec @@ -72,5 +72,8 @@ STRUCT Operator : ( ("|=", BorAssign), ("^=", BxorAssign), (">>>=", ZextAssign), + + ("///", TripleSlash), + # arrow function ("=>", ArrowFunction)) diff --git a/src/MapleFE/typescript/separator.spec b/src/MapleFE/typescript/separator.spec index 9804f9b97f..b06a949337 100644 --- a/src/MapleFE/typescript/separator.spec +++ b/src/MapleFE/typescript/separator.spec @@ -42,5 +42,4 @@ STRUCT Separator : ((" ", Whitespace), ("?.",Optional), ("@", At), ("#", Pound), - ("\t", Tab), - ("///", TripleSlash)) + ("\t", Tab)) diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index 0c0af20afa..54a95b6c35 100644 --- a/src/MapleFE/typescript/src/lang_spec.cpp +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -396,21 +396,21 @@ bool TypescriptLexer::FindNextTLPlaceHolder(unsigned start_idx, std::string& str // This is to catch TS triple-slash directives : /// ', + "///" + '<' + "reference" + "types" + '=' + Literal + '/' + '>', + "///" + '<' + "reference" + "lib" + '=' + Literal + '/' + '>', + "///" + '<' + "reference" + "no-default-lib" + '=' + Literal + '/' + '>') + attr.action.%1,%2,%3,%4 : BuildTripleSlash(%4, %6) + ##----------------------------------- ##rule Statement[Yield, Return] : ## BlockStatement[?Yield, ?Return] @@ -820,7 +826,8 @@ rule Statement : ONEOF( # WithStatement[?Yield, ?Return] LabelledStatement, ThrowStatement, - TryStatement) + TryStatement, + TripleSlash) # DebuggerStatement attr.property : Top attr.property : Single # This is extremely important to give CallExpression the -- Gitee From bc6411a2a8bf4f1d9ac242abcb1351723f3f35f3 Mon Sep 17 00:00:00 2001 From: eching Date: Thu, 24 Feb 2022 02:18:28 -0800 Subject: [PATCH 16/20] Emit C++ definition for generator class. Refactor function class generation to use common interface in commit 146feddc for function parameter info. --- src/MapleFE/ast2cpp/include/cpp_declaration.h | 2 - src/MapleFE/ast2cpp/include/cpp_emitter.h | 2 + src/MapleFE/ast2cpp/include/helper.h | 5 +- src/MapleFE/ast2cpp/src/cpp_declaration.cpp | 67 +++++------- src/MapleFE/ast2cpp/src/cpp_definition.cpp | 14 ++- src/MapleFE/ast2cpp/src/cpp_emitter.cpp | 8 ++ src/MapleFE/ast2cpp/src/helper.cpp | 103 +++++++++++++++++- 7 files changed, 152 insertions(+), 49 deletions(-) diff --git a/src/MapleFE/ast2cpp/include/cpp_declaration.h b/src/MapleFE/ast2cpp/include/cpp_declaration.h index fcf6b61c32..9a5c3690e3 100644 --- a/src/MapleFE/ast2cpp/include/cpp_declaration.h +++ b/src/MapleFE/ast2cpp/include/cpp_declaration.h @@ -36,8 +36,6 @@ public: return EmitTreeNode(GetASTModule()); } - std::string GenFunctionClass(FunctionNode* node); - void AddImportedModule(const std::string& module); bool IsImportedModule(const std::string& module); diff --git a/src/MapleFE/ast2cpp/include/cpp_emitter.h b/src/MapleFE/ast2cpp/include/cpp_emitter.h index 74d81734fd..6de6325525 100644 --- a/src/MapleFE/ast2cpp/include/cpp_emitter.h +++ b/src/MapleFE/ast2cpp/include/cpp_emitter.h @@ -34,6 +34,8 @@ public: bool IsClassId(TreeNode *node); bool IsVarTypeClass(TreeNode* var); void InsertEscapes(std::string& str); + bool IsGenerator(TreeNode *node); + FunctionNode* GetGeneratorFunc(TreeNode *node); }; } // namespace maplefe diff --git a/src/MapleFE/ast2cpp/include/helper.h b/src/MapleFE/ast2cpp/include/helper.h index 297d57f407..47c543d71e 100644 --- a/src/MapleFE/ast2cpp/include/helper.h +++ b/src/MapleFE/ast2cpp/include/helper.h @@ -34,8 +34,9 @@ extern std::unordered_mapTypeIdToJSType; extern std::unordered_mapTypeIdToJSTypeCXX; extern TypeId hlpGetTypeId(TreeNode* node); extern std::string GenClassFldAddProp(std::string, std::string, std::string, std::string, std::string); -extern std::string FunctionTemplate(std::string retType, std::string funcName, std::string params, std::string args); -extern std::string GenGeneratorClass(std::string funcName, std::vector>args); +extern std::string FunctionClassDecl(std::string retType, std::string funcName, unsigned nodeId); +extern std::string GeneratorClassDecl(std::string funcName, unsigned nodeId); +extern std::string GeneratorClassDef(std::string ns, std::string funcName, unsigned nodeId); extern std::string tab(int n); extern bool IsClassMethod(TreeNode* node); extern std::string GetClassOfAssignedFunc(TreeNode* node); diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index 96a1e654b0..8b80ce0cc2 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -327,28 +327,6 @@ bool CppDecl::IsImportedModule(const std::string& module) { return res != mImportedModules.end(); } -// Generate class to encap TS/JS required func interfaces -// note: for top level and nested functions only. Not for class methods. -std::string CppDecl::GenFunctionClass(FunctionNode* node) { - std::string params, args, retType; - for (unsigned i = 0; i < node->GetParamsNum(); ++i) { - if (i) { - params += ", "s; - args += ", "s; - } - if (auto n = node->GetParam(i)) { - params += EmitTreeNode(n); - args += GetIdentifierName(n); - if (i==0) - HandleThisParam(node->GetParamsNum(), n, params, args); - } - } - if (node->GetParamsNum() == 0) - HandleThisParam(0, nullptr, params, args); - - return FunctionTemplate(GetTypeString(node->GetType(), nullptr), GetIdentifierName(node), params, args); -} - void CppDecl::CollectFuncArgInfo(TreeNode* node) { if (!node->IsFunction()) return; @@ -403,26 +381,34 @@ namespace )""" + module + R"""( { for(unsigned i = 0; i < num; ++i) { CfgFunc *func = mod->GetNestedFuncAtIndex(i); TreeNode *node = func->GetFuncNode(); + std::string funcName = GetIdentifierName(node); + if (!IsClassMethod(node)) { - bool isGenerator = static_cast(node)->IsGenerator(); - CollectFuncArgInfo(node); std::string ns = GetNamespace(node); if (!ns.empty()) str += "namespace "s + ns + " {\n"s; - if (isGenerator) - str += GenGeneratorClass(GetIdentifierName(node), hFuncTable.GetArgInfo(node->GetNodeId())); - else - str += GenFunctionClass(static_cast(node)); // gen func cls for each top level func + CollectFuncArgInfo(node); + bool isGenerator = static_cast(node)->IsGenerator(); + std::string generatorClassDef; + if (isGenerator) { + str += GeneratorClassDecl(funcName, node->GetNodeId()); + generatorClassDef = GeneratorClassDef(ns, funcName, node->GetNodeId()); + AddDefinition(generatorClassDef); + } + else { + // gen function class for each top level function + str += FunctionClassDecl(GetTypeString(static_cast(node)->GetType(), nullptr), GetIdentifierName(node), node->GetNodeId()); + } if (!mHandler->IsFromLambda(node)) { // top level funcs instantiated here as function objects from their func class // top level lamda funcs instantiated later in assignment stmts - std::string typeName = isGenerator? GeneratorFuncName(node->GetName()): ClsName(node->GetName()); - std::string funcinit = typeName + "* "s + node->GetName() + " = new "s + typeName + "();\n"s; + std::string typeName = isGenerator? GeneratorFuncName(funcName): ClsName(funcName); + std::string funcinit = typeName + "* "s + funcName + " = new "s + typeName + "();\n"s; if (ns.empty()) AddDefinition(funcinit); else AddDefinition("namespace "s + ns + " {\n"s + funcinit + "\n}\n"s); - str += "extern "s + typeName + "* "s + node->GetName() + ";\n"s; + str += "extern "s + typeName + "* "s + funcName + ";\n"s; } if (!ns.empty()) str += "\n} // namespace " + ns + '\n'; @@ -657,6 +643,10 @@ std::string GetUserTypeString(UserTypeNode* n) { std::string CppDecl::GetTypeString(TreeNode *node, TreeNode *child) { std::string str; if (node) { + if (IsGenerator(node)) { // check generator type + if (auto func = GetGeneratorFunc(node)) + return GeneratorName(GetIdentifierName(func)) + "*"s; + } TypeId k = node->GetTypeId(); if (k == TY_None || k == TY_Class) { switch(node->GetKind()) { @@ -706,11 +696,6 @@ std::string CppDecl::GetTypeString(TreeNode *node, TreeNode *child) { if (str != "none"s) return str + " "s; } - if (mHandler->IsGeneratorUsed(node->GetNodeId())) { - // check if generator type - if (auto func = mHandler->GetGeneratorUsed(node->GetNodeId())) - return GeneratorName(GetIdentifierName(func)) + "*"s; - } } return "t2crt::JS_Val "s; } @@ -727,8 +712,14 @@ std::string CppDecl::EmitUserTypeNode(UserTypeNode *node) { std::string str, usrType; if (auto n = node->GetId()) { - if (n->IsTypeIdClass()) - usrType = n->GetName() + "*"s; + if (n->IsTypeIdClass()) { + if (mHandler->IsGeneratorUsed(n->GetNodeId())) { + // Check if a generator type : TODO: this needs TI + auto func = mHandler->GetGeneratorUsed(n->GetNodeId()); + usrType = GetIdentifierName(func) + "*"s; + } else + usrType = n->GetName() + "*"s; + } else if (IsBuiltinObj(n->GetName())) usrType = "t2crt::"s + n->GetName() + "*"s; else // TypeAlias Id gets returned here diff --git a/src/MapleFE/ast2cpp/src/cpp_definition.cpp b/src/MapleFE/ast2cpp/src/cpp_definition.cpp index 6ac4cfd415..098ffd00b0 100644 --- a/src/MapleFE/ast2cpp/src/cpp_definition.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_definition.cpp @@ -273,6 +273,10 @@ std::string CppDef::EmitFunctionNode(FunctionNode *node) { std::string str, className, ns = GetNamespace(node); if (!ns.empty()) ns += "::"s; + + if (node->IsGenerator()) { + // TODO + } if (node->IsConstructor()) { className = ns + GetClassName(node); str = "\n"s; @@ -547,6 +551,13 @@ std::string CppDef::EmitDeclNode(DeclNode *node) { // For func var of JS_Let/JS_Const, emit both var type & name if (auto n = node->GetVar()) { varType = n->GetTypeId(); +#if 1 + if (varType == TY_None) { + // TODO: remove this workaround when the var type is corrected in AST + if (IsGenerator(n)) + varType = TY_Class; + } +#endif if (mIsInit || node->GetProp() == JS_Var) { // handle declnode inside for-of/for-in (uses GetSet() and has null GetInit()) if (!node->GetInit() && node->GetParent() && !node->GetParent()->IsForLoop()) @@ -572,9 +583,8 @@ std::string CppDef::EmitDeclNode(DeclNode *node) { hFuncTable.AddNameIsTopLevelFunc(varStr); } } else { - // if no type info, assume type is any and wrap initializer in JS_Val. str += varStr + " = "; - if (varType == TY_None) + if (varType == TY_None) // no type info. assume TY_Any and wrap val in JS_Val str += "t2crt::JS_Val("s + EmitTreeNode(n) + ")"s; else str += EmitTreeNode(n); diff --git a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp index ab730ccb84..c4fe55f87d 100644 --- a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp @@ -126,4 +126,12 @@ void CppEmitter::InsertEscapes(std::string& str) { Emitter::Replace(str, "\"", "\\\"", 0); } +bool CppEmitter::IsGenerator(TreeNode* node) { + return mHandler->IsGeneratorUsed(node->GetNodeId()); +} + +FunctionNode* CppEmitter::GetGeneratorFunc(TreeNode* node) { + return mHandler->GetGeneratorUsed(node->GetNodeId()); +} + } // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/helper.cpp b/src/MapleFE/ast2cpp/src/helper.cpp index 5ee7e1b5f9..4b01b7891b 100644 --- a/src/MapleFE/ast2cpp/src/helper.cpp +++ b/src/MapleFE/ast2cpp/src/helper.cpp @@ -108,19 +108,66 @@ std::string GenClassFldAddProp(std::string objName, // for ctor(), it calls _body() but ignores return val from _body(), and instead returns _this // per TS/JS spec. -std::string FunctionTemplate(std::string retType, std::string funcName, std::string params, std::string args) { +std::string FunctionClassDecl(std::string retType, std::string funcName, unsigned nodeId) { + std::vector> funcParams = hFuncTable.GetArgInfo(nodeId); + std::string args, params; + std::string t2cObjType = "t2crt::Object*"; + std::string thisType = t2cObjType; + + // Map TS function paramters to C++ interface args and params: + // + // TS2cpp's C++ mapping for TS func has a "this" obj in the c++ func param list + // which will be generated from AST if "this" is declared as a TS func parameter + // as required by TS strict mode. However TS funcs that do not reference 'this' + // are not required to declare it, in which case emitter has to insert one. + // + // Cases: + // o if TS func has no param + // - insert param "ts2crt::Object* _this" + // o if 1st TS func param is not "this" + // - insert param "ts2crt::Object* _this" + // o if 1st TS func param is "this" + // - rename to "_this" + // - if type is Any (JS_Val), change to "ts2crt::Object*" + + if (funcParams.size() == 0) { + // TS func has no param. Insert _this for ts2cpp mapping. + params += t2cObjType + " "s + "_this"s; + args += "_this"s; + } + for (bool firstParam=true; auto elem : funcParams) { + std::string type = elem.first, name = elem.second; + if (!firstParam) { // not 1st param + params+= ", "s; + args += ", "s; + } else { // 1st param of TS func + firstParam = false; + if (name.compare("this") != 0) { + // 1st TS param not "this" - insert _this parameter + params += t2cObjType + " "s + "_this"s + ", "s; + args += "_this"s + ", "s; + thisType = t2cObjType; + } else { + // 1st TS param is "this" - change to "_this" + name = "_this"; + if (type.compare("t2crt::JS_Val") == 0) + type = t2cObjType; // change type Any to Object* + thisType = type; + } + } + params += type + " "s + name; + args += name; + } std::string str; std::string clsName = ClsName(funcName); std::string functorArgs = args; std::string functorParams = params; - std::string thisType; functorArgs.replace(0, 5, "_thisArg"); // replace _this with _thisArg size_t pos; if ((pos = functorParams.find("_this, ")) != std::string::npos) functorParams.erase(0, pos+7); else if ((pos = functorParams.find("_this")) != std::string::npos) functorParams.erase(0, pos+5); - thisType = params.substr(0, pos-1); str = R"""( class )""" + clsName + R"""( : public t2crt::Function { @@ -149,10 +196,11 @@ class )""" + clsName + R"""( : public t2crt::Function { // Template for generating Generators and Generator Functions: // For each TS generator function, 2 C++ classes: generator and generator function are emitted. // The generator function has only a single instance. It is called to create generator instances. -std::string GenGeneratorClass(std::string funcName, std::vector> args) { +std::string GeneratorClassDecl(std::string funcName, unsigned nodeId) { std::string str; std::string generatorName = GeneratorName(funcName); std::string generatorFuncName = GeneratorFuncName(funcName); + std::vector> args = hFuncTable.GetArgInfo(nodeId); // Different formats of arg list as needed by generator and generator function interfaces: // - args for function class functor and generation class constructor @@ -191,7 +239,7 @@ public: // closure capture fields )""" + captureFields + R"""( // iterator interface (override _return and _throw when needed) - t2crt::IteratorResult _next(t2crt::JS_Val* arg) override; + t2crt::IteratorResult _next(t2crt::JS_Val* arg = nullptr) override; }; // )""" + funcName + R"""( generator function @@ -210,6 +258,51 @@ public: return str; } +std::string GeneratorClassDef(std::string ns, std::string funcName, unsigned nodeId) { + std::string str, params, ctorArgs, functorArgs; + std::string generatorName = ns + GeneratorName(funcName); + std::string generatorFuncName = ns + GeneratorFuncName(funcName); + std::vector> args = hFuncTable.GetArgInfo(nodeId); + + if (!ns.empty()) + funcName = ns + "::" + funcName; + for (bool hasArg=false; auto elem : args) { + if (!hasArg) + hasArg = true; + else { + functorArgs += ", "s; + params += ", "s; + } + functorArgs += elem.first + " " + elem.second; //1st=type 2nd=name + params += " " + elem.second; + } + ctorArgs = functorArgs.empty()? std::string(): (", "s + functorArgs); + params = params.empty()? std::string(): (", "s + params); + + str = R"""( +t2crt::IteratorResult )""" + generatorName + R"""(::_next(t2crt::JS_Val* arg) { + t2crt::IteratorResult res; + + if (_finished) { + res._done = true; + return res; + } + + // iterate by calling generation function with captures in generator + res = foo->_body(this, _yield)""" + params + R"""(); + if (res._done == true) + _finished = true; + return res; +} + +)""" + generatorName + "* "s + generatorFuncName + R"""(::operator()()""" + functorArgs + R"""() { + return new )""" + generatorName + R"""((&t2crt::Generator, foo->prototype)""" + params + R"""(); +} + +)"""; + return str; +} + bool IsClassMethod(TreeNode* node) { return(node->IsFunction() && node->GetParent() && node->GetParent()->IsClass()); } -- Gitee From 37256ff7d81b73fa1f9f96d025da4df10f477f2f Mon Sep 17 00:00:00 2001 From: eching Date: Thu, 24 Feb 2022 04:50:47 -0800 Subject: [PATCH 17/20] Fix regression caused by commit 37160b8d. --- src/MapleFE/ast2cpp/src/cpp_declaration.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index 8b80ce0cc2..154ea8e854 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -897,12 +897,9 @@ std::string CppDecl::EmitInterface(StructNode *node) { if (superClass.back() == '*') superClass.pop_back(); } - - if (auto n = node->GetStructId()) { - ifName = GetIdentifierName(n); - str = "class "s + ifName + " : public "s + superClass + " {\n"s; - } - str += " public:\n"s; + ifName = node->GetName(); + str = "class "s + ifName + " : public "s + superClass + " {\n"s; + str += " public:\n"s; // Generate code to add prop in class constructor for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { -- Gitee From eb032cdd220f13dfc4a2b0be10e173f1dca05c48 Mon Sep 17 00:00:00 2001 From: Wen HU Date: Thu, 24 Feb 2022 13:25:17 -0500 Subject: [PATCH 18/20] only set TY_Class for non-enum --- src/MapleFE/astopt/src/ast_ti.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MapleFE/astopt/src/ast_ti.cpp b/src/MapleFE/astopt/src/ast_ti.cpp index 4ca2aed22d..13c0256111 100644 --- a/src/MapleFE/astopt/src/ast_ti.cpp +++ b/src/MapleFE/astopt/src/ast_ti.cpp @@ -1823,7 +1823,10 @@ UserTypeNode *TypeInferVisitor::VisitUserTypeNode(UserTypeNode *node) { SetTypeId(node, TY_Array); SetTypeIdx(node, TY_Array); } else if (node->GetId()) { - SetTypeId(node, TY_Class); + // non-enum user type which keep TY_None + if (node->GetId()->GetTypeId() != TY_None) { + SetTypeId(node, TY_Class); + } UpdateTypeIdx(node, node->GetId()); } TreeNode *parent = node->GetParent(); -- Gitee From 821eb0626027d61c13e7f81aaef418a995451a81 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Thu, 24 Feb 2022 11:25:44 -0800 Subject: [PATCH 19/20] Handle newly-added TripleSlashNode in emitter --- src/MapleFE/ast2cpp/include/emitter.h | 4 ++- src/MapleFE/ast2cpp/src/emitter.cpp | 51 ++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/MapleFE/ast2cpp/include/emitter.h b/src/MapleFE/ast2cpp/include/emitter.h index 7ad2b1e895..59178b2881 100644 --- a/src/MapleFE/ast2cpp/include/emitter.h +++ b/src/MapleFE/ast2cpp/include/emitter.h @@ -120,11 +120,12 @@ public: virtual std::string EmitAwaitNode(AwaitNode *node); virtual std::string EmitNameTypePairNode(NameTypePairNode *node); virtual std::string EmitTupleTypeNode(TupleTypeNode *node); + virtual std::string EmitTripleSlashNode(TripleSlashNode *node); virtual std::string EmitModuleNode(ModuleNode *node); virtual std::string EmitAttrNode(AttrNode *node); + virtual std::string EmitArrayTypeNode(ArrayTypeNode *node); virtual std::string EmitPrimTypeNode(PrimTypeNode *node); virtual std::string EmitPrimArrayTypeNode(PrimArrayTypeNode *node); - virtual std::string EmitArrayTypeNode(ArrayTypeNode *node); virtual std::string EmitTreeNode(TreeNode *node); virtual std::string& HandleTreeNode(std::string &str, TreeNode *node); @@ -141,6 +142,7 @@ public: //static const char *GetEnumStructProp(StructProp k); //static const char *GetEnumForLoopProp(ForLoopProp k); //static const char *GetEnumLambdaProperty(LambdaProperty k); + const char *GetEnumTripleSlashProp(TripleSlashProp k); std::string &AddParentheses(std::string &str, TreeNode *node); }; diff --git a/src/MapleFE/ast2cpp/src/emitter.cpp b/src/MapleFE/ast2cpp/src/emitter.cpp index e4926858fa..3ae234f9db 100644 --- a/src/MapleFE/ast2cpp/src/emitter.cpp +++ b/src/MapleFE/ast2cpp/src/emitter.cpp @@ -45,7 +45,8 @@ std::string Emitter::GetEnding(TreeNode *n) { std::string str; switch(n->GetKind()) { case NK_Function: - str = "\n"s; + case NK_TripleSlash: + str += '\n'; break; default: str += ';'; @@ -60,7 +61,7 @@ std::string Emitter::GetEnding(TreeNode *n) { case NK_Namespace: case NK_Declare: case NK_Module: - str += "\n"s; + str += '\n'; } return str; } @@ -1925,6 +1926,19 @@ std::string Emitter::EmitTupleTypeNode(TupleTypeNode *node) { mPrecedence = '\030'; return str; } + +std::string Emitter::EmitTripleSlashNode(TripleSlashNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + str += "/// GetProp()); + if (auto n = node->GetValue()) { + str += '=' + EmitTreeNode(n); + } + str += " />"s; + return str; +} + std::string Emitter::EmitModuleNode(ModuleNode *node) { if (node == nullptr) return std::string(); @@ -1953,6 +1967,12 @@ std::string Emitter::EmitAttrNode(AttrNode *node) { return HandleTreeNode(str, node); } +std::string Emitter::EmitArrayTypeNode(ArrayTypeNode *node) { + // TODO + std::string str = ""; + return str; +} + std::string Emitter::EmitPrimTypeNode(PrimTypeNode *node) { if (node == nullptr) return std::string(); @@ -1986,12 +2006,6 @@ std::string Emitter::EmitPrimArrayTypeNode(PrimArrayTypeNode *node) { return HandleTreeNode(str, node); } -std::string Emitter::EmitArrayTypeNode(ArrayTypeNode *node) { - // TODO - std::string str = ""; - return str; -} - std::string Emitter::EmitTreeNode(TreeNode *node) { if (node == nullptr) return std::string(); @@ -2140,6 +2154,9 @@ std::string Emitter::EmitTreeNode(TreeNode *node) { case NK_Infer: return EmitInferNode(static_cast(node)); break; + case NK_TripleSlash: + return EmitTripleSlashNode(static_cast(node)); + break; case NK_Block: return EmitBlockNode(static_cast(node)); break; @@ -2405,4 +2422,22 @@ const char *Emitter::GetEnumOprId(OprId k) { return "UNEXPECTED OprId"; } +const char *Emitter::GetEnumTripleSlashProp(TripleSlashProp k) { + switch (k) { + case TSP_Path: + return "path"; + case TSP_Types: + return "types"; + case TSP_Lib: + return "lib"; + case TSP_NoDefaultLib: + return "no-default-lib"; + case TSP_NA: + return "TSP_NA"; + default: + MASSERT(0 && "Unexpected enumerator"); + } + return "UNEXPECTED TripleSlashProp"; +} + } // namespace maplefe -- Gitee From 37d96c6ff6a41effa606160a834d7ff9868a3bd1 Mon Sep 17 00:00:00 2001 From: eching Date: Thu, 24 Feb 2022 13:24:02 -0800 Subject: [PATCH 20/20] Handle both named and un-named StructNode in GetIdentifierName(). --- src/MapleFE/ast2cpp/src/cpp_declaration.cpp | 6 +++--- src/MapleFE/ast2cpp/src/cpp_emitter.cpp | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index 154ea8e854..8119e39ff3 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -897,9 +897,9 @@ std::string CppDecl::EmitInterface(StructNode *node) { if (superClass.back() == '*') superClass.pop_back(); } - ifName = node->GetName(); - str = "class "s + ifName + " : public "s + superClass + " {\n"s; - str += " public:\n"s; + ifName = GetIdentifierName(node); + str = "class "s + ifName + " : public "s + superClass + " {\n"s; + str += " public:\n"s; // Generate code to add prop in class constructor for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { diff --git a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp index c4fe55f87d..b791306fa2 100644 --- a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp @@ -26,7 +26,13 @@ std::string CppEmitter::GetIdentifierName(TreeNode *node) { case NK_Decl: return GetIdentifierName(static_cast(node)->GetVar()); case NK_Struct: - return GetIdentifierName(static_cast(node)->GetStructId()); + // Named StructNode has name in StructId. Unamed StructNode is assigned + // anonymous name by frontend and can be accessed using node mStrIdx + // through node GetName() interface. + if (auto n = static_cast(node)->GetStructId()) + return GetIdentifierName(n); + else + return node->GetName(); // for anonomyous name case NK_Function: if (static_cast(node)->GetFuncName()) return GetIdentifierName(static_cast(node)->GetFuncName()); -- Gitee