aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nameof.cpp109
1 files changed, 57 insertions, 52 deletions
diff --git a/src/nameof.cpp b/src/nameof.cpp
index 027c703..b3874f3 100644
--- a/src/nameof.cpp
+++ b/src/nameof.cpp
@@ -33,29 +33,55 @@ THE SOFTWARE.
33 33
34// Return some name helping to identify an object 34// Return some name helping to identify an object
35[[nodiscard]] 35[[nodiscard]]
36static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableIndex depth_) 36static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableIndex const curDepth_)
37{ 37{
38 static constexpr StackIndex kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?} 38 static constexpr StackIndex kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?}
39 static constexpr StackIndex kResult{ 2 }; // where the result string is stored 39 static constexpr StackIndex kResult{ 2 }; // where the result string is stored
40 static constexpr StackIndex kCache{ 3 }; // a cache 40 static constexpr StackIndex kCache{ 3 }; // a cache
41 static constexpr StackIndex kFQN{ 4 }; // the name compositing stack 41 static constexpr StackIndex kFQN{ 4 }; // the name compositing stack
42 // no need to scan this table if the name we will discover is longer than one we already know 42 // no need to scan this table if the name we will discover is longer than one we already know
43 if (shortest_ <= depth_ + 1) { 43 TableIndex const _nextDepth{ curDepth_ + 1 };
44 if (shortest_ <= _nextDepth) {
44 return shortest_; 45 return shortest_;
45 } 46 }
47
48 auto _pushNameOnFQN = [L_](std::string_view const& name_, TableIndex const depth_) {
49 luaG_pushstring(L_, name_); // L_: o "r" {c} {fqn} ... name_
50 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {mt}
51 };
52
53 auto _popNameFromFQN = [L_](TableIndex const depth_) {
54 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... nil
55 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ...
56 };
57
58 auto _recurseIfTableThenPop = [&_pushNameOnFQN, &_popNameFromFQN, L_](std::string_view const& name_, TableIndex const depth_, int shortest_) {
59 STACK_CHECK_START_REL(L_, 0); // L_: o "r" {c} {fqn} ... <> {}?
60 if (lua_istable(L_, kIdxTop)) {
61 _pushNameOnFQN(name_, depth_);
62 shortest_ = DiscoverObjectNameRecur(L_, shortest_, TableIndex{ depth_ + 1 });
63 _popNameFromFQN(depth_);
64 }
65 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... <>
66 STACK_CHECK(L_, -1);
67 return shortest_;
68 };
69
46 STACK_GROW(L_, 3); 70 STACK_GROW(L_, 3);
47 STACK_CHECK_START_REL(L_, 0); 71 STACK_CHECK_START_REL(L_, 0);
48 // stack top contains the table to search in 72 // stack top contains the table to search in
49 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?} 73 LUA_ASSERT(L_, lua_istable(L_, kIdxTop));
74 lua_pushvalue(L_, kIdxTop); // L_: o "r" {c} {fqn} ... {?} {?}
50 lua_rawget(L_, kCache); // L_: o "r" {c} {fqn} ... {?} nil/1 75 lua_rawget(L_, kCache); // L_: o "r" {c} {fqn} ... {?} nil/1
51 // if table is already visited, we are done 76 // if table is already visited, we are done
52 if (!lua_isnil(L_, -1)) { 77 if (!lua_isnil(L_, kIdxTop)) {
53 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} 78 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?}
54 return shortest_; 79 return shortest_;
55 } 80 }
56 // examined table is not in the cache, add it now 81 // examined table is not in the cache, add it now
57 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} 82 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?}
58 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?} 83 // cache[o] = 1
84 lua_pushvalue(L_, kIdxTop); // L_: o "r" {c} {fqn} ... {?} {?}
59 lua_pushinteger(L_, 1); // L_: o "r" {c} {fqn} ... {?} {?} 1 85 lua_pushinteger(L_, 1); // L_: o "r" {c} {fqn} ... {?} {?} 1
60 lua_rawset(L_, kCache); // L_: o "r" {c} {fqn} ... {?} 86 lua_rawset(L_, kCache); // L_: o "r" {c} {fqn} ... {?}
61 // scan table contents 87 // scan table contents
@@ -65,15 +91,14 @@ static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableInde
65 // lua_Number const numKey = (luaG_type(L_, -2) == LuaType::NUMBER) ? lua_tonumber(L_, -2) : -6666; // only for debugging 91 // lua_Number const numKey = (luaG_type(L_, -2) == LuaType::NUMBER) ? lua_tonumber(L_, -2) : -6666; // only for debugging
66 STACK_CHECK(L_, 2); 92 STACK_CHECK(L_, 2);
67 // append key name to fqn stack 93 // append key name to fqn stack
68 ++depth_;
69 lua_pushvalue(L_, -2); // L_: o "r" {c} {fqn} ... {?} k v k 94 lua_pushvalue(L_, -2); // L_: o "r" {c} {fqn} ... {?} k v k
70 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k v 95 lua_rawseti(L_, kFQN, _nextDepth); // L_: o "r" {c} {fqn} ... {?} k v
71 if (lua_rawequal(L_, -1, kWhat)) { // is it what we are looking for? 96 if (lua_rawequal(L_, kIdxTop, kWhat)) { // is it what we are looking for?
72 STACK_CHECK(L_, 2); 97 STACK_CHECK(L_, 2);
73 // update shortest name 98 // update shortest name
74 if (depth_ < shortest_) { 99 if (_nextDepth < shortest_) {
75 shortest_ = depth_; 100 shortest_ = _nextDepth;
76 std::ignore = tools::PushFQN(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k v "fqn" 101 std::ignore = tools::PushFQN(L_, kFQN, _nextDepth); // L_: o "r" {c} {fqn} ... {?} k v "fqn"
77 lua_replace(L_, kResult); // L_: o "r" {c} {fqn} ... {?} k v 102 lua_replace(L_, kResult); // L_: o "r" {c} {fqn} ... {?} k v
78 } 103 }
79 // no need to search further at this level 104 // no need to search further at this level
@@ -87,19 +112,10 @@ static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableInde
87 112
88 case LuaType::TABLE: // L_: o "r" {c} {fqn} ... {?} k {} 113 case LuaType::TABLE: // L_: o "r" {c} {fqn} ... {?} k {}
89 STACK_CHECK(L_, 2); 114 STACK_CHECK(L_, 2);
90 shortest_ = DiscoverObjectNameRecur(L_, shortest_, depth_); 115 shortest_ = DiscoverObjectNameRecur(L_, shortest_, _nextDepth);
91 // search in the table's metatable too 116 // search in the table's metatable too
92 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k {} {mt} 117 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k {} {mt}
93 if (lua_istable(L_, -1)) { 118 shortest_ = _recurseIfTableThenPop("__metatable", _nextDepth, shortest_); // L_: o "r" {c} {fqn} ... {?} k {}
94 ++depth_;
95 luaG_pushstring(L_, "__metatable"); // L_: o "r" {c} {fqn} ... {?} k {} {mt} "__metatable"
96 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k {} {mt}
97 shortest_ = DiscoverObjectNameRecur(L_, shortest_, depth_);
98 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k {} {mt} nil
99 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k {} {mt}
100 --depth_;
101 }
102 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k {}
103 } 119 }
104 STACK_CHECK(L_, 2); 120 STACK_CHECK(L_, 2);
105 break; 121 break;
@@ -112,32 +128,15 @@ static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableInde
112 STACK_CHECK(L_, 2); 128 STACK_CHECK(L_, 2);
113 // search in the object's metatable (some modules are built that way) 129 // search in the object's metatable (some modules are built that way)
114 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k U {mt} 130 if (lua_getmetatable(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k U {mt}
115 if (lua_istable(L_, -1)) { 131 shortest_ = _recurseIfTableThenPop("__metatable", _nextDepth, shortest_); // L_: o "r" {c} {fqn} ... {?} k U
116 ++depth_;
117 luaG_pushstring(L_, "__metatable"); // L_: o "r" {c} {fqn} ... {?} k U {mt} "__metatable"
118 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k U {mt}
119 shortest_ = DiscoverObjectNameRecur(L_, shortest_, depth_);
120 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k U {mt} nil
121 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k U {mt}
122 --depth_;
123 }
124 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k U
125 } 132 }
133
126 STACK_CHECK(L_, 2); 134 STACK_CHECK(L_, 2);
127 // search in the object's uservalues 135 // search in the object's uservalues
128 { 136 {
129 UserValueIndex _uvi{ 1 }; 137 UserValueIndex _uvi{ 1 };
130 while (lua_getiuservalue(L_, kIdxTop, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u} 138 while (lua_getiuservalue(L_, kIdxTop, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u}
131 if (lua_istable(L_, -1)) { // if it is a table, look inside 139 shortest_ = _recurseIfTableThenPop("uservalue", _nextDepth, shortest_); // L_: o "r" {c} {fqn} ... {?} k U
132 ++depth_;
133 luaG_pushstring(L_, "uservalue"); // L_: o "r" {c} {fqn} ... {?} k v {u} "uservalue"
134 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k v {u}
135 shortest_ = DiscoverObjectNameRecur(L_, shortest_, depth_);
136 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k v {u} nil
137 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k v {u}
138 --depth_;
139 }
140 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k U
141 ++_uvi; 140 ++_uvi;
142 } 141 }
143 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now 142 // when lua_getiuservalue() returned LUA_TNONE, it pushed a nil. pop it now
@@ -145,18 +144,20 @@ static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableInde
145 } 144 }
146 STACK_CHECK(L_, 2); 145 STACK_CHECK(L_, 2);
147 break; 146 break;
147
148 case LuaType::FUNCTION: // L_: o "r" {c} {fqn} ... {?} k F
149 // TODO: explore the function upvalues
150 break;
148 } 151 }
149 // make ready for next iteration 152 // make ready for next iteration
150 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k 153 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... {?} k
151 // remove name from fqn stack 154 // remove name from fqn stack
152 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} k nil 155 _popNameFromFQN(_nextDepth);
153 lua_rawseti(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k
154 STACK_CHECK(L_, 1); 156 STACK_CHECK(L_, 1);
155 --depth_;
156 } // L_: o "r" {c} {fqn} ... {?} 157 } // L_: o "r" {c} {fqn} ... {?}
157 STACK_CHECK(L_, 0); 158 STACK_CHECK(L_, 0);
158 // remove the visited table from the cache, in case a shorter path to the searched object exists 159 // remove the visited table from the cache, in case a shorter path to the searched object exists
159 lua_pushvalue(L_, -1); // L_: o "r" {c} {fqn} ... {?} {?} 160 lua_pushvalue(L_, kIdxTop); // L_: o "r" {c} {fqn} ... {?} {?}
160 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} {?} nil 161 lua_pushnil(L_); // L_: o "r" {c} {fqn} ... {?} {?} nil
161 lua_rawset(L_, kCache); // L_: o "r" {c} {fqn} ... {?} 162 lua_rawset(L_, kCache); // L_: o "r" {c} {fqn} ... {?}
162 STACK_CHECK(L_, 0); 163 STACK_CHECK(L_, 0);
@@ -168,14 +169,18 @@ static int DiscoverObjectNameRecur(lua_State* const L_, int shortest_, TableInde
168// "type", "name" = lanes.nameof(o) 169// "type", "name" = lanes.nameof(o)
169LUAG_FUNC(nameof) 170LUAG_FUNC(nameof)
170{ 171{
171 StackIndex const _what{ lua_gettop(L_) }; 172 auto const _argCount{ lua_gettop(L_) };
172 if (_what > 1) { 173 if (_argCount > 1) {
173 raise_luaL_argerror(L_, _what, "too many arguments."); 174 raise_luaL_argerror(L_, StackIndex{ _argCount }, "too many arguments.");
174 } 175 }
175 176
176 // nil, boolean, light userdata, number and string aren't identifiable 177 // nil, boolean, light userdata, number and string aren't identifiable
177 if (luaG_type(L_, StackIndex{ 1 }) < LuaType::TABLE) { 178 auto const _isIdentifiable = [L_]() {
178 lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "type" 179 auto const _valType{ luaG_type(L_, kIdxTop) };
180 return _valType == LuaType::TABLE || _valType == LuaType::FUNCTION || _valType == LuaType::USERDATA || _valType == LuaType::THREAD;
181 };
182 if (!_isIdentifiable()) {
183 luaG_pushstring(L_, luaG_typename(L_, kIdxTop)); // L_: o "type"
179 lua_insert(L_, -2); // L_: "type" o 184 lua_insert(L_, -2); // L_: "type" o
180 return 2; 185 return 2;
181 } 186 }