Browse Source

Env: Allow load order control for native functions

master
Riyyi 1 year ago
parent
commit
b65482eb68
  1. 16
      src/env/environment.cpp
  2. 15
      src/env/environment.h
  3. 229
      src/env/functions/collection-access.cpp
  4. 203
      src/env/functions/collection-constructor.cpp
  5. 405
      src/env/functions/collection-modify.cpp
  6. 153
      src/env/functions/compare.cpp
  7. 73
      src/env/functions/convert.cpp
  8. 11
      src/env/functions/format.cpp
  9. 77
      src/env/functions/meta.cpp
  10. 127
      src/env/functions/mutable.cpp
  11. 153
      src/env/functions/operators.cpp
  12. 83
      src/env/functions/other.cpp
  13. 147
      src/env/functions/predicate.cpp
  14. 93
      src/env/functions/repl.cpp
  15. 24
      src/env/macro.h
  16. 1
      src/repl.cpp

16
src/env/environment.cpp vendored

@ -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) void Environment::registerFunction(const std::string& name, FunctionType function)
{ {
s_functions.insert_or_assign(name, function); s_functions.insert_or_assign(name, function);

15
src/env/environment.h vendored

@ -24,6 +24,7 @@ public:
static EnvironmentPtr create(EnvironmentPtr outer); static EnvironmentPtr create(EnvironmentPtr outer);
static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments); static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments);
static void loadFunctions();
static void registerFunction(const std::string& name, FunctionType function); static void registerFunction(const std::string& name, FunctionType function);
static void installFunctions(EnvironmentPtr env); static void installFunctions(EnvironmentPtr env);
@ -34,6 +35,20 @@ public:
private: private:
Environment() {} 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 }; EnvironmentPtr m_outer { nullptr };
std::unordered_map<std::string, ValuePtr> m_values; std::unordered_map<std::string, ValuePtr> m_values;

229
src/env/functions/collection-access.cpp vendored

@ -14,126 +14,129 @@
namespace blaze { namespace blaze {
// (first (list 1 2 3)) -> 1 void Environment::loadCollectionAccess()
ADD_FUNCTION( {
"first", // (first (list 1 2 3)) -> 1
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("first", SIZE(), 1); "first",
{
if (is<Constant>(begin->get()) CHECK_ARG_COUNT_IS("first", SIZE(), 1);
&& std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>(); if (is<Constant>(begin->get())
} && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>();
VALUE_CAST(collection, Collection, (*begin));
return (collection->empty()) ? makePtr<Constant>() : 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<size_t>(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<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<List>();
}
VALUE_CAST(collection, Collection, (*begin));
return makePtr<List>(collection->rest());
});
// -----------------------------------------
// (get {:kw "value"} :kw) -> "value"
ADD_FUNCTION(
"get",
{
CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>();
}
VALUE_CAST(hash_map, HashMap, (*begin));
begin++;
if (SIZE() == 0) {
return makePtr<Constant>();
}
auto result = hash_map->get(*begin);
return (result) ? result : makePtr<Constant>();
});
// (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<Keyword>(pair.first.substr(1));
} }
else {
nodes.at(i) = makePtr<String>(pair.first); VALUE_CAST(collection, Collection, (*begin));
return (collection->empty()) ? makePtr<Constant>() : 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<size_t>(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<List>(nodes); return collection_nodes[index];
}); });
// (vals {"foo" 3 :bar 5}) -> (3 5) // (rest (list 1 2 3)) -> (2 3)
ADD_FUNCTION( ADD_FUNCTION(
"vals", "rest",
{ {
CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1); CHECK_ARG_COUNT_IS("rest", SIZE(), 1);
VALUE_CAST(hash_map, HashMap, (*begin)); if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<List>();
}
size_t count = hash_map->size(); VALUE_CAST(collection, Collection, (*begin));
auto nodes = ValueVector(count);
return makePtr<List>(collection->rest());
});
// -----------------------------------------
// (get {:kw "value"} :kw) -> "value"
ADD_FUNCTION(
"get",
{
CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>();
}
size_t i = 0; VALUE_CAST(hash_map, HashMap, (*begin));
auto elements = hash_map->elements(); begin++;
for (auto pair : elements) {
nodes.at(i) = pair.second; if (SIZE() == 0) {
i++; return makePtr<Constant>();
} }
auto result = hash_map->get(*begin);
return (result) ? result : makePtr<Constant>();
});
// (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<Keyword>(pair.first.substr(1));
}
else {
nodes.at(i) = makePtr<String>(pair.first);
}
i++;
}
return makePtr<List>(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<List>(nodes); return makePtr<List>(nodes);
}); });
}
} // namespace blaze } // namespace blaze

203
src/env/functions/collection-constructor.cpp vendored

