diff --git a/src/MapleFE/ast2cpp/include/cpp_definition.h b/src/MapleFE/ast2cpp/include/cpp_definition.h index 3d8157d8d2b3a771d8b1c77bbb2b52d293bd3292..73953d592d096be4b46f1a33f7420d497b6b869c 100644 --- a/src/MapleFE/ast2cpp/include/cpp_definition.h +++ b/src/MapleFE/ast2cpp/include/cpp_definition.h @@ -69,7 +69,7 @@ public: std::string EmitFuncScopeVarDecls(FunctionNode *node); std::string EmitStructNode(StructNode *node); std::string EmitStructLiteralNode(StructLiteralNode* node); - std::string EmitObjPropInit(std::string varName, TreeNode* idType, StructLiteralNode* n); + std::string EmitObjPropInit(TreeNode* var, std::string varName, TreeNode* idType, StructLiteralNode* n); std::string EmitDirectFieldInit(std::string varName, StructLiteralNode* node); std::string EmitCppCtor(ClassNode* node); std::string EmitCtorInstance(ClassNode *c); @@ -79,7 +79,6 @@ public: std::string EmitArrayLiterals(TreeNode* arrLiteral, int dim, std::string type); TypeId GetTypeIdFromDecl(TreeNode* id); bool IsClassField(ArrayElementNode* node, std::string propKey); - bool IsClassId(TreeNode* node); std::string GetTypeForTemplateArg(TreeNode* node); TreeNode* FindDeclType(TreeNode* node); std::string GetThisParamObjType(TreeNode *node); diff --git a/src/MapleFE/ast2cpp/include/cpp_emitter.h b/src/MapleFE/ast2cpp/include/cpp_emitter.h index 7d09327347869ac4848919ec8de5fcda1c4181e7..1ec4ffe9270f04ca5084d9b548d33cca6712e4ea 100644 --- a/src/MapleFE/ast2cpp/include/cpp_emitter.h +++ b/src/MapleFE/ast2cpp/include/cpp_emitter.h @@ -31,6 +31,8 @@ public: bool IsInNamespace(TreeNode *node); std::string GetNamespace(TreeNode *node); std::string GetQualifiedName(IdentifierNode *node); + bool IsClassId(TreeNode *node); + bool IsVarTypeClass(TreeNode* var); }; } // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp index 8272ffefe62277c9c020bd21c1f3f1fd682cf961..4a53c953c5254c9f2a9e75bbd886a3252d91317c 100644 --- a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -755,15 +755,16 @@ std::string CppDecl::EmitClassNode(ClassNode *node) { if (node == nullptr) return std::string(); + std::string clsName = node->GetName(); // 1. c++ class for JS object base = (node->GetSuperClassesNum() != 0)? node->GetSuperClass(0)->GetName() : "t2crt::Object"; - str += "class "s + node->GetName() + " : public "s + base + " {\n"s; + str += "class "s + clsName + " : public "s + base + " {\n"s; str += "public:\n"; // constructor decl - str += " "s + node->GetName() + "(t2crt::Function* ctor, t2crt::Object* proto);\n"s; - str += " ~"s + node->GetName() + "(){}\n"; + str += " "s + clsName + "(t2crt::Function* ctor, t2crt::Object* proto);\n"s; + str += " ~"s + clsName + "(){}\n"; // class field decl and init. TODO: handle private, protected attrs. for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { @@ -776,8 +777,8 @@ std::string CppDecl::EmitClassNode(ClassNode *node) { IdentifierNode* id = static_cast(n); if (HasAttrStatic(id)) { // static field - add field to ctor prop and init later at field def in cpp - staticProps += tab(3) + "this->AddProp(\""s + n->GetName() + "\", t2crt::JS_Val("s + - TypeIdToJSTypeCXX[n->GetTypeId()] + ", &"s + node->GetName() + "::"s + id->GetName() + "));\n"s; + staticProps += tab(3) + "this->AddProp(\""s + clsName + "\", t2crt::JS_Val("s + + TypeIdToJSTypeCXX[n->GetTypeId()] + ", &"s + clsName + "::"s + id->GetName() + "));\n"s; } else if (auto init = id->GetInit()) { if (init->IsArrayLiteral() && id->GetType() && id->GetType()->IsPrimArrayType()) { // Generate initializer for t2crt::Array member field decl in header file @@ -809,7 +810,7 @@ std::string CppDecl::EmitClassNode(ClassNode *node) { for (unsigned i = 0; i < node->GetConstructorsNum(); ++i) { std::string ctor; if (auto c = node->GetConstructor(i)) { - ctor = indent + " "s + node->GetName() + "* operator()("s + node->GetName() + "* obj"s; + ctor = indent + " "s + clsName + "* operator()("s + clsName + "* obj"s; for (unsigned k = 0; k < c->GetParamsNum(); ++k) { ctor += ", "s; if (auto n = c->GetParam(k)) { @@ -823,13 +824,14 @@ std::string CppDecl::EmitClassNode(ClassNode *node) { // Generate decl for default constructor function if none declared for class if (node->GetConstructorsNum() == 0) - str += indent + " "s + node->GetName() + "* operator()("s + node->GetName() + "* obj);\n"s; + str += indent + " "s + clsName + "* operator()("s + clsName + "* obj);\n"s; // Generate new() function - str += indent + " "s+node->GetName()+"* _new() {return new "s+node->GetName()+"(this, this->prototype);}\n"s; - str += indent + " virtual const char* __GetClassName() const {return \""s + node->GetName() + " \";}\n"s; + str += indent + " "s+clsName+"* _new() {return new "s+clsName+"(this, this->prototype);}\n"s; + str += indent + " virtual const char* __GetClassName() const {return \""s + clsName + " \";}\n"s; str += indent + "};\n"; - str += "};\n\n"; + str += "};\n"; + str += "extern " + clsName + "::Ctor "s + clsName + "_ctor;\n"s; // emit declaration for JS class object constructor return str; } diff --git a/src/MapleFE/ast2cpp/src/cpp_definition.cpp b/src/MapleFE/ast2cpp/src/cpp_definition.cpp index 3bf7f1d473ecb1c5173bbebede9e16be22cf1a20..85f391f61262c743ba98503c7e47078c5777462f 100644 --- a/src/MapleFE/ast2cpp/src/cpp_definition.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_definition.cpp @@ -30,8 +30,8 @@ std::string CppDef::EmitCtorInstance(ClassNode *c) { prototypeProto = proto + ".prototype"s; proto.insert(0, "&"s, 0, std::string::npos); } - str = "\n// Instantiate constructor\n"s; - str += thisClass + "::Ctor "s + thisClass+"_ctor("s +ctor+","s+proto+","+prototypeProto+");\n"s; + str = "\n// Instantiate constructor for class "+ thisClass+ "\n"s; + str += thisClass + "::Ctor "s + thisClass+"_ctor("s +ctor+","s+proto+","+prototypeProto+");\n\n"s; // piggy back generation of static field definition for (unsigned i = 0; i < c->GetFieldsNum(); ++i) { @@ -406,7 +406,7 @@ std::string CppDef::EmitDirectFieldInit(std::string varName, StructLiteralNode* auto lit = field->GetLiteral(); std::string fieldName = EmitTreeNode(field->GetFieldName()); std::string fieldVal = EmitTreeNode(lit); - if (false) // TODO: Check if it accesses a Cxx class field + if (mHandler->IsCppField(field)) // Check if it accesses a Cxx class field str += tab(1) + varName + "->"s + fieldName + " = "s + fieldVal + ";\n"s; else str += tab(1) + "(*"s + varName + ")[\""s + fieldName + "\"] = "s + fieldVal + ";\n"s; @@ -415,7 +415,7 @@ std::string CppDef::EmitDirectFieldInit(std::string varName, StructLiteralNode* return str; } -std::string CppDef::EmitObjPropInit(std::string varName, TreeNode* varIdType, StructLiteralNode* node) { +std::string CppDef::EmitObjPropInit(TreeNode* var, std::string varName, TreeNode* varIdType, StructLiteralNode* node) { if (varName.empty()) return std::string(); @@ -426,11 +426,10 @@ std::string CppDef::EmitObjPropInit(std::string varName, TreeNode* varIdType, St if (userType == nullptr) { // no type info - create instance of builtin t2crt::Object with proplist str = varName+ " = t2crt::Object_ctor._new("s + EmitTreeNode(node) + ")"s; - } else if (IsClassId(userType->GetId())) { - // user def class type + } else if (IsVarTypeClass(var)) { + // init var of type TS class // - create obj instance of user defined class and do direct field access init // - todo: handle class with generics - // - todo: generate addprop instead of direct field access if prop is not a field in class decl str = varName+ " = "s +userType->GetId()->GetName()+ "_ctor._new();\n"s; str += EmitDirectFieldInit(varName, node); } else { @@ -526,7 +525,7 @@ std::string CppDef::EmitDeclNode(DeclNode *node) { if (n->IsArrayLiteral()) str += varStr + " = " + EmitArrayLiteral(idType, n); else if (n->IsStructLiteral()) - str += EmitObjPropInit(varStr, idType, static_cast(n)); + str += EmitObjPropInit(node->GetVar(), varStr, idType, static_cast(n)); else if (node->GetVar()->IsIdentifier() && n->IsIdentifier() && n->IsTypeIdClass()) str += varStr + "= &"s + n->GetName() + "_ctor"s; // init with ctor address else if (n->IsFunction()) { @@ -981,18 +980,6 @@ std::string CppDef::EmitBracketNotationProp(ArrayElementNode* ae, OprId binOpId, return str; } -// return true if identifier is a class -bool CppDef::IsClassId(TreeNode* node) { - if (node != nullptr && - node->IsIdentifier() && - node->IsTypeIdClass() && - mHandler->FindDecl(static_cast(node)) && - mHandler->FindDecl(static_cast(node))->IsClass()) - return true; - else - return false; -} - std::string CppDef::EmitBinOperatorNode(BinOperatorNode *node) { if (node == nullptr) return std::string(); diff --git a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp index d770142bfeb7127edca370856c842d35322eb933..efdf178a6cc0e5a65bd1f1dc6c733d8485a5193d 100644 --- a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp +++ b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp @@ -98,4 +98,28 @@ std::string CppEmitter::GetQualifiedName(IdentifierNode *node) { return ns.empty() ? name : ns + "::"s + name; } +// Returns true if identifier is a class +bool CppEmitter::IsClassId(TreeNode* node) { + if (node == nullptr || !node->IsIdentifier()) + return false; + if (auto decl = mHandler->FindDecl(static_cast(node), true)) { // deep, cross module lookup + if (decl->IsClass()) + return true; + // TODO: handle type alias + } + return false; +} + +// Returns true if the declared type of a var is a TS class +bool CppEmitter::IsVarTypeClass(TreeNode* var) { + if (var == nullptr) + return false; + if (auto n = gTypeTable.GetTypeFromTypeIdx(var->GetTypeIdx())) { + if (n->IsClass()) + return true; + } + return false; +} + + } // namespace maplefe diff --git a/src/MapleFE/astopt/include/ast_handler.h b/src/MapleFE/astopt/include/ast_handler.h index a0a2494149994373a264b428fd6528115c3f5a1d..90949a367f3df6af64b5b7e7aa4eea98d1da6794 100644 --- a/src/MapleFE/astopt/include/ast_handler.h +++ b/src/MapleFE/astopt/include/ast_handler.h @@ -131,6 +131,8 @@ class Module_Handler { std::unordered_map mArrayDeclId2EleTypeIdMap; // fields' nodeid set std::unordered_set mDirectFieldSet; + // alias type, identifier node id + std::unordered_set mAliasTypeSet; public: explicit Module_Handler(unsigned f) : @@ -214,6 +216,12 @@ class Module_Handler { mNodeId2Decl[nid] = node; } + void AddAliasType(unsigned nid) { mAliasTypeSet.insert(nid); } + bool isAliasType(unsigned nid) { + return mAliasTypeSet.find(nid) != mAliasTypeSet.end(); + } + bool isAliasType(TreeNode *node) { return isAliasType(node->GetNodeId()); } + template T *NewTreeNode() { T *node = (T*)gTreePool.NewTreeNode(sizeof(T)); diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp index 126a95b1b325c6dc2f1735c8b7212212840b5d70..cd2f46565c0a93b42e1347cbb093c649f5d161e9 100644 --- a/src/MapleFE/astopt/src/ast_scp.cpp +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -490,6 +490,9 @@ TypeAliasNode *BuildScopeVisitor::VisitTypeAliasNode(TypeAliasNode *node) { if (ut->IsUserType()) { TreeNode *id = static_cast(ut)->GetId(); AddDecl(scope, id); + + // add to Alias type + mHandler->AddAliasType(id->GetNodeId()); } return node; } diff --git a/src/MapleFE/shared/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 60e34e943d57ff0258fcc5547b624bad794b2fa0..380d8ed41bed256c18b28a3ef4090e7e8f790096 100644 --- a/src/MapleFE/shared/include/lexer.h +++ b/src/MapleFE/shared/include/lexer.h @@ -126,6 +126,8 @@ public: const char* GetIdentifier(); bool GetComment(); + Token* FindRegExprToken(); + // For most languages, this does nothing. TS/JS are doing something. virtual bool CharIsSeparator(const char c) {return false;} @@ -138,14 +140,6 @@ public: //void PlantTraverseRuleTable(RuleTable*); //void PlantTraverseTableData(TableData*); - // - Token* FindSeparatorToken(SepId id); - Token* FindOperatorToken(OprId id); - Token* FindKeywordToken(const char *key); - Token* FindPreprocessorKeywordToken(const char *key); - Token* FindCommentToken(); - Token* FindRegExprToken(); - // When we start walk a rule table to find a token, do we need check if // the following data is a separator? bool mCheckSeparator; diff --git a/src/MapleFE/shared/include/token.h b/src/MapleFE/shared/include/token.h index b13cc60b53ab1022fe2b4f705b4e6983aa81df0c..5eef89450511577851c90e40f6dd31ddaddd6b73 100644 --- a/src/MapleFE/shared/include/token.h +++ b/src/MapleFE/shared/include/token.h @@ -159,5 +159,12 @@ struct Token { void Dump(); }; + // + Token* FindSeparatorToken(SepId id); + Token* FindOperatorToken(OprId id); + Token* FindKeywordToken(const char *key); + Token* FindPreprocessorKeywordToken(const char *key); + Token* FindCommentToken(); + } #endif diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index 502652577eda28ebf466fd391529997e4167dc4e..89460e331b044f22a6fc028693afeb9381ff4ccc 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -135,87 +135,6 @@ void Lexer::PrepareForString(const char *str) { endoffile = false; } -/////////////////////////////////////////////////////////////////////////// -// Utilities for finding system tokens -// Remember the order of tokens are operators, separators, and keywords. -/////////////////////////////////////////////////////////////////////////// - -Token* Lexer::FindOperatorToken(OprId id) { - Token *token = NULL; - bool found = false; - for (unsigned i = 0; i < gOperatorTokensNum; i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_OP); - if (token->GetOprId() == id) { - found = true; - break; - } - } - MASSERT(found && token); - return token; -} - -Token* Lexer::FindSeparatorToken(SepId id) { - Token *token = NULL; - bool found = false; - for (unsigned i = gOperatorTokensNum; i < gOperatorTokensNum + gSeparatorTokensNum; i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_SP); - if (token->GetSepId() == id) { - found = true; - break; - } - } - MASSERT(found && token); - return token; -} - -// The caller of this function makes sure 'key' is already in the -// string pool of Lexer. -Token* Lexer::FindKeywordToken(const char *key) { - Token *token = NULL; - bool found = false; - for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum; - i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; - i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_KW); - if (strlen(key) == strlen(token->GetName()) && - !strncmp(key, token->GetName(), strlen(key))) { - found = true; - break; - } - } - MASSERT(found && token); - return token; -} - -// The caller of this function makes sure 'key' is already in the -// string pool of Lexer. -Token* Lexer::FindPreprocessorKeywordToken(const char *key) { - Token *token = NULL; - bool found = false; - for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; - i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum + gPreprocessorKeywordTokensNum; - i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_PKW); - if (strlen(key) == strlen(token->GetName()) && - !strncmp(key, token->GetName(), strlen(key))) { - found = true; - break; - } - } - return found && token ? token : NULL; -} - -// CommentToken is the last predefined token -Token* Lexer::FindCommentToken() { - Token *token = &gSystemTokens[gSystemTokensNum - 1]; - MASSERT((token->mTkType == TT_CM) && "Last system token is not a comment token."); - return token; -} - ///////////////////////////////////////////////////////////////////////////// // Both ClearLeadingNewLine() and AddEndingNewLine() will later be implemented // as language specific, and they will be overriding functions. diff --git a/src/MapleFE/shared/src/parser.cpp b/src/MapleFE/shared/src/parser.cpp index 10ef502f776d447c79c8307590b10b27bcdf3bde..d13dc648a48fd724b7761c9e1536cebc4233679b 100644 --- a/src/MapleFE/shared/src/parser.cpp +++ b/src/MapleFE/shared/src/parser.cpp @@ -357,7 +357,7 @@ bool Parser::HandlePreprocessorToken(Token *t) { return false; } - Token *pt = mLexer->FindPreprocessorKeywordToken(t->mData.mName); + Token *pt = FindPreprocessorKeywordToken(t->mData.mName); if (pt == nullptr) return false; diff --git a/src/MapleFE/shared/src/token.cpp b/src/MapleFE/shared/src/token.cpp index 648406b7b943c2836c22c723e08758b22e853a7a..b647225d10cee689143776e5d82d256f16ab2808 100644 --- a/src/MapleFE/shared/src/token.cpp +++ b/src/MapleFE/shared/src/token.cpp @@ -14,8 +14,12 @@ */ #include "token.h" #include "stringpool.h" +#include "rule_summary.h" #include "massert.h" +#include +#include + namespace maplefe { #undef SEPARATOR @@ -167,4 +171,85 @@ bool Token::Equal(Token *t) { return equal; } +/////////////////////////////////////////////////////////////////////////// +// Utilities for finding system tokens +// Remember the order of tokens are operators, separators, and keywords. +/////////////////////////////////////////////////////////////////////////// + +Token* FindOperatorToken(OprId id) { + Token *token = NULL; + bool found = false; + for (unsigned i = 0; i < gOperatorTokensNum; i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_OP); + if (token->GetOprId() == id) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +Token* FindSeparatorToken(SepId id) { + Token *token = NULL; + bool found = false; + for (unsigned i = gOperatorTokensNum; i < gOperatorTokensNum + gSeparatorTokensNum; i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_SP); + if (token->GetSepId() == id) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +// The caller of this function makes sure 'key' is already in the +// string pool of Lexer. +Token* FindKeywordToken(const char *key) { + Token *token = NULL; + bool found = false; + for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum; + i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; + i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_KW); + if (strlen(key) == strlen(token->GetName()) && + !strncmp(key, token->GetName(), strlen(key))) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +// The caller of this function makes sure 'key' is already in the +// string pool of Lexer. +Token* FindPreprocessorKeywordToken(const char *key) { + Token *token = NULL; + bool found = false; + for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; + i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum + gPreprocessorKeywordTokensNum; + i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_PKW); + if (strlen(key) == strlen(token->GetName()) && + !strncmp(key, token->GetName(), strlen(key))) { + found = true; + break; + } + } + return found && token ? token : NULL; +} + +// CommentToken is the last predefined token +Token* FindCommentToken() { + Token *token = &gSystemTokens[gSystemTokensNum - 1]; + MASSERT((token->mTkType == TT_CM) && "Last system token is not a comment token."); + return token; +} + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers20.ts b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts new file mode 100644 index 0000000000000000000000000000000000000000..afe4d26516226adf676dc6949e8967248f417174 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts @@ -0,0 +1,11 @@ +class Klass { + items: number[] = []; + break() { + for (const i of this.items) + console.log(i); + } +} + +var obj: Klass = new Klass(); +obj.items.push(6, 2, 1, 4, 5, 3); +obj.break(); diff --git a/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result index db55fa564031d810e082c57e1e3f884f79b9ede4..7a631af42512bbc917e468232fa4ac02bdac890c 100644 --- a/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result +++ b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result @@ -2,8 +2,6 @@ Matched 7 tokens. Matched 14 tokens. ============= Module =========== == Sub Tree == -js_var Decl: str="This \ -is \ -a string literal" +js_var Decl: str="This is a string literal" == Sub Tree == console.log(str) diff --git a/src/MapleFE/typescript/include/lang_keywords.def b/src/MapleFE/typescript/include/lang_keywords.def index 76d3e2dd2a52571c1a79b6e085014545f4226575..b8e018414ebf9bbb63f34e64123c86172429f52e 100644 --- a/src/MapleFE/typescript/include/lang_keywords.def +++ b/src/MapleFE/typescript/include/lang_keywords.def @@ -89,13 +89,33 @@ LANGKEYWORD(async) LANGKEYWORD(global) +// Utility Types +LANGKEYWORD(Partial) +LANGKEYWORD(Required) +LANGKEYWORD(Readonly) +LANGKEYWORD(Record) +LANGKEYWORD(Pick) +LANGKEYWORD(Omit) +LANGKEYWORD(Exclude) +LANGKEYWORD(Extract) +LANGKEYWORD(NonNullable) +LANGKEYWORD(Parameters) +LANGKEYWORD(ConstructorParameters) +LANGKEYWORD(ReturnType) +LANGKEYWORD(InstanceType) +LANGKEYWORD(ThisParameterType) +LANGKEYWORD(OmitThisParameter) +LANGKEYWORD(ThisType) +LANGKEYWORD(Uppercase) +LANGKEYWORD(Lowercase) +LANGKEYWORD(Capitalize) +LANGKEYWORD(Uncapitalize) + +LANGKEYWORD(Error) + // extra LANGKEYWORD(console) LANGKEYWORD(log) LANGKEYWORD(null) - -LANGKEYWORD(Parameters) -LANGKEYWORD(Error) -LANGKEYWORD(NonNullable) diff --git a/src/MapleFE/typescript/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h index 4784801111983030d3cbb7bd7089a1c037ce9506..929de87c24b46706d9964306411a854a052ce0e2 100644 --- a/src/MapleFE/typescript/include/lang_spec.h +++ b/src/MapleFE/typescript/include/lang_spec.h @@ -33,6 +33,7 @@ public: bool StringToBool(std::string &s); Char StringToChar(std::string &s); bool StringIsNull(std::string &s); + const char* StringToString(std::string &); }; extern LitData ProcessLiteral(LitId type, const char *str); diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index e175d3e5ba79c5c174907b4949d53319ffa6906d..99b61265fedeb635afb44a5f6092e98bedd3b3dc 100644 --- a/src/MapleFE/typescript/src/lang_spec.cpp +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -44,6 +44,44 @@ bool StringToValueImpl::StringToBool(std::string &s) { bool StringToValueImpl::StringIsNull(std::string &s) {return false;} +const char* StringToValueImpl::StringToString(std::string &in_str) { + std::string target; + + // For most languages, the input 'in_str' still contains the leading " or ' and the + // ending " or '. They need to be removed. + std::string str; + + // If empty string literal, return the empty 'target'. + if (in_str.size() == 2) { + const char *s = gStringPool.FindString(target); + return s; + } else { + str.assign(in_str, 1, in_str.size() - 2); + } + + // For typescript, if a string literal is: + // s : string = "abc \ + // efg"; + // The \ is actually connnecting the next line into the string literal. + // We need handle the connection. + + std::string s_ret; + for (unsigned i = 0; i < str.length(); i++) { + char c = str[i]; + if (c == '\\') { + if ((i < str.length() - 1) && (str[i+1] == '\n')) { + // skip \ and \n + i += 1; + continue; + } + } + s_ret.push_back(c); + } + + const char *s = gStringPool.FindString(s_ret); + return s; +} + static char DeEscape(char c) { switch(c) { case 'b': @@ -440,7 +478,7 @@ bool TypescriptParser::TokenSplit(Token *t) { if (!type_arg->IsIdentifier()) return false; - Token *extends_token = mLexer->FindKeywordToken("extends"); + Token *extends_token = FindKeywordToken("extends"); Token *lt = mActiveTokens.ValueAtIndex(size - 2); @@ -456,8 +494,8 @@ bool TypescriptParser::TokenSplit(Token *t) { } // Now we got a matching case. - Token *gt_token = mLexer->FindOperatorToken(OPR_GT); - Token *assign_token = mLexer->FindOperatorToken(OPR_Assign); + Token *gt_token = FindOperatorToken(OPR_GT); + Token *assign_token = FindOperatorToken(OPR_Assign); mActiveTokens.PushBack(gt_token); mActiveTokens.PushBack(assign_token);