From b65482eb68d3e6263b236b91ac5c6ea34162a2d8 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sun, 27 Aug 2023 21:36:14 +0200 Subject: [PATCH] Env: Allow load order control for native functions --- src/env/environment.cpp | 16 + src/env/environment.h | 15 + src/env/functions/collection-access.cpp | 229 +++++------ src/env/functions/collection-constructor.cpp | 203 +++++----- src/env/functions/collection-modify.cpp | 405 ++++++++++--------- src/env/functions/compare.cpp | 153 +++---- src/env/functions/convert.cpp | 73 ++-- src/env/functions/format.cpp | 11 +- src/env/functions/meta.cpp | 77 ++-- src/env/functions/mutable.cpp | 127 +++--- src/env/functions/operators.cpp | 153 +++---- src/env/functions/other.cpp | 83 ++-- src/env/functions/predicate.cpp | 147 +++---- src/env/functions/repl.cpp | 93 ++--- src/env/macro.h | 24 +- src/repl.cpp | 1 + 16 files changed, 931 insertions(+), 879 deletions(-) diff --git a/src/env/environment.cpp b/src/env/environment.cpp index fe02120..956fdae 100644 --- a/src/env/environment.cpp +++ b/src/env/environment.cpp @@ -72,6 +72,22 @@ EnvironmentPtr Environment::create(const ValuePtr lambda, ValueVector&& argument // ----------------------------------------- +void Environment::loadFunctions() +{ + loadCollectionAccess(); + loadCollectionConstructor(); + loadCollectionModify(); + loadCompare(); + loadConvert(); + loadFormat(); + loadMeta(); + loadMutable(); + loadOperators(); + loadOther(); + loadPredicate(); + loadRepl(); +} + void Environment::registerFunction(const std::string& name, FunctionType function) { s_functions.insert_or_assign(name, function); diff --git a/src/env/environment.h b/src/env/environment.h index 583ead7..ebacea2 100644 --- a/src/env/environment.h +++ b/src/env/environment.h @@ -24,6 +24,7 @@ public: static EnvironmentPtr create(EnvironmentPtr outer); static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments); + static void loadFunctions(); static void registerFunction(const std::string& name, FunctionType function); static void installFunctions(EnvironmentPtr env); @@ -34,6 +35,20 @@ public: private: Environment() {} + // Outer environment native functions, "Core" + static void loadCollectionAccess(); + static void loadCollectionConstructor(); + static void loadCollectionModify(); + static void loadCompare(); + static void loadConvert(); + static void loadFormat(); + static void loadMeta(); + static void loadMutable(); + static void loadOperators(); + static void loadOther(); + static void loadPredicate(); + static void loadRepl(); + EnvironmentPtr m_outer { nullptr }; std::unordered_map m_values; diff --git a/src/env/functions/collection-access.cpp b/src/env/functions/collection-access.cpp index 9ce2aa3..501cfe7 100644 --- a/src/env/functions/collection-access.cpp +++ b/src/env/functions/collection-access.cpp @@ -14,126 +14,129 @@ namespace blaze { -// (first (list 1 2 3)) -> 1 -ADD_FUNCTION( - "first", - { - CHECK_ARG_COUNT_IS("first", SIZE(), 1); - - if (is(begin->get()) - && std::static_pointer_cast(*begin)->state() == Constant::Nil) { - return makePtr(); - } - - VALUE_CAST(collection, Collection, (*begin)); - - return (collection->empty()) ? makePtr() : collection->front(); - }); - -// (nth (list 1 2 3) 0) -> 1 -ADD_FUNCTION( - "nth", - { - CHECK_ARG_COUNT_IS("nth", SIZE(), 2); - - VALUE_CAST(collection, Collection, (*begin)); - VALUE_CAST(number_node, Number, (*(begin + 1))); - auto collection_nodes = collection->nodesRead(); - auto index = static_cast(number_node->number()); - - if (number_node->number() < 0 || index >= collection_nodes.size()) { - Error::the().add("index is out of range"); - return nullptr; - } - - return collection_nodes[index]; - }); - -// (rest (list 1 2 3)) -> (2 3) -ADD_FUNCTION( - "rest", - { - CHECK_ARG_COUNT_IS("rest", SIZE(), 1); - - if (is(begin->get()) - && std::static_pointer_cast(*begin)->state() == Constant::Nil) { - return makePtr(); - } - - VALUE_CAST(collection, Collection, (*begin)); - - return makePtr(collection->rest()); - }); - -// ----------------------------------------- - -// (get {:kw "value"} :kw) -> "value" -ADD_FUNCTION( - "get", - { - CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1); - - if (is(begin->get()) - && std::static_pointer_cast(*begin)->state() == Constant::Nil) { - return makePtr(); - } - - VALUE_CAST(hash_map, HashMap, (*begin)); - begin++; - - if (SIZE() == 0) { - return makePtr(); - } - - auto result = hash_map->get(*begin); - return (result) ? result : makePtr(); - }); - -// (keys {"foo" 3 :bar 5}) -> ("foo" :bar) -ADD_FUNCTION( - "keys", - { - CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1); - - VALUE_CAST(hash_map, HashMap, (*begin)); - - size_t count = hash_map->size(); - auto nodes = ValueVector(count); - - size_t i = 0; - auto elements = hash_map->elements(); - for (auto pair : elements) { - if (pair.first.front() == 0x7f) { // 127 - nodes.at(i) = makePtr(pair.first.substr(1)); +void Environment::loadCollectionAccess() +{ + // (first (list 1 2 3)) -> 1 + ADD_FUNCTION( + "first", + { + CHECK_ARG_COUNT_IS("first", SIZE(), 1); + + if (is(begin->get()) + && std::static_pointer_cast(*begin)->state() == Constant::Nil) { + return makePtr(); } - else { - nodes.at(i) = makePtr(pair.first); + + VALUE_CAST(collection, Collection, (*begin)); + + return (collection->empty()) ? makePtr() : collection->front(); + }); + + // (nth (list 1 2 3) 0) -> 1 + ADD_FUNCTION( + "nth", + { + CHECK_ARG_COUNT_IS("nth", SIZE(), 2); + + VALUE_CAST(collection, Collection, (*begin)); + VALUE_CAST(number_node, Number, (*(begin + 1))); + auto collection_nodes = collection->nodesRead(); + auto index = static_cast(number_node->number()); + + if (number_node->number() < 0 || index >= collection_nodes.size()) { + Error::the().add("index is out of range"); + return nullptr; } - i++; - } - return makePtr(nodes); - }); + return collection_nodes[index]; + }); -// (vals {"foo" 3 :bar 5}) -> (3 5) -ADD_FUNCTION( - "vals", - { - CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1); + // (rest (list 1 2 3)) -> (2 3) + ADD_FUNCTION( + "rest", + { + CHECK_ARG_COUNT_IS("rest", SIZE(), 1); - VALUE_CAST(hash_map, HashMap, (*begin)); + if (is(begin->get()) + && std::static_pointer_cast(*begin)->state() == Constant::Nil) { + return makePtr(); + } - size_t count = hash_map->size(); - auto nodes = ValueVector(count); + VALUE_CAST(collection, Collection, (*begin)); + + return makePtr(collection->rest()); + }); + + // ----------------------------------------- + + // (get {:kw "value"} :kw) -> "value" + ADD_FUNCTION( + "get", + { + CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1); + + if (is(begin->get()) + && std::static_pointer_cast(*begin)->state() == Constant::Nil) { + return makePtr(); + } - size_t i = 0; - auto elements = hash_map->elements(); - for (auto pair : elements) { - nodes.at(i) = pair.second; - i++; - } + VALUE_CAST(hash_map, HashMap, (*begin)); + begin++; + + if (SIZE() == 0) { + return makePtr(); + } + + auto result = hash_map->get(*begin); + return (result) ? result : makePtr(); + }); + + // (keys {"foo" 3 :bar 5}) -> ("foo" :bar) + ADD_FUNCTION( + "keys", + { + CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1); + + VALUE_CAST(hash_map, HashMap, (*begin)); + + size_t count = hash_map->size(); + auto nodes = ValueVector(count); + + size_t i = 0; + auto elements = hash_map->elements(); + for (auto pair : elements) { + if (pair.first.front() == 0x7f) { // 127 + nodes.at(i) = makePtr(pair.first.substr(1)); + } + else { + nodes.at(i) = makePtr(pair.first); + } + i++; + } + + return makePtr(nodes); + }); + + // (vals {"foo" 3 :bar 5}) -> (3 5) + ADD_FUNCTION( + "vals", + { + CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1); + + VALUE_CAST(hash_map, HashMap, (*begin)); + + size_t count = hash_map->size(); + auto nodes = ValueVector(count); + + size_t i = 0; + auto elements = hash_map->elements(); + for (auto pair : elements) { + nodes.at(i) = pair.second; + i++; + } - return makePtr(nodes); - }); + return makePtr(nodes); + }); +} } // namespace blaze diff --git a/src/env/functions/collection-constructor.cpp b/src/env/functions/collection-constructor.cpp index 60bba49..fcf99b3 100644 --- a/src/env/functions/collection-constructor.cpp +++ b/src/env/functions/collection-constructor.cpp @@ -14,106 +14,109 @@ namespace blaze { -// (list 1 2) -> (1 2) -ADD_FUNCTION( - "list", - { - return makePtr(begin, end); - }); - -// (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); +void Environment::loadCollectionConstructor() +{ + // (list 1 2) -> (1 2) + ADD_FUNCTION( + "list", + { + return makePtr(begin, end); + }); + + // (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)); - }); - -// ----------------------------------------- - -// (vec (list 1 2 3)) -ADD_FUNCTION( - "vec", - { - CHECK_ARG_COUNT_IS("vec", SIZE(), 1); - - if (is(begin->get())) { - return *begin; - } - - VALUE_CAST(collection, Collection, (*begin)); - - return makePtr(collection->nodesCopy()); - }); - -// (vector 1 2 3) -> [1 2 3] -ADD_FUNCTION( - "vector", - { - auto result = makePtr(); - - return makePtr(begin, end); - }); - -// ----------------------------------------- - -// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10} -ADD_FUNCTION( - "hash-map", - { - CHECK_ARG_COUNT_EVEN("hash-map", SIZE()); - - Elements elements; - for (auto it = begin; it != end; std::advance(it, 2)) { - const ValuePtr& value = *(std::next(it)); // temporary instance to get around const - elements.insert_or_assign(HashMap::getKeyString(*it), value); - } - - return makePtr(elements); - }); + // 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)); + }); + + // ----------------------------------------- + + // (vec (list 1 2 3)) + ADD_FUNCTION( + "vec", + { + CHECK_ARG_COUNT_IS("vec", SIZE(), 1); + + if (is(begin->get())) { + return *begin; + } + + VALUE_CAST(collection, Collection, (*begin)); + + return makePtr(collection->nodesCopy()); + }); + + // (vector 1 2 3) -> [1 2 3] + ADD_FUNCTION( + "vector", + { + auto result = makePtr(); + + return makePtr(begin, end); + }); + + // ----------------------------------------- + + // (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10} + ADD_FUNCTION( + "hash-map", + { + CHECK_ARG_COUNT_EVEN("hash-map", SIZE()); + + Elements elements; + for (auto it = begin; it != end; std::advance(it, 2)) { + const ValuePtr& value = *(std::next(it)); // temporary instance to get around const + elements.insert_or_assign(HashMap::getKeyString(*it), value); + } + + return makePtr(elements); + }); +} } // namespace blaze diff --git a/src/env/functions/collection-modify.cpp b/src/env/functions/collection-modify.cpp index af48e8b..1d4bf84 100644 --- a/src/env/functions/collection-modify.cpp +++ b/src/env/functions/collection-modify.cpp @@ -16,250 +16,253 @@ namespace blaze { -// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10 -ADD_FUNCTION( - "apply", - { - CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2); - - auto callable = *begin; - IS_VALUE(Callable, callable); - - VALUE_CAST(collection, Collection, (*std::prev(end))); - - auto arguments = ValueVector(begin + 1, end - 1); - arguments.reserve(arguments.size() + collection->size()); - - // Append list nodes to the argument leftovers - auto nodes = collection->nodesRead(); - for (const auto& node : nodes) { - arguments.push_back(node); - } - - ValuePtr value = nullptr; - if (is(callable.get())) { - auto function = std::static_pointer_cast(callable)->function(); - value = function(arguments.begin(), arguments.end()); - } - else { - auto lambda = std::static_pointer_cast(callable); - value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); - } - - return value; - }); - -// (cons 1 (list 2 3)) -ADD_FUNCTION( - "cons", - { - CHECK_ARG_COUNT_IS("cons", SIZE(), 2); - - ValuePtr first = *begin; - begin++; - - VALUE_CAST(collection, Collection, (*begin)); - const auto& collection_nodes = collection->nodesRead(); - - auto result_nodes = ValueVector(collection_nodes.size() + 1); - result_nodes.at(0) = first; - std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + 1); - - return makePtr(result_nodes); - }); - -// (concat (list 1) (list 2 3)) -> (1 2 3) -ADD_FUNCTION( - "concat", - { - size_t count = 0; - for (auto it = begin; it != end; ++it) { - VALUE_CAST(collection, Collection, (*it)); - count += collection->size(); - } - - auto result_nodes = ValueVector(count); - size_t offset = 0; - for (auto it = begin; it != end; ++it) { - const auto& collection_nodes = std::static_pointer_cast(*it)->nodesRead(); - std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset); - offset += collection_nodes.size(); - } - - return makePtr(result_nodes); - }); - -// (conj '(1 2 3) 4 5 6) -> (6 5 4 1 2 3) -// (conj [1 2 3] 4 5 6) -> [1 2 3 4 5 6] -ADD_FUNCTION( - "conj", - { - CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1); - - VALUE_CAST(collection, Collection, (*begin)); - begin++; - - const auto& collection_nodes = collection->nodesRead(); - size_t collection_count = collection_nodes.size(); - size_t argument_count = SIZE(); - - auto nodes = ValueVector(argument_count + collection_count); - - if (is(collection.get())) { - std::reverse_copy(begin, end, nodes.begin()); - std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count); +void Environment::loadCollectionModify() +{ + // (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10 + ADD_FUNCTION( + "apply", + { + CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2); + + auto callable = *begin; + IS_VALUE(Callable, callable); + + VALUE_CAST(collection, Collection, (*std::prev(end))); + + auto arguments = ValueVector(begin + 1, end - 1); + arguments.reserve(arguments.size() + collection->size()); + + // Append list nodes to the argument leftovers + auto nodes = collection->nodesRead(); + for (const auto& node : nodes) { + arguments.push_back(node); + } - return makePtr(nodes); - } + ValuePtr value = nullptr; + if (is(callable.get())) { + auto function = std::static_pointer_cast(callable)->function(); + value = function(arguments.begin(), arguments.end()); + } + else { + auto lambda = std::static_pointer_cast(callable); + value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); + } - std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin()); - std::copy(begin, end, nodes.begin() + collection_count); + return value; + }); - return makePtr(nodes); - }); + // (cons 1 (list 2 3)) + ADD_FUNCTION( + "cons", + { + CHECK_ARG_COUNT_IS("cons", SIZE(), 2); -// (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6) -ADD_FUNCTION( - "map", - { - CHECK_ARG_COUNT_IS("map", SIZE(), 2); + ValuePtr first = *begin; + begin++; - VALUE_CAST(callable, Callable, (*begin)); - VALUE_CAST(collection, Collection, (*(begin + 1))); + VALUE_CAST(collection, Collection, (*begin)); + const auto& collection_nodes = collection->nodesRead(); - size_t count = collection->size(); - auto nodes = ValueVector(count); + auto result_nodes = ValueVector(collection_nodes.size() + 1); + result_nodes.at(0) = first; + std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + 1); - if (is(callable.get())) { - auto function = std::static_pointer_cast(callable)->function(); - for (size_t i = 0; i < count; ++i) { - nodes.at(i) = function(collection->begin() + i, collection->begin() + i + 1); + return makePtr(result_nodes); + }); + + // (concat (list 1) (list 2 3)) -> (1 2 3) + ADD_FUNCTION( + "concat", + { + size_t count = 0; + for (auto it = begin; it != end; ++it) { + VALUE_CAST(collection, Collection, (*it)); + count += collection->size(); } - } - else { - auto lambda = std::static_pointer_cast(callable); - auto collection_nodes = collection->nodesRead(); - for (size_t i = 0; i < count; ++i) { - nodes.at(i) = (eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); + + auto result_nodes = ValueVector(count); + size_t offset = 0; + for (auto it = begin; it != end; ++it) { + const auto& collection_nodes = std::static_pointer_cast(*it)->nodesRead(); + std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset); + offset += collection_nodes.size(); } - } - return makePtr(nodes); - }); + return makePtr(result_nodes); + }); -// (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3) -ADD_FUNCTION( - "set-nth", - { - CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3); + // (conj '(1 2 3) 4 5 6) -> (6 5 4 1 2 3) + // (conj [1 2 3] 4 5 6) -> [1 2 3 4 5 6] + ADD_FUNCTION( + "conj", + { + CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1); - VALUE_CAST(collection, Collection, (*begin)); + VALUE_CAST(collection, Collection, (*begin)); + begin++; - VALUE_CAST(number_node, Number, (*(begin + 1))); - auto index = static_cast(number_node->number() < 0 ? 0 : number_node->number()); + const auto& collection_nodes = collection->nodesRead(); + size_t collection_count = collection_nodes.size(); + size_t argument_count = SIZE(); - auto value = *(begin + 2); + auto nodes = ValueVector(argument_count + collection_count); - 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(collection.get())) { + std::reverse_copy(begin, end, nodes.begin()); + std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count); - if (is(begin->get())) { - return makePtr(collection_nodes); - } + return makePtr(nodes); + } - return makePtr(collection_nodes); - }); + std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin()); + std::copy(begin, end, nodes.begin() + collection_count); -// (seq '(1 2 3)) -> (1 2 3) -// (seq [1 2 3]) -> (1 2 3) -// (seq "foo") -> ("f" "o" "o") -ADD_FUNCTION( - "seq", - { - CHECK_ARG_COUNT_IS("seq", SIZE(), 1); + return makePtr(nodes); + }); - auto front = *begin; - Value* front_raw_ptr = front.get(); + // (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6) + ADD_FUNCTION( + "map", + { + CHECK_ARG_COUNT_IS("map", SIZE(), 2); - if (is(front_raw_ptr) && std::static_pointer_cast(front)->state() == Constant::Nil) { - return makePtr(); - } - if (is(front_raw_ptr)) { - auto collection = std::static_pointer_cast(front); + VALUE_CAST(callable, Callable, (*begin)); + VALUE_CAST(collection, Collection, (*(begin + 1))); - if (collection->empty()) { - return makePtr(); + size_t count = collection->size(); + auto nodes = ValueVector(count); + + if (is(callable.get())) { + auto function = std::static_pointer_cast(callable)->function(); + for (size_t i = 0; i < count; ++i) { + nodes.at(i) = function(collection->begin() + i, collection->begin() + i + 1); + } + } + else { + auto lambda = std::static_pointer_cast(callable); + auto collection_nodes = collection->nodesRead(); + for (size_t i = 0; i < count; ++i) { + nodes.at(i) = (eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); + } + } + + return makePtr(nodes); + }); + + // (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3) + ADD_FUNCTION( + "set-nth", + { + 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(front_raw_ptr)) { - return front; + if (is(begin->get())) { + return makePtr(collection_nodes); } - return makePtr(collection->nodesCopy()); - } - if (is(front_raw_ptr)) { - auto string = std::static_pointer_cast(front); + return makePtr(collection_nodes); + }); - if (string->empty()) { + // (seq '(1 2 3)) -> (1 2 3) + // (seq [1 2 3]) -> (1 2 3) + // (seq "foo") -> ("f" "o" "o") + ADD_FUNCTION( + "seq", + { + CHECK_ARG_COUNT_IS("seq", SIZE(), 1); + + auto front = *begin; + Value* front_raw_ptr = front.get(); + + if (is(front_raw_ptr) && std::static_pointer_cast(front)->state() == Constant::Nil) { return makePtr(); } + if (is(front_raw_ptr)) { + auto collection = std::static_pointer_cast(front); - size_t count = string->size(); - auto nodes = ValueVector(count); + if (collection->empty()) { + return makePtr(); + } + + if (is(front_raw_ptr)) { + return front; + } - const auto& data = string->data(); - for (size_t i = 0; i < count; ++i) { - nodes.at(i) = makePtr(data[i]); + return makePtr(collection->nodesCopy()); } + if (is(front_raw_ptr)) { + auto string = std::static_pointer_cast(front); - return makePtr(nodes); - } + if (string->empty()) { + return makePtr(); + } + + size_t count = string->size(); + auto nodes = ValueVector(count); - Error::the().add(::format("wrong argument type: Collection or String, {}", front)); + const auto& data = string->data(); + for (size_t i = 0; i < count; ++i) { + nodes.at(i) = makePtr(data[i]); + } - return nullptr; - }); + return makePtr(nodes); + } -// ----------------------------------------- + Error::the().add(::format("wrong argument type: Collection or String, {}", front)); -// (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1} -ADD_FUNCTION( - "assoc", - { - CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1); + return nullptr; + }); - VALUE_CAST(hash_map, HashMap, (*begin)); - begin++; + // ----------------------------------------- - CHECK_ARG_COUNT_EVEN("assoc", SIZE()); + // (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1} + ADD_FUNCTION( + "assoc", + { + CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1); - Elements elements(hash_map->elements()); - for (auto it = begin; it != end; std::advance(it, 2)) { - const ValuePtr& value = *(std::next(it)); // temporary instance to get around const - elements.insert_or_assign(HashMap::getKeyString(*it), value); - } + VALUE_CAST(hash_map, HashMap, (*begin)); + begin++; - return makePtr(elements); - }); + CHECK_ARG_COUNT_EVEN("assoc", SIZE()); -// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2} -ADD_FUNCTION( - "dissoc", - { - CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1); + Elements elements(hash_map->elements()); + for (auto it = begin; it != end; std::advance(it, 2)) { + const ValuePtr& value = *(std::next(it)); // temporary instance to get around const + elements.insert_or_assign(HashMap::getKeyString(*it), value); + } - VALUE_CAST(hash_map, HashMap, (*begin)); - begin++; + return makePtr(elements); + }); - Elements elements(hash_map->elements()); - for (auto it = begin; it != end; ++it) { - elements.erase(HashMap::getKeyString(*it)); - } + // (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2} + ADD_FUNCTION( + "dissoc", + { + CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1); + + VALUE_CAST(hash_map, HashMap, (*begin)); + begin++; + + Elements elements(hash_map->elements()); + for (auto it = begin; it != end; ++it) { + elements.erase(HashMap::getKeyString(*it)); + } - return makePtr(elements); - }); + return makePtr(elements); + }); +} } // namespace blaze diff --git a/src/env/functions/compare.cpp b/src/env/functions/compare.cpp index abaa7e9..767cd15 100644 --- a/src/env/functions/compare.cpp +++ b/src/env/functions/compare.cpp @@ -14,6 +14,8 @@ namespace blaze { +void Environment::loadCompare() +{ #define NUMBER_COMPARE(operator) \ { \ bool result = true; \ @@ -38,95 +40,96 @@ namespace blaze { return makePtr((result) ? Constant::True : Constant::False); \ } -ADD_FUNCTION("<", NUMBER_COMPARE(<)); -ADD_FUNCTION("<=", NUMBER_COMPARE(<=)); -ADD_FUNCTION(">", NUMBER_COMPARE(>)); -ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); - -// ----------------------------------------- - -// (= 1 1) -> true -// (= "foo" "foo") -> true -ADD_FUNCTION( - "=", - { - CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2); - - std::function equal = - [&equal](ValuePtr lhs, ValuePtr rhs) -> bool { - if ((is(lhs.get()) || is(lhs.get())) - && (is(rhs.get()) || is(rhs.get()))) { - auto lhs_collection = std::static_pointer_cast(lhs); - auto rhs_collection = std::static_pointer_cast(rhs); - - if (lhs_collection->size() != rhs_collection->size()) { - return false; - } + ADD_FUNCTION("<", NUMBER_COMPARE(<)); + ADD_FUNCTION("<=", NUMBER_COMPARE(<=)); + ADD_FUNCTION(">", NUMBER_COMPARE(>)); + ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); + + // ----------------------------------------- + + // (= 1 1) -> true + // (= "foo" "foo") -> true + ADD_FUNCTION( + "=", + { + CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2); + + std::function equal = + [&equal](ValuePtr lhs, ValuePtr rhs) -> bool { + if ((is(lhs.get()) || is(lhs.get())) + && (is(rhs.get()) || is(rhs.get()))) { + auto lhs_collection = std::static_pointer_cast(lhs); + auto rhs_collection = std::static_pointer_cast(rhs); - auto lhs_it = lhs_collection->begin(); - auto rhs_it = rhs_collection->begin(); - for (; lhs_it != lhs_collection->end(); ++lhs_it, ++rhs_it) { - if (!equal(*lhs_it, *rhs_it)) { + if (lhs_collection->size() != rhs_collection->size()) { return false; } - } - - return true; - } - if (is(lhs.get()) && is(rhs.get())) { - const auto& lhs_nodes = std::static_pointer_cast(lhs)->elements(); - const auto& rhs_nodes = std::static_pointer_cast(rhs)->elements(); + auto lhs_it = lhs_collection->begin(); + auto rhs_it = rhs_collection->begin(); + for (; lhs_it != lhs_collection->end(); ++lhs_it, ++rhs_it) { + if (!equal(*lhs_it, *rhs_it)) { + return false; + } + } - if (lhs_nodes.size() != rhs_nodes.size()) { - return false; + return true; } - for (const auto& [key, value] : lhs_nodes) { - auto it = rhs_nodes.find(key); - if (it == rhs_nodes.cend() || !equal(value, it->second)) { + if (is(lhs.get()) && is(rhs.get())) { + const auto& lhs_nodes = std::static_pointer_cast(lhs)->elements(); + const auto& rhs_nodes = std::static_pointer_cast(rhs)->elements(); + + if (lhs_nodes.size() != rhs_nodes.size()) { return false; } - } - return true; - } + for (const auto& [key, value] : lhs_nodes) { + auto it = rhs_nodes.find(key); + if (it == rhs_nodes.cend() || !equal(value, it->second)) { + return false; + } + } - if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->data() == std::static_pointer_cast(rhs)->data()) { - return true; - } - if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->keyword() == std::static_pointer_cast(rhs)->keyword()) { - return true; - } - if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->number() == std::static_pointer_cast(rhs)->number()) { - return true; - } - if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->state() == std::static_pointer_cast(rhs)->state()) { - return true; - } - if (is(lhs.get()) && is(rhs.get()) - && std::static_pointer_cast(lhs)->symbol() == std::static_pointer_cast(rhs)->symbol()) { - return true; - } + return true; + } + + if (is(lhs.get()) && is(rhs.get()) + && std::static_pointer_cast(lhs)->data() == std::static_pointer_cast(rhs)->data()) { + return true; + } + if (is(lhs.get()) && is(rhs.get()) + && std::static_pointer_cast(lhs)->keyword() == std::static_pointer_cast(rhs)->keyword()) { + return true; + } + if (is(lhs.get()) && is(rhs.get()) + && std::static_pointer_cast(lhs)->number() == std::static_pointer_cast(rhs)->number()) { + return true; + } + if (is(lhs.get()) && is(rhs.get()) + && std::static_pointer_cast(lhs)->state() == std::static_pointer_cast(rhs)->state()) { + return true; + } + if (is(lhs.get()) && is(rhs.get()) + && std::static_pointer_cast(lhs)->symbol() == std::static_pointer_cast(rhs)->symbol()) { + return true; + } - return false; - }; + return false; + }; - bool result = true; - auto it = begin; - auto it_next = begin + 1; - for (; it_next != end; ++it, ++it_next) { - if (!equal(*it, *it_next)) { - result = false; - break; + bool result = true; + auto it = begin; + auto it_next = begin + 1; + for (; it_next != end; ++it, ++it_next) { + if (!equal(*it, *it_next)) { + result = false; + break; + } } - } - return makePtr((result) ? Constant::True : Constant::False); - }); + return makePtr((result) ? Constant::True : Constant::False); + }); +} } // namespace blaze diff --git a/src/env/functions/convert.cpp b/src/env/functions/convert.cpp index 9025c04..697e286 100644 --- a/src/env/functions/convert.cpp +++ b/src/env/functions/convert.cpp @@ -10,40 +10,43 @@ namespace blaze { -// (symbol "foo") -> foo -ADD_FUNCTION( - "symbol", - { - CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); - - 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()); - }); +void Environment::loadConvert() +{ + // (symbol "foo") -> foo + ADD_FUNCTION( + "symbol", + { + CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); + + 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()); + }); +} } // namespace blaze diff --git a/src/env/functions/format.cpp b/src/env/functions/format.cpp index a481522..f12f528 100644 --- a/src/env/functions/format.cpp +++ b/src/env/functions/format.cpp @@ -16,6 +16,8 @@ namespace blaze { +void Environment::loadFormat() +{ #define PRINTER_STRING(print_readably, concatenation) \ { \ std::string result; \ @@ -32,8 +34,8 @@ namespace blaze { return makePtr(result); \ } -ADD_FUNCTION("str", PRINTER_STRING(false, "")); -ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); + ADD_FUNCTION("str", PRINTER_STRING(false, "")); + ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); #define PRINTER_PRINT(print_readably) \ { \ @@ -50,7 +52,8 @@ ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); return makePtr(); \ } -ADD_FUNCTION("prn", PRINTER_PRINT(true)); -ADD_FUNCTION("println", PRINTER_PRINT(false)); + ADD_FUNCTION("prn", PRINTER_PRINT(true)); + ADD_FUNCTION("println", PRINTER_PRINT(false)); +} } // namespace blaze diff --git a/src/env/functions/meta.cpp b/src/env/functions/meta.cpp index a0cc891..a520b0b 100644 --- a/src/env/functions/meta.cpp +++ b/src/env/functions/meta.cpp @@ -12,42 +12,45 @@ namespace blaze { -// (meta [1 2 3]) -ADD_FUNCTION( - "meta", - { - CHECK_ARG_COUNT_IS("meta", SIZE(), 1); - - auto front = *begin; - Value* front_raw_ptr = begin->get(); - - if (!is(front_raw_ptr) && // List / Vector - !is(front_raw_ptr) && // HashMap - !is(front_raw_ptr)) { // Function / Lambda - Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); - return nullptr; - } - - return front->meta(); - }); - -// (with-meta [1 2 3] "some metadata") -ADD_FUNCTION( - "with-meta", - { - CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2); - - auto front = *begin; - Value* front_raw_ptr = begin->get(); - - if (!is(front_raw_ptr) && // List / Vector - !is(front_raw_ptr) && // HashMap - !is(front_raw_ptr)) { // Function / Lambda - Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); - return nullptr; - } - - return front->withMeta(*(begin + 1)); - }); +void Environment::loadMeta() +{ + // (meta [1 2 3]) + ADD_FUNCTION( + "meta", + { + CHECK_ARG_COUNT_IS("meta", SIZE(), 1); + + auto front = *begin; + Value* front_raw_ptr = begin->get(); + + if (!is(front_raw_ptr) && // List / Vector + !is(front_raw_ptr) && // HashMap + !is(front_raw_ptr)) { // Function / Lambda + Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); + return nullptr; + } + + return front->meta(); + }); + + // (with-meta [1 2 3] "some metadata") + ADD_FUNCTION( + "with-meta", + { + CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2); + + auto front = *begin; + Value* front_raw_ptr = begin->get(); + + if (!is(front_raw_ptr) && // List / Vector + !is(front_raw_ptr) && // HashMap + !is(front_raw_ptr)) { // Function / Lambda + Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); + return nullptr; + } + + return front->withMeta(*(begin + 1)); + }); +} } // namespace blaze diff --git a/src/env/functions/mutable.cpp b/src/env/functions/mutable.cpp index a2b9887..6e17179 100644 --- a/src/env/functions/mutable.cpp +++ b/src/env/functions/mutable.cpp @@ -15,67 +15,70 @@ namespace blaze { -// (atom 1) -ADD_FUNCTION( - "atom", - { - CHECK_ARG_COUNT_IS("atom", SIZE(), 1); - - return makePtr(*begin); - }); - -// (deref myatom) -ADD_FUNCTION( - "deref", - { - CHECK_ARG_COUNT_IS("deref", SIZE(), 1); - - VALUE_CAST(atom, Atom, (*begin)); - - return atom->deref(); - }); - -// (reset! myatom 2) -ADD_FUNCTION( - "reset!", - { - CHECK_ARG_COUNT_IS("reset!", SIZE(), 2); - - VALUE_CAST(atom, Atom, (*begin)); - auto value = *(begin + 1); - - atom->reset(value); - - return value; - }); - -// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2)))) -ADD_FUNCTION( - "swap!", - { - CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2); - - VALUE_CAST(atom, Atom, (*begin)); - - VALUE_CAST(callable, Callable, (*(begin + 1))); - - // Remove atom and function from the argument list, add atom value - begin += 2; - auto arguments = ValueVector(SIZE() + 1); - arguments[0] = atom->deref(); - std::copy(begin, end, arguments.begin() + 1); - - ValuePtr value = nullptr; - if (is(callable.get())) { - auto function = std::static_pointer_cast(callable)->function(); - value = function(arguments.begin(), arguments.end()); - } - else { - auto lambda = std::static_pointer_cast(callable); - value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); - } - - return atom->reset(value); - }); +void Environment::loadMutable() +{ + // (atom 1) + ADD_FUNCTION( + "atom", + { + CHECK_ARG_COUNT_IS("atom", SIZE(), 1); + + return makePtr(*begin); + }); + + // (deref myatom) + ADD_FUNCTION( + "deref", + { + CHECK_ARG_COUNT_IS("deref", SIZE(), 1); + + VALUE_CAST(atom, Atom, (*begin)); + + return atom->deref(); + }); + + // (reset! myatom 2) + ADD_FUNCTION( + "reset!", + { + CHECK_ARG_COUNT_IS("reset!", SIZE(), 2); + + VALUE_CAST(atom, Atom, (*begin)); + auto value = *(begin + 1); + + atom->reset(value); + + return value; + }); + + // (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2)))) + ADD_FUNCTION( + "swap!", + { + CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2); + + VALUE_CAST(atom, Atom, (*begin)); + + VALUE_CAST(callable, Callable, (*(begin + 1))); + + // Remove atom and function from the argument list, add atom value + begin += 2; + auto arguments = ValueVector(SIZE() + 1); + arguments[0] = atom->deref(); + std::copy(begin, end, arguments.begin() + 1); + + ValuePtr value = nullptr; + if (is(callable.get())) { + auto function = std::static_pointer_cast(callable)->function(); + value = function(arguments.begin(), arguments.end()); + } + else { + auto lambda = std::static_pointer_cast(callable); + value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); + } + + return atom->reset(value); + }); +} } // namespace blaze diff --git a/src/env/functions/operators.cpp b/src/env/functions/operators.cpp index f832e1f..f40a6b3 100644 --- a/src/env/functions/operators.cpp +++ b/src/env/functions/operators.cpp @@ -12,80 +12,83 @@ namespace blaze { -ADD_FUNCTION( - "+", - { - int64_t result = 0; - - for (auto it = begin; it != end; ++it) { - VALUE_CAST(number, Number, (*it)); - result += number->number(); - } - - return makePtr(result); - }); - -ADD_FUNCTION( - "-", - { - if (SIZE() == 0) { - return makePtr(0); - } - - // Start with the first number - VALUE_CAST(number, Number, (*begin)); - int64_t result = number->number(); - - // Skip the first node - for (auto it = begin + 1; it != end; ++it) { - VALUE_CAST(number, Number, (*it)); - result -= number->number(); - } - - return makePtr(result); - }); - -ADD_FUNCTION( - "*", - { - int64_t result = 1; - - for (auto it = begin; it != end; ++it) { - VALUE_CAST(number, Number, (*it)); - result *= number->number(); - } - - return makePtr(result); - }); - -ADD_FUNCTION( - "/", - { - CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1); - - // Start with the first number - VALUE_CAST(number, Number, (*begin)); - double result = number->number(); - - // Skip the first node - for (auto it = begin + 1; it != end; ++it) { - VALUE_CAST(number, Number, (*it)); - result /= number->number(); - } - - 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()); - }); +void Environment::loadOperators() +{ + ADD_FUNCTION( + "+", + { + int64_t result = 0; + + for (auto it = begin; it != end; ++it) { + VALUE_CAST(number, Number, (*it)); + result += number->number(); + } + + return makePtr(result); + }); + + ADD_FUNCTION( + "-", + { + if (SIZE() == 0) { + return makePtr(0); + } + + // Start with the first number + VALUE_CAST(number, Number, (*begin)); + int64_t result = number->number(); + + // Skip the first node + for (auto it = begin + 1; it != end; ++it) { + VALUE_CAST(number, Number, (*it)); + result -= number->number(); + } + + return makePtr(result); + }); + + ADD_FUNCTION( + "*", + { + int64_t result = 1; + + for (auto it = begin; it != end; ++it) { + VALUE_CAST(number, Number, (*it)); + result *= number->number(); + } + + return makePtr(result); + }); + + ADD_FUNCTION( + "/", + { + CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1); + + // Start with the first number + VALUE_CAST(number, Number, (*begin)); + double result = number->number(); + + // Skip the first node + for (auto it = begin + 1; it != end; ++it) { + VALUE_CAST(number, Number, (*it)); + result /= number->number(); + } + + 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()); + }); +} } // namespace blaze diff --git a/src/env/functions/other.cpp b/src/env/functions/other.cpp index 63b90fb..351f4e1 100644 --- a/src/env/functions/other.cpp +++ b/src/env/functions/other.cpp @@ -17,55 +17,58 @@ namespace blaze { -// (count '(1 2 3)) -> 3 -// (count [1 2 3]) -> 3 -ADD_FUNCTION( - "count", - { - CHECK_ARG_COUNT_IS("count", SIZE(), 1); +void Environment::loadOther() +{ + // (count '(1 2 3)) -> 3 + // (count [1 2 3]) -> 3 + ADD_FUNCTION( + "count", + { + CHECK_ARG_COUNT_IS("count", SIZE(), 1); - size_t result = 0; - if (is(begin->get()) && std::static_pointer_cast(*begin)->state() == Constant::Nil) { - // result = 0 - } - else if (is(begin->get())) { - result = std::static_pointer_cast(*begin)->size(); - } - else { - Error::the().add(::format("wrong argument type: Collection, '{}'", *begin)); - return nullptr; - } + size_t result = 0; + if (is(begin->get()) && std::static_pointer_cast(*begin)->state() == Constant::Nil) { + // result = 0 + } + else if (is(begin->get())) { + result = std::static_pointer_cast(*begin)->size(); + } + else { + Error::the().add(::format("wrong argument type: Collection, '{}'", *begin)); + return nullptr; + } - // FIXME: Add numeric_limits check for implicit cast: size_t > int64_t - return makePtr((int64_t)result); - }); + // FIXME: Add numeric_limits check for implicit cast: size_t > int64_t + return makePtr((int64_t)result); + }); -// ----------------------------------------- + // ----------------------------------------- -// (throw x) -ADD_FUNCTION( - "throw", - { - CHECK_ARG_COUNT_IS("throw", SIZE(), 1); + // (throw x) + ADD_FUNCTION( + "throw", + { + CHECK_ARG_COUNT_IS("throw", SIZE(), 1); - Error::the().add(*begin); + Error::the().add(*begin); - return nullptr; - }) + return nullptr; + }) -// ----------------------------------------- + // ----------------------------------------- -// (time-ms) -ADD_FUNCTION( - "time-ms", - { - CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0); + // (time-ms) + ADD_FUNCTION( + "time-ms", + { + CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0); - int64_t elapsed = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); + int64_t elapsed = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); - return makePtr(elapsed); - }); + return makePtr(elapsed); + }); +} } // namespace blaze diff --git a/src/env/functions/predicate.cpp b/src/env/functions/predicate.cpp index 2848fb8..ae7d474 100644 --- a/src/env/functions/predicate.cpp +++ b/src/env/functions/predicate.cpp @@ -10,6 +10,8 @@ namespace blaze { +void Environment::loadPredicate() +{ #define IS_CONSTANT(name, constant) \ { \ CHECK_ARG_COUNT_IS(name, SIZE(), 1); \ @@ -19,12 +21,12 @@ namespace blaze { && std::static_pointer_cast(*begin)->state() == constant); \ } -// (nil? nil) -ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil)); -ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True)); -ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False)); + // (nil? nil) + ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil)); + ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True)); + ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False)); -// ----------------------------------------- + // ----------------------------------------- #define IS_TYPE(type) \ { \ @@ -44,89 +46,90 @@ ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False)); return makePtr(result); \ } -// (symbol? 'foo) -ADD_FUNCTION("atom?", IS_TYPE(Atom)); -ADD_FUNCTION("keyword?", IS_TYPE(Keyword)); -ADD_FUNCTION("list?", IS_TYPE(List)); -ADD_FUNCTION("map?", IS_TYPE(HashMap)); -ADD_FUNCTION("number?", IS_TYPE(Number)); -ADD_FUNCTION("sequential?", IS_TYPE(Collection)); -ADD_FUNCTION("string?", IS_TYPE(String)); -ADD_FUNCTION("symbol?", IS_TYPE(Symbol)); -ADD_FUNCTION("vector?", IS_TYPE(Vector)); - -ADD_FUNCTION( - "fn?", - { - bool result = true; - - if (SIZE() == 0) { - result = false; - } - - for (auto it = begin; it != end; ++it) { - if (!is(it->get()) || is(it->get())) { + // (symbol? 'foo) + ADD_FUNCTION("atom?", IS_TYPE(Atom)); + ADD_FUNCTION("keyword?", IS_TYPE(Keyword)); + ADD_FUNCTION("list?", IS_TYPE(List)); + ADD_FUNCTION("map?", IS_TYPE(HashMap)); + ADD_FUNCTION("number?", IS_TYPE(Number)); + ADD_FUNCTION("sequential?", IS_TYPE(Collection)); + ADD_FUNCTION("string?", IS_TYPE(String)); + ADD_FUNCTION("symbol?", IS_TYPE(Symbol)); + ADD_FUNCTION("vector?", IS_TYPE(Vector)); + + ADD_FUNCTION( + "fn?", + { + bool result = true; + + if (SIZE() == 0) { result = false; - break; } - } - return makePtr(result); - }); + for (auto it = begin; it != end; ++it) { + if (!is(it->get()) || is(it->get())) { + result = false; + break; + } + } -ADD_FUNCTION( - "macro?", - { - bool result = true; + return makePtr(result); + }); - if (SIZE() == 0) { - result = false; - } + ADD_FUNCTION( + "macro?", + { + bool result = true; - for (auto it = begin; it != end; ++it) { - if (!is(it->get())) { + if (SIZE() == 0) { result = false; - break; } - } - - return makePtr(result); - }); -// ----------------------------------------- + for (auto it = begin; it != end; ++it) { + if (!is(it->get())) { + result = false; + break; + } + } -// (contains? {:foo 5} :foo) -> true -// (contains? {"bar" 5} "foo") -> false -ADD_FUNCTION( - "contains?", - { - CHECK_ARG_COUNT_IS("contains?", SIZE(), 2); + return makePtr(result); + }); - VALUE_CAST(hash_map, HashMap, (*begin)); + // ----------------------------------------- - if (SIZE() == 0) { - return makePtr(false); - } + // (contains? {:foo 5} :foo) -> true + // (contains? {"bar" 5} "foo") -> false + ADD_FUNCTION( + "contains?", + { + CHECK_ARG_COUNT_IS("contains?", SIZE(), 2); - return makePtr(hash_map->exists(*(begin + 1))); - }); + VALUE_CAST(hash_map, HashMap, (*begin)); -// (empty? '() '()) -> true -// (empty? [] [1 2 3] []) -> false -ADD_FUNCTION( - "empty?", - { - bool result = true; + if (SIZE() == 0) { + return makePtr(false); + } - for (auto it = begin; it != end; ++it) { - VALUE_CAST(collection, Collection, (*it)); - if (!collection->empty()) { - result = false; - break; + return makePtr(hash_map->exists(*(begin + 1))); + }); + + // (empty? '() '()) -> true + // (empty? [] [1 2 3] []) -> false + ADD_FUNCTION( + "empty?", + { + bool result = true; + + for (auto it = begin; it != end; ++it) { + VALUE_CAST(collection, Collection, (*it)); + if (!collection->empty()) { + result = false; + break; + } } - } - return makePtr((result) ? Constant::True : Constant::False); - }); + return makePtr((result) ? Constant::True : Constant::False); + }); +} } // namespace blaze diff --git a/src/env/functions/repl.cpp b/src/env/functions/repl.cpp index 3f934a3..9bb35d2 100644 --- a/src/env/functions/repl.cpp +++ b/src/env/functions/repl.cpp @@ -14,50 +14,53 @@ namespace blaze { -// REPL reader -ADD_FUNCTION( - "read-string", - { - CHECK_ARG_COUNT_IS("read-string", SIZE(), 1); - - VALUE_CAST(node, String, (*begin)); - std::string input = node->data(); - - return read(input); - }); - -// Read file contents -ADD_FUNCTION( - "slurp", - { - CHECK_ARG_COUNT_IS("slurp", SIZE(), 1); - - VALUE_CAST(node, String, (*begin)); - std::string path = node->data(); - - auto file = ruc::File(path); - - return makePtr(file.data()); - }); - -// Prompt readline -ADD_FUNCTION( - "readline", - { - CHECK_ARG_COUNT_IS("readline", SIZE(), 1); - - VALUE_CAST(prompt, String, (*begin)); - - return readline(prompt->data()); - }); - -// REPL eval -ADD_FUNCTION( - "eval", - { - CHECK_ARG_COUNT_IS("eval", SIZE(), 1); - - return eval(*begin, nullptr); - }); +void Environment::loadRepl() +{ + // REPL reader + ADD_FUNCTION( + "read-string", + { + CHECK_ARG_COUNT_IS("read-string", SIZE(), 1); + + VALUE_CAST(node, String, (*begin)); + std::string input = node->data(); + + return read(input); + }); + + // Read file contents + ADD_FUNCTION( + "slurp", + { + CHECK_ARG_COUNT_IS("slurp", SIZE(), 1); + + VALUE_CAST(node, String, (*begin)); + std::string path = node->data(); + + auto file = ruc::File(path); + + return makePtr(file.data()); + }); + + // Prompt readline + ADD_FUNCTION( + "readline", + { + CHECK_ARG_COUNT_IS("readline", SIZE(), 1); + + VALUE_CAST(prompt, String, (*begin)); + + return readline(prompt->data()); + }); + + // REPL eval + ADD_FUNCTION( + "eval", + { + CHECK_ARG_COUNT_IS("eval", SIZE(), 1); + + return eval(*begin, nullptr); + }); +} } // namespace blaze diff --git a/src/env/macro.h b/src/env/macro.h index 7630ca1..dba2625 100644 --- a/src/env/macro.h +++ b/src/env/macro.h @@ -8,25 +8,9 @@ #include "env/environment.h" -// 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 counter macro is used to make the struct names unique. - -#define FUNCTION_STRUCT_NAME(unique) __functionStruct##unique - -#define ADD_FUNCTION_IMPL(unique, symbol, lambda) \ - struct FUNCTION_STRUCT_NAME(unique) { \ - FUNCTION_STRUCT_NAME(unique) \ - (const std::string& __symbol, FunctionType __lambda) \ - { \ - Environment::registerFunction(__symbol, __lambda); \ - } \ - }; \ - static struct FUNCTION_STRUCT_NAME(unique) \ - FUNCTION_STRUCT_NAME(unique)( \ - symbol, \ - [](ValueVectorConstIt begin, ValueVectorConstIt end) -> ValuePtr lambda); - -#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__COUNTER__, symbol, lambda); +#define ADD_FUNCTION(symbol, lambda) \ + Environment::registerFunction( \ + symbol, \ + [](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda); #define SIZE() std::distance(begin, end) diff --git a/src/repl.cpp b/src/repl.cpp index ef84eed..8e83710 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -149,6 +149,7 @@ auto main(int argc, char* argv[]) -> int std::signal(SIGINT, blaze::cleanup); std::signal(SIGTERM, blaze::cleanup); + blaze::Environment::loadFunctions(); blaze::Environment::installFunctions(blaze::s_outer_env); installLambdas(blaze::s_outer_env); makeArgv(blaze::s_outer_env, arguments);