@ -14,106 +14,109 @@
namespace blaze { namespace blaze {
// (list 1 2) -> (1 2) void Environment::loadCollectionConstructor()
ADD_FUNCTION( {
"list", // (list 1 2) -> (1 2)
{ ADD_FUNCTION(
return makePtr<List>(begin, end); "list",
}); {
return makePtr<List>(begin, end);
// (make-list 4 nil) -> (nil nil nil nil) });
ADD_FUNCTION(
"make-list", // (make-list 4 nil) -> (nil nil nil nil)
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("make-list", SIZE(), 2); "make-list",
{
VALUE_CAST(number, Number, (*begin)); CHECK_ARG_COUNT_IS("make-list", SIZE(), 2);
auto count = static_cast<size_t>(number->number() < 0 ? 0 : number->number());
auto value = *std::next(begin); VALUE_CAST(number, Number, (*begin));
auto count = static_cast<size_t>(number->number() < 0 ? 0 : number->number());
auto nodes = ValueVector(count); auto value = *std::next(begin);
if (is<Atom>(value.get())) {
auto atom = std::static_pointer_cast<Atom>(value); auto nodes = ValueVector(count);
for (size_t i = 0; i < count; ++i) { if (is<Atom>(value.get())) {
nodes[i] = makePtr<Atom>(atom); auto atom = std::static_pointer_cast<Atom>(value);
for (size_t i = 0; i < count; ++i) {
nodes[i] = makePtr<Atom>(atom);
}
} }
} // else if (is<Collection>(value.get())) {
// else if (is<Collection>(value.get())) { // for (size_t i = 0; i < count; ++i) {
// for (size_t i = 0; i < count; ++i) { // auto nodes = std::static_pointer_cast<Collection>(value)->nodesCopy();
// auto nodes = std::static_pointer_cast<Collection>(value)->nodesCopy(); // if (is<Vector>(value.get())) {
// if (is<Vector>(value.get())) { // makePtr<Vector>(nodes);
// makePtr<Vector>(nodes); // continue;
// continue; // }
// } // nodes[i] = makePtr<List>(nodes);
// nodes[i] = makePtr<List>(nodes); // }
// } // }
// } // else if (is<Constant>(value.get())) {
// else if (is<Constant>(value.get())) { // for (size_t i = 0; i < count; ++i) {
// for (size_t i = 0; i < count; ++i) { // auto constant = std::static_pointer_cast<Constant>(value);
// auto constant = std::static_pointer_cast<Constant>(value); // nodes[i] = makePtr<Constant>(constant);
// nodes[i] = makePtr<Constant>(constant); // }
// } // }
// }
// TODO:
// TODO: // Atom
// Atom // Collection
// Collection // Constant
// Constant // Function
// Function // HashMap
// HashMap // Keyword
// Keyword // Lambda
// Lambda // List
// List // Macro
// Macro // Number
// Number // String
// String // Symbol
// Symbol // Vector
// Vector
return makePtr<List>(std::move(nodes));
return makePtr<List>(std::move(nodes)); });
});
// -----------------------------------------
// -----------------------------------------
// (vec (list 1 2 3))
// (vec (list 1 2 3)) ADD_FUNCTION(
ADD_FUNCTION( "vec",
"vec", {
{ CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
if (is<Vector>(begin->get())) {
if (is<Vector>(begin->get())) { return *begin;
return *begin; }
}
VALUE_CAST(collection, Collection, (*begin));
VALUE_CAST(collection, Collection, (*begin));
return makePtr<Vector>(collection->nodesCopy());
return makePtr<Vector>(collection->nodesCopy()); });
});
// (vector 1 2 3) -> [1 2 3]
// (vector 1 2 3) -> [1 2 3] ADD_FUNCTION(
ADD_FUNCTION( "vector",
"vector", {
{ auto result = makePtr<Vector>();
auto result = makePtr<Vector>();
return makePtr<Vector>(begin, end);
return makePtr<Vector>(begin, end); });
});
// -----------------------------------------
// -----------------------------------------
// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10}
// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10} ADD_FUNCTION(
ADD_FUNCTION( "hash-map",
"hash-map", {
{ CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
Elements elements;
Elements elements; for (auto it = begin; it != end; std::advance(it, 2)) {
for (auto it = begin; it != end; std::advance(it, 2)) { const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
const ValuePtr& value = *(std::next(it)); // temporary instance to get around const elements.insert_or_assign(HashMap::getKeyString(*it), value);
elements.insert_or_assign(HashMap::getKeyString(*it), value); }
}
return makePtr<HashMap>(elements);
return makePtr<HashMap>(elements); });
}); }
} // namespace blaze } // namespace blaze

405
src/env/functions/collection-modify.cpp vendored

