You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
3.9 KiB
185 lines
3.9 KiB
/* |
|
* Copyright (C) 2023 Riyyi |
|
* |
|
* SPDX-License-Identifier: MIT |
|
*/ |
|
|
|
#include <cstddef> // size_t |
|
#include <memory> // std:static_pointer_cast |
|
|
|
#include "blaze/ast.h" |
|
#include "blaze/env/macro.h" |
|
#include "blaze/forward.h" |
|
#include "blaze/util.h" |
|
|
|
namespace blaze { |
|
|
|
void Environment::loadCollectionAccess() |
|
{ |
|
// (count '(1 2 3)) -> 3 |
|
// (count [1 2 3]) -> 3 |
|
// (count {:foo 2 :bar 3}) -> 2 |
|
ADD_FUNCTION( |
|
"count", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("count", SIZE(), 1); |
|
|
|
size_t result = 0; |
|
if (is<Constant>(begin->get()) && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { |
|
// result = 0 |
|
} |
|
else if (is<Collection>(begin->get())) { |
|
result = std::static_pointer_cast<Collection>(*begin)->size(); |
|
} |
|
else if (is<HashMap>(begin->get())) { |
|
result = std::static_pointer_cast<HashMap>(*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<Number>((int64_t)result); |
|
}); |
|
|
|
// ----------------------------------------- |
|
|
|
// (first (list 1 2 3)) -> 1 |
|
ADD_FUNCTION( |
|
"first", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("first", SIZE(), 1); |
|
|
|
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); |
|
} |
|
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); |
|
}); |
|
} |
|
|
|
} // namespace blaze
|
|
|