diff --git a/Readme.md b/Readme.md index cd60a1f..cc0eacd 100644 --- a/Readme.md +++ b/Readme.md @@ -4,7 +4,7 @@ ### TODO - test whether AIG,,,10 csv row is parsed -- support for (), nil, t +- support for (), nil, t, in lsp code replace 0 by nil in logicals - print-table - download 10 years of data from api.nasdaq.com into test dir - documentation diff --git a/debug.lsp b/debug.lsp index 887b0b5..5c9aeaf 100644 --- a/debug.lsp +++ b/debug.lsp @@ -24,4 +24,9 @@ (print (string-lpad "lpad" 10 "x")) +(print nil) +(print ()) + +(print (make-list 5)) + (print "Debug ends") diff --git a/ml.cpp b/ml.cpp index 0d13f9c..14a8f1f 100644 --- a/ml.cpp +++ b/ml.cpp @@ -30,7 +30,6 @@ #define INVALID_ORDER "cannot order expression" #define BAD_CAST "cannot cast" #define ATOM_NOT_DEFINED "atom not defined" -#define EVAL_EMPTY_LIST "evaluated empty list" #define INTERNAL_ERROR "internal virtual machine error" #define INDEX_OUT_OF_RANGE "index out of range" #define MALFORMED_PROGRAM "malformed program" @@ -40,6 +39,7 @@ #define INT_TYPE "int" #define FLOAT_TYPE "float" #define UNIT_TYPE "unit" +#define NIL_TYPE "nil" #define FUNCTION_TYPE "function" #define ATOM_TYPE "atom" #define QUOTE_TYPE "quote" @@ -93,6 +93,12 @@ MlValue MlValue::string(const std::string &s) { return result; } +MlValue MlValue::nil() { + MlValue result; + result.type = NIL; + return result; +} + // Construct a lambda function MlValue::MlValue(const std::vector ¶ms, MlValue ret, MlEnvironment const &env) : type(LAMBDA) { // We store the params and the result in the list member @@ -162,7 +168,7 @@ bool MlValue::is_number() const { // Get the "truthy" boolean value of this value. bool MlValue::as_bool() const { - return *this != MlValue(0); + return type != NIL && *this != MlValue(0); // TODO remove 0 as false } // Get this item's integer value @@ -281,6 +287,8 @@ bool MlValue::operator==(MlValue other) const { // The values for quotes are stored in the // first slot of the list member. return list[0] == other.list[0]; + case NIL: + return other.type == NIL; default: return true; } @@ -516,6 +524,8 @@ std::string MlValue::get_type_name() { return FUNCTION_TYPE; case UNIT: return UNIT_TYPE; + case NIL: + return NIL_TYPE; default: // We don't know the name of this type. // This isn't the users fault, this is just unhandled. @@ -553,6 +563,8 @@ std::string MlValue::display() const { return "<" + str + " at " + to_string(long(stack_data.b)) + ">"; case UNIT: return "@"; + case NIL: + return "nil"; default: // We don't know how to display whatever type this is. // This isn't the users fault, this is just unhandled. @@ -594,6 +606,8 @@ std::string MlValue::debug() const { return "<" + str + " at " + to_string(long(stack_data.b)) + ">"; case UNIT: return "@"; + case NIL: + return "nil"; default: // We don't know how to debug whatever type this is. // This isn't the users fault, this is just unhandled. @@ -621,8 +635,7 @@ MlError::~MlError() { } std::string MlError::description() { - return "error: the expression `" + cause->debug() + "` failed in scope " + to_string(env) + " with message \"" + - msg + "\""; + return "error: the expression `" + cause->debug() + "` failed in scope " + to_string(env) + " with message \"" + msg + "\""; } void MlEnvironment::combine(MlEnvironment const &other) { @@ -657,9 +670,7 @@ MlValue MlValue::apply(std::vector args, MlEnvironment &env) { // Get the list of parameter atoms params = list[0].list; if (params.size() != args.size()) - throw MlError(MlValue(args), env, args.size() > params.size() ? - TOO_MANY_ARGS : TOO_FEW_ARGS - ); + throw MlError(MlValue(args), env, args.size() > params.size() ? TOO_MANY_ARGS : TOO_FEW_ARGS); // Get the captured scope from the lambda e = lambda_scope; @@ -701,7 +712,7 @@ MlValue MlValue::eval(MlEnvironment &env) { return env.get(str); case LIST: if (list.size() < 1) - throw MlError(*this, env, EVAL_EMPTY_LIST); + return MlValue::nil(); args = std::vector(list.begin() + 1, list.end()); @@ -747,6 +758,7 @@ MlValue parse(std::string &s, int &ptr) { if (s == "") { return MlValue(); + } else if (s[ptr] == '\'') { // If this is a quote ptr++; @@ -807,6 +819,7 @@ MlValue parse(std::string &s, int &ptr) { } return MlValue::string(x); + } else if (s[ptr] == '@') { ptr++; skip_whitespace(s, ptr); @@ -822,7 +835,11 @@ MlValue parse(std::string &s, int &ptr) { std::string x = s.substr(ptr, n); ptr += n; skip_whitespace(s, ptr); - return MlValue::atom(x); + if (x == "nil") + return MlValue::nil(); + else + return MlValue::atom(x); + } else { throw std::runtime_error(MALFORMED_PROGRAM); } @@ -1765,7 +1782,7 @@ int main(int argc, const char **argv) { try { load_std_lib(env); // for xcode profiling - // run(read_file_contents("/Users/vaclavt/Development/mlisp/tests/test.lsp"), env); + run(read_file_contents("/Users/vaclavt/Development/mlisp/tests/test.lsp"), env); if (argc == 1 || (argc == 2 && std::string(argv[1]) == "-i")) repl(env); diff --git a/ml.h b/ml.h index 42ea34d..9152f37 100644 --- a/ml.h +++ b/ml.h @@ -98,6 +98,9 @@ public: // Construct a string static MlValue string(const std::string &s); + // Construct a nil + static MlValue nil(); + // Construct a lambda function MlValue(const std::vector ¶ms, MlValue ret, MlEnvironment const &env); @@ -197,7 +200,8 @@ private: STRING, LAMBDA, BUILTIN, - UNIT + UNIT, + NIL } type; union { diff --git a/stdlib/stdlib.lsp b/stdlib/stdlib.lsp index 528f12a..c1ed474 100644 --- a/stdlib/stdlib.lsp +++ b/stdlib/stdlib.lsp @@ -69,6 +69,19 @@ 0) )) +(defun make-list-of (size val) + (do + (define lst '()) + (define i 0) + (while (< i size) + (define lst (push lst val)) + (define i (inc i))) + lst + )) + +(defun make-list (size) + (make-list-of size nil)) + ; quicksort (defun quick-sort-by (l cmp) diff --git a/tests/test.lsp b/tests/test.lsp index a1008ab..ad93dfc 100644 --- a/tests/test.lsp +++ b/tests/test.lsp @@ -14,6 +14,9 @@ (print "(member '(1 2 3) 3:" (member '(1 2 3) 3)) (print "(member '(1 2 3) 30:" (member '(1 2 3) 30)) +(print "(make-list 3) :" (make-list 3)) +(print "(make-list-of 3) :" (make-list-of 3 999)) + (defun fact (n) (if (<= n 1) @@ -45,7 +48,7 @@ (print "sorted: " (quick-sort '(1 2 3 4 5 6 7 8 9 10))) (print "sorted by: " (quick-sort-by '(10 9 8 7 6 5 4 3 2 1) (lambda (a b) (> a b)) )) (print "sorted by: " (quick-sort-by '(1 2 3 4 5 6 7 8 9 10) (lambda (a b) (> a b)) )) -(print "sorted by: " (quick-sort-by '(1 2 3 4 5 6 7 8 9 10) (lambda (a b) (< a b)) )) +(print "sorted by desc: " (quick-sort-by '(1 2 3 4 5 6 7 8 9 10) (lambda (a b) (< a b)) ))