@ -16,250 +16,253 @@
namespace blaze { namespace blaze {
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10 void Environment::loadCollectionModify()
ADD_FUNCTION( {
"apply", // (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
{ ADD_FUNCTION(
CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2); "apply",
{
auto callable = *begin; CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2);
IS_VALUE(Callable, callable);
auto callable = *begin;
VALUE_CAST(collection, Collection, (*std::prev(end))); IS_VALUE(Callable, callable);
auto arguments = ValueVector(begin + 1, end - 1); VALUE_CAST(collection, Collection, (*std::prev(end)));
arguments.reserve(arguments.size() + collection->size());
auto arguments = ValueVector(begin + 1, end - 1);
// Append list nodes to the argument leftovers arguments.reserve(arguments.size() + collection->size());
auto nodes = collection->nodesRead();
for (const auto& node : nodes) { // Append list nodes to the argument leftovers
arguments.push_back(node); auto nodes = collection->nodesRead();
} for (const auto& node : nodes) {
arguments.push_back(node);
ValuePtr value = nullptr; }
if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function();
value = function(arguments.begin(), arguments.end());
}
else {
auto lambda = std::static_pointer_cast<Lambda>(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<List>(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<Collection>(*it)->nodesRead();
std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset);
offset += collection_nodes.size();
}
return makePtr<List>(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<List>(collection.get())) {
std::reverse_copy(begin, end, nodes.begin());
std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count);
return makePtr<List>(nodes); ValuePtr value = nullptr;
} if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function();
value = function(arguments.begin(), arguments.end());
}
else {
auto lambda = std::static_pointer_cast<Lambda>(callable);
value = eval(lambda->body(), Environment::create(lambda, std::move(arguments)));
}
std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin()); return value;
std::copy(begin, end, nodes.begin() + collection_count); });
return makePtr<Vector>(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) ValuePtr first = *begin;
ADD_FUNCTION( begin++;
"map",
{
CHECK_ARG_COUNT_IS("map", SIZE(), 2);
VALUE_CAST(callable, Callable, (*begin)); VALUE_CAST(collection, Collection, (*begin));
VALUE_CAST(collection, Collection, (*(begin + 1))); const auto& collection_nodes = collection->nodesRead();
size_t count = collection->size(); auto result_nodes = ValueVector(collection_nodes.size() + 1);
auto nodes = ValueVector(count); result_nodes.at(0) = first;
std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + 1);
if (is<Function>(callable.get())) { return makePtr<List>(result_nodes);
auto function = std::static_pointer_cast<Function>(callable)->function(); });
for (size_t i = 0; i < count; ++i) {
nodes.at(i) = function(collection->begin() + i, collection->begin() + i + 1); // (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 result_nodes = ValueVector(count);
auto lambda = std::static_pointer_cast<Lambda>(callable); size_t offset = 0;
auto collection_nodes = collection->nodesRead(); for (auto it = begin; it != end; ++it) {
for (size_t i = 0; i < count; ++i) { const auto& collection_nodes = std::static_pointer_cast<Collection>(*it)->nodesRead();
nodes.at(i) = (eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset);
offset += collection_nodes.size();
} }
}
return makePtr<List>(nodes); return makePtr<List>(result_nodes);
}); });
// (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3) // (conj '(1 2 3) 4 5 6) -> (6 5 4 1 2 3)
ADD_FUNCTION( // (conj [1 2 3] 4 5 6) -> [1 2 3 4 5 6]
"set-nth", ADD_FUNCTION(
{ "conj",
CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3); {
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))); const auto& collection_nodes = collection->nodesRead();
auto index = static_cast<size_t>(number_node->number() < 0 ? 0 : number_node->number()); 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 (is<List>(collection.get())) {
if (index >= collection->size()) { // Enlarge list if index out of bounds std::reverse_copy(begin, end, nodes.begin());
collection_nodes.resize(index + 1, makePtr<Constant>()); std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count);
}
collection_nodes[index] = value;
if (is<Vector>(begin->get())) { return makePtr<List>(nodes);
return makePtr<Vector>(collection_nodes); }
}
return makePtr<List>(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) return makePtr<Vector>(nodes);
// (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; // (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6)
Value* front_raw_ptr = front.get(); ADD_FUNCTION(
"map",
{
CHECK_ARG_COUNT_IS("map", SIZE(), 2);
if (is<Constant>(front_raw_ptr) && std::static_pointer_cast<Constant>(front)->state() == Constant::Nil) { VALUE_CAST(callable, Callable, (*begin));
return makePtr<Constant>(); VALUE_CAST(collection, Collection, (*(begin + 1)));
}
if (is<Collection>(front_raw_ptr)) {
auto collection = std::static_pointer_cast<Collection>(front);
if (collection->empty()) { size_t count = collection->size();
return makePtr<Constant>(); auto nodes = ValueVector(count);
if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(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<Lambda>(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<List>(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<size_t>(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<Constant>());
} }
collection_nodes[index] = value;
if (is<List>(front_raw_ptr)) { if (is<Vector>(begin->get())) {
return front; return makePtr<Vector>(collection_nodes);
} }
return makePtr<List>(collection->nodesCopy()); return makePtr<List>(collection_nodes);
} });
if (is<String>(front_raw_ptr)) {
auto string = std::static_pointer_cast<String>(front);
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<Constant>(front_raw_ptr) && std::static_pointer_cast<Constant>(front)->state() == Constant::Nil) {
return makePtr<Constant>(); return makePtr<Constant>();
} }
if (is<Collection>(front_raw_ptr)) {
auto collection = std::static_pointer_cast<Collection>(front);
size_t count = string->size(); if (collection->empty()) {
auto nodes = ValueVector(count); return makePtr<Constant>();
}
if (is<List>(front_raw_ptr)) {
return front;
}
const auto& data = string->data(); return makePtr<List>(collection->nodesCopy());
for (size_t i = 0; i < count; ++i) {
nodes.at(i) = makePtr<String>(data[i]);
} }
if (is<String>(front_raw_ptr)) {
auto string = std::static_pointer_cast<String>(front);
return makePtr<List>(nodes); if (string->empty()) {
} return makePtr<Constant>();
}
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<String>(data[i]);
}
return nullptr; return makePtr<List>(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} return nullptr;
ADD_FUNCTION( });
"assoc",
{
CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1);
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()); VALUE_CAST(hash_map, HashMap, (*begin));
for (auto it = begin; it != end; std::advance(it, 2)) { begin++;
const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
elements.insert_or_assign(HashMap::getKeyString(*it), value);
}
return makePtr<HashMap>(elements); CHECK_ARG_COUNT_EVEN("assoc", SIZE());
});
// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2} Elements elements(hash_map->elements());
ADD_FUNCTION( for (auto it = begin; it != end; std::advance(it, 2)) {
"dissoc", const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
{ elements.insert_or_assign(HashMap::getKeyString(*it), value);
CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1); }
VALUE_CAST(hash_map, HashMap, (*begin)); return makePtr<HashMap>(elements);
begin++; });
Elements elements(hash_map->elements()); // (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2}
for (auto it = begin; it != end; ++it) { ADD_FUNCTION(
elements.erase(HashMap::getKeyString(*it)); "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<HashMap>(elements); return makePtr<HashMap>(elements);
}); });
}
} // namespace blaze } // namespace blaze

