Compare commits

...
4 Commits
14 changed files with 269 additions and 64 deletions
+1
View File
@@ -0,0 +1 @@
build/compile_commands.json
+15 -6
View File
@@ -21,6 +21,13 @@
namespace blaze { namespace blaze {
static auto cleanup(int signal) -> void
{
print("\033[0m\n");
Repl::cleanup();
std::exit(signal);
}
auto main(int argc, char* argv[]) -> int auto main(int argc, char* argv[]) -> int
{ {
bool dump_lexer = false; bool dump_lexer = false;
@@ -39,17 +46,17 @@ auto main(int argc, char* argv[]) -> int
arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No);
arg_parser.parse(argc, argv); arg_parser.parse(argc, argv);
Repl::init();
// Signal callbacks
std::signal(SIGINT, cleanup);
std::signal(SIGTERM, cleanup);
// Set settings // Set settings
g_outer_env->set("*DUMP-LEXER*", makePtr<Constant>(dump_lexer)); g_outer_env->set("*DUMP-LEXER*", makePtr<Constant>(dump_lexer));
g_outer_env->set("*DUMP-READER*", makePtr<Constant>(dump_reader)); g_outer_env->set("*DUMP-READER*", makePtr<Constant>(dump_reader));
g_outer_env->set("*PRETTY-PRINT*", makePtr<Constant>(pretty_print)); g_outer_env->set("*PRETTY-PRINT*", makePtr<Constant>(pretty_print));
// Signal callbacks
std::signal(SIGINT, Repl::cleanup);
std::signal(SIGTERM, Repl::cleanup);
Environment::loadFunctions();
Environment::installFunctions(g_outer_env);
Repl::makeArgv(g_outer_env, arguments); Repl::makeArgv(g_outer_env, arguments);
if (arguments.size() > 0) { if (arguments.size() > 0) {
@@ -73,6 +80,8 @@ auto main(int argc, char* argv[]) -> int
print("\033[0m"); print("\033[0m");
} }
Repl::cleanup();
return 0; return 0;
} }
+32 -7
View File
@@ -11,16 +11,18 @@
#include <functional> // std::function #include <functional> // std::function
#include <list> #include <list>
#include <map> #include <map>
#include <memory> // std::shared_ptr #include <memory> // std::make_shared, std::shared_ptr
#include <span> #include <span>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <typeinfo> // typeid #include <typeinfo> // typeid
#include <utility> // std::forward
#include <vector> #include <vector>
#include "ruc/format/formatter.h" #include "ruc/format/formatter.h"
#include "blaze/forward.h" #include "blaze/forward.h"
#include "blaze/to-from-hashmap.h"
namespace blaze { namespace blaze {
@@ -77,14 +79,13 @@ protected:
#define WITH_META(Type) \ #define WITH_META(Type) \
virtual ValuePtr withMetaImpl(ValuePtr meta) const override \ virtual ValuePtr withMetaImpl(ValuePtr meta) const override \
{ \ { \
return makePtr<Type>(*this, meta); \ return std::make_shared<Type>(*this, meta); \
} }
#define WITH_NO_META() \ #define WITH_NO_META() \
virtual ValuePtr withMetaImpl(ValuePtr meta) const override \ virtual ValuePtr withMetaImpl(ValuePtr) const override \
{ \ { \
(void)meta; \ return nullptr; \
return nullptr; \
} }
// ----------------------------------------- // -----------------------------------------
@@ -195,6 +196,20 @@ public:
HashMap(const HashMap& that, ValuePtr meta); HashMap(const HashMap& that, ValuePtr meta);
virtual ~HashMap() = default; virtual ~HashMap() = default;
static HashMapPtr create(const Elements& elements)
{
return std::make_shared<HashMap>(elements);
}
// Customization Point
template<typename T>
static HashMapPtr create(T value)
{
HashMapPtr hash_map;
to_hash_map(hash_map, std::forward<T>(value));
return hash_map;
}
static std::string getKeyString(ValuePtr key); static std::string getKeyString(ValuePtr key);
bool exists(const std::string& key); bool exists(const std::string& key);
@@ -222,6 +237,11 @@ public:
String(char character); String(char character);
virtual ~String() = default; virtual ~String() = default;
static ValuePtr create(const std::string& data)
{
return std::make_shared<String>(data);
}
const std::string& data() const { return m_data; } const std::string& data() const { return m_data; }
size_t size() const { return m_data.size(); } size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); } bool empty() const { return m_data.empty(); }
@@ -287,6 +307,11 @@ public:
Decimal(double decimal); Decimal(double decimal);
virtual ~Decimal() = default; virtual ~Decimal() = default;
static ValuePtr create(float value)
{
return std::make_shared<Decimal>(value);
}
double decimal() const { return m_decimal; } double decimal() const { return m_decimal; }
WITH_NO_META(); WITH_NO_META();
+4
View File
@@ -79,12 +79,16 @@ EnvironmentPtr Environment::create(const ValuePtr lambda, ValueVector&& argument
void Environment::loadFunctions() void Environment::loadFunctions()
{ {
s_function_parts.clear();
s_lambdas.clear();
loadCollectionAccess(); loadCollectionAccess();
loadCollectionConstructor(); loadCollectionConstructor();
loadCollectionModify(); loadCollectionModify();
loadCompare(); loadCompare();
loadConvert(); loadConvert();
loadFormat(); loadFormat();
loadMath();
loadMeta(); loadMeta();
loadMutable(); loadMutable();
loadOperators(); loadOperators();
+1
View File
@@ -51,6 +51,7 @@ private:
static void loadCompare(); static void loadCompare();
static void loadConvert(); static void loadConvert();
static void loadFormat(); static void loadFormat();
static void loadMath();
static void loadMeta(); static void loadMeta();
static void loadMutable(); static void loadMutable();
static void loadOperators(); static void loadOperators();
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cmath> // std::sin
#include <limits> // sdt::numeric_limits
#include <memory> // std::static_pointer_cast
#include "blaze/ast.h"
#include "blaze/env/macro.h"
#include "blaze/util.h"
namespace blaze {
void Environment::loadMath()
{
#define MATH_MAX_MIN(variant, limit, operator) \
{ \
CHECK_ARG_COUNT_AT_LEAST(#variant, SIZE(), 1); \
\
int64_t number = std::numeric_limits<int64_t>::limit(); \
double decimal = std::numeric_limits<double>::limit(); \
\
for (auto it = begin; it != end; ++it) { \
IS_VALUE(Numeric, (*it)); \
if (is<Number>(it->get())) { \
auto it_numeric = std::static_pointer_cast<Number>(*it)->number(); \
if (it_numeric operator number) { \
number = it_numeric; \
} \
} \
else { \
auto it_numeric = std::static_pointer_cast<Decimal>(*it)->decimal(); \
if (it_numeric operator decimal) { \
decimal = it_numeric; \
} \
} \
} \
\
if (number operator decimal) { \
return makePtr<Number>(number); \
} \
\
return makePtr<Decimal>(decimal); \
}
ADD_FUNCTION(
"max", "number...",
"Return largest of all arguments, where NUMBER is a number or decimal.",
MATH_MAX_MIN(max, lowest, >));
ADD_FUNCTION(
"min", "number...",
"Return smallest of all arguments, where NUMBER is a number or decimal.",
MATH_MAX_MIN(min, max, <));
#define MATH_COS_SIN(variant) \
{ \
CHECK_ARG_COUNT_IS(#variant, SIZE(), 1); \
\
auto value = *begin; \
IS_VALUE(Numeric, value); \
if (is<Number>(begin->get())) { \
return makePtr<Decimal>(std::variant((double)std::static_pointer_cast<Number>(value)->number())); \
} \
\
return makePtr<Decimal>(std::variant(std::static_pointer_cast<Decimal>(value)->decimal())); \
}
ADD_FUNCTION(
"cos", "arg",
"Return the cosine of ARG.",
MATH_COS_SIN(cos));
ADD_FUNCTION(
"sin", "arg",
"Return the sine of ARG.",
MATH_COS_SIN(sin));
}
} // namespace blaze
+33 -6
View File
@@ -4,8 +4,11 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <chrono> // std::chrono::sytem_clock #include <chrono> // std::chrono::sytem_clock
#include <cstdint> // int64_t #include <cstdint> // int64_t
#include <filesystem> // std::filesystem::current_path
#include "ruc/file.h"
#include "blaze/ast.h" #include "blaze/ast.h"
#include "blaze/env/macro.h" #include "blaze/env/macro.h"
@@ -17,10 +20,35 @@ namespace blaze {
void Environment::loadOther() void Environment::loadOther()
{ {
ADD_FUNCTION(
"pwd", "",
"Return the full filename of the current working directory.",
{
CHECK_ARG_COUNT_IS("pwd", SIZE(), 0);
auto path = std::filesystem::current_path().string();
return makePtr<String>(path);
});
ADD_FUNCTION(
"slurp", "",
"Read file contents",
{
CHECK_ARG_COUNT_IS("slurp", SIZE(), 1);
VALUE_CAST(node, String, (*begin));
std::string path = node->data();
auto file = ruc::File(path);
return makePtr<String>(file.data());
});
// -----------------------------------------
// (throw x) // (throw x)
ADD_FUNCTION( ADD_FUNCTION(
"throw", "throw", "",
"",
"", "",
{ {
CHECK_ARG_COUNT_IS("throw", SIZE(), 1); CHECK_ARG_COUNT_IS("throw", SIZE(), 1);
@@ -34,8 +62,7 @@ void Environment::loadOther()
// (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);
-18
View File
@@ -6,8 +6,6 @@
#include <string> #include <string>
#include "ruc/file.h"
#include "blaze/ast.h" #include "blaze/ast.h"
#include "blaze/env/macro.h" #include "blaze/env/macro.h"
#include "blaze/repl.h" #include "blaze/repl.h"
@@ -31,22 +29,6 @@ void Environment::loadRepl()
return Repl::read(input); return Repl::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<String>(file.data());
});
// Prompt readline // Prompt readline
ADD_FUNCTION( ADD_FUNCTION(
"readline", "readline",
+4 -2
View File
@@ -6,15 +6,17 @@
#pragma once #pragma once
#include <iterator> // std::distance
#include <unordered_map> #include <unordered_map>
#include "blaze/env/environment.h" #include "blaze/env/environment.h"
#include "blaze/forward.h"
#define ADD_FUNCTION(name, signature, documentation, lambda) \ #define ADD_FUNCTION(name, signature, documentation, lambda) \
Environment::registerFunction( \ blaze::Environment::registerFunction( \
{ name, \ { name, \
signature, \ signature, \
documentation, \ documentation, \
[](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda }); [](blaze::ValueVectorConstIt begin, blaze::ValueVectorConstIt end) -> blaze::ValuePtr lambda });
#define SIZE() std::distance(begin, end) #define SIZE() std::distance(begin, end)
+2
View File
@@ -15,7 +15,9 @@ namespace blaze {
// Types // Types
class Value; class Value;
class HashMap;
typedef std::shared_ptr<Value> ValuePtr; typedef std::shared_ptr<Value> ValuePtr;
typedef std::shared_ptr<HashMap> HashMapPtr;
typedef std::vector<ValuePtr> ValueVector; typedef std::vector<ValuePtr> ValueVector;
typedef ValueVector::iterator ValueVectorIt; typedef ValueVector::iterator ValueVectorIt;
typedef ValueVector::reverse_iterator ValueVectorReverseIt; typedef ValueVector::reverse_iterator ValueVectorReverseIt;
+10 -4
View File
@@ -25,12 +25,18 @@
namespace blaze { namespace blaze {
Readline g_readline; Readline g_readline;
EnvironmentPtr g_outer_env = Environment::create(); EnvironmentPtr g_outer_env;
auto Repl::cleanup(int signal) -> void auto Repl::init() -> void
{ {
::print("\033[0m\n"); g_outer_env = Environment::create();
std::exit(signal); Environment::loadFunctions();
Environment::installFunctions(g_outer_env);
}
auto Repl::cleanup() -> void
{
g_outer_env = nullptr;
} }
auto Repl::readline(const std::string& prompt) -> ValuePtr auto Repl::readline(const std::string& prompt) -> ValuePtr
+3 -1
View File
@@ -17,7 +17,9 @@ namespace blaze {
class Repl { class Repl {
public: public:
static auto cleanup(int signal) -> void; static auto init() -> void;
static auto cleanup() -> void;
static auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr; static auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr;
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void; static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void;
static auto print(ValuePtr value) -> std::string; static auto print(ValuePtr value) -> std::string;
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <utility> // std::forward
#include "ruc/meta/odr.h"
namespace blaze {
namespace detail {
// struct hashMapConstructor {
// template<typename HashMap>
// static void construct(HashMap& hash_map, bool boolean)
// {
// //..
// }
// };
// template<typename HashMap, typename T>
// void toHashMap(HashMap& hash_map, const T& value)
// {
// hashMapConstructor::construct(hash_map, value);
// }
struct toHashMapFunction {
template<typename HashMapPtr, typename T>
auto operator()(HashMapPtr& hash_map, T&& value) const
{
return to_hash_map(hash_map, std::forward<T>(value));
}
};
} // namespace detail
// Anonymous namespace prevents multiple definition of the reference
namespace {
// Function object
constexpr const auto& to_hash_map = ruc::detail::staticConst<detail::toHashMapFunction>; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable)
} // namespace
} // namespace blaze
// Customization Points
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
// blaze::to_hash_map is a function object, the type of which is
// blaze::detail::toHashMapFunction. In the blaze::detail namespace are the to_hash_map
// free functions. The function call operator of toHashMapFunction makes an
// unqualified call to to_hash_map which, since it shares the detail namespace with
// the to_hash_map free functions, will consider those in addition to any overloads
// that are found by argument-dependent lookup.
// Variable templates are linked externally, therefor every translation unit
// will see the same address for detail::staticConst<detail::toHashMapFunction>.
// Since blaze::to_hash_map is a reference to the variable template, it too will have
// the same address in all translation units.
+20 -20
View File
@@ -34,10 +34,10 @@
// ----------------------------------------- // -----------------------------------------
#define CHECK_ARG_COUNT_IS_IMPL(name, size, expected, result) \ #define CHECK_ARG_COUNT_IS_IMPL(name, size, expected, result) \
if (size != expected) { \ if (size != expected) { \
Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \ blaze::Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \
return result; \ return result; \
} }
#define CHECK_ARG_COUNT_IS_3(name, size, expected) \ #define CHECK_ARG_COUNT_IS_3(name, size, expected) \
@@ -52,10 +52,10 @@
// ----------------------------------------- // -----------------------------------------
#define CHECK_ARG_COUNT_AT_LEAST_IMPL(name, size, min, result) \ #define CHECK_ARG_COUNT_AT_LEAST_IMPL(name, size, min, result) \
if (size < min) { \ if (size < min) { \
Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \ blaze::Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \
return result; \ return result; \
} }
#define CHECK_ARG_COUNT_AT_LEAST_3(name, size, min) \ #define CHECK_ARG_COUNT_AT_LEAST_3(name, size, min) \
@@ -70,10 +70,10 @@
// ----------------------------------------- // -----------------------------------------
#define CHECK_ARG_COUNT_BETWEEN_IMPL(name, size, min, max, result) \ #define CHECK_ARG_COUNT_BETWEEN_IMPL(name, size, min, max, result) \
if (size < min || size > max) { \ if (size < min || size > max) { \
Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \ blaze::Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \
return result; \ return result; \
} }
#define CHECK_ARG_COUNT_BETWEEN_4(name, size, min, max) \ #define CHECK_ARG_COUNT_BETWEEN_4(name, size, min, max) \
@@ -88,10 +88,10 @@
// ----------------------------------------- // -----------------------------------------
#define CHECK_ARG_COUNT_EVEN_IMPL(name, size, result) \ #define CHECK_ARG_COUNT_EVEN_IMPL(name, size, result) \
if (size % 2 != 0) { \ if (size % 2 != 0) { \
Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \ blaze::Error::the().add(::format("wrong number of arguments: {}, {}", name, size)); \
return result; \ return result; \
} }
#define CHECK_ARG_COUNT_EVEN_2(name, size) \ #define CHECK_ARG_COUNT_EVEN_2(name, size) \
@@ -106,10 +106,10 @@
// ----------------------------------------- // -----------------------------------------
#define IS_VALUE_IMPL(type, value, result) \ #define IS_VALUE_IMPL(type, value, result) \
if (!is<type>(value.get())) { \ if (!is<type>(value.get())) { \
Error::the().add(::format("wrong argument type: {}, {}", #type, value)); \ blaze::Error::the().add(::format("wrong argument type: {}, {}", #type, value)); \
return result; \ return result; \
} }
#define IS_VALUE_2(type, value) \ #define IS_VALUE_2(type, value) \