2014-08-07 01:07:04 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <string>
|
2014-08-07 01:10:33 +00:00
|
|
|
#include <functional>
|
2014-08-11 02:57:24 +00:00
|
|
|
#include "util/sstream.h"
|
2014-08-30 00:46:17 +00:00
|
|
|
#include "util/exception.h"
|
2014-08-29 19:59:22 +00:00
|
|
|
#include "util/sexpr/option_declarations.h"
|
2014-09-02 19:57:20 +00:00
|
|
|
#include "library/aliases.h"
|
2014-08-07 01:07:04 +00:00
|
|
|
#include "frontends/lean/server.h"
|
|
|
|
#include "frontends/lean/parser.h"
|
|
|
|
|
2014-08-30 00:46:17 +00:00
|
|
|
// #define LEAN_SERVER_DIAGNOSTIC
|
|
|
|
|
|
|
|
#if defined(LEAN_SERVER_DIAGNOSTIC)
|
|
|
|
#define DIAG(CODE) CODE
|
|
|
|
#else
|
|
|
|
#define DIAG(CODE)
|
|
|
|
#endif
|
|
|
|
|
2014-08-07 01:07:04 +00:00
|
|
|
namespace lean {
|
2014-08-27 21:53:16 +00:00
|
|
|
server::file::file(std::istream & in, std::string const & fname):m_fname(fname) {
|
|
|
|
for (std::string line; std::getline(in, line);) {
|
|
|
|
m_lines.push_back(line);
|
|
|
|
}
|
|
|
|
}
|
2014-08-07 01:07:04 +00:00
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::file::replace_line(unsigned linenum, std::string const & new_line) {
|
2014-08-27 21:53:16 +00:00
|
|
|
lock_guard<mutex> lk(m_lines_mutex);
|
2014-08-11 17:40:18 +00:00
|
|
|
while (linenum >= m_lines.size())
|
|
|
|
m_lines.push_back("");
|
2014-08-28 04:09:52 +00:00
|
|
|
std::string const & old_line = m_lines[linenum];
|
|
|
|
unsigned i = 0;
|
|
|
|
while (i < old_line.size() && i < new_line.size() && old_line[i] == new_line[i])
|
|
|
|
i++;
|
|
|
|
m_info.block_new_info(true);
|
|
|
|
m_info.invalidate_line_col(linenum+1, i);
|
2014-08-11 17:40:18 +00:00
|
|
|
m_lines[linenum] = new_line;
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::file::insert_line(unsigned linenum, std::string const & new_line) {
|
2014-08-27 21:53:16 +00:00
|
|
|
lock_guard<mutex> lk(m_lines_mutex);
|
|
|
|
m_info.block_new_info(true);
|
|
|
|
m_info.insert_line(linenum+1);
|
2014-08-11 17:40:18 +00:00
|
|
|
while (linenum >= m_lines.size())
|
|
|
|
m_lines.push_back("");
|
|
|
|
m_lines.push_back("");
|
|
|
|
lean_assert(m_lines.size() >= linenum+1);
|
|
|
|
unsigned i = m_lines.size();
|
|
|
|
while (i > linenum) {
|
|
|
|
--i;
|
|
|
|
m_lines[i] = m_lines[i-1];
|
|
|
|
}
|
|
|
|
m_lines[linenum] = new_line;
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::file::remove_line(unsigned linenum) {
|
2014-08-27 21:53:16 +00:00
|
|
|
lock_guard<mutex> lk(m_lines_mutex);
|
|
|
|
m_info.block_new_info(true);
|
|
|
|
m_info.remove_line(linenum+1);
|
2014-08-11 17:40:18 +00:00
|
|
|
if (linenum >= m_lines.size())
|
|
|
|
return;
|
|
|
|
lean_assert(!m_lines.empty());
|
|
|
|
for (unsigned i = linenum; i < m_lines.size()-1; i++)
|
|
|
|
m_lines[i] = m_lines[i+1];
|
|
|
|
m_lines.pop_back();
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 01:12:22 +00:00
|
|
|
void server::file::show(std::ostream & out, bool valid) {
|
2014-08-30 00:46:17 +00:00
|
|
|
lock_guard<mutex> lk(m_lines_mutex);
|
2014-08-30 01:12:22 +00:00
|
|
|
for (unsigned i = 0; i < m_lines.size(); i++) {
|
|
|
|
if (valid) {
|
|
|
|
if (m_info.is_invalidated(i+1))
|
|
|
|
out << "*";
|
|
|
|
else
|
|
|
|
out << " ";
|
|
|
|
out << " ";
|
|
|
|
}
|
2014-08-30 00:46:17 +00:00
|
|
|
out << m_lines[i] << "\n";
|
2014-08-30 01:12:22 +00:00
|
|
|
}
|
2014-08-30 00:46:17 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 01:07:04 +00:00
|
|
|
/**
|
|
|
|
\brief Return index i <= m_snapshots.size() s.t.
|
|
|
|
* forall j < i, m_snapshots[j].m_line < line
|
|
|
|
* forall i <= j < m_snapshots.size(), m_snapshots[j].m_line >= line
|
|
|
|
*/
|
2014-08-11 17:40:18 +00:00
|
|
|
unsigned server::file::find(unsigned linenum) {
|
2014-08-07 01:07:04 +00:00
|
|
|
unsigned low = 0;
|
|
|
|
unsigned high = m_snapshots.size();
|
|
|
|
while (true) {
|
|
|
|
lean_assert(low <= high);
|
|
|
|
if (low == high)
|
|
|
|
return low;
|
|
|
|
unsigned mid = low + ((high - low)/2);
|
|
|
|
lean_assert(low <= mid && mid < high);
|
|
|
|
lean_assert(mid < m_snapshots.size());
|
|
|
|
snapshot const & s = m_snapshots[mid];
|
|
|
|
if (s.m_line < linenum) {
|
|
|
|
low = mid+1;
|
|
|
|
} else {
|
|
|
|
high = mid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 21:53:16 +00:00
|
|
|
/** \brief Copy lines [starting_from, m_lines.size()) to block and return the total number of lines */
|
|
|
|
unsigned server::file::copy_to(std::string & block, unsigned starting_from) {
|
|
|
|
unsigned num_lines = m_lines.size();
|
|
|
|
for (unsigned j = starting_from; j < num_lines; j++) {
|
|
|
|
block += m_lines[j];
|
|
|
|
block += '\n';
|
|
|
|
}
|
|
|
|
return num_lines;
|
2014-08-16 00:24:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 21:53:16 +00:00
|
|
|
server::worker::worker(environment const & env, io_state const & ios, definition_cache & cache):
|
|
|
|
m_empty_snapshot(env, ios.get_options()),
|
|
|
|
m_cache(cache),
|
|
|
|
m_todo_linenum(0),
|
|
|
|
m_todo_options(ios.get_options()),
|
|
|
|
m_terminate(false),
|
|
|
|
m_thread([=]() {
|
|
|
|
io_state _ios(ios);
|
|
|
|
while (!m_terminate) {
|
|
|
|
file_ptr todo_file;
|
2014-08-28 00:53:00 +00:00
|
|
|
unsigned todo_linenum = 0;
|
2014-08-27 21:53:16 +00:00
|
|
|
options todo_options;
|
|
|
|
// wait for next task
|
|
|
|
while (!m_terminate) {
|
|
|
|
unique_lock<mutex> lk(m_todo_mutex);
|
|
|
|
if (m_todo_file) {
|
|
|
|
todo_file = m_todo_file;
|
|
|
|
todo_linenum = m_todo_linenum;
|
|
|
|
todo_options = m_todo_options;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
m_todo_cv.wait(lk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// extract block of code and snapshot from todo_file
|
|
|
|
reset_interrupt();
|
2014-08-30 00:46:17 +00:00
|
|
|
bool worker_interrupted = false;
|
2014-08-27 21:53:16 +00:00
|
|
|
if (m_terminate)
|
|
|
|
break;
|
2014-08-30 00:46:17 +00:00
|
|
|
DIAG(std::cerr << "processing '" << todo_file->get_fname() << "'\n";)
|
2014-08-27 21:53:16 +00:00
|
|
|
std::string block;
|
|
|
|
unsigned num_lines;
|
|
|
|
snapshot s;
|
|
|
|
{
|
|
|
|
lean_assert(todo_file);
|
|
|
|
lock_guard<mutex> lk(todo_file->m_lines_mutex);
|
|
|
|
unsigned i = todo_file->find(todo_linenum);
|
|
|
|
todo_file->m_snapshots.resize(i);
|
|
|
|
s = i == 0 ? m_empty_snapshot : todo_file->m_snapshots[i-1];
|
|
|
|
lean_assert(s.m_line > 0);
|
2014-08-30 01:12:22 +00:00
|
|
|
todo_file->m_info.block_new_info(false);
|
|
|
|
todo_file->m_info.set_processed_upto(s.m_line);
|
2014-08-27 21:53:16 +00:00
|
|
|
num_lines = todo_file->copy_to(block, s.m_line - 1);
|
|
|
|
}
|
|
|
|
if (m_terminate)
|
|
|
|
break;
|
|
|
|
// parse block of code with respect to snapshot
|
|
|
|
try {
|
|
|
|
std::istringstream strm(block);
|
2014-08-30 00:46:17 +00:00
|
|
|
#if defined(LEAN_SERVER_DIAGNOSTIC)
|
|
|
|
std::shared_ptr<output_channel> out1(new stderr_channel());
|
|
|
|
std::shared_ptr<output_channel> out2(new stderr_channel());
|
|
|
|
#else
|
2014-08-27 21:53:16 +00:00
|
|
|
std::shared_ptr<output_channel> out1(new string_output_channel());
|
|
|
|
std::shared_ptr<output_channel> out2(new string_output_channel());
|
2014-08-30 00:46:17 +00:00
|
|
|
#endif
|
2014-08-27 21:53:16 +00:00
|
|
|
io_state tmp_ios(_ios, out1, out2);
|
|
|
|
tmp_ios.set_options(join(s.m_options, _ios.get_options()));
|
|
|
|
bool use_exceptions = false;
|
|
|
|
unsigned num_threads = 1;
|
|
|
|
parser p(s.m_env, tmp_ios, strm, todo_file->m_fname.c_str(), use_exceptions, num_threads,
|
|
|
|
s.m_lds, s.m_eds, s.m_line, &todo_file->m_snapshots, &todo_file->m_info);
|
|
|
|
p.set_cache(&m_cache);
|
|
|
|
p();
|
2014-08-30 00:46:17 +00:00
|
|
|
} catch (interrupted &) {
|
|
|
|
worker_interrupted = true;
|
|
|
|
} catch (exception & ex) {
|
|
|
|
DIAG(std::cerr << "worker exception: " << ex.what() << "\n";)
|
|
|
|
}
|
|
|
|
if (!m_terminate && !worker_interrupted) {
|
|
|
|
DIAG(std::cerr << "finished '" << todo_file->get_fname() << "'\n";)
|
2014-08-27 21:53:16 +00:00
|
|
|
unique_lock<mutex> lk(m_todo_mutex);
|
|
|
|
if (m_todo_file == todo_file && m_last_file == todo_file && m_todo_linenum == todo_linenum) {
|
|
|
|
m_todo_linenum = num_lines + 1;
|
|
|
|
m_todo_file = nullptr;
|
|
|
|
m_todo_cv.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}) {}
|
|
|
|
|
|
|
|
server::worker::~worker() {
|
|
|
|
m_terminate = true;
|
|
|
|
request_interrupt();
|
|
|
|
m_thread.join();
|
2014-08-16 00:24:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 21:53:16 +00:00
|
|
|
void server::worker::request_interrupt() {
|
|
|
|
m_todo_cv.notify_all();
|
|
|
|
m_thread.request_interrupt();
|
2014-08-16 00:24:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 21:53:16 +00:00
|
|
|
void server::worker::wait() {
|
|
|
|
while (true) {
|
|
|
|
unique_lock<mutex> lk(m_todo_mutex);
|
|
|
|
if (!m_todo_file)
|
|
|
|
break;
|
|
|
|
m_todo_cv.wait(lk);
|
2014-08-16 00:24:37 +00:00
|
|
|
}
|
2014-08-11 17:40:18 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 21:53:16 +00:00
|
|
|
void server::worker::set_todo(file_ptr const & f, unsigned linenum, options const & o) {
|
|
|
|
lock_guard<mutex> lk(m_todo_mutex);
|
|
|
|
if (m_last_file != f || linenum < m_todo_linenum)
|
|
|
|
m_todo_linenum = linenum;
|
|
|
|
m_todo_file = f;
|
|
|
|
m_last_file = f;
|
|
|
|
m_todo_options = o;
|
|
|
|
m_todo_cv.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
server::server(environment const & env, io_state const & ios, unsigned num_threads):
|
|
|
|
m_env(env), m_ios(ios), m_out(ios.get_regular_channel().get_stream()),
|
|
|
|
m_num_threads(num_threads), m_empty_snapshot(m_env, m_ios.get_options()),
|
|
|
|
m_worker(env, ios, m_cache) {
|
|
|
|
}
|
|
|
|
|
|
|
|
server::~server() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void server::interrupt_worker() {
|
|
|
|
m_worker.request_interrupt();
|
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
static std::string g_load("LOAD");
|
|
|
|
static std::string g_visit("VISIT");
|
|
|
|
static std::string g_replace("REPLACE");
|
|
|
|
static std::string g_insert("INSERT");
|
|
|
|
static std::string g_remove("REMOVE");
|
|
|
|
static std::string g_info("INFO");
|
2014-08-14 21:40:46 +00:00
|
|
|
static std::string g_set("SET");
|
2014-08-14 23:08:43 +00:00
|
|
|
static std::string g_eval("EVAL");
|
2014-08-17 19:14:42 +00:00
|
|
|
static std::string g_wait("WAIT");
|
2014-08-27 17:31:01 +00:00
|
|
|
static std::string g_clear_cache("CLEAR_CACHE");
|
2014-08-28 14:40:02 +00:00
|
|
|
static std::string g_echo("ECHO");
|
2014-08-29 19:59:22 +00:00
|
|
|
static std::string g_options("OPTIONS");
|
2014-08-30 00:46:17 +00:00
|
|
|
static std::string g_show("SHOW");
|
2014-08-30 01:12:22 +00:00
|
|
|
static std::string g_valid("VALID");
|
2014-08-30 00:46:17 +00:00
|
|
|
static std::string g_sleep("SLEEP");
|
2014-09-02 19:57:20 +00:00
|
|
|
static std::string g_findp("FINDP");
|
2014-08-11 17:40:18 +00:00
|
|
|
|
|
|
|
static bool is_command(std::string const & cmd, std::string const & line) {
|
|
|
|
return line.compare(0, cmd.size(), cmd) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string & ltrim(std::string & s) {
|
|
|
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string & rtrim(std::string & s) {
|
|
|
|
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string & trim(std::string & s) {
|
|
|
|
return ltrim(rtrim(s));
|
|
|
|
}
|
|
|
|
|
2014-08-07 01:07:04 +00:00
|
|
|
void server::process_from(unsigned linenum) {
|
2014-08-27 21:53:16 +00:00
|
|
|
m_worker.set_todo(m_file, linenum, m_ios.get_options());
|
2014-08-11 02:57:24 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::load_file(std::string const & fname) {
|
2014-08-27 21:53:16 +00:00
|
|
|
interrupt_worker();
|
2014-08-07 01:07:04 +00:00
|
|
|
std::ifstream in(fname);
|
|
|
|
if (in.bad() || in.fail()) {
|
2014-08-11 17:40:18 +00:00
|
|
|
m_out << "-- ERROR failed to open file '" << fname << "'" << std::endl;
|
2014-08-07 01:07:04 +00:00
|
|
|
} else {
|
2014-08-27 21:53:16 +00:00
|
|
|
m_file.reset(new file(in, fname));
|
2014-08-11 17:40:18 +00:00
|
|
|
m_file_map.insert(mk_pair(fname, m_file));
|
2014-08-16 00:24:37 +00:00
|
|
|
process_from(0);
|
2014-08-11 02:57:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::visit_file(std::string const & fname) {
|
2014-08-27 21:53:16 +00:00
|
|
|
interrupt_worker();
|
2014-08-11 17:40:18 +00:00
|
|
|
auto it = m_file_map.find(fname);
|
2014-08-16 00:24:37 +00:00
|
|
|
if (it == m_file_map.end()) {
|
2014-08-11 17:40:18 +00:00
|
|
|
load_file(fname);
|
2014-08-16 00:24:37 +00:00
|
|
|
} else {
|
2014-08-11 17:40:18 +00:00
|
|
|
m_file = it->second;
|
2014-08-16 00:24:37 +00:00
|
|
|
process_from(0);
|
|
|
|
}
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 02:57:24 +00:00
|
|
|
void server::read_line(std::istream & in, std::string & line) {
|
|
|
|
if (!std::getline(in, line))
|
|
|
|
throw exception("unexpected end of input");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given a line of the form "cmd linenum", return the linenum
|
|
|
|
unsigned server::get_linenum(std::string const & line, std::string const & cmd) {
|
|
|
|
std::string data = line.substr(cmd.size());
|
|
|
|
trim(data);
|
|
|
|
unsigned r = atoi(data.c_str());
|
|
|
|
if (r == 0)
|
|
|
|
throw exception("line numbers are indexed from 1");
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-11 17:40:18 +00:00
|
|
|
void server::check_file() {
|
|
|
|
if (!m_file)
|
|
|
|
throw exception("no file has been loaded/visited");
|
|
|
|
}
|
|
|
|
|
|
|
|
void server::replace_line(unsigned linenum, std::string const & new_line) {
|
2014-08-27 21:53:16 +00:00
|
|
|
interrupt_worker();
|
2014-08-11 17:40:18 +00:00
|
|
|
check_file();
|
|
|
|
m_file->replace_line(linenum, new_line);
|
2014-08-16 00:24:37 +00:00
|
|
|
process_from(linenum);
|
2014-08-11 17:40:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void server::insert_line(unsigned linenum, std::string const & new_line) {
|
2014-08-27 21:53:16 +00:00
|
|
|
interrupt_worker();
|
2014-08-11 17:40:18 +00:00
|
|
|
check_file();
|
|
|
|
m_file->insert_line(linenum, new_line);
|
2014-08-16 00:24:37 +00:00
|
|
|
process_from(linenum);
|
2014-08-11 17:40:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void server::remove_line(unsigned linenum) {
|
2014-08-27 21:53:16 +00:00
|
|
|
interrupt_worker();
|
2014-08-11 17:40:18 +00:00
|
|
|
check_file();
|
|
|
|
m_file->remove_line(linenum);
|
2014-08-16 00:24:37 +00:00
|
|
|
process_from(linenum);
|
2014-08-11 17:40:18 +00:00
|
|
|
}
|
|
|
|
|
2014-08-14 21:40:46 +00:00
|
|
|
void server::set_option(std::string const & line) {
|
|
|
|
std::string cmd = "set_option ";
|
|
|
|
cmd += line;
|
|
|
|
std::istringstream strm(cmd);
|
|
|
|
m_out << "-- BEGINSET" << std::endl;
|
|
|
|
try {
|
|
|
|
parser p(m_env, m_ios, strm, "SET_command", true);
|
|
|
|
p();
|
|
|
|
m_ios.set_options(p.ios().get_options());
|
|
|
|
} catch (exception & ex) {
|
|
|
|
m_out << ex.what() << std::endl;
|
|
|
|
}
|
|
|
|
m_out << "-- ENDSET" << std::endl;
|
|
|
|
}
|
|
|
|
|
2014-08-16 00:24:37 +00:00
|
|
|
void server::show_info(unsigned linenum) {
|
2014-08-21 23:49:21 +00:00
|
|
|
check_file();
|
2014-09-03 02:04:01 +00:00
|
|
|
m_out << "-- BEGININFO";
|
|
|
|
if (m_file->infom().is_invalidated(linenum))
|
|
|
|
m_out << " STALE";
|
|
|
|
if (linenum >= m_file->infom().get_processed_upto())
|
|
|
|
m_out << " NAY";
|
|
|
|
m_out << std::endl;
|
2014-08-27 21:53:16 +00:00
|
|
|
m_file->infom().display(m_env, m_ios, linenum);
|
2014-08-27 01:06:37 +00:00
|
|
|
m_out << "-- ENDINFO" << std::endl;
|
2014-08-16 00:24:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:06:37 +00:00
|
|
|
void server::eval_core(environment const & env, options const & o, std::string const & line) {
|
2014-08-14 23:08:43 +00:00
|
|
|
std::istringstream strm(line);
|
2014-08-27 17:46:49 +00:00
|
|
|
io_state ios(m_ios, o);
|
2014-08-14 23:08:43 +00:00
|
|
|
m_out << "-- BEGINEVAL" << std::endl;
|
|
|
|
try {
|
2014-08-27 17:46:49 +00:00
|
|
|
parser p(env, ios, strm, "EVAL_command", true);
|
2014-08-14 23:08:43 +00:00
|
|
|
p();
|
|
|
|
} catch (exception & ex) {
|
|
|
|
m_out << ex.what() << std::endl;
|
|
|
|
}
|
|
|
|
m_out << "-- ENDEVAL" << std::endl;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:06:37 +00:00
|
|
|
void server::eval(std::string const & line) {
|
|
|
|
if (!m_file) {
|
|
|
|
eval_core(m_env, m_ios.get_options(), line);
|
2014-08-27 21:53:16 +00:00
|
|
|
} else if (auto p = m_file->infom().get_final_env_opts()) {
|
2014-08-27 17:46:49 +00:00
|
|
|
eval_core(p->first, join(p->second, m_ios.get_options()), line);
|
2014-08-27 01:06:37 +00:00
|
|
|
} else {
|
|
|
|
eval_core(m_env, m_ios.get_options(), line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-29 19:59:22 +00:00
|
|
|
void server::show_options() {
|
|
|
|
m_out << "-- BEGINOPTIONS" << std::endl;
|
2014-09-03 00:29:49 +00:00
|
|
|
options const & o = m_ios.get_options();
|
2014-08-29 19:59:22 +00:00
|
|
|
option_declarations const & decls = get_option_declarations();
|
|
|
|
for (auto it = decls.begin(); it != decls.end(); it++) {
|
|
|
|
option_declaration const & d = it->second;
|
2014-09-03 00:29:49 +00:00
|
|
|
m_out << "-- " << d.get_name() << "|" << d.kind() << "|";
|
2014-09-03 00:42:21 +00:00
|
|
|
d.display_value(m_out, o);
|
2014-09-03 00:29:49 +00:00
|
|
|
m_out << "|" << d.get_description() << "\n";
|
2014-08-29 19:59:22 +00:00
|
|
|
}
|
|
|
|
m_out << "-- ENDOPTIONS" << std::endl;
|
|
|
|
}
|
|
|
|
|
2014-08-30 01:12:22 +00:00
|
|
|
void server::show(bool valid) {
|
2014-08-30 00:46:17 +00:00
|
|
|
check_file();
|
|
|
|
m_out << "-- BEGINSHOW" << std::endl;
|
2014-08-30 01:12:22 +00:00
|
|
|
m_file->show(m_out, valid);
|
2014-08-30 00:46:17 +00:00
|
|
|
m_out << "-- ENDSHOW" << std::endl;
|
|
|
|
}
|
|
|
|
|
2014-09-02 19:57:20 +00:00
|
|
|
static name string_to_name(std::string const & str) {
|
|
|
|
name result;
|
|
|
|
std::string id_part;
|
|
|
|
for (unsigned i = 0; i < str.size(); i++) {
|
|
|
|
if (str[i] == '.') {
|
|
|
|
result = name(result, id_part.c_str());
|
|
|
|
id_part.clear();
|
|
|
|
} else {
|
|
|
|
id_part.push_back(str[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name(result, id_part.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return true iff the last part of p is a prefix of the last part of n
|
|
|
|
static bool is_last_prefix_of(name const & p, name const & n) {
|
|
|
|
if (p.is_string() && n.is_string()) {
|
|
|
|
char const * it1 = p.get_string();
|
|
|
|
char const * it2 = n.get_string();
|
|
|
|
if (!it1 || !it2)
|
|
|
|
return false;
|
|
|
|
while (*it1 && *it2 && *it1 == *it2) {
|
|
|
|
++it1;
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
return *it1 == 0;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Auxiliary function for find_prefix
|
|
|
|
// 1) If p is atomic, then we just check if p is a prefix of the last component of n.
|
|
|
|
// 2) Otherwise, we check if p.get_prefix() == n.get_prefix(), and
|
|
|
|
// p.get_string() is a prefix of n.get_string()
|
|
|
|
static bool is_findp_prefix_of(name const & p, name const & n) {
|
|
|
|
if (p.is_atomic())
|
|
|
|
return is_last_prefix_of(p, n);
|
|
|
|
else
|
|
|
|
return p.get_prefix() == n.get_prefix() && is_last_prefix_of(p, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void server::display_decl(name const & short_name, name const & long_name, environment const & env, options const & o) {
|
|
|
|
declaration const & d = env.get(long_name);
|
|
|
|
io_state_stream out = regular(env, m_ios).update_options(o);
|
|
|
|
out << short_name << "|" << mk_pair(flatten(out.get_formatter()(d.get_type())), o) << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void server::find_prefix(unsigned linenum, std::string const & prefix) {
|
|
|
|
check_file();
|
|
|
|
m_out << "-- BEGINFINDP";
|
|
|
|
unsigned upto = m_file->infom().get_processed_upto();
|
|
|
|
optional<pair<environment, options>> env_opts = m_file->infom().get_closest_env_opts(linenum);
|
|
|
|
if (!env_opts) {
|
|
|
|
m_out << " NAY" << std::endl;
|
|
|
|
m_out << "-- ENDFINDP" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (upto < linenum)
|
|
|
|
m_out << " STALE";
|
|
|
|
environment const & env = env_opts->first;
|
|
|
|
options opts = env_opts->second;
|
|
|
|
opts = join(opts, m_ios.get_options());
|
|
|
|
m_out << std::endl;
|
|
|
|
name p = string_to_name(prefix);
|
|
|
|
name_set already_added;
|
|
|
|
for_each_expr_alias(env, [&](name const & n, list<name> const & ds) {
|
|
|
|
if (is_findp_prefix_of(p, n)) {
|
|
|
|
unsigned num = length(ds);
|
|
|
|
if (num == 1) {
|
|
|
|
display_decl(n, head(ds), env, opts);
|
|
|
|
already_added.insert(car(ds));
|
|
|
|
} else if (num > 1) {
|
|
|
|
m_out << n << "\n";
|
|
|
|
for (name const & d : ds) {
|
|
|
|
display_decl(d, d, env, opts);
|
|
|
|
already_added.insert(d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
env.for_each_declaration([&](declaration const & d) {
|
|
|
|
if (!already_added.contains(d.get_name()) && is_findp_prefix_of(p, d.get_name()))
|
|
|
|
display_decl(d.get_name(), d.get_name(), env, opts);
|
|
|
|
});
|
|
|
|
m_out << "-- ENDFINDP" << std::endl;
|
|
|
|
}
|
|
|
|
|
2014-08-07 01:07:04 +00:00
|
|
|
bool server::operator()(std::istream & in) {
|
|
|
|
for (std::string line; std::getline(in, line);) {
|
2014-08-11 02:57:24 +00:00
|
|
|
try {
|
2014-08-11 17:40:18 +00:00
|
|
|
if (is_command(g_load, line)) {
|
|
|
|
std::string fname = line.substr(g_load.size());
|
|
|
|
trim(fname);
|
|
|
|
load_file(fname);
|
|
|
|
} else if (is_command(g_visit, line)) {
|
|
|
|
std::string fname = line.substr(g_visit.size());
|
2014-08-11 02:57:24 +00:00
|
|
|
trim(fname);
|
2014-08-11 17:40:18 +00:00
|
|
|
visit_file(fname);
|
2014-08-28 14:40:02 +00:00
|
|
|
} else if (is_command(g_echo, line)) {
|
|
|
|
std::string str = line.substr(g_echo.size());
|
|
|
|
m_out << "--" << str << "\n";
|
2014-08-11 02:57:24 +00:00
|
|
|
} else if (is_command(g_replace, line)) {
|
|
|
|
unsigned linenum = get_linenum(line, g_replace);
|
|
|
|
read_line(in, line);
|
|
|
|
replace_line(linenum-1, line);
|
|
|
|
} else if (is_command(g_insert, line)) {
|
2014-08-11 17:40:18 +00:00
|
|
|
unsigned linenum = get_linenum(line, g_insert);
|
2014-08-11 02:57:24 +00:00
|
|
|
read_line(in, line);
|
|
|
|
insert_line(linenum-1, line);
|
|
|
|
} else if (is_command(g_remove, line)) {
|
2014-08-11 17:40:18 +00:00
|
|
|
unsigned linenum = get_linenum(line, g_remove);
|
2014-08-11 02:57:24 +00:00
|
|
|
remove_line(linenum-1);
|
|
|
|
} else if (is_command(g_info, line)) {
|
|
|
|
unsigned linenum = get_linenum(line, g_info);
|
|
|
|
show_info(linenum);
|
2014-08-14 21:40:46 +00:00
|
|
|
} else if (is_command(g_set, line)) {
|
|
|
|
read_line(in, line);
|
|
|
|
set_option(line);
|
2014-08-14 23:08:43 +00:00
|
|
|
} else if (is_command(g_eval, line)) {
|
|
|
|
read_line(in, line);
|
|
|
|
eval(line);
|
2014-08-27 17:31:01 +00:00
|
|
|
} else if (is_command(g_clear_cache, line)) {
|
|
|
|
m_cache.clear();
|
2014-08-29 19:59:22 +00:00
|
|
|
} else if (is_command(g_options, line)) {
|
|
|
|
show_options();
|
2014-08-17 19:14:42 +00:00
|
|
|
} else if (is_command(g_wait, line)) {
|
2014-08-27 21:53:16 +00:00
|
|
|
m_worker.wait();
|
2014-08-30 00:46:17 +00:00
|
|
|
} else if (is_command(g_show, line)) {
|
2014-08-30 01:12:22 +00:00
|
|
|
show(false);
|
|
|
|
} else if (is_command(g_valid, line)) {
|
|
|
|
show(true);
|
2014-08-30 00:46:17 +00:00
|
|
|
} else if (is_command(g_sleep, line)) {
|
|
|
|
unsigned ms = get_linenum(line, g_sleep);
|
|
|
|
chrono::milliseconds d(ms);
|
|
|
|
this_thread::sleep_for(d);
|
2014-09-02 19:57:20 +00:00
|
|
|
} else if (is_command(g_findp, line)) {
|
|
|
|
unsigned linenum = get_linenum(line, g_findp);
|
|
|
|
read_line(in, line);
|
|
|
|
find_prefix(linenum, line);
|
2014-08-07 01:07:04 +00:00
|
|
|
} else {
|
2014-08-11 02:57:24 +00:00
|
|
|
throw exception(sstream() << "unexpected command line: " << line);
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
2014-08-11 02:57:24 +00:00
|
|
|
} catch (exception & ex) {
|
2014-08-11 17:40:18 +00:00
|
|
|
m_out << "-- ERROR " << ex.what() << std::endl;
|
2014-08-07 01:07:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|