153
src/env/functions/compare.cpp vendored

@ -14,6 +14,8 @@
namespace blaze { namespace blaze {
void Environment::loadCompare()
{
#define NUMBER_COMPARE(operator) \ #define NUMBER_COMPARE(operator) \
{ \ { \
bool result = true; \ bool result = true; \
@ -38,95 +40,96 @@ namespace blaze {
return makePtr<Constant>((result) ? Constant::True : Constant::False); \ return makePtr<Constant>((result) ? Constant::True : Constant::False); \
} }
ADD_FUNCTION("<", NUMBER_COMPARE(<)); ADD_FUNCTION("<", NUMBER_COMPARE(<));
ADD_FUNCTION("<=", NUMBER_COMPARE(<=)); ADD_FUNCTION("<=", NUMBER_COMPARE(<=));
ADD_FUNCTION(">", NUMBER_COMPARE(>)); ADD_FUNCTION(">", NUMBER_COMPARE(>));
ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
// ----------------------------------------- // -----------------------------------------
// (= 1 1) -> true // (= 1 1) -> true
// (= "foo" "foo") -> true // (= "foo" "foo") -> true
ADD_FUNCTION( ADD_FUNCTION(
"=", "=",
{ {
CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2); CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2);
std::function<bool(ValuePtr, ValuePtr)> equal = std::function<bool(ValuePtr, ValuePtr)> equal =
[&equal](ValuePtr lhs, ValuePtr rhs) -> bool { [&equal](ValuePtr lhs, ValuePtr rhs) -> bool {
if ((is<List>(lhs.get()) || is<Vector>(lhs.get())) if ((is<List>(lhs.get()) || is<Vector>(lhs.get()))
&& (is<List>(rhs.get()) || is<Vector>(rhs.get()))) { && (is<List>(rhs.get()) || is<Vector>(rhs.get()))) {
auto lhs_collection = std::static_pointer_cast<Collection>(lhs); auto lhs_collection = std::static_pointer_cast<Collection>(lhs);
auto rhs_collection = std::static_pointer_cast<Collection>(rhs); auto rhs_collection = std::static_pointer_cast<Collection>(rhs);
if (lhs_collection->size() != rhs_collection->size()) {
return false;
}
auto lhs_it = lhs_collection->begin(); if (lhs_collection->size() != rhs_collection->size()) {
auto rhs_it = rhs_collection->begin();
for (; lhs_it != lhs_collection->end(); ++lhs_it, ++rhs_it) {
if (!equal(*lhs_it, *rhs_it)) {
return false; return false;
} }
}
return true;
}
if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) { auto lhs_it = lhs_collection->begin();
const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements(); auto rhs_it = rhs_collection->begin();
const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements(); 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 true;
return false;
} }
for (const auto& [key, value] : lhs_nodes) { if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) {
auto it = rhs_nodes.find(key); const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements();
if (it == rhs_nodes.cend() || !equal(value, it->second)) { const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements();
if (lhs_nodes.size() != rhs_nodes.size()) {
return false; 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<String>(lhs.get()) && is<String>(rhs.get()) return true;
&& std::static_pointer_cast<String>(lhs)->data() == std::static_pointer_cast<String>(rhs)->data()) { }
return true;
} if (is<String>(lhs.get()) && is<String>(rhs.get())
if (is<Keyword>(lhs.get()) && is<Keyword>(rhs.get()) && std::static_pointer_cast<String>(lhs)->data() == std::static_pointer_cast<String>(rhs)->data()) {
&& std::static_pointer_cast<Keyword>(lhs)->keyword() == std::static_pointer_cast<Keyword>(rhs)->keyword()) { return true;
return true; }
} if (is<Keyword>(lhs.get()) && is<Keyword>(rhs.get())
if (is<Number>(lhs.get()) && is<Number>(rhs.get()) && std::static_pointer_cast<Keyword>(lhs)->keyword() == std::static_pointer_cast<Keyword>(rhs)->keyword()) {
&& std::static_pointer_cast<Number>(lhs)->number() == std::static_pointer_cast<Number>(rhs)->number()) { return true;
return true; }
} if (is<Number>(lhs.get()) && is<Number>(rhs.get())
if (is<Constant>(lhs.get()) && is<Constant>(rhs.get()) && std::static_pointer_cast<Number>(lhs)->number() == std::static_pointer_cast<Number>(rhs)->number()) {
&& std::static_pointer_cast<Constant>(lhs)->state() == std::static_pointer_cast<Constant>(rhs)->state()) { return true;
return true; }
} if (is<Constant>(lhs.get()) && is<Constant>(rhs.get())
if (is<Symbol>(lhs.get()) && is<Symbol>(rhs.get()) && std::static_pointer_cast<Constant>(lhs)->state() == std::static_pointer_cast<Constant>(rhs)->state()) {
&& std::static_pointer_cast<Symbol>(lhs)->symbol() == std::static_pointer_cast<Symbol>(rhs)->symbol()) { return true;
return true; }
} if (is<Symbol>(lhs.get()) && is<Symbol>(rhs.get())
&& std::static_pointer_cast<Symbol>(lhs)->symbol() == std::static_pointer_cast<Symbol>(rhs)->symbol()) {
return true;
}
return false; return false;
}; };
bool result = true; bool result = true;
auto it = begin; auto it = begin;
auto it_next = begin + 1; auto it_next = begin + 1;
for (; it_next != end; ++it, ++it_next) { for (; it_next != end; ++it, ++it_next) {
if (!equal(*it, *it_next)) { if (!equal(*it, *it_next)) {
result = false; result = false;
break; break;
}
} }
}
return makePtr<Constant>((result) ? Constant::True : Constant::False); return makePtr<Constant>((result) ? Constant::True : Constant::False);
}); });
}
} // namespace blaze } // namespace blaze

