fixes & enhandcements

(benchmark code..) implemented
repl completion very first version
(string xx) added
some builtin renames
a bit of comments
a bit of cocumentation
(sleep interval) added
This commit is contained in:
2021-03-14 16:15:04 +01:00
parent 8fad428a4b
commit c4e4522492
12 changed files with 276 additions and 110 deletions

205
ml.cpp
View File

@@ -3,13 +3,13 @@
#include "ml_io.h"
#include "ml_date.h"
#include "ml_string.h"
#include "ml_util.h"
#include "clib/csvparser.h"
#include "clib/sslclient.h"
#include "clib/json11.h"
#include "clib/printf.h"
#include "linenoise.h"
#include <cmath>
#include <map>
@@ -19,7 +19,7 @@
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <chrono>
#define TOO_FEW_ARGS "too few arguments to function"
#define TOO_MANY_ARGS "too many arguments to function"
@@ -257,6 +257,20 @@ MlValue MlValue::cast_to_float() const {
}
}
// Cast this to a string
MlValue MlValue::cast_to_string() const {
switch (type) {
case INT:
return MlValue::string(to_string(stack_data.i));
case FLOAT:
return MlValue::string(to_string(stack_data.f));
case STRING:
return *this;
default:
throw MlError(*this, MlEnvironment(), BAD_CAST);
}
}
bool MlValue::operator==(MlValue other) const {
// If either of these values are floats, promote the
@@ -1110,6 +1124,7 @@ namespace builtin {
return MlValue(now());
}
// Converts date to formated string.
MlValue date_to_str(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -1119,6 +1134,7 @@ namespace builtin {
return MlValue::string(date_to_string(args[0].as_int(), args[1].as_string()));
}
// Converst string to time of secs since epoch
MlValue str_to_date(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -1129,6 +1145,7 @@ namespace builtin {
return MlValue(string_to_date(args[0].as_string(), args[1].as_string()));
}
// Add number of units to date. A unit is one of 'year', 'month', 'day', 'hour', 'minute' or 'second'
MlValue date_add(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -1353,7 +1370,17 @@ namespace builtin {
return args[0].cast_to_int();
}
// Index a list
// Cast an item to a string
MlValue cast_to_string(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (args.size() != 1)
throw MlError(MlValue(STRING_TYPE, cast_to_string), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return args[0].cast_to_string();
}
// Index a list
MlValue index(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -1474,22 +1501,24 @@ namespace builtin {
return MlValue(parsed);
}
MlValue replace(std::vector<MlValue> args, MlEnvironment &env) {
// Replace a substring with a replacement string in a source string
MlValue string_replace(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (args.size() != 3)
throw MlError(MlValue("replace", replace), env, args.size() > 3 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw MlError(MlValue("string-replace", string_replace), env, args.size() > 3 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
std::string src = args[0].as_string();
replace_substring(src, args[1].as_string(), args[2].as_string());
return MlValue::string(src);
}
MlValue regex_search(std::vector<MlValue> args, MlEnvironment &env) {
// Returns true if where contains regex
MlValue string_regex(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (args.size() != 2) // if (args.size() < 2 || args.size() > 3)
throw MlError(MlValue("regex_search", regex_search), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw MlError(MlValue("string-regex?", string_regex), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return MlValue(regexp_search(args[0].as_string(), args[1].as_string()));
}
@@ -1608,53 +1637,39 @@ namespace builtin {
}
return MlValue(result);
}
// Benchmarks a block of expressions in the current environment (SPECIAL FORM)
MlValue benchmark(std::vector<MlValue> args, MlEnvironment &env) {
// TODO add some memory stats
using namespace std::chrono;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
MlValue acc;
for (size_t i = 1; i < args.size(); i++)
acc = args[i].eval(env);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double, std::milli> time_span = t2 - t1;
std::cout << args[0].as_string() << " " << time_span.count() << " ms" << std::endl;
return acc;
}
}
// void completion(const char *buf, linenoiseCompletions *lc) {
// if (buf[0] == 'h') {
// linenoiseAddCompletion(lc,"hello");
// linenoiseAddCompletion(lc,"hello there");
// }
// }
// char *hints(const char *buf, int *color, int *bold) {
// if (!strcasecmp(buf,"hello")) {
// *color = 35;
// *bold = 0;
// return " World";
// }
// return NULL;
// }
void repl(MlEnvironment &env) {
std::string code;
std::string input;
MlValue tmp;
std::vector<MlValue> parsed;
char *line;
// TODO not portable and in function
std::string history_file;
std::string file{"/.ml_history.txt"};
const char *t = std::getenv("HOME");
if (t == nullptr)
history_file = "/tmp/" + file;
else
history_file = std::string{t} + "/" + file;
// linenoiseHistorySetMaxLen(500);
// linenoiseSetCompletionCallback(completion);
// linenoiseSetHintsCallback(hints);
linenoiseSetMultiLine(1);
linenoiseHistoryLoad(history_file.c_str());
setup_linenoise(env);
while (true) {
// std::cout << ">>> ";
// std::getline(std::cin, input);
char *line = linenoise(">>> ");
if (line == nullptr) break;
line = linenoise(">>> ");
linenoiseHistoryAdd(line);
linenoise_line_read(line);
input = std::string(line);
@@ -1680,23 +1695,11 @@ void repl(MlEnvironment &env) {
}
}
linenoiseHistorySave(history_file.c_str());
close_linenoise();
}
void load_std_lib(MlEnvironment &env) {
std::string loader =
R"( (define ___lib_path '("/usr/local/var/mlisp"))
(for d ___lib_path
(if (is-dir? d)
(for f (ls-dir d)
(if (regex-search? f "^.*\.l(i)?sp$")
(include (+ d "/" f))
'())
)
'()))
)";
run(loader, env);
run(STDLIB_LOADER, env);
}
// Does this environment, or its parent environment, have a variable?
@@ -1730,6 +1733,7 @@ MlValue MlEnvironment::get(const std::string &name) const {
if (name == "defun") return MlValue("defun", builtin::defun);
if (name == "define") return MlValue("define", builtin::define);
if (name == "lambda") return MlValue("lambda", builtin::lambda);
if (name == "benchmark") return MlValue("benchmark", builtin::benchmark);
// Comparison operations
if (name == "=") return MlValue("=", builtin::eq);
@@ -1794,13 +1798,14 @@ MlValue MlEnvironment::get(const std::string &name) const {
if (name == "debug") return MlValue("debug", builtin::debug);
if (name == "sprintf") return MlValue("sprintf", builtin::sprintf);
if (name == "display") return MlValue("display", builtin::display);
if (name == "replace") return MlValue("replace", builtin::replace);
if (name == "regex-search?") return MlValue("regex-search?", builtin::regex_search);
if (name == "string-replace") return MlValue("string-replace", builtin::string_replace);
if (name == "string-regex?") return MlValue("string-regex?", builtin::string_regex);
if (name == "string-pad") return MlValue("string-pad", builtin::string_pad);
// Casting operations
if (name == "int") return MlValue("int", builtin::cast_to_int);
if (name == "float") return MlValue("float", builtin::cast_to_float);
if (name == "string") return MlValue("string", builtin::cast_to_string);
// Constants
if (name == "endl") return MlValue::string("\n");
@@ -1816,9 +1821,41 @@ MlValue MlEnvironment::get(const std::string &name) const {
throw MlError(MlValue::atom(name), *this, ATOM_NOT_DEFINED);
}
// Get vector of executables in this scope
std::vector<std::string> MlEnvironment::get_lambdas_list() const {
std::vector<std::string> lambdas {128};
for (auto it = defs.begin(); it != defs.end(); it++) {
if (it->second.get_type_name()==FUNCTION_TYPE) {
lambdas.push_back(it->first);
}
}
std::vector<std::string> commands {
"eval", "type", "parse", "do", "if", "for", "while", "scope", "quote", "defun",
"define", "lambda", "benchmark", "=", "!=", ">", "<", ">=", "<=", "+", "-", "*", "/", "%",
"list", "insert", "index", "remove", "len", "push", "pop", "head", "tail", "first", "last",
"range", "map", "filter", "reduce", "exit", "quit", "print", "input", "random", "include",
"read-file", "write-file", "read-url", "system-cmd", "ls-dir", "is-file?", "is-dir?",
"parse-csv", "parse-json", "get-universal-time", "date-to-str", "str-to-date", "date-add", "debug",
"sprintf", "display", "string-replace", "string-regex?", "string-pad", "int", "float", "string" };
lambdas.insert(end(lambdas), begin(commands), end(commands));
return lambdas;
}
bool cmdOptionExists(char **begin, char **end, const std::string &option) { return std::find(begin, end, option) != end; }
std::vector<std::string> getCmdOption(char *argv[], int argc, const std::string &option) {
std::vector<std::string> tokens;
for (int i = 1; i < argc; ++i) {
if (option == argv[i] && i + 1 < argc) {
i++;
tokens.push_back(std::string(argv[i]));
}
}
return tokens;
}
int main(int argc, char *argv[]) {
MlEnvironment env;
std::vector<MlValue> args;
@@ -1828,29 +1865,35 @@ int main(int argc, char *argv[]) {
srand(time(NULL));
try {
load_std_lib(env);
// for xcode profiling
// run(read_file_contents("/Users/vaclavt/Development/mlisp/tests/test.lsp"), env);
// help
if (cmdOptionExists(argv, argv + argc, "-h")) {
std::cout << "Usage:\n\t-h print this help\n\t-f source_file - executes code in file\n\t-c code - runs passed code\n\t-i runs repl\n\t-v prints version string\n\n";
return 0;
}
// version
if (cmdOptionExists(argv, argv + argc, "-v")) {
std::cout << VERSION << std::endl;
return 0;
}
if (argc == 1 || (argc == 2 && std::string(argv[1]) == "-i"))
// skip loading std lib
if (!cmdOptionExists(argv, argv + argc, "-b")) {
load_std_lib(env);
}
// help
if (cmdOptionExists(argv, argv + argc, "-h")) {
std::cout << "Usage:\n\t-h print this help\n\t-f source_file - executes code in file\n\t-c code - runs passed code\n\t-i runs repl\n\t-b skip stdlib loading\n\t-v prints version string\n\n";
return 0;
}
// version
if (cmdOptionExists(argv, argv + argc, "-v")) {
std::cout << VERSION << std::endl;
return 0;
}
// passed code
if (cmdOptionExists(argv, argv + argc, "-c")) {
std::vector<std::string> codes = getCmdOption(argv, argc, "-c");
for (size_t i = 0; i < codes.size(); i++)
run(codes[i], env);
// run files
} else if (cmdOptionExists(argv, argv + argc, "-f")) {
std::vector<std::string> files = getCmdOption(argv, argc, "-f");
for (size_t i = 0; i < files.size(); i++)
run(read_file_contents(files[i]), env);
// repl
} else {
repl(env);
else if (argc == 3 && std::string(argv[1]) == "-c")
run(argv[2], env);
else if (argc == 3 && std::string(argv[1]) == "-f")
run(read_file_contents(argv[2]), env);
else std::cerr << "invalid arguments" << std::endl;
}
} catch (MlError &e) {
std::cerr << e.description() << std::endl;
} catch (std::runtime_error &e) {