diff --git a/.gitignore b/.gitignore index f71bf2703f6ebf9a684037b3df228a6082d56a73..dcf0dec08f06bb5391c8935caae1a02ce71b0c3c 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* diff --git a/src/MapleFE/ast2cpp/include/cpp_declaration.h b/src/MapleFE/ast2cpp/include/cpp_declaration.h index fcf6b61c323171b9e610b6907c739231132cc512..9a5c3690e3be0f9bd17865c27c256252fad0157a 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 74d81734fdf2746d8b6853074ccabc0cf39d7ef1..6de63255253141a10d91f861eccc9f23f35aae56 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/emitter.h b/src/MapleFE/ast2cpp/include/emitter.h index 7ad2b1e895eccb8911887cf04aa5a5431ea06007..59178b28813af0c000055392021b181de013f287 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/include/helper.h b/src/MapleFE/ast2cpp/include/helper.h index 297d57f4070a956300db59c14899edab68cef580..47c543d71e16d5c1ff17d6c21634858bf0bbbec6 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 96a1e654b0ad4ce3770cbe39f3821cb78f2548cd..8119e39ff33404d5e09efa148247eb630bac2495 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 @@ -906,11 +897,8 @@ 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; - } + ifName = GetIdentifierName(node); + str = "class "s + ifName + " : public "s + superClass + " {\n"s; str += " public:\n"s; // Generate code to add prop in class constructor diff --git a/src/MapleFE/ast2cpp/src/cpp_definition.cpp b/src/MapleFE/ast2cpp/src/cpp_definition.cpp index 6ac4cfd41551455954c094d2a829b45992f6f6e9..098ffd00b031d62662e59cedf8c6f5dd3670a943 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 ab730ccb84fc15d9f1f607c160f8bddd81f275db..b791306fa2702a556ad1650550f80900ce318429 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()); @@ -126,4 +132,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/emitter.cpp b/src/MapleFE/ast2cpp/src/emitter.cpp index e4926858fae238e405496ce4a490d8e76b6d6703..3ae234f9dbc026e5d0ec17eb4ca0fd89924a221f 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 diff --git a/src/MapleFE/ast2cpp/src/helper.cpp b/src/MapleFE/ast2cpp/src/helper.cpp index 5ee7e1b5f90db1160d66573baa814b8228c9af0f..4b01b7891b65e157f2dc5596a41f1d46d9bba5fa 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()); } diff --git a/src/MapleFE/ast2mpl/src/mpl_processor.cpp b/src/MapleFE/ast2mpl/src/mpl_processor.cpp index e66c75643e45e1dd2d50e92777fdf1c50cf68cb8..a943ae29b8ffbfb96745bb411e02c4aff25c05d0 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/astopt/include/ast_info.h b/src/MapleFE/astopt/include/ast_info.h index 4753f50dace00bff128a2e2753bec54cd5d5773f..de56fcf645574eaef13096dd707166bc0c01008e 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 e841e0d65a0c061c6c4ee9df7481a9b74f4b654b..14b560d3a48d1280409a3d898ee1e80e6d36f4ff 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);\ + gTypeTable.AddType(node);\ + mStrIdx2TypeIdxMap[stridx] = node->GetTypeIdx();\ + } #include "lang_builtin.def" } @@ -245,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(); @@ -490,10 +502,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); @@ -739,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()) { @@ -793,6 +809,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 +842,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 +876,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/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 9179704ab7e33a937ccc8b436abd125fe2d06911..7a87e6f2566455db9171a1c58a626b1e5cdb6ce1 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); } @@ -428,6 +431,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 +442,41 @@ DeclNode *BuildScopeVisitor::VisitDeclNode(DeclNode *node) { node->GetVar()->SetScope(scope); } } else { - // use 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 + 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; } diff --git a/src/MapleFE/astopt/src/ast_ti.cpp b/src/MapleFE/astopt/src/ast_ti.cpp index 22706289ed7bda7a3ff2fc87224962a9d16fc330..13c0256111e65804dae3b020bbc2f8924f486be1 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,10 @@ UserTypeNode *TypeInferVisitor::VisitUserTypeNode(UserTypeNode *node) { SetTypeId(node, TY_Array); SetTypeIdx(node, TY_Array); } else if (node->GetId()) { - UpdateTypeId(node, node->GetId()); + // 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(); diff --git a/src/MapleFE/autogen/reserved.spec b/src/MapleFE/autogen/reserved.spec index 445cc388cc7acb78a21415b5119eb36e5e3b8aff..1832b7c5dcb0cdf016191982576d931dd51444a7 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/docs/builtin-constructors.md b/src/MapleFE/docs/builtin-constructors.md index b38060c8add67af8b593b04c5294ecb66a0f55e2..d5936b12a4d8ab368fab159c07d039a85774ef72 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: diff --git a/src/MapleFE/docs/readme b/src/MapleFE/docs/readme index 732f9f3725c3049fc9bbad1ecaa4016af160b2d0..9ff4bbefc70014338c1bd442785b82389db6b262 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 diff --git a/src/MapleFE/scripts/maplefe-autogen.py b/src/MapleFE/scripts/maplefe-autogen.py index 1dd330b3171d70be47f029bddf72fa28b7e02749..f0ffce0cf1f8723de889853653e340c32e058df9 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"; diff --git a/src/MapleFE/shared/include/ast.h b/src/MapleFE/shared/include/ast.h index 58d327ce4fc805b2834e182011b870f95f73f99f..4ef9361c73e6c6afca0cb01d4e51b632b6374970 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 df99869326ebf7eb81550f2a848277d7d739c885..e6c720c14006f403b4b22198267c15217799b57e 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/ast_scope.h b/src/MapleFE/shared/include/ast_scope.h index 32131f660cd0b39e07589e967b8660f1f9c5c7b0..088072c362f6c492203110f4d0689223a2281428 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/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 151f55b258b5ebb5e8a6c92faecead47c5edb363..00a3f708629d9e8e8d347b56e6e942b241c768fb 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/include/parser.h b/src/MapleFE/shared/include/parser.h index a747c23656ba23838301a06b86ad6ed762098a68..26d4f73af706de7c750aa1326d749dc441219989 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 1b3f48505e78db1c50ff16b47ee3e1e016e44553..ef4710d3862514ff281d00f5f277cbf93d708a66 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 b09021d0b2e245794d97cc4a420c3e0898afdc3b..2ffa34dd44fa1f53b361757b863c4d9ae861e8b4 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/src/ast.cpp b/src/MapleFE/shared/src/ast.cpp index d0772ef4090bbd156e7069f79e4068d715da7edf..937d6431c5b012e9e83f255cde59fd2f8dd0b623 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 8657146ac7d6991cbbd1fc9724777133e07a4f91..e715baa5a137440ac60f7652e975f3f61c698a8e 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/ast_scope.cpp b/src/MapleFE/shared/src/ast_scope.cpp index 7441ddac5ef88164751bc1e475463b9ff510dbc7..f1e5505be67a6b5e36140edc8200f9c4c4f62fd3 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; } diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index ccd8a5a2550bfde4a62a4a98b4df4660e8a2d61f..694f86a8edafedea9ff0584a140a9b0e25777951 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; @@ -654,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 12e8d953dc4e61a8ad5ddeb8efc18b7c7d9251a4..ea109fc5f0ec11dd79ebe3b3e199f0b68e1bd6b0 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) @@ -806,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) @@ -1260,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) { @@ -1806,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/typetable.cpp b/src/MapleFE/shared/src/typetable.cpp index ad58543fd809f6c4f6a31c1204ba28f853c1db07..c528450f355fa108fbe9af320fb24b12b24a2ca5 100644 --- a/src/MapleFE/shared/src/typetable.cpp +++ b/src/MapleFE/shared/src/typetable.cpp @@ -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); AddType(node); +#define TYPE(T) node = CreateBuiltinType(#T, TY_##T); AddType(node); #define PRIMTYPE(T) // additional usertype Boolean TYPE(Boolean); diff --git a/src/MapleFE/shared/src/vfy.cpp b/src/MapleFE/shared/src/vfy.cpp index cb03fb5439385aabf65f7bf4684633acb8c0cb85..02a87ff57b13acdecd16e77d55cd209417e93aca 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 42db4d50cd1948ed6342f61d5646f75724f35a84..c71e900f9a1c38da2856901eb5858a378b61611c 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 f9052bd4b2db8b75cc78e04aad0acd979d29b938..0e74c743cd4c0c3b70270bc58d388ad13603002f 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 6cfe3baf6e1b7b01004cdd387139257599dd0990..5723b480b3cd59e04d86d6d935f9bd949971c926 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/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h index 929de87c24b46706d9964306411a854a052ce0e2..96aef8bf12195fd32df8cf8630e6beb6632f8c9a 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/operator.spec b/src/MapleFE/typescript/operator.spec index 48d5037f5a9897174513ea3644d3a34ffcabee28..d09db223d3cdc7069e1300fde8861a08f6ff9b8d 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/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index b2022817b90b2ef798909c39710dcb1cc7649f29..54a95b6c359fbcf625b2aa4318eef9467487130a 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 : /// ', + "///" + '<' + "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 diff --git a/tools/setup_tools.sh b/tools/setup_tools.sh index 8b320e302c9bbea3c91e45d002c860ca8262dbc6..a8672855b9e1285a4513f70c93d5b64dd72e92ab 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