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.
149 lines
3.8 KiB
149 lines
3.8 KiB
/* |
|
* Copyright (C) 2023 Riyyi |
|
* |
|
* SPDX-License-Identifier: MIT |
|
*/ |
|
|
|
#include <charconv> // std::from_chars, std::to_chars |
|
#include <memory> |
|
#include <system_error> // std::errc |
|
|
|
#include "ast.h" |
|
#include "env/macro.h" |
|
#include "util.h" |
|
|
|
namespace blaze { |
|
|
|
void Environment::loadConvert() |
|
{ |
|
// (number-to-string 123) -> "123" |
|
ADD_FUNCTION( |
|
"number-to-string", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("number-to-string", SIZE(), 1); |
|
|
|
IS_VALUE(Numeric, (*begin)); |
|
|
|
char result[32]; |
|
auto conversion = std::to_chars(result, |
|
result + sizeof(result), |
|
is<Number>(begin->get()) |
|
? std::static_pointer_cast<Number>(*begin)->number() |
|
: std::static_pointer_cast<Decimal>(*begin)->decimal()); |
|
if (conversion.ec != std::errc()) { |
|
return makePtr<Constant>(Constant::Nil); |
|
} |
|
|
|
return makePtr<String>(std::string(result, conversion.ptr - result)); |
|
}); |
|
|
|
// (string-to-char "123") -> 49 |
|
ADD_FUNCTION( |
|
"string-to-char", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("string-to-char", SIZE(), 1); |
|
|
|
VALUE_CAST(string_value, String, (*begin)); |
|
std::string data = string_value->data(); |
|
|
|
return makePtr<Number>(data.c_str()[0]); |
|
}); |
|
|
|
// (string-to-number "123") -> 123 |
|
ADD_FUNCTION( |
|
"string-to-number", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("string-to-number", SIZE(), 1); |
|
|
|
VALUE_CAST(string_value, String, (*begin)); |
|
std::string data = string_value->data(); |
|
|
|
if (data.find('.') == std::string::npos) { |
|
int64_t number; |
|
auto conversion_number = std::from_chars(data.c_str(), data.c_str() + data.size(), number); |
|
if (conversion_number.ec != std::errc()) { |
|
return makePtr<Constant>(Constant::Nil); |
|
} |
|
|
|
return makePtr<Number>(number); |
|
} |
|
|
|
double decimal; |
|
auto conversion_decimal = std::from_chars(data.c_str(), data.c_str() + data.size(), decimal); |
|
if (conversion_decimal.ec != std::errc()) { |
|
return makePtr<Constant>(Constant::Nil); |
|
} |
|
|
|
return makePtr<Decimal>(decimal); |
|
}); |
|
|
|
#define STRING_TO_COLLECTION(name, type) \ |
|
{ \ |
|
CHECK_ARG_COUNT_IS(name, SIZE(), 1); \ |
|
\ |
|
VALUE_CAST(string_value, String, (*begin)); \ |
|
std::string data = string_value->data(); \ |
|
\ |
|
ValueVector nodes(data.size()); \ |
|
for (size_t i = 0; i < data.size(); ++i) { \ |
|
nodes.at(i) = makePtr<Number>(data.c_str()[i]); \ |
|
} \ |
|
\ |
|
return makePtr<type>(nodes); \ |
|
} |
|
|
|
// (string-to-list "foo") -> (102 111 111) |
|
// (string-to-vector "foo") -> [102 111 111] |
|
ADD_FUNCTION("string-to-list", "", "", STRING_TO_COLLECTION("string-to-list", List)); |
|
ADD_FUNCTION("string-to-vector", "", "", STRING_TO_COLLECTION("string-to-vector", Vector)); |
|
|
|
// ------------------------------------- |
|
|
|
// (symbol "foo") -> foo |
|
ADD_FUNCTION( |
|
"symbol", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); |
|
|
|
if (is<Symbol>(begin->get())) { |
|
return *begin; |
|
} |
|
|
|
VALUE_CAST(string_value, String, (*begin)); |
|
|
|
return makePtr<Symbol>(string_value->data()); |
|
}); |
|
|
|
// (keyword "foo") -> :foo |
|
// (keyword 123) -> :123 |
|
ADD_FUNCTION( |
|
"keyword", |
|
"", |
|
"", |
|
{ |
|
CHECK_ARG_COUNT_IS("keyword", SIZE(), 1); |
|
|
|
if (is<Keyword>(begin->get())) { |
|
return *begin; |
|
} |
|
else if (is<Number>(begin->get())) { |
|
VALUE_CAST(number_value, Number, (*begin)); |
|
|
|
return makePtr<Keyword>(number_value->number()); |
|
} |
|
|
|
VALUE_CAST(string_value, String, (*begin)); |
|
|
|
return makePtr<Keyword>(string_value->data()); |
|
}); |
|
} |
|
|
|
} // namespace blaze
|
|
|