From 401d88647172a1d80b8f79cad00871f2f971981e Mon Sep 17 00:00:00 2001 From: yehandong Date: Fri, 17 Dec 2021 16:52:43 -0800 Subject: [PATCH 01/20] Add linenum, colnum, line begin, line end to token. --- src/MapleFE/autogen/src/token_gen.cpp | 8 ++++---- src/MapleFE/shared/include/token.h | 6 ++++++ src/MapleFE/shared/src/token.cpp | 7 +++++++ src/MapleFE/shared/src/tokenpool.cpp | 7 +++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/MapleFE/autogen/src/token_gen.cpp b/src/MapleFE/autogen/src/token_gen.cpp index 725192414d..59bb94456c 100644 --- a/src/MapleFE/autogen/src/token_gen.cpp +++ b/src/MapleFE/autogen/src/token_gen.cpp @@ -155,7 +155,7 @@ void TokenGen::GenCppFile() { std::list::iterator oit = gTokenTable.mOperators->begin(); for (; oit != gTokenTable.mOperators->end(); oit++, overall_index++) { - std::string output = " {.mTkType = TT_OP, {.mOprId = "; + std::string output = " {.mTkType = TT_OP, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mOprId = "; Operator opr = *oit; std::string opr_name = "OPR_"; opr_name += FindOperatorName(opr.mID); @@ -186,7 +186,7 @@ void TokenGen::GenCppFile() { std::list::iterator sit = gTokenTable.mSeparators->begin(); for (; sit != gTokenTable.mSeparators->end(); sit++, overall_index++) { - std::string output = " {.mTkType = TT_SP, {.mSepId = "; + std::string output = " {.mTkType = TT_SP, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mSepId = "; Separator sep = *sit; std::string sep_name = "SEP_"; sep_name += FindSeparatorName(sep.mID); @@ -217,7 +217,7 @@ void TokenGen::GenCppFile() { unsigned kw_size = gTokenTable.mKeywords.size(); for (unsigned index = 0; index < kw_size; index++, overall_index++) { - std::string output = " {.mTkType = TT_KW, {.mName = "; + std::string output = " {.mTkType = TT_KW, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mName = "; std::string keyword = gTokenTable.mKeywords[index]; output += "\""; output += keyword; @@ -247,7 +247,7 @@ void TokenGen::GenCppFile() { } // Write the comment token - std::string output = " {.mTkType = TT_CM, {.mName = NULL}, .mAltTokens = NULL}"; + std::string output = " {.mTkType = TT_CM, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mName = NULL}, .mAltTokens = NULL}"; mCppFile.WriteOneLine(output.c_str(), output.size()); mCppFile.WriteOneLine("};", 2); mCppFile.WriteOneLine("}", 1); diff --git a/src/MapleFE/shared/include/token.h b/src/MapleFE/shared/include/token.h index 2d650fab76..243c09a1dd 100644 --- a/src/MapleFE/shared/include/token.h +++ b/src/MapleFE/shared/include/token.h @@ -112,6 +112,12 @@ struct RegExprData { struct Token { TK_Type mTkType; + + unsigned mLineNum; // line num + unsigned mColNum; // column num + bool mLineBegin; // first token of line? + bool mLineEnd; // last token of line? + union { const char *mName; // Identifier, Keyword. In the gStringPool LitData mLitData; diff --git a/src/MapleFE/shared/src/token.cpp b/src/MapleFE/shared/src/token.cpp index 66e4a85ece..b0f35583e1 100644 --- a/src/MapleFE/shared/src/token.cpp +++ b/src/MapleFE/shared/src/token.cpp @@ -127,6 +127,13 @@ void Token::Dump() { default: break; } + + DUMP1(" line: ", mLineNum); + DUMP1(" col: ", mColNum); + if (mLineBegin) + DUMP0(" line-first "); + if (mLineEnd) + DUMP0(" line-last "); } } diff --git a/src/MapleFE/shared/src/tokenpool.cpp b/src/MapleFE/shared/src/tokenpool.cpp index 263e76a03c..89dfde73e9 100644 --- a/src/MapleFE/shared/src/tokenpool.cpp +++ b/src/MapleFE/shared/src/tokenpool.cpp @@ -23,8 +23,15 @@ char* TokenPool::NewToken(unsigned size) { char *addr = mMemPool.Alloc(size); MASSERT(addr && "MemPool failed to alloc a token."); Token *token = (Token*)addr; + token->mAltTokens = NULL; + token->mLineNum = 0; + token->mColNum = 0; + token->mLineBegin = false; + token->mLineEnd = false; + mTokens.PushBack((Token*)addr); return addr; } + } -- Gitee From 4acf5e5e7bae50e62c2548312d94a97d1aabe1e9 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Fri, 17 Dec 2021 17:59:45 -0800 Subject: [PATCH 02/20] Assign a pseudo class name to unnamed class --- src/MapleFE/astopt/include/ast_adj.h | 1 + src/MapleFE/astopt/src/ast_adj.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/MapleFE/astopt/include/ast_adj.h b/src/MapleFE/astopt/include/ast_adj.h index cc85af1341..025ae5d8c1 100644 --- a/src/MapleFE/astopt/include/ast_adj.h +++ b/src/MapleFE/astopt/include/ast_adj.h @@ -62,6 +62,7 @@ class AdjustASTVisitor : public AstVisitor { std::unordered_map mRenameMap; void CheckAndRenameCppKeywords(TreeNode *node); + void AssignPseudoName(TreeNode *node); DeclNode *VisitDeclNode(DeclNode *node); ImportNode *VisitImportNode(ImportNode *node); diff --git a/src/MapleFE/astopt/src/ast_adj.cpp b/src/MapleFE/astopt/src/ast_adj.cpp index ec48977fe2..634a282752 100644 --- a/src/MapleFE/astopt/src/ast_adj.cpp +++ b/src/MapleFE/astopt/src/ast_adj.cpp @@ -52,6 +52,7 @@ IdentifierNode *AdjustASTVisitor::VisitIdentifierNode(IdentifierNode *node) { ClassNode *AdjustASTVisitor::VisitClassNode(ClassNode *node) { (void) AstVisitor::VisitClassNode(node); CheckAndRenameCppKeywords(node); + AssignPseudoName(node); // skip getting canonical type if not only fields if (node->GetMethodsNum() || node->GetSuperClassesNum() || node->GetSuperInterfacesNum() || node->GetSuperClassesNum() || node->GetTypeParamsNum()) { @@ -517,4 +518,14 @@ void AdjustASTVisitor::CheckAndRenameCppKeywords(TreeNode *node) { } } +void AdjustASTVisitor::AssignPseudoName(TreeNode *node) { + if (!mHandler->IsTS() || node->GetStrIdx() != 0) { + return; + } + static int pseudo = 0; + // Set a pseudo name + unsigned newidx = gStringPool.GetStrIdx("__Pseudo_" + std::to_string(++pseudo)); + node->SetStrIdx(newidx); +} + } -- Gitee From 48eaf795b845222062d36e50f8f084ac1334b411 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Sat, 18 Dec 2021 17:55:25 -0800 Subject: [PATCH 03/20] Reimplement proto.js with Map --- src/MapleFE/docs/utils/proto.js | 74 ++++++++++++++++----------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 9d25dde1ef..088d62a353 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -15,47 +15,43 @@ let arr = [1, 2, 3] function* generator() { yield 1; } +function insert(graph, ...args) { + for (let arg of args) { + let [obj, name] = typeof arg === "string" ? [eval(arg), arg] : arg; + if (typeof obj !== "undefined" && obj !== null) + if (!graph.has(obj)) { + graph.set(obj, name !== null || typeof obj !== "function" ? name : obj.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); + insert(graph, [obj.prototype, graph.get(obj) + "Prototype"], [obj.__proto__, null], [obj.constructor, null]); + } else if (name !== null) + graph.set(obj, name); + } +} + // Dump graphs with edges for prototype, __proto__ and constructor properties of each objects +const gen = generator.prototype.__proto__; for(let g = 0; g < 4; ++g) { - let objs = [Function, Object], names = ["Function", "Object"], gen = undefined; - if (g < 2) { - objs.unshift ( arr, Array, Vehicle, Car, MyCar, car, mycar); - names.unshift("arr", "Array", "Vehicle", "Car", "MyCar", "car", "mycar"); - } else { - gen = generator.prototype.__proto__; - objs.unshift ( generator, generator(), generator.constructor, gen, gen.__proto__); - names.unshift("generator", "generator_instance", "GeneratorFunction", "GeneratorPrototype", "IteratorPrototype"); - } - console.log("digraph JS" + g + " {\nranksep=0.6;\nnodesep=0.6;\n" + (g % 2 == 0 ? "newrank=true;\n" : "")); - let num = objs.length; - let k = num, suffix = "Prototype"; - // Add prototype objects and edges for them - for(let i = 0; i < num; ++i) { - console.log(names[i].includes(suffix) ? names[i] + "[shape=box];" : ""); - if(typeof objs[i].prototype !== "undefined") { - objs[k] = objs[i].prototype; - let special = names[i] === "GeneratorFunction" && objs[k].prototype === gen; - names[k] = special ? "Generator" : names[i] + suffix; - console.log(special ? "GeneratorPrototype -> " + names[k] + " [label=\"prototype\", color=blue, fontcolor=blue, dir=back];" : ""); - console.log(g % 2 == 0 ? "subgraph cluster_" + names[i] + " {\nrank=same;\ncolor=white;\n" + names[i] + ";\n" - + names[k] + "[shape=box];\n }" : names[k] + "[shape=box];"); - console.log(names[i] + " -> " + names[k] + " [label=\"prototype\", color=blue, fontcolor=blue];"); - k++; - } - } - // Add edges for __proto__ and constructor properties of each objects - num = objs.length; - for(let i = 0; i < num; ++i) { - console.log("\n/* Object.getOwnPropertyNames(" + names[i] + "):\n", Object.getOwnPropertyNames(objs[i]), "\n" - + names[i] + ".toString(): " + (names[i] === "Generator" ? "-" : objs[i].toString().replace(/\s+/g, " ")) + "\n*/"); - for(let j = 0; j < num; ++j) { - // Edges for constructor properties in the second graph only - if(g % 2 == 1 && objs[i].constructor === objs[j]) - console.log(names[i] + " -> " + names[j] + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); - // Edges for __proto__ properties - if(objs[i].__proto__ === objs[j]) - console.log(names[i] + " -> " + names[j] + " [label=\"__proto__\", color=red, fontcolor=red];"); - } + let graph = new Map(); + if (g < 2) + insert(graph, "Function", "Object", "Array", "arr", "mycar", "car"); + else + insert(graph, "Function", "Object", "generator", [generator(), "generator_instance"], [generator.__proto__, "Generator"], + [generator.constructor, "GeneratorFunction"], [gen, "GeneratorPrototype"], [gen.__proto__, "IteratorPrototype"]); + console.log("digraph JS" + g + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (g % 2 == 1 ? "" : "newrank=true;")); + for (let [key, value] of graph) { + console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), + "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); + console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); + // Add edges for prototype properties of objects + if (typeof key.prototype !== "undefined" && key.prototype !== null) + console.log((g % 2 == 1 ? "" : "subgraph cluster_" + value + + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n }") + + value + " -> " + graph.get(key.prototype) + " [label=\"prototype\", color=blue, fontcolor=blue];"); + // Add edges for constructor properties of objects + if (g % 2 == 1 && key.constructor !== "undefined" && key.constructor !== null) + console.log(value + " -> " + graph.get(key.constructor) + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); + // Add edges for __proto__ properties of objects + if (key.__proto__ !== "undefined" && key.__proto__ !== null) + console.log(value + " -> " + graph.get(key.__proto__) + " [label=\"__proto__\", color=red, fontcolor=red];"); } console.log("}"); } -- Gitee From 20b5bc6d057421af30d99c5f9f775c72c5dff891 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Sat, 18 Dec 2021 17:58:39 -0800 Subject: [PATCH 04/20] Remove proto2.ts --- src/MapleFE/docs/utils/proto2.ts | 54 -------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 src/MapleFE/docs/utils/proto2.ts diff --git a/src/MapleFE/docs/utils/proto2.ts b/src/MapleFE/docs/utils/proto2.ts deleted file mode 100644 index d7d0c40652..0000000000 --- a/src/MapleFE/docs/utils/proto2.ts +++ /dev/null @@ -1,54 +0,0 @@ -interface IPrototype { prototype: any; } -type TPrototype = IPrototype & Function; -interface IProto { __proto__: any; } -type TProto = IProto & Object; - -// Command line to get graphs: tsc -t es6 proto2.ts; nodejs proto2.js | ./viewdot.sh -class Vehicle { -} -class Car implements Vehicle { - name: string; - constructor (name) { this.name = name; } -} -class MyCar extends Car { - constructor (name) { super(name); } -} - -let car = new Car("A car"); -let mycar = new MyCar("My car"); -let arr = [] - -// Dump graphs with edges for prototype, __proto__ and constructor properties of each objects -for(let g = 0; g < 2; ++g) { - let objs = [ arr, Array, Vehicle, Car, MyCar, car, mycar, Function, Object, ]; - let names = [ "arr", "Array", "Vehicle", "Car", "MyCar", "car", "mycar", "Function", "Object", ]; - console.log("digraph JS" + g + " {\nranksep=0.6;\nnodesep=0.6;\n" + (g == 0 ? "newrank=true;\n" : "")); - let num = objs.length; - let k = num; - // Add prototype objects and edges for them - for(let i = 0; i < num; ++i) { - let x = typeof (objs[i] as unknown as TPrototype).prototype; - if(x === "function" || x === "object") { - objs[k] = (objs[i] as unknown as TPrototype).prototype; - names[k] = names[i] + "_prototype"; - console.log(g == 0 ? "subgraph cluster_" + names[i] + " {\nrank=same;\ncolor=white;\n" - + names[i] + ";\n" + names[k] + "[label=\"" + names[i] + ".prototype\", shape=box];\n }" - : names[k] + "[label=\"" + names[i] + ".prototype\", shape=box];"); - console.log(names[i] + " -> " + names[k] + " [label=\"prototype\", color=blue, fontcolor=blue];"); - k++; - } - } - // Add edges for __proto__ and constructor properties of each objects - num = objs.length; - for(let i = 0; i < num; ++i) { - for(let j = 0; j < num; ++j) { - // Edges for constructor properties in the second graph only - if(g > 0 && objs[i].constructor === objs[j]) - console.log(names[i] + " -> " + names[j] + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); - // Edges for __proto__ properties - if((objs[i] as unknown as TProto).__proto__ === objs[j]) - console.log(names[i] + " -> " + names[j] + " [label=\"__proto__\", color=red, fontcolor=red];"); - } - } - console.log("}"); -} -- Gitee From 1b8a4b99a7ea899b952dab71776907e83a83afbc Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Sat, 18 Dec 2021 18:26:23 -0800 Subject: [PATCH 05/20] Add graphs for Math, JSON, Promise and Symbol --- src/MapleFE/docs/utils/proto.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 088d62a353..5fb6dbd252 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -27,15 +27,17 @@ function insert(graph, ...args) { } } -// Dump graphs with edges for prototype, __proto__ and constructor properties of each objects +// Dump graphs with edges for prototype, __proto__ and constructor properties of each object const gen = generator.prototype.__proto__; -for(let g = 0; g < 4; ++g) { +for(let g = 0; g < 6; ++g) { let graph = new Map(); if (g < 2) insert(graph, "Function", "Object", "Array", "arr", "mycar", "car"); - else + else if (g < 4) insert(graph, "Function", "Object", "generator", [generator(), "generator_instance"], [generator.__proto__, "Generator"], [generator.constructor, "GeneratorFunction"], [gen, "GeneratorPrototype"], [gen.__proto__, "IteratorPrototype"]); + else + insert(graph, "Function", "Object", "Symbol", "Math", "JSON", "Promise"); console.log("digraph JS" + g + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (g % 2 == 1 ? "" : "newrank=true;")); for (let [key, value] of graph) { console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), -- Gitee From 18aca7e4683e0eb884fb6a84b140313e60513b0d Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 09:46:17 -0800 Subject: [PATCH 06/20] Add a flag '// digraph JS' to indicate the end of a graph --- src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp | 2 +- src/MapleFE/docs/utils/proto.js | 2 +- src/MapleFE/docs/utils/viewdot.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp index 7c9ae38db3..4820cf0929 100644 --- a/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp +++ b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp @@ -133,7 +133,7 @@ void GenerateDOTGraph( std::vector&obj, std::vector&name) std::cout << names[i] << " -> " << names[j] << " [label=\"__proto__\", color=red, fontcolor=red];" << std::endl; } } - std::cout << "}" << std::endl; + std::cout << "} // digraph JS" << g << std::endl; } } diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 5fb6dbd252..17094831e5 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -55,5 +55,5 @@ for(let g = 0; g < 6; ++g) { if (key.__proto__ !== "undefined" && key.__proto__ !== null) console.log(value + " -> " + graph.get(key.__proto__) + " [label=\"__proto__\", color=red, fontcolor=red];"); } - console.log("}"); + console.log("} // digraph JS" + g); } diff --git a/src/MapleFE/docs/utils/viewdot.sh b/src/MapleFE/docs/utils/viewdot.sh index ab1c2f0a41..a6c0b72b3c 100755 --- a/src/MapleFE/docs/utils/viewdot.sh +++ b/src/MapleFE/docs/utils/viewdot.sh @@ -2,7 +2,7 @@ if [ $# -lt 1 ]; then out=$(cat) ts=/tmp/viewdot-$$ - grep -n -e "digraph [^{]* {" -e "^}" <<< "$out" | grep -A1 "digraph [^{]* {" | + grep -n -e "digraph [^{]* {" -e "^} // digraph JS" <<< "$out" | grep -A1 "digraph [^{]* {" | grep -v ^-- | sed 'N;s/\n/ /' | sed -e 's/:.*digraph [^{]* { */,/' -e 's/:.*/p/g' | { while read cmd; do idx=$((idx+1)) -- Gitee From a681819cfe695d75c917950bbfc044324938be1d Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 10:08:00 -0800 Subject: [PATCH 07/20] Make proto.js work with js68 as well --- src/MapleFE/docs/utils/proto.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 17094831e5..6ab6812fd2 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -28,6 +28,7 @@ function insert(graph, ...args) { } // Dump graphs with edges for prototype, __proto__ and constructor properties of each object +let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') const gen = generator.prototype.__proto__; for(let g = 0; g < 6; ++g) { let graph = new Map(); @@ -40,8 +41,9 @@ for(let g = 0; g < 6; ++g) { insert(graph, "Function", "Object", "Symbol", "Math", "JSON", "Promise"); console.log("digraph JS" + g + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (g % 2 == 1 ? "" : "newrank=true;")); for (let [key, value] of graph) { - console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), - "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); + if (nodejs) + console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), + "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); // Add edges for prototype properties of objects if (typeof key.prototype !== "undefined" && key.prototype !== null) -- Gitee From 89c1577278224119c6681fd2aff593f71fbea5b3 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 11:56:19 -0800 Subject: [PATCH 08/20] Add graphs for closure --- src/MapleFE/docs/utils/proto.js | 65 +++++++++++++++++++------------ src/MapleFE/docs/utils/viewdot.sh | 14 ++++--- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 6ab6812fd2..52c9239680 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -14,7 +14,25 @@ let mycar = new MyCar("My car"); let arr = [1, 2, 3] function* generator() { yield 1; } +const gen = generator.prototype.__proto__; + +function makeClosure(a) { + return function (b) { + return a + b; + } +} +const closure = makeClosure(1); + +// All data for generating graphs +let data = [ + ["Classes", ["Array", "arr", "mycar", "car"]], + ["Generator", ["generator", [generator(), "generator_instance"], [generator.__proto__, "Generator"], + [generator.constructor, "GeneratorFunction"], [gen, "GeneratorPrototype"], [gen.__proto__, "IteratorPrototype"]]], + ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], + ["Closure", ["makeClosure", "closure"]], +]; +// Gether all reachable objects from their prototype, __proto__ and constructor properties function insert(graph, ...args) { for (let arg of args) { let [obj, name] = typeof arg === "string" ? [eval(arg), arg] : arg; @@ -29,33 +47,30 @@ function insert(graph, ...args) { // Dump graphs with edges for prototype, __proto__ and constructor properties of each object let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') -const gen = generator.prototype.__proto__; -for(let g = 0; g < 6; ++g) { +for (let entry of data) { + let [title, objs] = entry; let graph = new Map(); - if (g < 2) - insert(graph, "Function", "Object", "Array", "arr", "mycar", "car"); - else if (g < 4) - insert(graph, "Function", "Object", "generator", [generator(), "generator_instance"], [generator.__proto__, "Generator"], - [generator.constructor, "GeneratorFunction"], [gen, "GeneratorPrototype"], [gen.__proto__, "IteratorPrototype"]); - else - insert(graph, "Function", "Object", "Symbol", "Math", "JSON", "Promise"); - console.log("digraph JS" + g + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (g % 2 == 1 ? "" : "newrank=true;")); - for (let [key, value] of graph) { - if (nodejs) - console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), - "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); - console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); - // Add edges for prototype properties of objects - if (typeof key.prototype !== "undefined" && key.prototype !== null) - console.log((g % 2 == 1 ? "" : "subgraph cluster_" + value - + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n }") - + value + " -> " + graph.get(key.prototype) + " [label=\"prototype\", color=blue, fontcolor=blue];"); - // Add edges for constructor properties of objects - if (g % 2 == 1 && key.constructor !== "undefined" && key.constructor !== null) + insert(graph, "Function", "Object", ...objs); + for (let ctor of ["", "_with_ctors"]) { + console.log("digraph JS_" + title + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); + for (let [key, value] of graph) { + // Add comments with detailed information of keys + if (nodejs) + console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), + "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); + console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); + // Add edges for prototype properties of objects + if (typeof key.prototype !== "undefined" && key.prototype !== null) + console.log((ctor != "" ? "" : "subgraph cluster_" + value + + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n }") + + value + " -> " + graph.get(key.prototype) + " [label=\"prototype\", color=blue, fontcolor=blue];"); + // Add edges for constructor properties of objects + if (ctor != "" && key.constructor !== "undefined" && key.constructor !== null) console.log(value + " -> " + graph.get(key.constructor) + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); - // Add edges for __proto__ properties of objects - if (key.__proto__ !== "undefined" && key.__proto__ !== null) + // Add edges for __proto__ properties of objects + if (key.__proto__ !== "undefined" && key.__proto__ !== null) console.log(value + " -> " + graph.get(key.__proto__) + " [label=\"__proto__\", color=red, fontcolor=red];"); + } + console.log("} // digraph JS_" + title + ctor); } - console.log("} // digraph JS" + g); } diff --git a/src/MapleFE/docs/utils/viewdot.sh b/src/MapleFE/docs/utils/viewdot.sh index a6c0b72b3c..f9252d7c0a 100755 --- a/src/MapleFE/docs/utils/viewdot.sh +++ b/src/MapleFE/docs/utils/viewdot.sh @@ -1,17 +1,19 @@ #!/bin/bash if [ $# -lt 1 ]; then out=$(cat) - ts=/tmp/viewdot-$$ + tmpdir=$(mktemp -dt viewdot-XXXXXX) + trap "rm -rf $tmpdir" SIGINT SIGQUIT SIGKILL grep -n -e "digraph [^{]* {" -e "^} // digraph JS" <<< "$out" | grep -A1 "digraph [^{]* {" | grep -v ^-- | sed 'N;s/\n/ /' | sed -e 's/:.*digraph [^{]* { */,/' -e 's/:.*/p/g' | { while read cmd; do - idx=$((idx+1)) - sed -n $cmd <<< "$out" > "$ts"-$idx.dot - dot -Tpng -o "$ts"-$idx.png "$ts"-$idx.dot - env LC_ALL=C viewnior $VIEWOP "$ts"-$idx.png & + name=$(sed -n $cmd <<< "$out" | head -1 | sed 's/.*digraph \([^{]*\) {.*/\1/') + echo $$-$name + sed -n $cmd <<< "$out" > "$tmpdir"/$$-$name.dot + dot -Tpng -o "$tmpdir"/$$-$name.png "$tmpdir"/$$-$name.dot + env LC_ALL=C viewnior "$tmpdir"/$$-$name.png & done wait - rm -f "$ts"-[0-9]*.png "$ts"-[0-9]*.dot; } + rm -rf "$tmpdir"; } exit fi for f; do -- Gitee From 84557c3251e04f8cc67dadd8d1d1765b96997597 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 15:55:09 -0800 Subject: [PATCH 09/20] Fix up every object with null as its name in a graph --- src/MapleFE/docs/utils/proto.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 52c9239680..b08607b74e 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -14,7 +14,7 @@ let mycar = new MyCar("My car"); let arr = [1, 2, 3] function* generator() { yield 1; } -const gen = generator.prototype.__proto__; +const gpt = generator.prototype.__proto__; function makeClosure(a) { return function (b) { @@ -26,23 +26,27 @@ const closure = makeClosure(1); // All data for generating graphs let data = [ ["Classes", ["Array", "arr", "mycar", "car"]], - ["Generator", ["generator", [generator(), "generator_instance"], [generator.__proto__, "Generator"], - [generator.constructor, "GeneratorFunction"], [gen, "GeneratorPrototype"], [gen.__proto__, "IteratorPrototype"]]], + ["Generator", ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], + [gpt.__proto__, "IteratorPrototype"], [gpt.constructor, "Generator"]]], ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], ["Closure", ["makeClosure", "closure"]], ]; -// Gether all reachable objects from their prototype, __proto__ and constructor properties -function insert(graph, ...args) { +// Gather all reachable objects from their prototype, __proto__ and constructor properties +function insert(g, depth, ...args) { for (let arg of args) { - let [obj, name] = typeof arg === "string" ? [eval(arg), arg] : arg; - if (typeof obj !== "undefined" && obj !== null) - if (!graph.has(obj)) { - graph.set(obj, name !== null || typeof obj !== "function" ? name : obj.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); - insert(graph, [obj.prototype, graph.get(obj) + "Prototype"], [obj.__proto__, null], [obj.constructor, null]); + let [o, name] = typeof arg === "string" ? [eval(arg), arg] : arg; + if (typeof o !== "undefined" && o !== null) + if (!g.has(o)) { + g.set(o, name !== null || typeof o !== "function" ? name : o.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); + insert(g, ++depth, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); } else if (name !== null) - graph.set(obj, name); + g.set(o, name); } + if (depth === 0) + for (let [index, entry] of Array.from(g).entries()) + if (entry[1] === null) // Fix up every object with null as its name + g.set(entry[0], "Node_" + index); } // Dump graphs with edges for prototype, __proto__ and constructor properties of each object @@ -50,7 +54,7 @@ let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node for (let entry of data) { let [title, objs] = entry; let graph = new Map(); - insert(graph, "Function", "Object", ...objs); + insert(graph, 0, "Function", "Object", ...objs); for (let ctor of ["", "_with_ctors"]) { console.log("digraph JS_" + title + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); for (let [key, value] of graph) { @@ -62,7 +66,7 @@ for (let entry of data) { // Add edges for prototype properties of objects if (typeof key.prototype !== "undefined" && key.prototype !== null) console.log((ctor != "" ? "" : "subgraph cluster_" + value - + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n }") + + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n}\n") + value + " -> " + graph.get(key.prototype) + " [label=\"prototype\", color=blue, fontcolor=blue];"); // Add edges for constructor properties of objects if (ctor != "" && key.constructor !== "undefined" && key.constructor !== null) -- Gitee From ab5cab0725ff415ca6c0dd276dd95d877770e292 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 16:44:54 -0800 Subject: [PATCH 10/20] Replace any non word character '[^a-zA-Z0-9_]' with underscore in an object name --- src/MapleFE/docs/utils/proto.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index b08607b74e..abf283a5eb 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -39,14 +39,16 @@ function insert(g, depth, ...args) { if (typeof o !== "undefined" && o !== null) if (!g.has(o)) { g.set(o, name !== null || typeof o !== "function" ? name : o.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); - insert(g, ++depth, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); + insert(g, depth + 1, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); } else if (name !== null) g.set(o, name); } if (depth === 0) for (let [index, entry] of Array.from(g).entries()) if (entry[1] === null) // Fix up every object with null as its name - g.set(entry[0], "Node_" + index); + g.set(entry[0], "Object_" + index); + else + g.set(entry[0], entry[1].replace(/[^\w]/g, "_")); } // Dump graphs with edges for prototype, __proto__ and constructor properties of each object -- Gitee From 0ccefd9e4f60b89261adfb541d5dbd600d2a30fa Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 19:05:26 -0800 Subject: [PATCH 11/20] Add graphs for iterator --- src/MapleFE/docs/utils/proto.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index abf283a5eb..f76c5e9db4 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -10,7 +10,7 @@ class MyCar extends Car { } let car = new Car("A car"); -let mycar = new MyCar("My car"); +let myCar = new MyCar("My car"); let arr = [1, 2, 3] function* generator() { yield 1; } @@ -23,13 +23,18 @@ function makeClosure(a) { } const closure = makeClosure(1); +let myMap = new Map(); +let myMapIterator = myMap[Symbol.iterator](); +let MapIteratorPrototype = Object.getPrototypeOf(new Map()[Symbol.iterator]()); + // All data for generating graphs let data = [ - ["Classes", ["Array", "arr", "mycar", "car"]], + ["Classes", ["Array", "arr", "myCar", "car"]], ["Generator", ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], [gpt.__proto__, "IteratorPrototype"], [gpt.constructor, "Generator"]]], ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], ["Closure", ["makeClosure", "closure"]], + ["Iterators", ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]]], ]; // Gather all reachable objects from their prototype, __proto__ and constructor properties @@ -43,12 +48,15 @@ function insert(g, depth, ...args) { } else if (name !== null) g.set(o, name); } - if (depth === 0) - for (let [index, entry] of Array.from(g).entries()) - if (entry[1] === null) // Fix up every object with null as its name - g.set(entry[0], "Object_" + index); - else - g.set(entry[0], entry[1].replace(/[^\w]/g, "_")); + if (depth === 0) { + let visited = new Set(); + for (let [index, [key, value]] of Array.from(g).entries()) { + value = value === null || value === "" ? "Object_" + index : value.replace(/[^A-Za-z0-9]+/g, "_"); + if (visited.has(value)) value += "__" + index; + visited.add(value); + g.set(key, value); + } + } } // Dump graphs with edges for prototype, __proto__ and constructor properties of each object -- Gitee From 2c59aebd892c5ab1599c33d25793fd6233517bbf Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 19:39:12 -0800 Subject: [PATCH 12/20] Add AsyncGenerator, AsyncGeneratorFunction and AsyncFunction --- src/MapleFE/docs/utils/proto.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index f76c5e9db4..18d757d5d8 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -27,6 +27,10 @@ let myMap = new Map(); let myMapIterator = myMap[Symbol.iterator](); let MapIteratorPrototype = Object.getPrototypeOf(new Map()[Symbol.iterator]()); +async function asyncFunc() {} +async function* asyncGenerator() {} + const agpt = asyncGenerator.prototype.__proto__; + // All data for generating graphs let data = [ ["Classes", ["Array", "arr", "myCar", "car"]], @@ -35,6 +39,8 @@ let data = [ ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], ["Closure", ["makeClosure", "closure"]], ["Iterators", ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]]], + ["Async", ["asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], + [agpt.__proto__, "AsyncIteratorPrototype"], [agpt.constructor, "AsyncGenerator"], "asyncFunc"]], ]; // Gather all reachable objects from their prototype, __proto__ and constructor properties -- Gitee From ffc82da5bf9c6b0ebdfa695ea84646ecaa8e2dc5 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 19:51:29 -0800 Subject: [PATCH 13/20] AsyncGenerator should be asyncGenerator.__proto__ instead of agpt.constructor --- src/MapleFE/docs/utils/proto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 18d757d5d8..fdb7b930c2 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -39,8 +39,8 @@ let data = [ ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], ["Closure", ["makeClosure", "closure"]], ["Iterators", ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]]], - ["Async", ["asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], - [agpt.__proto__, "AsyncIteratorPrototype"], [agpt.constructor, "AsyncGenerator"], "asyncFunc"]], + ["Async", ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], + [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]]], ]; // Gather all reachable objects from their prototype, __proto__ and constructor properties -- Gitee From 6a1880f2a8a5b44eec0533465dea6fd0dbd1521e Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Mon, 20 Dec 2021 20:58:32 -0800 Subject: [PATCH 14/20] Use an object literal instead of an array for all data --- src/MapleFE/docs/utils/proto.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index fdb7b930c2..03d432750b 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -32,16 +32,16 @@ async function* asyncGenerator() {} const agpt = asyncGenerator.prototype.__proto__; // All data for generating graphs -let data = [ - ["Classes", ["Array", "arr", "myCar", "car"]], - ["Generator", ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], - [gpt.__proto__, "IteratorPrototype"], [gpt.constructor, "Generator"]]], - ["Builtins", ["Symbol", "Math", "JSON", "Promise"]], - ["Closure", ["makeClosure", "closure"]], - ["Iterators", ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]]], - ["Async", ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], - [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]]], -]; +let data = { + Classes : ["Array", "arr", "myCar", "car"], + Generator: ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], + [gpt.__proto__, "IteratorPrototype"], [gpt.constructor, "Generator"]], + Builtins : ["Symbol", "Math", "JSON", "Promise"], + Closure : ["makeClosure", "closure"], + Iterators: ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]], + Async : ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], + [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]], +}; // Gather all reachable objects from their prototype, __proto__ and constructor properties function insert(g, depth, ...args) { @@ -67,12 +67,11 @@ function insert(g, depth, ...args) { // Dump graphs with edges for prototype, __proto__ and constructor properties of each object let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') -for (let entry of data) { - let [title, objs] = entry; +for (let prop in data) { let graph = new Map(); - insert(graph, 0, "Function", "Object", ...objs); + insert(graph, 0, "Function", "Object", ...data[prop]); for (let ctor of ["", "_with_ctors"]) { - console.log("digraph JS_" + title + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); + console.log("digraph JS_" + prop + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); for (let [key, value] of graph) { // Add comments with detailed information of keys if (nodejs) @@ -91,6 +90,6 @@ for (let entry of data) { if (key.__proto__ !== "undefined" && key.__proto__ !== null) console.log(value + " -> " + graph.get(key.__proto__) + " [label=\"__proto__\", color=red, fontcolor=red];"); } - console.log("} // digraph JS_" + title + ctor); + console.log("} // digraph JS_" + prop + ctor); } } -- Gitee From 2a2d4fba8583da32ec324cfae97317d7eaf51bba Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Tue, 21 Dec 2021 09:41:21 -0800 Subject: [PATCH 15/20] Get Generator object with generator.__proto__ instead of gpt.constructor --- src/MapleFE/docs/utils/proto.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 03d432750b..e87e77d780 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -29,17 +29,17 @@ let MapIteratorPrototype = Object.getPrototypeOf(new Map()[Symbol.iterator]()); async function asyncFunc() {} async function* asyncGenerator() {} - const agpt = asyncGenerator.prototype.__proto__; +const agpt = asyncGenerator.prototype.__proto__; // All data for generating graphs let data = { Classes : ["Array", "arr", "myCar", "car"], Generator: ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], - [gpt.__proto__, "IteratorPrototype"], [gpt.constructor, "Generator"]], + [gpt.__proto__, "IteratorPrototype"], [generator.__proto__, "Generator"]], Builtins : ["Symbol", "Math", "JSON", "Promise"], Closure : ["makeClosure", "closure"], Iterators: ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]], - Async : ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGen_instance"], [agpt, "AsyncGeneratorPrototype"], + Async : ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGenerator_instance"], [agpt, "AsyncGeneratorPrototype"], [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]], }; @@ -78,17 +78,12 @@ for (let prop in data) { console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); - // Add edges for prototype properties of objects - if (typeof key.prototype !== "undefined" && key.prototype !== null) - console.log((ctor != "" ? "" : "subgraph cluster_" + value - + " {\nrank=same;\ncolor=white;\n" + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n}\n") - + value + " -> " + graph.get(key.prototype) + " [label=\"prototype\", color=blue, fontcolor=blue];"); - // Add edges for constructor properties of objects - if (ctor != "" && key.constructor !== "undefined" && key.constructor !== null) - console.log(value + " -> " + graph.get(key.constructor) + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); - // Add edges for __proto__ properties of objects - if (key.__proto__ !== "undefined" && key.__proto__ !== null) - console.log(value + " -> " + graph.get(key.__proto__) + " [label=\"__proto__\", color=red, fontcolor=red];"); + // Add edges for prototype, constructor and __proto__ properties of objects + for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) + if (typeof key[f] !== "undefined" && key[f] !== null && graph.has(key[f]) && (ctor != "" || f !== "constructor")) + console.log((ctor != "" || f !== "prototype" ? "" : "subgraph cluster_" + value + " {\nrank=same;\ncolor=white;\n" + + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n}\n") + value + " -> " + graph.get(key[f]) + + " [label=\"" + (f === "constructor" ? "ctor" : f) + "\", color=" + c + ", fontcolor=" + c + "];"); } console.log("} // digraph JS_" + prop + ctor); } -- Gitee From e8f19cea878538fa898876a34e0c1ad459766610 Mon Sep 17 00:00:00 2001 From: yehandong Date: Tue, 21 Dec 2021 09:53:50 -0800 Subject: [PATCH 16/20] Removed lexer AppendSemicolon --- src/MapleFE/shared/include/lexer.h | 3 --- src/MapleFE/shared/src/lexer.cpp | 3 --- src/MapleFE/typescript/include/lang_spec.h | 1 - src/MapleFE/typescript/src/lang_spec.cpp | 6 ------ 4 files changed, 13 deletions(-) diff --git a/src/MapleFE/shared/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 52a66ff83c..863e630e95 100644 --- a/src/MapleFE/shared/include/lexer.h +++ b/src/MapleFE/shared/include/lexer.h @@ -128,9 +128,6 @@ public: // For most languages, this does nothing. TS/JS are doing something. virtual bool CharIsSeparator(const char c) {return false;} - // For most languages, this does nothing. TS/JS are doing something. - virtual void AppendSemiColon() {} - virtual TempLitData* GetTempLit() {return NULL;} virtual bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end) {return false;} virtual bool FindNextTLPlaceHolder(unsigned start, std::string& s, unsigned& end) {return false;} diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index 39d8706273..83f9589a1b 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -72,9 +72,6 @@ int Lexer::ReadALine() { curidx += 3; } - if (current_line_size > 0 && _linenum == _total_linenum) - AppendSemiColon(); - return current_line_size; } diff --git a/src/MapleFE/typescript/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h index b58ce7ec9d..aa302bfdef 100644 --- a/src/MapleFE/typescript/include/lang_spec.h +++ b/src/MapleFE/typescript/include/lang_spec.h @@ -44,7 +44,6 @@ extern LitData ProcessLiteral(LitId type, const char *str); class TypescriptLexer : public Lexer { public: bool CharIsSeparator(const char); - void AppendSemiColon(); TempLitData* GetTempLit(); bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end); diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp index a9c107db5a..d73777758c 100644 --- a/src/MapleFE/typescript/src/lang_spec.cpp +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -177,12 +177,6 @@ bool TypescriptLexer::CharIsSeparator(const char c) { return false; } -// Add a ';' to the end of _line. -void TypescriptLexer::AppendSemiColon() { - //line[current_line_size] = ';'; - //current_line_size++; -} - // NOTE: right now we rely on 'tsc' to assure the input is legal, // so I'll make many things easier and will skip many lexical // checks. Just make it easy for now. -- Gitee From 24705d025848776f31094ec8eef401856749113d Mon Sep 17 00:00:00 2001 From: yehandong Date: Tue, 21 Dec 2021 10:12:42 -0800 Subject: [PATCH 17/20] Now tokens have line/col number ready! --- src/MapleFE/shared/src/lexer.cpp | 18 +++++++++++++++- src/MapleFE/shared/src/token.cpp | 35 ++++++++++++++++---------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index 83f9589a1b..f9c750fe96 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -326,9 +326,12 @@ Token* Lexer::LexToken(void) { // Read a token until end of line. // Return NULL if no token read. Token* Lexer::LexTokenNoNewLine(void) { + unsigned old_curidx = curidx; bool is_comment = GetComment(); if (is_comment) { Token *t = FindCommentToken(); + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -337,6 +340,8 @@ Token* Lexer::LexTokenNoNewLine(void) { OprId opr = GetOperator(); if (opr != OPR_NA) { Token *t = FindOperatorToken(opr); + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -344,7 +349,6 @@ Token* Lexer::LexTokenNoNewLine(void) { // There is a corner case: .2 // The dot is lexed as separator, and 2 is an integer. But actually it's a decimal. - unsigned old_curidx = curidx; SepId sep = GetSeparator(); unsigned new_curidx = curidx; @@ -357,6 +361,8 @@ Token* Lexer::LexTokenNoNewLine(void) { if (ld.mType != LT_NA) { MASSERT(ld.mType == LT_FPLiteral || ld.mType == LT_DoubleLiteral); Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; t->SetLiteral(ld); if (mTrace) t->Dump(); @@ -367,6 +373,8 @@ Token* Lexer::LexTokenNoNewLine(void) { } Token *t = FindSeparatorToken(sep); + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -375,6 +383,8 @@ Token* Lexer::LexTokenNoNewLine(void) { const char *keyword = GetKeyword(); if (keyword != NULL) { Token *t = FindKeywordToken(keyword); + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -383,6 +393,8 @@ Token* Lexer::LexTokenNoNewLine(void) { LitData ld = GetLiteral(); if (ld.mType != LT_NA) { Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; t->SetLiteral(ld); if (mTrace) t->Dump(); @@ -393,6 +405,8 @@ Token* Lexer::LexTokenNoNewLine(void) { if (identifier != NULL) { Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); t->SetIdentifier(identifier); + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -401,6 +415,8 @@ Token* Lexer::LexTokenNoNewLine(void) { TempLitData* tldata = GetTempLit(); if (tldata != NULL) { Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; t->SetTempLit(tldata); if (mTrace) t->Dump(); diff --git a/src/MapleFE/shared/src/token.cpp b/src/MapleFE/shared/src/token.cpp index b0f35583e1..1c23c988d7 100644 --- a/src/MapleFE/shared/src/token.cpp +++ b/src/MapleFE/shared/src/token.cpp @@ -30,7 +30,7 @@ const char* SeparatorTokenGetName(SepId id) { void SeparatorTokenDump(SepId id) { const char *name = SeparatorTokenGetName(id); - DUMP1("Separator Token: ", name); + DUMP1_NORETURN("Separator Token: ", name); return; } @@ -46,34 +46,34 @@ const char* OperatorTokenGetName(OprId id) { void OperatorTokenDump(OprId id) { const char *name = OperatorTokenGetName(id); - DUMP1("Operator Token: ", name); + DUMP1_NORETURN("Operator Token: ", name); return; } void LiteralTokenDump(LitData data) { switch (data.mType) { case LT_IntegerLiteral: - DUMP1("Integer Literal Token:", data.mData.mInt); + DUMP1_NORETURN("Integer Literal Token:", data.mData.mInt); break; case LT_FPLiteral: - DUMP1("Floating Literal Token:", data.mData.mFloat); + DUMP1_NORETURN("Floating Literal Token:", data.mData.mFloat); break; case LT_DoubleLiteral: - DUMP1("Double Literal Token:", data.mData.mDouble); + DUMP1_NORETURN("Double Literal Token:", data.mData.mDouble); break; case LT_BooleanLiteral: - DUMP1("Boolean Literal Token:", data.mData.mBool); + DUMP1_NORETURN("Boolean Literal Token:", data.mData.mBool); break; case LT_CharacterLiteral: { Char the_char = data.mData.mChar; if (the_char.mIsUnicode) - DUMP1("Char Literal Token(Unicode):", the_char.mData.mUniValue); + DUMP1_NORETURN("Char Literal Token(Unicode):", the_char.mData.mUniValue); else - DUMP1("Char Literal Token:", the_char.mData.mChar); + DUMP1_NORETURN("Char Literal Token:", the_char.mData.mChar); break; } case LT_StringLiteral: - DUMP1("String Literal Token:", gStringPool.GetStringFromStrIdx(data.mData.mStrIdx)); + DUMP1_NORETURN("String Literal Token:", gStringPool.GetStringFromStrIdx(data.mData.mStrIdx)); break; case LT_NullLiteral: DUMP0("Null Literal Token:"); @@ -105,10 +105,10 @@ void Token::Dump() { OperatorTokenDump(mData.mOprId); break; case TT_ID: - DUMP1("Identifier Token: ", mData.mName); + DUMP1_NORETURN("Identifier Token: ", mData.mName); break; case TT_KW: - DUMP1("Keyword Token: ", mData.mName); + DUMP1_NORETURN("Keyword Token: ", mData.mName); break; case TT_CM: DUMP0("Comment Token: "); @@ -117,9 +117,9 @@ void Token::Dump() { DUMP0("TemplateLiteral Token: "); break; case TT_RE: - DUMP1("RegExpr Token: ", mData.mRegExprData.mExpr); + DUMP1_NORETURN("RegExpr Token: ", mData.mRegExprData.mExpr); if (mData.mRegExprData.mFlags) - DUMP1(" : ", mData.mRegExprData.mFlags); + DUMP1_NORETURN(" : ", mData.mRegExprData.mFlags); break; case TT_LT: LiteralTokenDump(mData.mLitData); @@ -128,12 +128,13 @@ void Token::Dump() { break; } - DUMP1(" line: ", mLineNum); - DUMP1(" col: ", mColNum); + DUMP1_NORETURN(" line: ", mLineNum); + DUMP1_NORETURN(" col: ", mColNum); if (mLineBegin) - DUMP0(" line-first "); + DUMP0_NORETURN(" line-first "); if (mLineEnd) - DUMP0(" line-last "); + DUMP0_NORETURN(" line-last "); + DUMP_RETURN(); } } -- Gitee From b276c7394a07ece6a9f312be3748dcdaa2511dc1 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Tue, 21 Dec 2021 11:00:15 -0800 Subject: [PATCH 18/20] Make all function nodes be filled in gray --- src/MapleFE/docs/utils/proto.js | 89 +++++++++++++++++---------------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index e87e77d780..f0f83ea0df 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -27,64 +27,69 @@ let myMap = new Map(); let myMapIterator = myMap[Symbol.iterator](); let MapIteratorPrototype = Object.getPrototypeOf(new Map()[Symbol.iterator]()); -async function asyncFunc() {} +async function asyncFunction() {} async function* asyncGenerator() {} const agpt = asyncGenerator.prototype.__proto__; // All data for generating graphs -let data = { +let graphData = { Classes : ["Array", "arr", "myCar", "car"], Generator: ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], [gpt.__proto__, "IteratorPrototype"], [generator.__proto__, "Generator"]], Builtins : ["Symbol", "Math", "JSON", "Promise"], Closure : ["makeClosure", "closure"], Iterators: ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]], - Async : ["asyncFunc", "asyncGenerator", [asyncGenerator(), "asyncGenerator_instance"], [agpt, "AsyncGeneratorPrototype"], + Async : ["asyncFunction", "asyncGenerator", [asyncGenerator(), "asyncGenerator_instance"], [agpt, "AsyncGeneratorPrototype"], [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]], }; -// Gather all reachable objects from their prototype, __proto__ and constructor properties -function insert(g, depth, ...args) { - for (let arg of args) { - let [o, name] = typeof arg === "string" ? [eval(arg), arg] : arg; - if (typeof o !== "undefined" && o !== null) - if (!g.has(o)) { - g.set(o, name !== null || typeof o !== "function" ? name : o.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); - insert(g, depth + 1, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); - } else if (name !== null) +generateGraph(graphData); + +function generateGraph(data) { + // Gather all reachable objects from their prototype, __proto__ and constructor properties + function insert(g, depth, ...args) { + for (let arg of args) { + let [o, name] = typeof arg === "string" ? [eval(arg), arg] : arg; + if (typeof o !== "undefined" && o !== null) + if (!g.has(o)) { + g.set(o, name !== null || typeof o !== "function" ? name : o.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); + insert(g, depth + 1, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); + } else if (name !== null) g.set(o, name); - } - if (depth === 0) { - let visited = new Set(); - for (let [index, [key, value]] of Array.from(g).entries()) { - value = value === null || value === "" ? "Object_" + index : value.replace(/[^A-Za-z0-9]+/g, "_"); - if (visited.has(value)) value += "__" + index; - visited.add(value); - g.set(key, value); + } + if (depth === 0) { + let visited = new Set(); + for (let [index, [key, val]] of Array.from(g).entries()) { + val = val === null || val === "" ? "Object_" + index : val.replace(/[^A-Za-z0-9]+/g, "_"); + if (visited.has(val)) val += "__" + index; + visited.add(val); + g.set(key, val); + } } } -} -// Dump graphs with edges for prototype, __proto__ and constructor properties of each object -let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') -for (let prop in data) { - let graph = new Map(); - insert(graph, 0, "Function", "Object", ...data[prop]); - for (let ctor of ["", "_with_ctors"]) { - console.log("digraph JS_" + prop + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); - for (let [key, value] of graph) { - // Add comments with detailed information of keys - if (nodejs) - console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + value + "):\n", Object.getOwnPropertyNames(key), - "\n" + value + ".toString(): " + (typeof key !== "function" ? "-" : key.toString().replace(/\s+/g, " ")) + "\n*/"); - console.log(value + (value.includes("Prototype") ? "[shape=box];" : "[shape=oval];")); - // Add edges for prototype, constructor and __proto__ properties of objects - for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) - if (typeof key[f] !== "undefined" && key[f] !== null && graph.has(key[f]) && (ctor != "" || f !== "constructor")) - console.log((ctor != "" || f !== "prototype" ? "" : "subgraph cluster_" + value + " {\nrank=same;\ncolor=white;\n" - + value + ";\n" + graph.get(key.prototype) + "[shape=box];\n}\n") + value + " -> " + graph.get(key[f]) - + " [label=\"" + (f === "constructor" ? "ctor" : f) + "\", color=" + c + ", fontcolor=" + c + "];"); + // Dump graphs with edges for prototype, __proto__ and constructor properties of each object + let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') + for (let prop in data) { + let graph = new Map(); + insert(graph, 0, "Function", "Object", ...data[prop]); + for (let ctor of ["", "_with_ctors"]) { + console.log("digraph JS_" + prop + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); + for (let [key, val] of graph) { + let func = typeof key === "function"; + // Add comments with detailed information of keys + if (nodejs) + console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + val + "):\n", Object.getOwnPropertyNames(key), + "\n" + val + ".toString(): " + (func ? key.toString().replace(/\s+/g, " ") : "-") + "\n*/"); + console.log(val + " [shape=" + (val.includes("Prototype") ? "box" : "oval") + (func ? ", style=filled" : "") + "];"); + // Add edges for prototype, constructor and __proto__ properties of objects + for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) + if (typeof key[f] !== "undefined" && key[f] !== null && graph.has(key[f]) && (ctor != "" || f !== "constructor")) + console.log((ctor != "" || f !== "prototype" ? "" : "subgraph cluster_" + val + " {\nrank=same;\ncolor=white;\n" + + val + ";\n" + graph.get(key.prototype) + " [shape=box];\n}\n") + val + " -> " + graph.get(key[f]) + + " [label=\"" + (f === "constructor" ? "ctor" : f) + "\", color=" + c + ", fontcolor=" + c + "];"); + } + console.log("} // digraph JS_" + prop + ctor); } - console.log("} // digraph JS_" + prop + ctor); } -} +} // generateGraph -- Gitee From 2151e2d600298643810d96a74dcb45d72c1567f5 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Tue, 21 Dec 2021 12:35:01 -0800 Subject: [PATCH 19/20] Add node index to each object label --- src/MapleFE/docs/utils/proto.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index f0f83ea0df..33a7a0ed16 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -75,13 +75,14 @@ function generateGraph(data) { insert(graph, 0, "Function", "Object", ...data[prop]); for (let ctor of ["", "_with_ctors"]) { console.log("digraph JS_" + prop + ctor + " {\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); - for (let [key, val] of graph) { + for (let [index, [key, val]] of Array.from(graph).entries()) { let func = typeof key === "function"; // Add comments with detailed information of keys if (nodejs) console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + val + "):\n", Object.getOwnPropertyNames(key), "\n" + val + ".toString(): " + (func ? key.toString().replace(/\s+/g, " ") : "-") + "\n*/"); - console.log(val + " [shape=" + (val.includes("Prototype") ? "box" : "oval") + (func ? ", style=filled" : "") + "];"); + console.log(val + " [label=\"" + val + " " + index + "\", shape=" + + (val.includes("Prototype") ? "box" : "oval") + (func ? ", style=filled" : "") + "];"); // Add edges for prototype, constructor and __proto__ properties of objects for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) if (typeof key[f] !== "undefined" && key[f] !== null && graph.has(key[f]) && (ctor != "" || f !== "constructor")) -- Gitee From 1e64f46b75f3f333b314a5796cb00f42043c44f3 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Tue, 21 Dec 2021 13:06:19 -0800 Subject: [PATCH 20/20] Assign index nubmers 0-3 to Object, ObjectPrototype, FunctionPrototype and Function respectively --- src/MapleFE/docs/utils/proto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js index 33a7a0ed16..80bf386e32 100644 --- a/src/MapleFE/docs/utils/proto.js +++ b/src/MapleFE/docs/utils/proto.js @@ -81,7 +81,7 @@ function generateGraph(data) { if (nodejs) console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + val + "):\n", Object.getOwnPropertyNames(key), "\n" + val + ".toString(): " + (func ? key.toString().replace(/\s+/g, " ") : "-") + "\n*/"); - console.log(val + " [label=\"" + val + " " + index + "\", shape=" + console.log(val + " [label=\"" + val + " " + (index < 4 ? 3 - index : index) + "\", shape=" + (val.includes("Prototype") ? "box" : "oval") + (func ? ", style=filled" : "") + "];"); // Add edges for prototype, constructor and __proto__ properties of objects for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) -- Gitee