73
src/env/functions/convert.cpp vendored

@ -10,40 +10,43 @@
namespace blaze { namespace blaze {
// (symbol "foo") -> foo void Environment::loadConvert()
ADD_FUNCTION( {
"symbol", // (symbol "foo") -> foo
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); "symbol",
{
if (is<Symbol>(begin->get())) { CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
return *begin;
} if (is<Symbol>(begin->get())) {
return *begin;
VALUE_CAST(stringValue, String, (*begin)); }
return makePtr<Symbol>(stringValue->data()); VALUE_CAST(stringValue, String, (*begin));
});
return makePtr<Symbol>(stringValue->data());
// (keyword "foo") -> :foo });
// (keyword 123) -> :123
ADD_FUNCTION( // (keyword "foo") -> :foo
"keyword", // (keyword 123) -> :123
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); "keyword",
{
if (is<Keyword>(begin->get())) { CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
return *begin;
} if (is<Keyword>(begin->get())) {
else if (is<Number>(begin->get())) { return *begin;
VALUE_CAST(numberValue, Number, (*begin)); }
else if (is<Number>(begin->get())) {
return makePtr<Keyword>(numberValue->number()); VALUE_CAST(numberValue, Number, (*begin));
}
return makePtr<Keyword>(numberValue->number());
VALUE_CAST(stringValue, String, (*begin)); }
return makePtr<Keyword>(stringValue->data()); VALUE_CAST(stringValue, String, (*begin));
});
return makePtr<Keyword>(stringValue->data());
});
}
} // namespace blaze } // namespace blaze

11
src/env/functions/format.cpp vendored

@ -16,6 +16,8 @@
namespace blaze { namespace blaze {
void Environment::loadFormat()
{
#define PRINTER_STRING(print_readably, concatenation) \ #define PRINTER_STRING(print_readably, concatenation) \
{ \ { \
std::string result; \ std::string result; \
@ -32,8 +34,8 @@ namespace blaze {
return makePtr<String>(result); \ return makePtr<String>(result); \
} }
ADD_FUNCTION("str", PRINTER_STRING(false, "")); ADD_FUNCTION("str", PRINTER_STRING(false, ""));
ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
#define PRINTER_PRINT(print_readably) \ #define PRINTER_PRINT(print_readably) \
{ \ { \
@ -50,7 +52,8 @@ ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
return makePtr<Constant>(); \ return makePtr<Constant>(); \
} }
ADD_FUNCTION("prn", PRINTER_PRINT(true)); ADD_FUNCTION("prn", PRINTER_PRINT(true));
ADD_FUNCTION("println", PRINTER_PRINT(false)); ADD_FUNCTION("println", PRINTER_PRINT(false));
}
} // namespace blaze } // namespace blaze

77
src/env/functions/meta.cpp vendored

@ -12,42 +12,45 @@
namespace blaze { namespace blaze {
// (meta [1 2 3]) void Environment::loadMeta()
ADD_FUNCTION( {
"meta", // (meta [1 2 3])
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("meta", SIZE(), 1); "meta",
{
auto front = *begin; CHECK_ARG_COUNT_IS("meta", SIZE(), 1);
Value* front_raw_ptr = begin->get();
auto front = *begin;
if (!is<Collection>(front_raw_ptr) && // List / Vector Value* front_raw_ptr = begin->get();
!is<HashMap>(front_raw_ptr) && // HashMap
!is<Callable>(front_raw_ptr)) { // Function / Lambda if (!is<Collection>(front_raw_ptr) && // List / Vector
Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); !is<HashMap>(front_raw_ptr) && // HashMap
return nullptr; !is<Callable>(front_raw_ptr)) { // Function / Lambda
} Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front));
return nullptr;
return front->meta(); }
});
return front->meta();
// (with-meta [1 2 3] "some metadata") });
ADD_FUNCTION(
"with-meta", // (with-meta [1 2 3] "some metadata")
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2); "with-meta",
{
auto front = *begin; CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2);
Value* front_raw_ptr = begin->get();
auto front = *begin;
if (!is<Collection>(front_raw_ptr) && // List / Vector Value* front_raw_ptr = begin->get();
!is<HashMap>(front_raw_ptr) && // HashMap
!is<Callable>(front_raw_ptr)) { // Function / Lambda if (!is<Collection>(front_raw_ptr) && // List / Vector
Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); !is<HashMap>(front_raw_ptr) && // HashMap
return nullptr; !is<Callable>(front_raw_ptr)) { // Function / Lambda
} Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front));
return nullptr;
return front->withMeta(*(begin + 1)); }
});
return front->withMeta(*(begin + 1));
});
}
} // namespace blaze } // namespace blaze

