Josh Posted June 13, 2017 Share Posted June 13, 2017 A few people have asked for information on the Lua debugging protocol, so I am posting some of the internals here. It would be a good idea to start researching Lua IDEs and see if there is something we can utilize for Leadwerks 5. This is the code that handles the network connection with the editor: void Interpreter::DebugUpdate(const std::string& err, const bool wait) { if (!connected) return; Message* message; const char* name; lua_Debug ar; std::string s; std::string ts; vector<std::string> sarr; vector<std::string>::iterator it; vector<std::string> pair; int size; int i; long starttime = Time::Millisecs(); bool connectionstarted=false; int handle; bool intable=false; Object* o; int l; int countbreakpoints; int editmode; std::string source; int linenumber; std::string hex; int pointer; stringstream ss; Stream* stream; bool paused = timepausestate; Time::Pause(); Window* window = NULL; #ifdef _WIN32 AllowSetForegroundWindow(-1); #endif while (true) { message = client->Update(); if (!wait) { if (message==NULL) { if (!paused) Time::Resume(); return; } } if (message != NULL) { switch (message->id) { case MESSAGE_EDITBREAKPOINTS: stream = BankStream::Create(message->data,false); countbreakpoints = stream->ReadInt(); for (int i=0; i<countbreakpoints; i++) { editmode=stream->ReadInt(); source = stream->ReadString(); linenumber = stream->ReadInt(); if (editmode==1) { SetBreakpoint(source,linenumber); } else { RemoveBreakpoint(source,linenumber); } } break; //case MESSAGE_CONNECT: // //System::Notify("MESSAGE_CONNECT"); // connected=true; // if (err!="") client->Send(MESSAGE_SENDERRORMESSAGE,err,MESSAGE_RELIABLE|MESSAGE_SEQUENCED); // break; /*case MESSAGE_DEBUGPOINTERINFOREQUEST: hex = message->data->PeekString(0); //o = (Object*)Int(hex); //client->Send(MESSAGE_DEBUGPOINTERINFO,o->Debug()); if (debugobjectmap[hex]!=NULL) { client->Send(MESSAGE_DEBUGPOINTERINFO,hex+debugobjectmap[hex]->Debug()); } else { client->Send(MESSAGE_DEBUGPOINTERINFO,hex); } break;*/ case MESSAGE_PAUSE: client->Send(MESSAGE_SENDCALLSTACK,GetCallStack(),MESSAGE_RELIABLE|MESSAGE_SEQUENCED); DebugUpdate(); break; case MESSAGE_DISCONNECT: //Window* window = Window::GetCurrent(); //if (window) window->Activate(); //lua_sethook(L,DebugHook,0,0); if (!paused) Time::Resume(); return; break; case MESSAGE_DEBUGSTEP: window = Window::GetCurrent(); //if (window) window->Activate(); //lua_sethook(L,DebugHook,LUA_MASKLINE,0); steppingmode=STEP_LINE; if (!paused) Time::Resume(); return; break; case MESSAGE_DEBUGSTEPIN: window = Window::GetCurrent(); //if (window) window->Activate(); //lua_sethook(L,DebugHook,LUA_MASKCALL,0); steppingmode=STEP_IN; if (!paused) Time::Resume(); return; break; case MESSAGE_DEBUGSTEPOUT: window = Window::GetCurrent(); //if (window) window->Activate(); //lua_sethook(L,DebugHook,LUA_MASKRET,0); steppingmode=STEP_OUT; if (!paused) Time::Resume(); return; break; case MESSAGE_DEBUGRESUME: //lua_sethook(L,DebugHook,0,0); //System::Notify("DebugResume!"); window = Window::GetCurrent(); if (window) window->Activate(); steppingmode=0; if (!paused) Time::Resume(); return; break; } } Time::Delay(1); } } The entire debug tree is sent back to the editor as a single string. Here is the function that creates it: std::string Interpreter::GetCallStack() { std::string err; std::string vname; lua_Debug ar; int level = 0; std::string tab; int size = GetCallStackSize(); int i; int stacksize = GetStackSize(); const char* name; debugobjectmap.clear(); int executionlevel = executionstack.size()-1; //System::Notify("Interpreter::GetCallStack()"); //Display call stack. I'm going to make the main function '0' and reverse the level numbers //because that makes more sense to me, but remember 0 = the current level. for (level=0; level<size; level++) { lua_getstack(L, size -1- level, &ar); err += (tab+"Level"+String(size -1- level)+" {\n"); lua_getinfo(L, "nSluf", &ar); err += (tab+" source: "+std::string(ar.source)+"\n"); err += (tab+" short_src: "+std::string(ar.short_src)+"\n"); err += (tab+" linedefined: "+String(ar.linedefined)+"\n"); err += (tab+" lastlinedefined: "+String(ar.lastlinedefined)+"\n"); err += (tab+" what: "+std::string(ar.what)+"\n"); err += (tab+" currentline: "+String(ar.currentline)+"\n"); //if (ar.name==NULL) //{ // if (level==0) ar.name="(called from C++)"; //} if (ar.name!=NULL) err += (tab+" name: "+std::string(ar.name)+"\n"); if (ar.namewhat!=NULL) err += (tab+" namewhat: "+std::string(ar.namewhat)+"\n"); err += (tab+" nups: "+String(ar.nups)+"\n"); if (level==size-1) { if (std::string(ar.what)!="C") { skipnextdebugstep = true; } } //Display locals err += (tab+" locals {"+"\n"); i = 1; while (true) { name = lua_getlocal(L, &ar, i++); if (name==NULL) break; vname=std::string(name); if (String::Left(vname,2)!="(*" && String::Left(vname,1)!="_") { err+=(tab+" "+vname+"="+GetVariableValue()+"\n"); } lua_pop(L,1); } err += (tab+" }\n"); tab += " "; } //Add closing brackets for (level=0; level<size-1; level++) { tab = ""; for (i=0; i<size-level-1; i++) tab+=" "; err += (tab+"}\n"); } err += ("\n"); //Display globals err += (" Globals {\n"); lua_getglobal(L,"_G"); for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { if (!lua_isfunction(L,-1)) { // if (!lua_isuserdata(L,-1)) // { vname=GetVariableValue(-2,0,false); if (skipdebugdefaultglobals) { /*if (vname=="_G") continue; if (vname=="_VERSION") continue; if (vname=="coroutine") continue; if (vname=="debug") continue; if (vname=="io") continue; if (vname=="math") continue; if (vname=="os") continue; if (vname=="package") continue; if (vname=="string")continue; if (vname=="table") continue;*/ if (hiddenglobals[vname]==true) continue; } //Print(vname+"="+GetVariableValue(-1)); err += (" "+vname+"="+GetVariableValue(-1)+"\n"); // } } } err += " }"; err += "}"; lua_pop(L,1); SetStackSize(stacksize); return err; } Each object has a Debug() function that contributes to this string. Here is what the entity Debug function looks like: std::string Entity::Debug() { int i; std::string s; s = "{"; s+="0xhexaddress="+Object::GetAddress(this)+","; //s+= "Entity={"; s+= "position="+position.Debug()+","; s+= "rotation="+rotation.Debug()+","; s+= "scale="+scale.Debug()+","; s+= "mat="+mat.Debug()+","; s+= "localaabb="+localaabb.Debug()+","; s+= "aabb="+aabb.Debug()+","; s+= "recursiveaabb="+recursiveaabb.Debug()+","; s+= "color={"; s+= "0="+color[0].Debug()+","; s+= "1="+color[1].Debug()+","; s+= "2="+color[2].Debug(); s+= "},"; //s+= "color[0]="+color[0].Debug()+","; //s+= "color[1]="+color[1].Debug()+","; //s+= "color[2]="+color[2].Debug()+","; s+= "parent="+Object::GetAddress(parent)+","; s+= "kids={"; for (i=0; i<CountChildren(); i++) { //s+= "["+String(i)+"]child"+String(i); s+= "["+String(i)+"]="+Object::GetAddress(GetChild(i)); if (i<CountChildren()-1) { s += ","; } } /*s+= "[0]=child0,"; s+= "[1]=child1,"; s+= "[2]=child2";*/ //s+= "}"; s+= "}"; s+= "}"; return s; //return GetObjectAddress(this); } And here is the Vec3 Debug function: std::string Vec3::Debug() { return "_{"+String(x)+","+String(y)+","+String(z)+"}"; } Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
AggrorJorn Posted June 13, 2017 Share Posted June 13, 2017 Not trying to be pushy or anything but have you had a look at Visual code? Have look at how you can implement your own debugger. https://code.visualstudio.com/docs/extensions/example-debuggers 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.