diff --git a/src/functions.cpp b/src/functions.cpp index aa92cc2..37a52b8 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -410,7 +410,6 @@ ADD_FUNCTION( return makePtr(file.data()); }); - ADD_FUNCTION( "eval", { @@ -422,6 +421,119 @@ ADD_FUNCTION( return eval(nodes.front(), nullptr); }); +// (atom 1) +ADD_FUNCTION( + "atom", + { + if (nodes.size() != 1) { + Error::the().add(format("wrong number of arguments: atom, {}", nodes.size())); + return nullptr; + } + + return makePtr(nodes.front()); + }); + +// (atom? myatom 2 "foo") +ADD_FUNCTION( + "atom?", + { + bool result = true; + + if (nodes.size() == 0) { + result = false; + } + + for (auto node : nodes) { + if (!is(node.get())) { + result = false; + break; + } + } + + return makePtr((result) ? Value::True : Value::False); + }); + +// (deref myatom) +ADD_FUNCTION( + "deref", + { + if (nodes.size() != 1) { + Error::the().add(format("wrong number of arguments: deref, {}", nodes.size())); + return nullptr; + } + + if (!is(nodes.front().get())) { + Error::the().add(format("wrong argument type: atom, '{}'", nodes.front())); + return nullptr; + } + + return std::static_pointer_cast(nodes.front())->deref(); + }); + +// (reset! myatom 2) +ADD_FUNCTION( + "reset!", + { + if (nodes.size() != 2) { + Error::the().add(format("wrong number of arguments: reset!, {}", nodes.size())); + return nullptr; + } + + if (!is(nodes.front().get())) { + Error::the().add(format("wrong argument type: atom, '{}'", nodes.front())); + return nullptr; + } + + auto atom = std::static_pointer_cast(*nodes.begin()); + auto value = *std::next(nodes.begin()); + + atom->reset(value); + + return value; + }); + +// (swap! myatom (fn* [x] (+ 1 x))) +ADD_FUNCTION( + "swap!", + { + if (nodes.size() < 2) { + Error::the().add(format("wrong number of arguments: reset!, {}", nodes.size())); + return nullptr; + } + + auto first_argument = *nodes.begin(); + auto second_argument = *std::next(nodes.begin()); + + if (!is(first_argument.get())) { + Error::the().add(format("wrong argument type: atom, '{}'", first_argument)); + return nullptr; + } + + if (!is(second_argument.get())) { + Error::the().add(format("wrong argument type: function, '{}'", second_argument)); + return nullptr; + } + + auto atom = std::static_pointer_cast(first_argument); + + // Remove atom and function from the argument list, add atom value + nodes.pop_front(); + nodes.pop_front(); + nodes.push_front(atom->deref()); + + ASTNodePtr value = nullptr; + if (is(second_argument.get())) { + auto function = std::static_pointer_cast(second_argument)->function(); + value = function(nodes); + } + else { + auto lambda = std::static_pointer_cast(second_argument); + value = eval(lambda->body(), Environment::create(lambda, nodes)); + } + + return atom->reset(value); + }); + // ----------------------------------------- void installFunctions(EnvironmentPtr env)