127
src/env/functions/mutable.cpp vendored

@ -15,67 +15,70 @@
namespace blaze { namespace blaze {
// (atom 1) void Environment::loadMutable()
ADD_FUNCTION( {
"atom", // (atom 1)
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("atom", SIZE(), 1); "atom",
{
return makePtr<Atom>(*begin); CHECK_ARG_COUNT_IS("atom", SIZE(), 1);
});
return makePtr<Atom>(*begin);
// (deref myatom) });
ADD_FUNCTION(
"deref", // (deref myatom)
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("deref", SIZE(), 1); "deref",
{
VALUE_CAST(atom, Atom, (*begin)); CHECK_ARG_COUNT_IS("deref", SIZE(), 1);
return atom->deref(); VALUE_CAST(atom, Atom, (*begin));
});
return atom->deref();
// (reset! myatom 2) });
ADD_FUNCTION(
"reset!", // (reset! myatom 2)
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("reset!", SIZE(), 2); "reset!",
{
VALUE_CAST(atom, Atom, (*begin)); CHECK_ARG_COUNT_IS("reset!", SIZE(), 2);
auto value = *(begin + 1);
VALUE_CAST(atom, Atom, (*begin));
atom->reset(value); auto value = *(begin + 1);
return value; 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!", // (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
{ ADD_FUNCTION(
CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2); "swap!",
{
VALUE_CAST(atom, Atom, (*begin)); CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2);
VALUE_CAST(callable, Callable, (*(begin + 1))); VALUE_CAST(atom, Atom, (*begin));
// Remove atom and function from the argument list, add atom value VALUE_CAST(callable, Callable, (*(begin + 1)));
begin += 2;
auto arguments = ValueVector(SIZE() + 1); // Remove atom and function from the argument list, add atom value
arguments[0] = atom->deref(); begin += 2;
std::copy(begin, end, arguments.begin() + 1); auto arguments = ValueVector(SIZE() + 1);
arguments[0] = atom->deref();
ValuePtr value = nullptr; std::copy(begin, end, arguments.begin() + 1);
if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function(); ValuePtr value = nullptr;
value = function(arguments.begin(), arguments.end()); if (is<Function>(callable.get())) {
} auto function = std::static_pointer_cast<Function>(callable)->function();
else { value = function(arguments.begin(), arguments.end());
auto lambda = std::static_pointer_cast<Lambda>(callable); }
value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); else {
} auto lambda = std::static_pointer_cast<Lambda>(callable);
value = eval(lambda->body(), Environment::create(lambda, std::move(arguments)));
return atom->reset(value); }
});
return atom->reset(value);
});
}
} // namespace blaze } // namespace blaze

153
src/env/functions/operators.cpp vendored

