diff --git a/debug.lsp b/debug.lsp index 242960d..024862d 100644 --- a/debug.lsp +++ b/debug.lsp @@ -1,5 +1,14 @@ -(defun a (aa) (print aa)) -(a 1 2) +(define a 20) +(cond + ((> a 30) (print "a > 30")) + ((> a 20) (print "a > 20")) + (1 (print "a je" a))) + +(define a 25) +(cond + ((> a 30) (print "a > 30")) + ((> a 20) (print "a > 20")) + (1 (print "a je" a))) ;; (define csv_date (str-to-date "01/01/2021" "%m/%d/%Y")) ;; (date-to-str 3141583200 "%m/%d/%Y") diff --git a/ml.cpp b/ml.cpp index cb86fc7..50e7766 100644 --- a/ml.cpp +++ b/ml.cpp @@ -165,7 +165,6 @@ std::vector MlValue::get_used_atoms() { } } -// Is this a builtin function? bool MlValue::is_builtin() const { return type == BUILTIN; } @@ -178,6 +177,10 @@ bool MlValue::is_string() const { return type == STRING; } +bool MlValue::is_list() const { + return type == LIST; +} + // Get the "truthy" boolean value of this value. bool MlValue::as_bool() const { return type != NIL && *this != MlValue(0l); // TODO remove 0 as false @@ -376,13 +379,13 @@ MlValue MlValue::operator+(const MlValue &other) const { // before continuing with the addition. if (other.type == FLOAT) return MlValue(cast_to_float() + other.stack_data.f); - // Otherwise, do integer addition. + // Otherwise, do integer addition. else return MlValue(stack_data.i + other.stack_data.i); case STRING: // If the other value is also a string, do the concat if (other.type == STRING) return MlValue::string(str + other.str); - // We throw an error if we try to concat anything of non-string type + // We throw an error if we try to concat anything of non-string type else throw MlError(*this, MlEnvironment(), INVALID_BIN_OP); case LIST: // If the other value is also a list, do the concat @@ -921,6 +924,28 @@ MlValue if_then_else(std::vector args, MlEnvironment &env) { return MlValue(0l); } +// cond (SPECIAL FORM), in lisp it's macro, but we don't have support for macros yet +MlValue cond(std::vector args, MlEnvironment &env) { + if (args.size() < 2) + throw MlError(MlValue("cond", cond), env, TOO_FEW_ARGS); + + MlValue acc; + for (auto &arg : args) { + if (!arg.is_list()) + throw MlError(MlValue("cond", cond), env, INVALID_ARGUMENT); + + std::vector list = arg.as_list(); + if (list[0].eval(env).as_bool()) { + for (size_t i = 1; i < list.size(); i++) + acc = list[i].eval(env); + + return acc; + } + } + + return MlValue::nil(); +} + // Define a variable with a value (SPECIAL FORM) MlValue define(std::vector args, MlEnvironment &env) { if (args.size() != 2) @@ -1934,8 +1959,10 @@ bool MlEnvironment::has(const std::string &name) const { // Get the value associated with this name in this scope MlValue MlEnvironment::get(const std::string &name) const { // Special forms - if (name == "if") return MlValue("if", builtin::if_then_else); if (name == "define") return MlValue("define", builtin::define); + if (name == "set!") return MlValue("set!", builtin::setx); + if (name == "if") return MlValue("if", builtin::if_then_else); + if (name == "cond") return MlValue("if", builtin::cond); if (name == "do") return MlValue("do", builtin::do_block); if (name == "for") return MlValue("for", builtin::for_loop); if (name == "while") return MlValue("while", builtin::while_loop); @@ -1945,7 +1972,6 @@ MlValue MlEnvironment::get(const std::string &name) const { if (name == "lambda") return MlValue("lambda", builtin::lambda); if (name == "and") return MlValue("and", builtin::do_and); if (name == "or") return MlValue("or", builtin::do_or); - if (name == "set!") return MlValue("set!", builtin::setx); // Comparison operations if (name == "=") return MlValue("=", builtin::eq); diff --git a/ml.h b/ml.h index 21d3080..64d8ee0 100644 --- a/ml.h +++ b/ml.h @@ -145,6 +145,8 @@ public: bool is_string() const; + bool is_list() const; + // Get the boolean value of this value. bool as_bool() const; diff --git a/utils/Lisp.tmLanguage b/utils/Lisp.tmLanguage index d740721..d399193 100644 --- a/utils/Lisp.tmLanguage +++ b/utils/Lisp.tmLanguage @@ -136,7 +136,7 @@ match - (?<=\()(?i:\*|\*\*|\*\*\*|\+|\+\+|\+\+\+|\-|/|//|///|/=|1\+|1\-|<|<=|=|>|>=|if|do|for|while|scope|quote|defun|and|or|set!|eval|type|parse|list|insert|index|remove|len|push|pop|head|tail|first|last|range|map|filter|reduce|exit|quit|print|input|random|include|read-file|read-file-lines|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-split|string-pad|string-rltrim|string-case|string-len|string-substr|string-find|benchmark|thread-create|thread-under-lock|thread-sleep|threads-join|try|throw|usql|first|second|third|fourth|fifth|sixth|seventh|eight|nth|print|get-universal-time|not|is-pos?|is-neg?|neg|dec|inc|string-ltrim|string-rtrim|string-trim|string-rpad|string-lpad|string-upcase|string-downcase|string-join|itok|ktoi|sleep|get-env|member|make-list-of|make-list|empty-list?|uniq|flatten|quick-sort-by|quick-sort|quick-sort-reverse|start-of-day|end-of-day|start-of-month|start-of-next-month|end-of-next-month|end-of-month|start-of-prev-month|end-of-prev-month|start-of-year|end-of-year|make-csv)(?=\s+) + (?<=\()(?i:\*|\*\*|\*\*\*|\+|\+\+|\+\+\+|\-|/|//|///|/=|1\+|1\-|<|<=|=|>|>=|if|cond|do|for|while|scope|quote|defun|and|or|set!|eval|type|parse|list|insert|index|remove|len|push|pop|head|tail|first|last|range|map|filter|reduce|exit|quit|print|input|random|include|read-file|read-file-lines|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-split|string-pad|string-rltrim|string-case|string-len|string-substr|string-find|benchmark|thread-create|thread-under-lock|thread-sleep|threads-join|try|throw|usql|first|second|third|fourth|fifth|sixth|seventh|eight|nth|print|get-universal-time|not|is-pos?|is-neg?|neg|dec|inc|string-ltrim|string-rtrim|string-trim|string-rpad|string-lpad|string-upcase|string-downcase|string-join|itok|ktoi|sleep|get-env|member|make-list-of|make-list|empty-list?|uniq|flatten|quick-sort-by|quick-sort|quick-sort-reverse|start-of-day|end-of-day|start-of-month|start-of-next-month|end-of-next-month|end-of-month|start-of-prev-month|end-of-prev-month|start-of-year|end-of-year|make-csv)(?=\s+) name keyword.control.lisp