This commit is contained in:
Robert Bendun 2022-05-25 15:53:09 +02:00
parent ad79c17551
commit 7cc61e30e4
2 changed files with 72 additions and 9 deletions

View File

@ -6,7 +6,7 @@ DEBUG_FLAGS=-O0 -ggdb
CXX=g++ CXX=g++
LDFLAGS=-L./lib/midi/ LDFLAGS=-L./lib/midi/
LDLIBS=-lmidi-alsa -lasound LDLIBS=-lmidi-alsa -lasound -lreadline
Obj= \ Obj= \
context.o \ context.o \

View File

@ -7,10 +7,15 @@
#include <musique.hh> #include <musique.hh>
#include <midi.hh> #include <midi.hh>
#include <readline/readline.h>
#include <readline/history.h>
namespace fs = std::filesystem; namespace fs = std::filesystem;
static bool ast_only_mode = false; static bool ast_only_mode = false;
static bool enable_repl = false;
#define Ignore(Call) do { auto const ignore_ ## __LINE__ = (Call); (void) ignore_ ## __LINE__; } while(0)
static std::string_view pop(std::span<char const*> &span) static std::string_view pop(std::span<char const*> &span)
{ {
@ -28,6 +33,8 @@ void usage()
" where options are:\n" " where options are:\n"
" -c,--run CODE\n" " -c,--run CODE\n"
" executes given code\n" " executes given code\n"
" -i,--interactive,--repl\n"
" enables interactive mode even when another code was passed\n"
" --ast\n" " --ast\n"
" prints ast for given code\n" " prints ast for given code\n"
" -l,--list\n" " -l,--list\n"
@ -35,6 +42,25 @@ void usage()
std::exit(1); std::exit(1);
} }
static void trim(std::string_view &s)
{
// left trim
if (auto const i = std::find_if_not(s.begin(), s.end(), unicode::is_space); i != s.begin()) {
// std::string_view::remove_prefix has UB when we wan't to remove more characters then str has
// src: https://en.cppreference.com/w/cpp/string/basic_string_view/remove_prefix
if (i != s.end()) {
s.remove_prefix(std::distance(s.begin(), i));
} else {
s = {};
}
}
// right trim
if (auto const ws_end = std::find_if_not(s.rbegin(), s.rend(), unicode::is_space); ws_end != s.rbegin()) {
s.remove_suffix(std::distance(ws_end.base(), s.end()));
}
}
struct Runner struct Runner
{ {
midi::ALSA alsa; midi::ALSA alsa;
@ -84,10 +110,6 @@ struct Run
static Result<void> Main(std::span<char const*> args) static Result<void> Main(std::span<char const*> args)
{ {
if (args.empty()) {
usage();
}
std::vector<Run> runnables; std::vector<Run> runnables;
while (not args.empty()) { while (not args.empty()) {
@ -119,12 +141,13 @@ static Result<void> Main(std::span<char const*> args)
continue; continue;
} }
std::cerr << "musique: error: unrecognized command line option: " << arg << std::endl; if (arg == "--repl" || arg == "-i" || arg == "--interactive") {
std::exit(1); enable_repl = true;
continue;
} }
if (runnables.empty()) { std::cerr << "musique: error: unrecognized command line option: " << arg << std::endl;
usage(); std::exit(1);
} }
Runner runner("14"); Runner runner("14");
@ -149,11 +172,51 @@ static Result<void> Main(std::span<char const*> args)
Try(runner.run(eternal_sources.back(), path)); Try(runner.run(eternal_sources.back(), path));
} }
if (runnables.empty() || enable_repl) {
for (;;) {
char *input_buffer = readline("> ");
if (input_buffer == nullptr) {
break;
}
// Raw input line used for execution in language
std::string_view raw = input_buffer;
// Used to recognize REPL commands
std::string_view command = raw;
trim(command);
if (command.empty()) {
// Line is empty so there is no need to execute it or parse it
free(input_buffer);
continue;
}
add_history(input_buffer);
if (command.starts_with(':')) {
command.remove_prefix(1);
if (command == "exit") { break; }
if (command == "clear") { std::cout << "\x1b[1;1H\x1b[2J" << std::flush; continue; }
if (command.starts_with('!')) { Ignore(system(command.data() + 1)); continue; }
std::cerr << "musique: error: unrecognized REPL command '" << command << '\'' << std::endl;
continue;
}
Try(runner.run(raw, "<repl>"));
// We don't free input line since there could be values that still relay on it
}
}
return {}; return {};
} }
int main(int argc, char const** argv) int main(int argc, char const** argv)
{ {
rl_readline_name = *argv;
// Set editing mode to Vim-like
rl_editing_mode = 0;
auto const args = std::span(argv, argc).subspan(1); auto const args = std::span(argv, argc).subspan(1);
auto const result = Main(args); auto const result = Main(args);
if (not result.has_value()) { if (not result.has_value()) {