diff --git a/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h b/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h index 5a5cd376fd09a3569d811ee550735576223aedf4..6cd956c2e1d6ff5353c4bfc2c8cdd855d0ff1b6d 100644 --- a/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h +++ b/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h @@ -24,9 +24,6 @@ #include #include -// Copied from astopt/include/ast_adj.h -#define RENAMINGSUFFIX "__RENAMED" - using namespace std::string_literals; namespace t2crt { diff --git a/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp index 4820cf09291685f64ec666948430893c35d36fbb..1fa036b3af6abfe5822658fdc80dbd882d9bfdd6 100644 --- a/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp +++ b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp @@ -1,6 +1,7 @@ #include #include #include "../include/ts2cpp.h" +#include "ast_common.h" std::ostream& operator<< (std::ostream& out, const t2crt::JS_Val& v) { switch(v.type) { diff --git a/src/MapleFE/ast2cpp/src/ast2cpp.cpp b/src/MapleFE/ast2cpp/src/ast2cpp.cpp index 9f503460c0715c830a9f41b7ea133a5927b3789b..449e4b9c17caeb49da0feb1e037cf51a99b2ade2 100644 --- a/src/MapleFE/ast2cpp/src/ast2cpp.cpp +++ b/src/MapleFE/ast2cpp/src/ast2cpp.cpp @@ -172,13 +172,13 @@ int A2C::ProcessAST() { if (mFlags & FLG_trace_2) { std::cout << "============= AstGraph ===========" << std::endl; AstGraph graph(module); - graph.DumpGraph("After BuildCFG()", &std::cout); + graph.DumpGraph("After TypeInference()", &std::cout); } if (mFlags & FLG_trace_2) { std::cout << "============= AstDump ===========" << std::endl; AstDump astdump(module); - astdump.Dump("After BuildCFG()", &std::cout); + astdump.Dump("After TypeInference()", &std::cout); } // data flow analysis diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index f2cc18da6152e174f40bca84cb2cff2e24412e4e..8272ffefe62277c9c020bd21c1f3f1fd682cf961 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -18,7 +18,7 @@ #include #include #include "helper.h" -#include "ast_adj.h" +#include "ast_common.h" namespace maplefe { diff --git a/src/MapleFE/astopt/include/ast_adj.h b/src/MapleFE/astopt/include/ast_adj.h index 025ae5d8c1565e975d849cc3405fd6c11cec11cc..0f1f2bce9848d11a84f8472817acccd32d5a6671 100644 --- a/src/MapleFE/astopt/include/ast_adj.h +++ b/src/MapleFE/astopt/include/ast_adj.h @@ -40,9 +40,6 @@ class AST_ADJ { void AdjustAST(); }; -// If you change RENAMINGSUFFIX, you have to update ast2cpp/runtime/include/ts2cpp.h as well -#define RENAMINGSUFFIX "__RENAMED" - class AdjustASTVisitor : public AstVisitor { private: Module_Handler *mHandler; diff --git a/src/MapleFE/astopt/include/ast_common.h b/src/MapleFE/astopt/include/ast_common.h index d479cf5c66e92a3b03d7d2836da803cc432501f7..7c25f1ca9f1e7553c799aefcba22a8f93d64c638 100644 --- a/src/MapleFE/astopt/include/ast_common.h +++ b/src/MapleFE/astopt/include/ast_common.h @@ -18,6 +18,9 @@ namespace maplefe { +#define DEFAULTVALUE 0xdeadbeef +#define RENAMINGSUFFIX "__RENAMED" + #define NOTYETIMPL(M) { if (mFlags & FLG_trace) { MNYI(M); }} #define MSGNOLOC0(M) { if (mFlags & FLG_trace_3) { MMSGNOLOC0(M); }} #define MSGNOLOC(M,v) { if (mFlags & FLG_trace_3) { MMSGNOLOC(M,v); }} diff --git a/src/MapleFE/astopt/include/ast_handler.h b/src/MapleFE/astopt/include/ast_handler.h index a6d6dedec6d5cae76ff708c1e5c02101e9e4c277..d6ca33098d4699f655494c3e1cb8d3fbff4b87dd 100644 --- a/src/MapleFE/astopt/include/ast_handler.h +++ b/src/MapleFE/astopt/include/ast_handler.h @@ -31,8 +31,6 @@ #include "ast_common.h" #include "gen_astvisitor.h" -#define DEFAULTVALUE 0xdeadbeef - namespace maplefe { class CfgBB; diff --git a/src/MapleFE/astopt/include/ast_scp.h b/src/MapleFE/astopt/include/ast_scp.h index df514cd4c4f9ec39ca9f1c681a3d909af5902e4f..46a4266dfa1e5dda737a15b42532ab75c69605cb 100644 --- a/src/MapleFE/astopt/include/ast_scp.h +++ b/src/MapleFE/astopt/include/ast_scp.h @@ -114,6 +114,7 @@ class BuildScopeVisitor : public BuildScopeBaseVisitor { LambdaNode *VisitLambdaNode(LambdaNode *node); ClassNode *VisitClassNode(ClassNode *node); StructNode *VisitStructNode(StructNode *node); + StructLiteralNode *VisitStructLiteralNode(StructLiteralNode *node); InterfaceNode *VisitInterfaceNode(InterfaceNode *node); NamespaceNode *VisitNamespaceNode(NamespaceNode *node); ForLoopNode *VisitForLoopNode(ForLoopNode *node); diff --git a/src/MapleFE/astopt/include/ast_ti.h b/src/MapleFE/astopt/include/ast_ti.h index 4e7897d34512cbb2575d1a20559e6dbc7655554a..d68659824380d5305909a8f04a9c71a880c92129 100644 --- a/src/MapleFE/astopt/include/ast_ti.h +++ b/src/MapleFE/astopt/include/ast_ti.h @@ -63,6 +63,7 @@ class BuildIdDirectFieldVisitor : public AstVisitor { ~BuildIdDirectFieldVisitor() = default; FieldNode *VisitFieldNode(FieldNode *node); + FieldLiteralNode *VisitFieldLiteralNode(FieldLiteralNode *node); ArrayElementNode *VisitArrayElementNode(ArrayElementNode *node); void Dump(); }; @@ -136,11 +137,15 @@ class TypeInferVisitor : public TypeInferBaseVisitor { void SetUpdated(bool b = true) {mUpdated = b;} void SetTypeId(TreeNode *node, TypeId tid); - void SetTypeIdx(TreeNode *node, unsigned tidx); + void SetTypeId(TreeNode *node1, TreeNode *node2); void UpdateTypeId(TreeNode *node, TypeId tid); void UpdateTypeId(TreeNode *node1, TreeNode *node2); + + void SetTypeIdx(TreeNode *node, unsigned tidx); + void SetTypeIdx(TreeNode *node1, TreeNode *node2); void UpdateTypeIdx(TreeNode *node, unsigned tidx); void UpdateTypeIdx(TreeNode *node1, TreeNode *node2); + void UpdateFuncRetTypeId(FunctionNode *node, TypeId tid, unsigned tidx); void UpdateTypeUseNode(TreeNode *target, TreeNode *input); void UpdateArgArrayDecls(unsigned nid, TypeId tid); diff --git a/src/MapleFE/astopt/include/ast_xxport.h b/src/MapleFE/astopt/include/ast_xxport.h index 27b94f7529fe44e069e04797b4414b141da6f383..bd5014f29a255d0824ccf03abab9d1ba932e3441 100644 --- a/src/MapleFE/astopt/include/ast_xxport.h +++ b/src/MapleFE/astopt/include/ast_xxport.h @@ -139,6 +139,9 @@ class AST_XXport { // hidx is the handler index of node with index nid TreeNode *GetExportedNodeFromImportedNode(unsigned hidx, unsigned nid); + // get identifier from node + TreeNode *GetIdentifier(TreeNode *node); + void Dump(); }; diff --git a/src/MapleFE/astopt/src/ast_handler.cpp b/src/MapleFE/astopt/src/ast_handler.cpp index 35dc32a627b54bbcf0501c8dea52a13645ffe853..4d647bbdeeb53aac2c7818d2881f050bd47263be 100644 --- a/src/MapleFE/astopt/src/ast_handler.cpp +++ b/src/MapleFE/astopt/src/ast_handler.cpp @@ -195,8 +195,7 @@ TreeNode *Module_Handler::FindDecl(IdentifierNode *node, bool deep) { mNodeId2Decl[nid] = decl; } - if (deep && decl && !decl->IsTypeIdModule() && - GetASTXXport()->IsImportedDeclId(mHidx, decl->GetNodeId())) { + if (deep && decl && GetASTXXport()->IsImportedDeclId(mHidx, decl->GetNodeId())) { decl = GetASTXXport()->GetExportedNodeFromImportedNode(mHidx, decl->GetNodeId()); } diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 1f49b955d1a1016b9169a586d144ebdb94982c0c..a11790d4b41af6029ff75f7daee36526e4b0bd9a 100644 --- a/src/MapleFE/astopt/src/ast_scp.cpp +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -120,6 +120,13 @@ void BuildScopeVisitor::AddTypeAndDecl(ASTScope *scope, TreeNode *node) { AddDecl(scope, node); } +#define ADD_DECL(K) {\ + TreeNode *node = mHandler->NewTreeNode(); \ + unsigned idx = gStringPool.GetStrIdx(K); \ + node->SetStrIdx(idx); \ + AddDecl(scope, node); \ +} + void BuildScopeVisitor::InitInternalTypes() { // add primitive and builtin types to root scope ModuleNode *module = mHandler->GetASTModule(); @@ -145,6 +152,12 @@ void BuildScopeVisitor::InitInternalTypes() { console->AddMethod(log); log->SetScope(scp); AddDecl(scp, log); + + // add dummy decl for some keywords + ADD_DECL("undefined"); + ADD_DECL("null"); + ADD_DECL("Error"); + ADD_DECL("NonNullable"); } ClassNode *BuildScopeVisitor::AddClass(std::string name, unsigned tyidx) { @@ -221,6 +234,18 @@ FunctionNode *BuildScopeVisitor::VisitFunctionNode(FunctionNode *node) { for(unsigned i = 0; i < node->GetTypeParamsNum(); i++) { TreeNode *it = node->GetTypeParamAtIndex(i); + // add type parameter as decl + if (it->IsTypeParameter()) { + TypeParameterNode *tpn = static_cast(it); + TreeNode *id = tpn->GetId(); + if (id->IsIdentifier()) { + AddDecl(scope, id); + } else { + NOTYETIMPL("function type parameter not identifier"); + } + continue; + } + // add it to scope's mTypes only if it is a new type TreeNode *tn = it; if (it->IsUserType()) { @@ -278,9 +303,15 @@ ClassNode *BuildScopeVisitor::VisitClassNode(ClassNode *node) { // add fields as decl for(unsigned i = 0; i < node->GetFieldsNum(); i++) { - TreeNode *it = node->GetField(i); - if (it->IsIdentifier()) { - AddDecl(scope, it); + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + StrIndexSigNode *sn = static_cast(fld); + fld = sn->GetKey(); + } + if (fld->IsIdentifier()) { + AddDecl(scope, fld); + } else { + NOTYETIMPL("new type of class field"); } } mScopeStack.push(scope); @@ -304,9 +335,13 @@ InterfaceNode *BuildScopeVisitor::VisitInterfaceNode(InterfaceNode *node) { // add fields as decl for(unsigned i = 0; i < node->GetFieldsNum(); i++) { - TreeNode *it = node->GetField(i); - if (it->IsIdentifier()) { - AddDecl(scope, it); + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + StrIndexSigNode *sn = static_cast(fld); + fld = sn->GetKey(); + } + if (fld->IsIdentifier()) { + AddDecl(scope, fld); } } mScopeStack.push(scope); @@ -330,9 +365,13 @@ StructNode *BuildScopeVisitor::VisitStructNode(StructNode *node) { // add fields as decl for(unsigned i = 0; i < node->GetFieldsNum(); i++) { - TreeNode *it = node->GetField(i); - if (it->IsIdentifier()) { - AddDecl(scope, it); + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + StrIndexSigNode *sn = static_cast(fld); + fld = sn->GetKey(); + } + if (fld && fld->IsIdentifier()) { + AddDecl(scope, fld); } } mScopeStack.push(scope); @@ -341,6 +380,30 @@ StructNode *BuildScopeVisitor::VisitStructNode(StructNode *node) { return node; } +StructLiteralNode *BuildScopeVisitor::VisitStructLiteralNode(StructLiteralNode *node) { + ASTScope *parent = mScopeStack.top(); + // struct is a decl + if (parent) { + AddDecl(parent, node); + AddType(parent, node); + } + + ASTScope *scope = NewScope(parent, node); + + // add fields as decl + for(unsigned i = 0; i < node->GetFieldsNum(); i++) { + FieldLiteralNode *fld = node->GetField(i); + TreeNode *name = fld->GetFieldName(); + if (name && name->IsIdentifier()) { + AddDecl(scope, name); + } + } + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitStructLiteralNode(node); + mScopeStack.pop(); + return node; +} + NamespaceNode *BuildScopeVisitor::VisitNamespaceNode(NamespaceNode *node) { node->SetTypeId(TY_Namespace); TreeNode *id = node->GetId(); diff --git a/src/MapleFE/astopt/src/ast_ti.cpp b/src/MapleFE/astopt/src/ast_ti.cpp index fa7b0c129cb8069483e4cb0a3f45024b37b8e31a..205a0e0f814f2c4bd9c3e9a1af4b518503d44db6 100644 --- a/src/MapleFE/astopt/src/ast_ti.cpp +++ b/src/MapleFE/astopt/src/ast_ti.cpp @@ -104,6 +104,19 @@ FieldNode *BuildIdDirectFieldVisitor::VisitFieldNode(FieldNode *node) { return node; } +FieldLiteralNode *BuildIdDirectFieldVisitor::VisitFieldLiteralNode(FieldLiteralNode *node) { + (void) AstVisitor::VisitFieldLiteralNode(node); + TreeNode *name = node->GetFieldName(); + IdentifierNode *field = static_cast(name); + TreeNode *decl = NULL; + decl = mHandler->FindDecl(field); + if (decl) { + mHandler->AddDirectField(field); + mHandler->AddDirectField(node); + } + return node; +} + ArrayElementNode *BuildIdDirectFieldVisitor::VisitArrayElementNode(ArrayElementNode *node) { (void) AstVisitor::VisitArrayElementNode(node); TreeNode *array = node->GetArray(); @@ -297,6 +310,15 @@ void TypeInferVisitor::SetTypeIdx(TreeNode *node, unsigned tidx) { } } +void TypeInferVisitor::SetTypeId(TreeNode *node1, TreeNode *node2) { + SetTypeId(node1, node2->GetTypeId()); + SetTypeIdx(node1, node2->GetTypeIdx()); +} + +void TypeInferVisitor::SetTypeIdx(TreeNode *node1, TreeNode *node2) { + SetTypeIdx(node1, node2->GetTypeIdx()); +} + void TypeInferVisitor::UpdateTypeId(TreeNode *node, TypeId tid) { if (tid == TY_None || !node || node->IsLiteral()) { return; @@ -1152,7 +1174,7 @@ DeclNode *TypeInferVisitor::VisitDeclNode(DeclNode *node) { } ImportNode *TypeInferVisitor::VisitImportNode(ImportNode *node) { - (void) AstVisitor::VisitImportNode(node); + //(void) AstVisitor::VisitImportNode(node); TreeNode *target = node->GetTarget(); unsigned hidx = DEFAULTVALUE; unsigned hstridx = 0; @@ -1203,8 +1225,7 @@ ImportNode *TypeInferVisitor::VisitImportNode(ImportNode *node) { } else { exported = mXXport->GetExportedNamedNode(hidx, bfnode->GetStrIdx()); if (exported) { - UpdateTypeId(bfnode, exported->GetTypeId()); - UpdateTypeIdx(bfnode, exported->GetTypeIdx()); + SetTypeId(bfnode, exported); } } if (!exported) { @@ -1212,20 +1233,18 @@ ImportNode *TypeInferVisitor::VisitImportNode(ImportNode *node) { } } - UpdateTypeId(p, bfnode->GetTypeId()); - UpdateTypeIdx(p, bfnode->GetTypeIdx()); + SetTypeId(p, bfnode); if (afnode) { - UpdateTypeId(afnode, bfnode->GetTypeId()); - UpdateTypeIdx(afnode, bfnode->GetTypeIdx()); + SetTypeId(afnode, bfnode); } } } return node; } -// check if node is identifier with name "default__RENAMED" +// check if node is identifier with name "default"+RENAMINGSUFFIX static bool IsDefault(TreeNode *node) { - return node->GetStrIdx() == gStringPool.GetStrIdx("default__RENAMED"); + return node->GetStrIdx() == gStringPool.GetStrIdx(std::string("default") + RENAMINGSUFFIX); } ExportNode *TypeInferVisitor::VisitExportNode(ExportNode *node) { @@ -1582,8 +1601,7 @@ TerOperatorNode *TypeInferVisitor::VisitTerOperatorNode(TerOperatorNode *node) { (void) VisitTreeNode(ta); (void) VisitTreeNode(tb); (void) VisitTreeNode(tc); - UpdateTypeId(node, tb->GetTypeId()); - UpdateTypeId(node, tc->GetTypeId()); + UpdateTypeId(node, tb); return node; } @@ -1598,8 +1616,8 @@ TypeAliasNode *TypeInferVisitor::VisitTypeAliasNode(TypeAliasNode *node) { UserTypeNode *id = node->GetId(); TreeNode *alias = node->GetAlias(); TypeId tid = alias->GetTypeId(); - UpdateTypeId(id, tid); - UpdateTypeId(node, tid); + unsigned tidx = alias->GetTypeIdx(); + UpdateTypeId(id, alias); return node; } diff --git a/src/MapleFE/astopt/src/ast_xxport.cpp b/src/MapleFE/astopt/src/ast_xxport.cpp index dc7a746d0b985f90f47f0a6e3abcda4b8d4a6b75..87290dbc2ac3d76d2dce61981f7a3cc0f3143cfc 100644 --- a/src/MapleFE/astopt/src/ast_xxport.cpp +++ b/src/MapleFE/astopt/src/ast_xxport.cpp @@ -217,7 +217,8 @@ void AST_XXport::CollectImportInfo(unsigned hidx) { info->mNodeIdPairs.insert(pnid); TypeId tid = exported->GetTypeId(); bfnode->SetTypeId(tid); - bfnode->SetTypeIdx(tid); + unsigned tidx = exported->GetTypeIdx(); + bfnode->SetTypeIdx(tidx); } else { NOTYETIMPL("failed to find the exported - default"); } @@ -231,10 +232,11 @@ void AST_XXport::CollectImportInfo(unsigned hidx) { std::pair pnid(exported->GetNodeId(), afnode->GetNodeId()); info->mNodeIdPairs.insert(pnid); TypeId tid = exported->GetTypeId(); + unsigned tidx = exported->GetTypeIdx(); bfnode->SetTypeId(tid); - bfnode->SetTypeIdx(tid); + bfnode->SetTypeIdx(tidx); afnode->SetTypeId(tid); - afnode->SetTypeIdx(tid); + afnode->SetTypeIdx(tidx); } else if (bfnode) { // import bfnode TreeNode *exported = FindExportedDecl(targethidx, bfnode->GetStrIdx()); @@ -245,8 +247,9 @@ void AST_XXport::CollectImportInfo(unsigned hidx) { std::pair pnid(exported->GetNodeId(), bfnode->GetNodeId()); info->mNodeIdPairs.insert(pnid); TypeId tid = exported->GetTypeId(); + unsigned tidx = exported->GetTypeIdx(); bfnode->SetTypeId(tid); - bfnode->SetTypeIdx(tid); + bfnode->SetTypeIdx(tidx); } else { NOTYETIMPL("failed to find the exported"); } @@ -264,6 +267,27 @@ void AST_XXport::CollectImportInfo(unsigned hidx) { } } +TreeNode *AST_XXport::GetIdentifier(TreeNode *node) { + switch (node->GetKind()) { + case NK_Identifier: + break; + case NK_TypeAlias: { + TypeAliasNode *ta = static_cast(node); + node = GetIdentifier(ta->GetId()); + break; + } + case NK_UserType: { + UserTypeNode *ut = static_cast(node); + node = GetIdentifier(ut->GetId()); + break; + } + default: + NOTYETIMPL("need to extract identifier"); + break; + } + return node; +} + void AST_XXport::CollectExportInfo(unsigned hidx) { Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); ModuleNode *module = handler->GetASTModule(); @@ -331,25 +355,31 @@ void AST_XXport::CollectExportInfo(unsigned hidx) { p->SetAfter(NULL); } - bfnode = p->GetBefore(); afnode = p->GetAfter(); + bfnode = p->GetBefore(); + if (!bfnode->IsIdentifier()) { + bfnode = GetIdentifier(bfnode); + } + unsigned exportednid = (afnode ? afnode->GetNodeId(): bfnode->GetNodeId()); if (p->IsDefault()) { info->mDefaultNodeId = exportednid; - AddExportedDeclIds(hidx, exportednid); } else if (mExportNodeSets[hidx].size() == 1 && node->GetPairsNum() == 1) { info->mDefaultNodeId = bfnode->GetNodeId(); - std::pair pnid(bfnode->GetNodeId(), afnode ? afnode->GetNodeId() : 0); + std::pair pnid(bfnode->GetNodeId(), exportednid); info->mNodeIdPairs.insert(pnid); - AddExportedDeclIds(hidx, exportednid); } else { - std::pair pnid(bfnode->GetNodeId(), afnode ? afnode->GetNodeId() : 0); + std::pair pnid(bfnode->GetNodeId(), exportednid); info->mNodeIdPairs.insert(pnid); - AddExportedDeclIds(hidx, exportednid); } + AddExportedDeclIds(hidx, exportednid); } - mExports[hidx].insert(info); + if (info->mDefaultNodeId || info->mNodeIdPairs.size()) { + mExports[hidx].insert(info); + } else { + delete info; + } } } @@ -451,23 +481,23 @@ TreeNode *AST_XXport::GetExportedNamedNode(unsigned hidx, unsigned stridx) { // hidx is the index of handler, string is the string index of identifier TreeNode *AST_XXport::GetExportedNodeFromImportedNode(unsigned hidx, unsigned nid) { - TreeNode *node = NULL; + TreeNode *node = mAstOpt->GetNodeFromNodeId(nid); for (auto it : mImports[hidx]) { if (it->mDefaultNodeId == nid) { - TreeNode *node = GetExportedDefault(it->mModuleStrIdx); + node = GetExportedDefault(it->mModuleStrIdx); return node; } for (auto it1 : it->mNodeIdPairs) { unsigned nid2 = it1.second; if (nid2 == nid) { unsigned nid1 = it1.first; - TreeNode *node1 = mAstOpt->GetNodeFromNodeId(nid1); - return node1; + node = mAstOpt->GetNodeFromNodeId(nid1); + return node; } } } - return NULL; + return node; } ImportNode *XXportBasicVisitor::VisitImportNode(ImportNode *node) { diff --git a/src/MapleFE/shared/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 863e630e958decb28724a7a653cfd3960e9dad2e..292cb2a97cdd9493d54c094af7f6fef96179c7c3 100644 --- a/src/MapleFE/shared/include/lexer.h +++ b/src/MapleFE/shared/include/lexer.h @@ -76,6 +76,7 @@ public: } void SetTrace() {mTrace = true;} + bool GetTrace() {return mTrace;} void SetLineMode() {mLineMode = true;} void ResetLineMode(){mLineMode = false;} diff --git a/src/MapleFE/shared/include/parser.h b/src/MapleFE/shared/include/parser.h index 1669e43d52dca6359f42c9633af94f1b0d1adbf3..14abcafe61c4c88cdb5c2e34fd7e9b98a27605e8 100644 --- a/src/MapleFE/shared/include/parser.h +++ b/src/MapleFE/shared/include/parser.h @@ -49,6 +49,7 @@ typedef enum AppealStatus { FailChildrenFailed, Fail2ndOf1st, FailLookAhead, + FailASI, // Succ : Really does the matching, will be saved in SuccMatch // SuccWasSucc : Was matched, not tried traversal for a second timewill, @@ -57,9 +58,11 @@ typedef enum AppealStatus { // in RecurionNodes where it does multiple instances of // traversal. But it doesn't make any change compared // to the last real Succ. It will NOT be saved in SuccMatch + // SuccASI: TS/JS auto-semicolon-insert Succ, SuccWasSucc, SuccStillWasSucc, + SuccASI, AppealStatus_NA }AppealStatus; @@ -227,7 +230,7 @@ struct RecStackEntry { //////////////////////////////////////////////////////////////////////////// class Parser { -private: +protected: friend class RecursionTraversal; // Matching on alternative tokens needs a state machine. @@ -293,7 +296,7 @@ public: bool TraverseOneof(RuleTable*, AppealNode*); bool TraverseZeroormore(RuleTable*, AppealNode*); bool TraverseZeroorone(RuleTable*, AppealNode*); - virtual bool TraverseASI(RuleTable*, AppealNode*) {return false;} + virtual bool TraverseASI(RuleTable*, AppealNode*, AppealNode *&) {return false;} // There are some special cases we can speed up the traversal. // 1. If the target is a token, we just need compare mCurToken with it. diff --git a/src/MapleFE/shared/src/parser.cpp b/src/MapleFE/shared/src/parser.cpp index fc499967ef715f2842d1fd43c935315c4a58f0e2..19a3da4f2dd8906051af8bf492fb8ddb2addb867 100644 --- a/src/MapleFE/shared/src/parser.cpp +++ b/src/MapleFE/shared/src/parser.cpp @@ -393,6 +393,9 @@ unsigned Parser::LexOneLine() { unsigned token_num = 0; Token *t = NULL; + Token *last_token = NULL; + bool line_begin = true; + // Check if there are already pending tokens. if (mCurToken < mActiveTokens.GetNum()) return mActiveTokens.GetNum() - mCurToken; @@ -425,7 +428,14 @@ unsigned Parser::LexOneLine() { // 3. handle regular expression t = GetRegExpr(t); + if (line_begin) { + t->mLineBegin = true; + line_begin = false; + if (mLexer->GetTrace()) + DUMP0("Set as Line First."); + } mActiveTokens.PushBack(t); + last_token = t; token_num++; } } else { @@ -442,6 +452,13 @@ unsigned Parser::LexOneLine() { } } + // We are done with a meaningful line + if (token_num) { + last_token->mLineEnd = true; + if (mLexer->GetTrace()) + DUMP0("Set as Line End."); + } + return token_num; } @@ -689,8 +706,9 @@ bool Parser::TraverseTempLiteral() { AppealNode *child = NULL; succ_expr = TraverseRuleTable(t, mRootNode, child); if (succ_expr) { - MASSERT(child); - mRootNode->CopyMatch(child); + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); // Need adjust the mCurToken. A rule could try multiple possible // children rules, although there is one and only one valid child // for a Top table. However, the mCurToken could deviate from @@ -707,8 +725,9 @@ bool Parser::TraverseTempLiteral() { child = NULL; succ_type = TraverseRuleTable(t, mRootNode, child); if (succ_type) { - MASSERT(child); - mRootNode->CopyMatch(child); + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); // Need adjust the mCurToken. A rule could try multiple possible // children rules, although there is one and only one valid child // for a Top table. However, the mCurToken could deviate from @@ -749,8 +768,9 @@ bool Parser::TraverseStmt() { AppealNode *child = NULL; succ = TraverseRuleTable(t, mRootNode, child); if (succ) { - MASSERT(child); - mRootNode->CopyMatch(child); + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); // Need adjust the mCurToken. A rule could try multiple possible // children rules, although there is one and only one valid child // for a Top table. However, the mCurToken could deviate from @@ -817,6 +837,9 @@ void Parser::DumpExitTable(const char *table_name, unsigned indent, std::cout << " succ" << "}"; DumpSuccTokens(appeal); std::cout << std::endl; + } else if (reason == SuccASI) { + std::cout << " succASI" << "}"; + std::cout << std::endl; } else if (reason == FailWasFailed) std::cout << " fail@WasFailed" << "}" << std::endl; else if (reason == FailNotRightToken) @@ -833,6 +856,8 @@ void Parser::DumpExitTable(const char *table_name, unsigned indent, std::cout << " fail@2ndOf1st" << "}" << std::endl; else if (reason == FailLookAhead) std::cout << " fail@LookAhead" << "}" << std::endl; + else if (reason == FailASI) + std::cout << " fail@ASI" << "}" << std::endl; else if (reason == AppealStatus_NA) std::cout << " fail@NA" << "}" << std::endl; } @@ -939,6 +964,18 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal DumpEnterTable(name, mIndentation); } + if (rule_table->mType == ET_ASI) { + bool found = TraverseASI(rule_table, parent, child); + if (mTraceTable) { + if (found) + DumpExitTable(name, mIndentation, SuccASI); + else + DumpExitTable(name, mIndentation, FailASI); + } + mIndentation -= 2; + return found; + } + // Lookahead fail is fast to check, even faster than check WasFailed. if (LookAheadFail(rule_table, mCurToken) && (rule_table->mType != ET_Zeroormore) && @@ -1225,9 +1262,11 @@ bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) case ET_Concatenate: matched = TraverseConcatenate(rule_table, appeal); break; - case ET_ASI: - matched = TraverseASI(rule_table, appeal); + case ET_ASI: { + AppealNode *child = NULL; + matched = TraverseASI(rule_table, appeal, child); break; + } case ET_Data: { // This is a rare case where a rule table contains only table, either a token // or a single child rule. In this case, we need merge the child's match into @@ -1668,6 +1707,7 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { for (unsigned i = 0; i < rule_table->mNum; i++) { bool is_zeroxxx = false; + bool is_asi = false; bool is_token = false; bool old_mInAltTokensMatching = mInAltTokensMatching; @@ -1676,6 +1716,8 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { RuleTable *zero_rt = data->mData.mEntry; if (zero_rt->mType == ET_Zeroormore || zero_rt->mType == ET_Zeroorone) is_zeroxxx = true; + if (zero_rt->mType == ET_ASI) + is_asi = true; } else if (data->mType == DT_Token) { is_token = true; } @@ -1701,11 +1743,17 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { child->SetChildIndex(i); found_subtable |= temp_found; - if (temp_found && child) { - for (unsigned id = 0; id < child->GetMatchNum(); id++) { - unsigned match = child->GetMatch(id); - if (!subtable_succ_tokens.Find(match)) - subtable_succ_tokens.PushBack(match); + if (temp_found ) { + if (child) { + for (unsigned id = 0; id < child->GetMatchNum(); id++) { + unsigned match = child->GetMatch(id); + if (!subtable_succ_tokens.Find(match)) + subtable_succ_tokens.PushBack(match); + } + } else if (is_asi) { + // ASI succeeded, without child. It means semicolon is skipped. + // Keep prev. NO moving mCurToken. + subtable_succ_tokens.PushBack(prev); } } } @@ -1780,8 +1828,14 @@ bool Parser::TraverseTableData(TableData *data, AppealNode *appeal, AppealNode * // we are working on right now is not the last token. It's one of the previous matches. // So we need check if we are matching the last token. if (mEndOfFile && mCurToken >= mActiveTokens.GetNum()) { - if (!(mInAltTokensMatching && (mCurToken == mATMToken))) + if (!(mInAltTokensMatching && (mCurToken == mATMToken))) { + if (data->mType == DT_Subtable) { + RuleTable *t = data->mData.mEntry; + if (t->mType == ET_ASI) + return TraverseASI(t, appeal, child_node); + } return false; + } } unsigned old_pos = mCurToken; @@ -2222,13 +2276,15 @@ void Parser::SortOutConcatenate(AppealNode *parent) { for (int i = rule_table->mNum - 1; i >= 0; i--) { TableData *data = rule_table->mData + i; AppealNode *child = parent->FindIndexedChild(last_match, i); - // It's possible that we find NO child if 'data' is a ZEROORxxx table + // It's possible that we find NO child if 'data' is a ZEROORxxx table or ASI. bool good_child = false; if (!child) { if (data->mType == DT_Subtable) { RuleTable *table = data->mData.mEntry; if (table->mType == ET_Zeroorone || table->mType == ET_Zeroormore) good_child = true; + if (table->mType == ET_ASI) + good_child = true; } MASSERT(good_child); } else { diff --git a/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts new file mode 100644 index 0000000000000000000000000000000000000000..b07b07525bb2d8d56c392da58000ff3701fcc84b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts @@ -0,0 +1,19 @@ +class Klass { + data: any; + constructor() { + { + this.data = [ + new Array(123, 456) + ]; + } + } + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco3.ts b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e599b2155c6c1712aafee180d57f2582731cba9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts @@ -0,0 +1,29 @@ +function class_deco(name: string): Function { + function deco(ctor: Function): void { + console.log("Class constructor is :", ctor, ", Name is: ", name); + } + return deco; +} + +@class_deco('Klass') +class Klass { + data: any = null; + public setData(value: any) { + this.data= [ + { + n: value, + }, + ]; + } + + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.setData(123); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco4.ts b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts new file mode 100644 index 0000000000000000000000000000000000000000..063acd21db109419d51de9c374457bf468f8ee9d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts @@ -0,0 +1,22 @@ +function class_deco(name: string): Function { + function deco(ctor: Function): void { + console.log("Class constructor is :", ctor, ", Name is: ", name); + } + return deco; +} + +@class_deco('Klass') +class Klass { + data: + {} = {}; + + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c499b0516d5c4150e7c79c227737c21af60edb8b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result @@ -0,0 +1,7 @@ +Matched 6 tokens. +Matched 9 tokens. +============= Module =========== +== Sub Tree == +console.log("Hello") +== Sub Tree == +console.log diff --git a/src/MapleFE/typescript/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h index aa302bfdef26782ef530ba7c93afa3acebbf424b..f0ec422f1a2d3563ccf6fed3e65e4ed3236734ac 100644 --- a/src/MapleFE/typescript/include/lang_spec.h +++ b/src/MapleFE/typescript/include/lang_spec.h @@ -58,7 +58,7 @@ class TypescriptParser : public Parser { public: TypescriptParser(const char *f) : Parser(f) {} Token* GetRegExpr(Token *t); - bool TraverseASI(RuleTable*, AppealNode*); + bool TraverseASI(RuleTable*, AppealNode*, AppealNode *&); }; } diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index d73777758c4ee570eca1029cd66e696c861aaec5..7b5f1f12a765b381eea8dfa3f7a68ace9704db70 100644 --- a/src/MapleFE/typescript/src/lang_spec.cpp +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -418,13 +418,66 @@ Token* TypescriptParser::GetRegExpr(Token *t) { // 'appeal' is the node of 'rule_table'. -bool TypescriptParser::TraverseASI(RuleTable *rule_table, AppealNode *appeal) { +// 'child' was NULL when passed in. +bool TypescriptParser::TraverseASI(RuleTable *rule_table, + AppealNode *appeal, + AppealNode *&child) { + // Usually mCurToken is a new token to be matched. So if it's end of file, we simply return false. + // However, (1) if mCurToken is actually an ATMToken, which means it needs to be matched + // multiple times, we are NOT at the end yet. + // (2) If we are traverse a Concatenate rule, and the previous sub-rule has multiple matches, + // and we are trying the current sub-rule, ie. 'data', using one of the matches. + // The lexer actually reaches the EndOfFile in previous matchings, but the mCurToken + // we are working on right now is not the last token. It's one of the previous matches. + // So we need check if we are matching the last token. + //if (mEndOfFile && mCurToken >= mActiveTokens.GetNum()) { + // if (!(mInAltTokensMatching && (mCurToken == mATMToken))) + // return false; + //} + + if (mCurToken <= 1) + return false; + + if (mEndOfFile && mCurToken == mActiveTokens.GetNum()) + return true; + + unsigned old_pos = mCurToken; + bool found = false; + Token *curr_token = GetActiveToken(mCurToken); + Token *prev_token = GetActiveToken(mCurToken - 1); + MASSERT((rule_table->mNum == 1) && "ASI node has more than one elements?"); + TableData *data = rule_table->mData; - AppealNode *child = NULL; - bool found = TraverseTableData(data, appeal, child); - if (child) + MASSERT(data->mType == DT_Token && "ASI data is not a token?"); + + Token *semicolon = &gSystemTokens[data->mData.mTokenId]; + MASSERT(semicolon->IsSeparator()); + MASSERT(semicolon->GetSepId() == SEP_Semicolon); + + if (curr_token == semicolon) { + // To simplify the code, I reused TraverseToken(). + found = TraverseToken(semicolon, appeal, child); + } else { + if (curr_token->mLineBegin && + prev_token->mLineEnd && + prev_token->IsSeparator()){ + if (prev_token->GetSepId() == SEP_Rbrace || + prev_token->GetSepId() == SEP_Rbrack || + prev_token->GetSepId() == SEP_Rparen) { + if (mTraceTable) { + std::cout << "TraverseASI, Auto-insert one semicolon." << std::endl; + } + return true; + } + } + } + + if (child) { + child->SetChildIndex(0); appeal->CopyMatch(child); + } + return found; }