Some output now going through PrintBuffer

This commit is contained in:
2021-10-21 13:15:04 -04:00
parent 458497956d
commit 1a25fed15f
9 changed files with 139 additions and 46 deletions

View File

@@ -1,9 +1,18 @@
#include "print.hpp"
#include "pprint.hpp"
#include "util.hpp"
#include "table.hpp"
#include <ostream>
#include <iostream>
// This file provides these functions for lua.
//
// They direct all output to std::cout
//
extern "C" {
void luai_writestring(const char *s, size_t len);
void luai_writeline();
}
void luai_writestring(const char *s, size_t len) {
std::cout.write(s, len);
}
@@ -250,15 +259,6 @@ void pprint(LuaStack &LS0, LuaSlot root, bool indent, std::ostream *os) {
LS.result();
}
LuaDefine(pprint_pprint, "f") {
LuaStack LS(L);
for (int i = 1; i <= lua_gettop(L); i++) {
LuaSpecial root(i);
pprint(LS, root, true, &std::cout);
std::cout << std::endl;
}
return LS.result();
}
LuaDefine(string_pprint, "c") {
LuaArg root, indent;

View File

@@ -6,20 +6,11 @@
//
/////////////////////////////////////////////////////////
#ifndef PRINT_HPP
#define PRINT_HPP
#ifndef PPRINT_HPP
#define PPRINT_HPP
#include "luastack.hpp"
// This file provides these functions for lua.
//
// They direct all output to std::cout
//
extern "C" {
void luai_writestring(const char *s, size_t len);
void luai_writeline();
}
// Output a simple value to a stream.
//
// If the value is a string, number, boolean, or nil, it is
@@ -52,4 +43,4 @@ void pprint(LuaStack &LS, LuaSlot val, bool indent, std::ostream *os);
int lfn_pprint_pprint(lua_State *L);
int lfn_string_pprint(lua_State *L);
#endif // PRINT_HPP
#endif // PPRINT_HPP

View File

@@ -96,22 +96,30 @@ private:
// a newline (or any other weird control characters).
void add_line(const char *line, int len);
// Return the line number beyond the end of the buffer.
int last_line() const { return first_line_ + int(lines_.size()); }
// Get the specified line number.
const std::string &nth(int n) const { return lines_[n - first_line_]; }
public:
PrintBuffer(util::WorldType wt);
// Get the current first line.
int first_line() const { return first_line_; }
// Return the line number beyond the end of the buffer.
int last_line() const { return first_line_ + int(lines_.size()); }
// Get the current first unchecked line.
int first_unchecked() const { return first_unchecked_; }
// Get the specified line number.
const std::string &nth(int n) const { return lines_[n - first_line_]; }
// Add a string. If the string doesn't end in a newline, a newline
// is added. The string is broken into lines, and the lines are added
// to the PrintBuffer.
void add_string(const char *text, int len);
void add_string(const std::string &s);
// Discard lines up to but not including line N.
void discard_upto(int n);

View File

@@ -14,8 +14,9 @@
#include "traceback.hpp"
#include "textgame.hpp"
#include "luaconsole.hpp"
#include "print.hpp"
#include "pprint.hpp"
#include <memory>
#include <algorithm>
class TextGame : public DrivenEngine {
@@ -26,6 +27,7 @@ private:
Gui gui_;
int64_t gui_place_;
int64_t actor_id_;
int64_t printbuffer_line_;
void do_view_command(const StringVec &cmd);
void do_menu_command(const StringVec &cmd);
@@ -39,6 +41,7 @@ private:
void do_command(const StringVec &exp);
void check_redirects();
void channel_printbuffer();
public:
virtual void event_init(int argc, char *argv[]);
@@ -167,12 +170,26 @@ void TextGame::check_redirects() {
}
}
void TextGame::channel_printbuffer() {
const PrintBuffer *printbuffer = world_->get_printbuffer(actor_id_);
if (printbuffer == nullptr) return;
if (printbuffer->first_line() > printbuffer_line_) {
printbuffer_line_ = printbuffer->first_line();
}
while (printbuffer_line_ < printbuffer->first_unchecked()) {
std::cerr << "* " << printbuffer->nth(printbuffer_line_) << std::endl;
printbuffer_line_ += 1;
}
}
void TextGame::event_init(int argc, char *argv[])
{
world_.reset(new World(util::WORLD_TYPE_STANDALONE));
world_->update_source(get_lua_source());
world_->run_unittests();
actor_id_ = world_->create_login_actor();
printbuffer_line_ = 0;
std::cerr << "Login actor ID: " << actor_id_ << std::endl;
get_stdio_channel()->out()->write_bytes(console_.get_prompt());
}
@@ -188,9 +205,11 @@ void TextGame::event_update()
if (action == LuaConsole::DO_LUA) {
do_lua(console_.lua_expression());
console_.clear();
channel_printbuffer();
} else if (action == LuaConsole::DO_COMMAND) {
do_command(console_.words());
console_.clear();
channel_printbuffer();
} else if (action == LuaConsole::DO_SYNTAX) {
std::cerr << console_.syntax() << std::endl;
console_.clear();

View File

@@ -1,5 +1,6 @@
#include "world.hpp"
#include "pprint.hpp"
LuaDefine(tangible_animstate, "c") {
LuaArg tanobj;
@@ -209,3 +210,14 @@ LuaDefine(world_settabletype, "f") {
return LS.result();
}
LuaDefine(world_pprint, "f") {
World *w = World::fetch_global_pointer(L);
std::ostream *ostream = w->lthread_print_stream();
LuaStack LS(L);
for (int i = 1; i <= lua_gettop(L); i++) {
LuaSpecial root(i);
pprint(LS, root, true, ostream);
(*ostream) << std::endl;
}
return LS.result();
}

View File

@@ -4,7 +4,7 @@
#include "animqueue.hpp"
#include "gui.hpp"
#include "traceback.hpp"
#include "print.hpp"
#include "pprint.hpp"
#include <iostream>
void World::store_global_pointer(lua_State *L, World *v) {
@@ -49,7 +49,7 @@ World::World(util::WorldType wt) {
Gui::store_global_pointer(state(), nullptr);
// Clear the lthread state.
set_lthread_state(0, 0, false);
clear_lthread_state();
// Set the tabletype of the registry.
LS.settabletype(LuaRegistry, LUA_TT_REGISTRY);
@@ -262,6 +262,7 @@ int64_t World::create_login_actor() {
LS.rawset(mt, "__index", classtab);
LS.result();
tan->configure_id_pool_for_actor();
tan->print_buffer_.reset(new PrintBuffer(world_type_));
assert(stack_is_clear());
return tan->id();
}
@@ -305,9 +306,9 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
lua_pushvalue(L, actor.index());
lua_pushvalue(L, place.index());
Gui::store_global_pointer(L, gui);
set_lthread_state(actor_id, place_id, false);
open_lthread_state(actor_id, place_id, false, false);
int status = traceback_pcall(L, 2, 0);
set_lthread_state(0, 0, false);
close_lthread_state();
Gui::store_global_pointer(L, nullptr);
if (status != 0) {
gui->clear();
@@ -372,25 +373,27 @@ void World::invoke_lua(int64_t actor_id, int64_t place_id, const std::string &ac
// Call the closure.
int top = lua_gettop(L);
lua_pushvalue(L, closure.index());
set_lthread_state(actor_id, place_id, false);
open_lthread_state(actor_id, place_id, false, true);
status = traceback_pcall(L, 0, LUA_MULTRET);
set_lthread_state(0, 0, false);
// If there's an error message, print it.
// Otherwise, pretty-print the results.
std::ostream *ostream = lthread_print_stream();
if (status == LUA_OK) {
for (int i = top + 1; i <= lua_gettop(L); i++) {
LuaSpecial root(i);
pprint(LS, root, true, &std::cout);
std::cout << std::endl;
pprint(LS, root, true, ostream);
(*ostream) << std::endl;
}
} else {
const char *msg = lua_tostring(L, top);
const char *msg = lua_tostring(L, -1);
if (msg == NULL) {
msg = "(error object is not a string)";
}
std::cerr << msg << std::endl;
(*ostream) << msg << std::endl;
}
close_lthread_state();
LS.result();
assert(stack_is_clear());
}
@@ -535,10 +538,10 @@ void World::run_scheduled_threads(int64_t clk) {
// Resume the coroutine.
lua_State *CO = LS.ckthread(thread);
set_lthread_state(LS.ckinteger(actorid), sched.place_id(), LS.ckboolean(useppool));
open_lthread_state(LS.ckinteger(actorid), sched.place_id(), LS.ckboolean(useppool), true);
int status = lua_resume(CO, nullptr, LS.ckboolean(isnew) ? 3 : 0);
set_lthread_state(0, 0, false);
close_lthread_state();
// Three possible outcomes: finished, yielded, or errored.
if (status == LUA_YIELD) {
// When the wait statement yields, it yields the desired timestamp.
@@ -580,10 +583,60 @@ int64_t World::alloc_id_predictable() {
return t->id_player_pool_.get_one();
}
void World::set_lthread_state(int64_t actor, int64_t place, bool ppool) {
const PrintBuffer *World::get_printbuffer(int64_t actor_id) {
Tangible *actor = tangible_get(actor_id);
if (actor != nullptr) {
return actor->print_buffer_.get();
}
return nullptr;
}
void World::clear_lthread_state() {
lthread_prints_.reset();
lthread_actor_id_ = 0;
lthread_place_id_ = 0;
lthread_use_ppool_ = false;
}
void World::open_lthread_state(int64_t actor, int64_t place, bool ppool, bool prints) {
lthread_actor_id_ = actor;
lthread_place_id_ = place;
lthread_use_ppool_ = ppool;
if (prints) {
lthread_prints_.reset(new std::ostringstream);
} else {
lthread_prints_.reset();
}
}
void World::close_lthread_state() {
// Copy prints from lthread_prints_ stringstream into
// the appropriate actor's PrintBuffer. If for some reason
// there isn't an actor, or if the actor doesn't have a PrintBuffer,
// send the output to std::cerr.
if (lthread_prints_ != nullptr) {
const std::string &output = lthread_prints_->str();
PrintBuffer *pbuffer = nullptr;
Tangible *actor = tangible_get(lthread_actor_id_);
if (actor != nullptr) {
pbuffer = actor->print_buffer_.get();
}
if (pbuffer != nullptr) {
pbuffer->add_string(output);
} else {
std::cerr << output;
}
}
// Now clean up everything.
clear_lthread_state();
}
std::ostream *World::lthread_print_stream() const {
if (lthread_prints_ != nullptr) {
return lthread_prints_.get();
} else {
return &std::cerr;
}
}
void World::serialize(StreamBuffer *sb) {

View File

@@ -1,5 +1,5 @@
#include "world.hpp"
#include "print.hpp"
#include "pprint.hpp"
#include <cassert>
void World::tangible_walkto(int64_t id, int64_t animid, float x, float y) {

View File

@@ -182,6 +182,10 @@ public:
//
void invoke(const Invocation &inv);
// Get the PrintBuffer of the actor.
//
const PrintBuffer *get_printbuffer(int64_t actor_id);
// Update the source database from disk.
//
// Special case: if the source pointer is nullptr, does not update.
@@ -225,11 +229,16 @@ public:
// * lthread_actor_id: current actor
// * lthread_place_id: current place
// * lthread_use_ppool: true if we should use the player ID pool.
// * lthread_prints_: a stringstream which will collect 'print' statements.
//
// As soon as the lua code stops executing, these variables are
// cleared.
//
void set_lthread_state(int64_t actor_id, int64_t place_id, bool ppool);
void clear_lthread_state();
void open_lthread_state(int64_t actor_id, int64_t place_id, bool ppool, bool prints);
void close_lthread_state();
std::ostream *lthread_print_stream() const;
// Allocate a single ID.
//
@@ -448,6 +457,7 @@ private:
int64_t lthread_actor_id_;
int64_t lthread_place_id_;
int64_t lthread_use_ppool_;
std::unique_ptr<std::ostringstream> lthread_prints_;
friend class Tangible;
friend int lfn_tangible_animate(lua_State *L);