@ -12,80 +12,83 @@
namespace blaze { namespace blaze {
ADD_FUNCTION( void Environment::loadOperators()
"+", {
{ ADD_FUNCTION(
int64_t result = 0; "+",
{
for (auto it = begin; it != end; ++it) { int64_t result = 0;
VALUE_CAST(number, Number, (*it));
result += number->number(); for (auto it = begin; it != end; ++it) {
} VALUE_CAST(number, Number, (*it));
result += number->number();
return makePtr<Number>(result); }
});
return makePtr<Number>(result);
ADD_FUNCTION( });
"-",
{ ADD_FUNCTION(
if (SIZE() == 0) { "-",
return makePtr<Number>(0); {
} if (SIZE() == 0) {
return makePtr<Number>(0);
// Start with the first number }
VALUE_CAST(number, Number, (*begin));
int64_t result = number->number(); // Start with the first number
VALUE_CAST(number, Number, (*begin));
// Skip the first node int64_t result = number->number();
for (auto it = begin + 1; it != end; ++it) {
VALUE_CAST(number, Number, (*it)); // Skip the first node
result -= number->number(); for (auto it = begin + 1; it != end; ++it) {
} VALUE_CAST(number, Number, (*it));
result -= number->number();
return makePtr<Number>(result); }
});
return makePtr<Number>(result);
ADD_FUNCTION( });
"*",
{ ADD_FUNCTION(
int64_t result = 1; "*",
{
for (auto it = begin; it != end; ++it) { int64_t result = 1;
VALUE_CAST(number, Number, (*it));
result *= number->number(); for (auto it = begin; it != end; ++it) {
} VALUE_CAST(number, Number, (*it));
result *= number->number();
return makePtr<Number>(result); }
});
return makePtr<Number>(result);
ADD_FUNCTION( });
"/",
{ ADD_FUNCTION(
CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1); "/",
{
// Start with the first number CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1);
VALUE_CAST(number, Number, (*begin));
double result = number->number(); // Start with the first number
VALUE_CAST(number, Number, (*begin));
// Skip the first node double result = number->number();
for (auto it = begin + 1; it != end; ++it) {
VALUE_CAST(number, Number, (*it)); // Skip the first node
result /= number->number(); for (auto it = begin + 1; it != end; ++it) {
} VALUE_CAST(number, Number, (*it));
result /= number->number();
return makePtr<Number>((int64_t)result); }
});
return makePtr<Number>((int64_t)result);
// (% 5 2) -> 1 });
ADD_FUNCTION(
"%", // (% 5 2) -> 1
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("/", SIZE(), 2); "%",
{
VALUE_CAST(divide, Number, (*begin)); CHECK_ARG_COUNT_IS("/", SIZE(), 2);
VALUE_CAST(by, Number, (*(begin + 1)));
VALUE_CAST(divide, Number, (*begin));
return makePtr<Number>(divide->number() % by->number()); VALUE_CAST(by, Number, (*(begin + 1)));
});
return makePtr<Number>(divide->number() % by->number());
});
}
} // namespace blaze } // namespace blaze

83
src/env/functions/other.cpp vendored

@ -17,55 +17,58 @@
namespace blaze { namespace blaze {
// (count '(1 2 3)) -> 3 void Environment::loadOther()
// (count [1 2 3]) -> 3 {
ADD_FUNCTION( // (count '(1 2 3)) -> 3
"count", // (count [1 2 3]) -> 3
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("count", SIZE(), 1); "count",
{
CHECK_ARG_COUNT_IS("count", SIZE(), 1);
size_t result = 0; size_t result = 0;
if (is<Constant>(begin->get()) && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { if (is<Constant>(begin->get()) && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
// result = 0 // result = 0
} }
else if (is<Collection>(begin->get())) { else if (is<Collection>(begin->get())) {
result = std::static_pointer_cast<Collection>(*begin)->size(); result = std::static_pointer_cast<Collection>(*begin)->size();
} }
else { else {
Error::the().add(::format("wrong argument type: Collection, '{}'", *begin)); Error::the().add(::format("wrong argument type: Collection, '{}'", *begin));
return nullptr; return nullptr;
} }
// FIXME: Add numeric_limits check for implicit cast: size_t > int64_t // FIXME: Add numeric_limits check for implicit cast: size_t > int64_t
return makePtr<Number>((int64_t)result); return makePtr<Number>((int64_t)result);
}); });
// ----------------------------------------- // -----------------------------------------
// (throw x) // (throw x)
ADD_FUNCTION( ADD_FUNCTION(
"throw", "throw",
{ {
CHECK_ARG_COUNT_IS("throw", SIZE(), 1); CHECK_ARG_COUNT_IS("throw", SIZE(), 1);
Error::the().add(*begin); Error::the().add(*begin);
return nullptr; return nullptr;
}) })
// ----------------------------------------- // -----------------------------------------
// (time-ms) // (time-ms)
ADD_FUNCTION( ADD_FUNCTION(
"time-ms", "time-ms",
{ {
CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0); CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0);
int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()) std::chrono::system_clock::now().time_since_epoch())
.count(); .count();
return makePtr<Number>(elapsed); return makePtr<Number>(elapsed);
}); });
}
} // namespace blaze } // namespace blaze

147
src/env/functions/predicate.cpp vendored

