mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 21:35:45 +02:00
crucible: remove ArgList and drop the unimplemented interpreter classes
Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
parent
e8eaa7e471
commit
4a9f26d12e
@ -1,106 +0,0 @@
|
||||
#ifndef CRUCIBLE_INTERP_H
|
||||
#define CRUCIBLE_INTERP_H
|
||||
|
||||
#include "crucible/error.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace crucible {
|
||||
using namespace std;
|
||||
|
||||
struct ArgList : public vector<string> {
|
||||
ArgList(const char **argv);
|
||||
// using vector<string>::vector ... doesn't work:
|
||||
// error: ‘std::vector<std::basic_string<char> >::vector’ names constructor
|
||||
// Still doesn't work in 4.9 because it can't manage a conversion
|
||||
ArgList(const vector<string> &&that);
|
||||
};
|
||||
|
||||
struct ArgActor {
|
||||
struct ArgActorBase {
|
||||
virtual void predicate(void *obj, string arg);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ArgActorDerived {
|
||||
function<void(T, string)> m_func;
|
||||
|
||||
ArgActorDerived(decltype(m_func) func) :
|
||||
m_func(func)
|
||||
{
|
||||
}
|
||||
|
||||
void predicate(void *obj, string arg) override
|
||||
{
|
||||
T &op = *(reinterpret_cast<T*>(obj));
|
||||
m_func(op, obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ArgActor(T, function<void(T, string)> func) :
|
||||
m_actor(make_shared(ArgActorDerived<T>(func)))
|
||||
{
|
||||
}
|
||||
|
||||
ArgActor() = default;
|
||||
|
||||
void predicate(void *t, string arg)
|
||||
{
|
||||
if (m_actor) {
|
||||
m_actor->predicate(t, arg);
|
||||
} else {
|
||||
THROW_ERROR(invalid_argument, "null m_actor for predicate arg '" << arg << "'");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<ArgActorBase> m_actor;
|
||||
};
|
||||
|
||||
struct ArgParser {
|
||||
~ArgParser();
|
||||
ArgParser();
|
||||
|
||||
void add_opt(string opt, ArgActor actor);
|
||||
|
||||
template <class T>
|
||||
void
|
||||
parse(T t, const ArgList &args)
|
||||
{
|
||||
void *vt = &t;
|
||||
parse_backend(vt, args);
|
||||
}
|
||||
|
||||
private:
|
||||
void parse_backend(void *t, const ArgList &args);
|
||||
map<string, ArgActor> m_string_opts;
|
||||
};
|
||||
|
||||
struct Command {
|
||||
virtual ~Command();
|
||||
virtual int exec(const ArgList &args) = 0;
|
||||
};
|
||||
|
||||
struct Proc : public Command {
|
||||
int exec(const ArgList &args) override;
|
||||
Proc(const function<int(const ArgList &)> &f);
|
||||
private:
|
||||
function<int(const ArgList &)> m_cmd;
|
||||
};
|
||||
|
||||
struct Interp {
|
||||
virtual ~Interp();
|
||||
Interp(const map<string, shared_ptr<Command> > &cmdlist);
|
||||
void add_command(const string &name, const shared_ptr<Command> &command);
|
||||
int exec(const ArgList &args);
|
||||
private:
|
||||
Interp(const Interp &) = delete;
|
||||
map<string, shared_ptr<Command> > m_commands;
|
||||
};
|
||||
|
||||
};
|
||||
#endif // CRUCIBLE_INTERP_H
|
@ -8,7 +8,6 @@ OBJS = \
|
||||
extentwalker.o \
|
||||
fd.o \
|
||||
fs.o \
|
||||
interp.o \
|
||||
ntoa.o \
|
||||
path.o \
|
||||
process.o \
|
||||
|
@ -1,96 +0,0 @@
|
||||
#include "crucible/interp.h"
|
||||
|
||||
#include "crucible/chatter.h"
|
||||
|
||||
namespace crucible {
|
||||
using namespace std;
|
||||
|
||||
int
|
||||
Proc::exec(const ArgList &args)
|
||||
{
|
||||
return m_cmd(args);
|
||||
}
|
||||
|
||||
Proc::Proc(const function<int(const ArgList &)> &f) :
|
||||
m_cmd(f)
|
||||
{
|
||||
}
|
||||
|
||||
Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
ArgList::ArgList(const char **argv)
|
||||
{
|
||||
while (argv && *argv) {
|
||||
push_back(*argv++);
|
||||
}
|
||||
}
|
||||
|
||||
ArgList::ArgList(const vector<string> &&that) :
|
||||
vector<string>(that)
|
||||
{
|
||||
}
|
||||
|
||||
Interp::~Interp()
|
||||
{
|
||||
}
|
||||
|
||||
Interp::Interp(const map<string, shared_ptr<Command> > &cmdlist) :
|
||||
m_commands(cmdlist)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Interp::add_command(const string &name, const shared_ptr<Command> &command)
|
||||
{
|
||||
m_commands[name] = command;
|
||||
}
|
||||
|
||||
int
|
||||
Interp::exec(const ArgList &args)
|
||||
{
|
||||
auto next_arg = args.begin();
|
||||
++next_arg;
|
||||
return m_commands.at(args[0])->exec(vector<string>(next_arg, args.end()));
|
||||
}
|
||||
|
||||
ArgParser::~ArgParser()
|
||||
{
|
||||
}
|
||||
|
||||
ArgParser::ArgParser()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::add_opt(string opt, ArgActor actor)
|
||||
{
|
||||
m_string_opts[opt] = actor;
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::parse_backend(void *t, const ArgList &args)
|
||||
{
|
||||
bool quote_args = false;
|
||||
for (string arg : args) {
|
||||
if (quote_args) {
|
||||
cerr << "arg: '" << arg << "'" << endl;
|
||||
continue;
|
||||
}
|
||||
if (arg == "--") {
|
||||
quote_args = true;
|
||||
continue;
|
||||
}
|
||||
if (arg.compare(0, 2, "--") == 0) {
|
||||
auto found = m_string_opts.find(arg.substr(2, string::npos));
|
||||
if (found != m_string_opts.end()) {
|
||||
found->second.predicate(t, "foo");
|
||||
}
|
||||
(void)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
11
src/bees.cc
11
src/bees.cc
@ -1,7 +1,6 @@
|
||||
#include "bees-version.h"
|
||||
#include "bees.h"
|
||||
|
||||
#include "crucible/interp.h"
|
||||
#include "crucible/limits.h"
|
||||
#include "crucible/process.h"
|
||||
#include "crucible/string.h"
|
||||
@ -25,7 +24,7 @@ using namespace crucible;
|
||||
using namespace std;
|
||||
|
||||
int
|
||||
do_cmd_help(const ArgList &argv)
|
||||
do_cmd_help(const char **argv)
|
||||
{
|
||||
cerr << "Usage: " << argv[0] << " fs-root-path [fs-root-path-2...]\n"
|
||||
"Performs best-effort extent-same deduplication on btrfs.\n"
|
||||
@ -555,8 +554,10 @@ BeesTempFile::make_copy(const BeesFileRange &src)
|
||||
}
|
||||
|
||||
int
|
||||
bees_main(ArgList args)
|
||||
bees_main(int argc, const char **argv)
|
||||
{
|
||||
vector<string> args(argv, argv + argc);
|
||||
|
||||
set_catch_explainer([&](string s) {
|
||||
BEESLOG("\n\n*** EXCEPTION ***\n\t" << s << "\n***\n");
|
||||
BEESCOUNT(exception_caught);
|
||||
@ -603,11 +604,9 @@ main(int argc, const char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
ArgList args(argv + 1);
|
||||
|
||||
int rv = 1;
|
||||
catch_and_explain([&]() {
|
||||
rv = bees_main(args);
|
||||
rv = bees_main(argc, argv);
|
||||
});
|
||||
return rv;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ PROGRAMS = \
|
||||
crc64 \
|
||||
execpipe \
|
||||
fd \
|
||||
interp \
|
||||
limits \
|
||||
path \
|
||||
process \
|
||||
|
@ -1,88 +0,0 @@
|
||||
#include "tests.h"
|
||||
|
||||
#include "crucible/interp.h"
|
||||
|
||||
using namespace crucible;
|
||||
using namespace std;
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
How this should work:
|
||||
|
||||
Interpreter reads an arg list:
|
||||
|
||||
argv[0] --method0args --method1arg arg1 --method1arg=arg1 -- args...
|
||||
|
||||
argv[0] should look up a shared_ptr<Command> which creates an object of
|
||||
type shared_ptr<Process>. This object is used to receive args by
|
||||
method calls or one at a time.
|
||||
|
||||
<Command> and <Process> can be the same object, or not.
|
||||
|
||||
Process p methods:
|
||||
|
||||
p->spawn(Interp*) -> Process
|
||||
p->exec(ArgList) -> Process / Result
|
||||
p->method (from ArgParser<>)
|
||||
p->finish() -> void (destroys object without early destruction warnings...?)
|
||||
p->~Process() -> complains loudly if finish() not called first...?
|
||||
|
||||
Result might be a pair of Process, string. Or just string.
|
||||
|
||||
ArgParser should be more like GetOpt:
|
||||
|
||||
build a dictionary and an arg list from arguments
|
||||
Process methods should interrogate ArgParser
|
||||
ArgParser might have a table of boolean and string option names so it can reject invalid options
|
||||
but if it had that, we could also pass in Process and have it call methods on it
|
||||
...but that is a _lot_ of pointer-hiding when we could KISS
|
||||
...but if we had that solved, argparser tables look like lists of method names
|
||||
ArgParser<T> has a table of names and methods on object of type T
|
||||
ArgParser hides everything behind void* and hands off to a compiled implementation to do callbacks
|
||||
|
||||
Extreme simplification: arguments are themselves executable
|
||||
|
||||
so '--method_foo arg' really means construct MethodFoo(arg) and cast to shared_ptr<ProcArg>
|
||||
then Process->invokeSomething(ProcArg)
|
||||
too extreme, use argparser instead
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void
|
||||
test_arg_parser()
|
||||
{
|
||||
ArgParser ap;
|
||||
ArgList al( { "abc", "--def", "ghi" } );
|
||||
ap.parse(NULL, al);
|
||||
}
|
||||
|
||||
struct Thing {
|
||||
int m_i;
|
||||
double m_d;
|
||||
string m_s;
|
||||
|
||||
void set_i(int i) { cerr << "i = " << i << endl; m_i = i; }
|
||||
void set_d(double d) { cerr << "d = " << d << endl; m_d = d; }
|
||||
void set_s(string s) { cerr << "s = " << s << endl; m_s = s; }
|
||||
};
|
||||
|
||||
template <typename F, typename T, typename A>
|
||||
void
|
||||
assign(T& t, F f, A a)
|
||||
{
|
||||
cerr << __PRETTY_FUNCTION__ << " - a = " << a << endl;
|
||||
(t.*f)(a);
|
||||
}
|
||||
|
||||
int
|
||||
main(int, char**)
|
||||
{
|
||||
RUN_A_TEST(test_arg_parser());
|
||||
|
||||
Thing p;
|
||||
assign(p, &Thing::set_i, 5);
|
||||
|
||||
cerr << "p.m_i = " << p.m_i << endl;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user