diff --git a/src/ast.cpp b/src/ast.cpp index c1f4307..00b810c 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -185,6 +185,11 @@ Keyword::Keyword(const std::string& data) { } +Keyword::Keyword(int64_t number) + : m_data(std::string(1, 0x7f) + std::to_string(number)) // 127 +{ +} + // ----------------------------------------- Number::Number(int64_t number) diff --git a/src/ast.h b/src/ast.h index 58e63cc..77996a6 100644 --- a/src/ast.h +++ b/src/ast.h @@ -238,6 +238,7 @@ private: class Keyword final : public Value { public: Keyword(const std::string& data); + Keyword(int64_t number); virtual ~Keyword() = default; virtual bool isKeyword() const override { return true; } diff --git a/src/eval-special-form.cpp b/src/eval-special-form.cpp index 6c897d9..2b34681 100644 --- a/src/eval-special-form.cpp +++ b/src/eval-special-form.cpp @@ -331,6 +331,39 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env) return; // TCO } +// (while true body...) +void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env) +{ + CHECK_ARG_COUNT_AT_LEAST("while", nodes.size(), 2, void()); + + // Condition + ValuePtr predicate = *nodes.begin(); + + // Printer p; + + m_ast = predicate; + m_env = env; + ValuePtr condition = evalImpl(); + while (!is(condition.get()) + || std::static_pointer_cast(condition)->state() == Constant::True) { + for (auto it = nodes.begin() + 1; it != nodes.end(); ++it) { + m_ast = *it; + m_env = env; + evalImpl(); + } + + m_ast = predicate; + m_env = env; + condition = evalImpl(); + + // print("{}\n", p.print(condition)); + } + + m_ast = makePtr(); + m_env = env; + return; // TCO +} + // ----------------------------------------- } // namespace blaze diff --git a/src/eval.cpp b/src/eval.cpp index b086705..ffbbc2a 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -109,6 +109,10 @@ ValuePtr Eval::evalImpl() evalQuasiQuote(nodes, env); continue; // TCO } + if (symbol == "while") { + evalWhile(nodes, env); + continue; // TCO + } } auto evaluated_list = std::static_pointer_cast(evalAst(ast, env)); diff --git a/src/eval.h b/src/eval.h index 5e240c8..f49672b 100644 --- a/src/eval.h +++ b/src/eval.h @@ -44,6 +44,7 @@ private: void evalIf(const ValueVector& nodes, EnvironmentPtr env); void evalLet(const ValueVector& nodes, EnvironmentPtr env); void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env); + void evalWhile(const ValueVector& nodes, EnvironmentPtr env); ValuePtr apply(std::shared_ptr evaluated_list); diff --git a/src/functions.cpp b/src/functions.cpp index 68aeed8..96f3e70 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -10,6 +10,7 @@ #include // std::advance, std::distance, std::next, std::prev #include // std::static_pointer_cast #include +#include #include "ruc/file.h" #include "ruc/format/format.h" @@ -24,7 +25,7 @@ // At the top-level you cant invoke any function, but you can create variables. // Using a struct's constructor you can work around this limitation. -// Also the line number in the file is used to make the struct names unique. +// Also, the counter macro is used to make the struct names unique. #define FUNCTION_STRUCT_NAME(unique) __functionStruct##unique @@ -41,7 +42,7 @@ symbol, \ [](ValueVectorConstIt begin, ValueVectorConstIt end) -> ValuePtr lambda); -#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda); +#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__COUNTER__, symbol, lambda); #define SIZE() std::distance(begin, end) @@ -113,6 +114,18 @@ ADD_FUNCTION( return makePtr((int64_t)result); }); +// (% 5 2) -> 1 +ADD_FUNCTION( + "%", + { + CHECK_ARG_COUNT_IS("/", SIZE(), 2); + + VALUE_CAST(divide, Number, (*begin)); + VALUE_CAST(by, Number, (*(begin + 1))); + + return makePtr(divide->number() % by->number()); + }); + // // ----------------------------------------- #define NUMBER_COMPARE(operator) \ @@ -146,12 +159,14 @@ ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); // ----------------------------------------- +// (list 1 2) -> (1 2) ADD_FUNCTION( "list", { return makePtr(begin, end); }); +// (empty?) ADD_FUNCTION( "empty?", { @@ -230,6 +245,8 @@ ADD_FUNCTION("println", PRINTER_PRINT(false)); // ----------------------------------------- +// (= 1 1) -> true +// (= "foo" "foo") -> true ADD_FUNCTION( "=", { @@ -447,6 +464,32 @@ ADD_FUNCTION( return makePtr(result_nodes); }); +// (set-nth-element (list 1 2 3) 1 "foo") -> (1 "foo" 3) +ADD_FUNCTION( + "set-nth-element", + { + CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3); + + VALUE_CAST(collection, Collection, (*begin)); + + VALUE_CAST(number_node, Number, (*(begin + 1))); + auto index = static_cast(number_node->number() < 0 ? 0 : number_node->number()); + + auto value = *(begin + 2); + + auto collection_nodes = collection->nodesCopy(); + if (index >= collection->size()) { // Enlarge list if index out of bounds + collection_nodes.resize(index + 1, makePtr()); + } + collection_nodes[index] = value; + + if (is(begin->get())) { + return makePtr(collection_nodes); + } + + return makePtr(collection_nodes); + }); + // (vec (list 1 2 3)) ADD_FUNCTION( "vec", @@ -462,7 +505,7 @@ ADD_FUNCTION( return makePtr(collection->nodesCopy()); }); -// (nth (list 1 2 3) 0) +// (nth (list 1 2 3) 0) -> 1 ADD_FUNCTION( "nth", { @@ -497,7 +540,7 @@ ADD_FUNCTION( return (collection->empty()) ? makePtr() : collection->front(); }); -// (rest (list 1 2 3)) +// (rest (list 1 2 3)) -> (2 3) ADD_FUNCTION( "rest", { @@ -673,22 +716,41 @@ ADD_FUNCTION( // ----------------------------------------- -#define STRING_TO_TYPE(name, type) \ - { \ - CHECK_ARG_COUNT_IS(name, SIZE(), 1); \ - \ - if (is(begin->get())) { \ - return *begin; \ - } \ - \ - VALUE_CAST(stringValue, String, (*begin)); \ - \ - return makePtr(stringValue->data()); \ - } +// (symbol "foo") -> foo +ADD_FUNCTION( + "symbol", + { + CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); -// (symbol "foo") -ADD_FUNCTION("symbol", STRING_TO_TYPE("symbol", Symbol)); -ADD_FUNCTION("keyword", STRING_TO_TYPE("keyword", Keyword)); + if (is(begin->get())) { + return *begin; + } + + VALUE_CAST(stringValue, String, (*begin)); + + return makePtr(stringValue->data()); + }); + +// (keyword "foo") -> :foo +// (keyword 123) -> :123 +ADD_FUNCTION( + "keyword", + { + CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); + + if (is(begin->get())) { + return *begin; + } + else if (is(begin->get())) { + VALUE_CAST(numberValue, Number, (*begin)); + + return makePtr(numberValue->number()); + } + + VALUE_CAST(stringValue, String, (*begin)); + + return makePtr(stringValue->data()); + }); // ----------------------------------------- @@ -978,6 +1040,58 @@ ADD_FUNCTION( return nullptr; }); +// (make-list 4 nil) -> (nil nil nil nil) +ADD_FUNCTION( + "make-list", + { + CHECK_ARG_COUNT_IS("make-list", SIZE(), 2); + + VALUE_CAST(number, Number, (*begin)); + auto count = static_cast(number->number() < 0 ? 0 : number->number()); + auto value = *std::next(begin); + + auto nodes = ValueVector(count); + if (is(value.get())) { + auto atom = std::static_pointer_cast(value); + for (size_t i = 0; i < count; ++i) { + nodes[i] = makePtr(atom); + } + } + // else if (is(value.get())) { + // for (size_t i = 0; i < count; ++i) { + // auto nodes = std::static_pointer_cast(value)->nodesCopy(); + // if (is(value.get())) { + // makePtr(nodes); + // continue; + // } + // nodes[i] = makePtr(nodes); + // } + // } + // else if (is(value.get())) { + // for (size_t i = 0; i < count; ++i) { + // auto constant = std::static_pointer_cast(value); + // nodes[i] = makePtr(constant); + // } + // } + + // TODO: + // Atom + // Collection + // Constant + // Function + // HashMap + // Keyword + // Lambda + // List + // Macro + // Number + // String + // Symbol + // Vector + + return makePtr(std::move(nodes)); + }); + // ----------------------------------------- void installFunctions(EnvironmentPtr env)