@ -10,6 +10,8 @@
namespace blaze { namespace blaze {
void Environment::loadPredicate()
{
#define IS_CONSTANT(name, constant) \ #define IS_CONSTANT(name, constant) \
{ \ { \
CHECK_ARG_COUNT_IS(name, SIZE(), 1); \ CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
@ -19,12 +21,12 @@ namespace blaze {
&& std::static_pointer_cast<Constant>(*begin)->state() == constant); \ && std::static_pointer_cast<Constant>(*begin)->state() == constant); \
} }
// (nil? nil) // (nil? nil)
ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil)); ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil));
ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True)); ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True));
ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False)); ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False));
// ----------------------------------------- // -----------------------------------------
#define IS_TYPE(type) \ #define IS_TYPE(type) \
{ \ { \
@ -44,89 +46,90 @@ ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False));
return makePtr<Constant>(result); \ return makePtr<Constant>(result); \
} }
// (symbol? 'foo) // (symbol? 'foo)
ADD_FUNCTION("atom?", IS_TYPE(Atom)); ADD_FUNCTION("atom?", IS_TYPE(Atom));
ADD_FUNCTION("keyword?", IS_TYPE(Keyword)); ADD_FUNCTION("keyword?", IS_TYPE(Keyword));
ADD_FUNCTION("list?", IS_TYPE(List)); ADD_FUNCTION("list?", IS_TYPE(List));
ADD_FUNCTION("map?", IS_TYPE(HashMap)); ADD_FUNCTION("map?", IS_TYPE(HashMap));
ADD_FUNCTION("number?", IS_TYPE(Number)); ADD_FUNCTION("number?", IS_TYPE(Number));
ADD_FUNCTION("sequential?", IS_TYPE(Collection)); ADD_FUNCTION("sequential?", IS_TYPE(Collection));
ADD_FUNCTION("string?", IS_TYPE(String)); ADD_FUNCTION("string?", IS_TYPE(String));
ADD_FUNCTION("symbol?", IS_TYPE(Symbol)); ADD_FUNCTION("symbol?", IS_TYPE(Symbol));
ADD_FUNCTION("vector?", IS_TYPE(Vector)); ADD_FUNCTION("vector?", IS_TYPE(Vector));
ADD_FUNCTION( ADD_FUNCTION(
"fn?", "fn?",
{ {
bool result = true; bool result = true;
if (SIZE() == 0) { if (SIZE() == 0) {
result = false;
}
for (auto it = begin; it != end; ++it) {
if (!is<Callable>(it->get()) || is<Macro>(it->get())) {
result = false; result = false;
break;
} }
}
return makePtr<Constant>(result); for (auto it = begin; it != end; ++it) {
}); if (!is<Callable>(it->get()) || is<Macro>(it->get())) {
result = false;
break;
}
}
ADD_FUNCTION( return makePtr<Constant>(result);
"macro?", });
{
bool result = true;
if (SIZE() == 0) { ADD_FUNCTION(
result = false; "macro?",
} {
bool result = true;
for (auto it = begin; it != end; ++it) { if (SIZE() == 0) {
if (!is<Macro>(it->get())) {
result = false; result = false;
break;
} }
}
return makePtr<Constant>(result);
});
// ----------------------------------------- for (auto it = begin; it != end; ++it) {
if (!is<Macro>(it->get())) {
result = false;
break;
}
}
// (contains? {:foo 5} :foo) -> true return makePtr<Constant>(result);
// (contains? {"bar" 5} "foo") -> false });
ADD_FUNCTION(
"contains?",
{
CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
VALUE_CAST(hash_map, HashMap, (*begin)); // -----------------------------------------
if (SIZE() == 0) { // (contains? {:foo 5} :foo) -> true
return makePtr<Constant>(false); // (contains? {"bar" 5} "foo") -> false
} ADD_FUNCTION(
"contains?",
{
CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
return makePtr<Constant>(hash_map->exists(*(begin + 1))); VALUE_CAST(hash_map, HashMap, (*begin));
});
// (empty? '() '()) -> true if (SIZE() == 0) {
// (empty? [] [1 2 3] []) -> false return makePtr<Constant>(false);
ADD_FUNCTION( }
"empty?",
{
bool result = true;
for (auto it = begin; it != end; ++it) { return makePtr<Constant>(hash_map->exists(*(begin + 1)));
VALUE_CAST(collection, Collection, (*it)); });
if (!collection->empty()) {
result = false; // (empty? '() '()) -> true
break; // (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<Constant>((result) ? Constant::True : Constant::False); return makePtr<Constant>((result) ? Constant::True : Constant::False);
}); });
}
} // namespace blaze } // namespace blaze

93
src/env/functions/repl.cpp vendored

@ -14,50 +14,53 @@
namespace blaze { namespace blaze {
// REPL reader void Environment::loadRepl()
ADD_FUNCTION( {
"read-string", // REPL reader
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("read-string", SIZE(), 1); "read-string",
{
VALUE_CAST(node, String, (*begin)); CHECK_ARG_COUNT_IS("read-string", SIZE(), 1);
std::string input = node->data();
VALUE_CAST(node, String, (*begin));
return read(input); std::string input = node->data();
});
return read(input);
// Read file contents });
ADD_FUNCTION(
"slurp", // Read file contents
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("slurp", SIZE(), 1); "slurp",
{
VALUE_CAST(node, String, (*begin)); CHECK_ARG_COUNT_IS("slurp", SIZE(), 1);
std::string path = node->data();
VALUE_CAST(node, String, (*begin));
auto file = ruc::File(path); std::string path = node->data();
return makePtr<String>(file.data()); auto file = ruc::File(path);
});
return makePtr<String>(file.data());
// Prompt readline });
ADD_FUNCTION(
"readline", // Prompt readline
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("readline", SIZE(), 1); "readline",
{
VALUE_CAST(prompt, String, (*begin)); CHECK_ARG_COUNT_IS("readline", SIZE(), 1);
return readline(prompt->data()); VALUE_CAST(prompt, String, (*begin));
});
return readline(prompt->data());
// REPL eval });
ADD_FUNCTION(
"eval", // REPL eval
{ ADD_FUNCTION(
CHECK_ARG_COUNT_IS("eval", SIZE(), 1); "eval",
{
return eval(*begin, nullptr); CHECK_ARG_COUNT_IS("eval", SIZE(), 1);
});
return eval(*begin, nullptr);
});
}
} // namespace blaze } // namespace blaze

24
src/env/macro.h vendored

@ -8,25 +8,9 @@
#include "env/environment.h" #include "env/environment.h"
// At the top-level you cant invoke any function, but you can create variables. #define ADD_FUNCTION(symbol, lambda) \
// Using a struct's constructor you can work around this limitation. Environment::registerFunction( \
// Also, the counter macro is used to make the struct names unique. symbol, \
[](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda);
#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 SIZE() std::distance(begin, end) #define SIZE() std::distance(begin, end)

1
src/repl.cpp

@ -149,6 +149,7 @@ auto main(int argc, char* argv[]) -> int
std::signal(SIGINT, blaze::cleanup); std::signal(SIGINT, blaze::cleanup);
std::signal(SIGTERM, blaze::cleanup); std::signal(SIGTERM, blaze::cleanup);
blaze::Environment::loadFunctions();
blaze::Environment::installFunctions(blaze::s_outer_env); blaze::Environment::installFunctions(blaze::s_outer_env);
installLambdas(blaze::s_outer_env); installLambdas(blaze::s_outer_env);
makeArgv(blaze::s_outer_env, arguments); makeArgv(blaze::s_outer_env, arguments);

Loading…
Cancel
Save