Compare commits

...
9 Commits
26 changed files with 950 additions and 320 deletions
+40 -15
View File
@@ -2,7 +2,7 @@
# User config between these lines # User config between these lines
# Set project name # Set project name
set(PROJECT "blaze") set(PROJECT "stepA_mal")
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(BLAZE_STANDALONE TRUE) set(BLAZE_STANDALONE TRUE)
@@ -64,11 +64,26 @@ add_subdirectory("vendor/ruc")
# Define source files # Define source files
file(GLOB_RECURSE PROJECT_SOURCES "src/*.cpp") file(GLOB_RECURSE PROJECT_SOURCES "src/*.cpp")
file(GLOB_RECURSE EXCLUDED_SOURCES "src/step*.cpp")
list(REMOVE_ITEM PROJECT_SOURCES ${EXCLUDED_SOURCES})
add_executable(${PROJECT} ${PROJECT_SOURCES}) function(add_step TARGET_NAME MAIN_PATH)
target_include_directories(${PROJECT} PRIVATE add_executable(${TARGET_NAME} ${PROJECT_SOURCES} ${MAIN_PATH})
"src") target_include_directories(${TARGET_NAME} PRIVATE "src")
target_link_libraries(${PROJECT} readline ruc) target_link_libraries(${TARGET_NAME} readline ruc)
endfunction()
add_step(step0_repl "src/step0_repl.cpp")
add_step(step1_read_print "src/step1_read_print.cpp")
add_step(step2_eval "src/step2_eval.cpp")
add_step(step3_env "src/step3_env.cpp")
add_step(step4_if_fn_do "src/step4_if_fn_do.cpp")
add_step(step5_tco "src/step5_tco.cpp")
add_step(step6_file "src/step6_file.cpp")
add_step(step7_quote "src/step7_quote.cpp")
add_step(step8_macros "src/step8_macros.cpp")
add_step(step9_try "src/step9_try.cpp")
add_step(stepA_mal "src/stepA_mal.cpp")
# ------------------------------------------ # ------------------------------------------
# Execute target # Execute target
@@ -81,41 +96,51 @@ add_custom_target(run
# Test targets # Test targets
add_custom_target(test0 add_custom_target(test0
COMMAND env STEP=step0_repl MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step0_repl.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step0_repl.mal -- ./${PROJECT})
add_dependencies(test0 ${PROJECT}) add_dependencies(test0 ${PROJECT})
add_custom_target(test1 add_custom_target(test1
COMMAND env STEP=step1_read_print MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step1_read_print.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step1_read_print.mal -- ./${PROJECT})
add_dependencies(test1 ${PROJECT}) add_dependencies(test1 ${PROJECT})
add_custom_target(test2 add_custom_target(test2
COMMAND env STEP=step_eval MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step2_eval.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step2_eval.mal -- ./${PROJECT})
add_dependencies(test2 ${PROJECT}) add_dependencies(test2 ${PROJECT})
add_custom_target(test3 add_custom_target(test3
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step3_env.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step3_env.mal -- ./${PROJECT})
add_dependencies(test3 ${PROJECT}) add_dependencies(test3 ${PROJECT})
add_custom_target(test4 add_custom_target(test4
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step4_if_fn_do.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step4_if_fn_do.mal -- ./${PROJECT})
add_dependencies(test4 ${PROJECT}) add_dependencies(test4 ${PROJECT})
add_custom_target(test5 add_custom_target(test5
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step5_tco.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step5_tco.mal -- ./${PROJECT})
add_dependencies(test5 ${PROJECT}) add_dependencies(test5 ${PROJECT})
add_custom_target(test6 add_custom_target(test6
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step6_file.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step6_file.mal -- ./${PROJECT})
add_dependencies(test6 ${PROJECT}) add_dependencies(test6 ${PROJECT})
add_custom_target(test7 add_custom_target(test7
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step7_quote.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step7_quote.mal -- ./${PROJECT})
add_dependencies(test7 ${PROJECT}) add_dependencies(test7 ${PROJECT})
add_custom_target(test8 add_custom_target(test8
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step8_macros.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step8_macros.mal -- ./${PROJECT})
add_dependencies(test8 ${PROJECT}) add_dependencies(test8 ${PROJECT})
add_custom_target(test9 add_custom_target(test9
COMMAND env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step9_try.mal -- ./${PROJECT}) COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/step9_try.mal -- ./${PROJECT})
add_dependencies(test9 ${PROJECT}) add_dependencies(test9 ${PROJECT})
add_custom_target(testA
COMMAND ../vendor/mal/runtest.py --deferrable --optional ../tests/stepA_mal.mal -- ./${PROJECT})
add_dependencies(testA ${PROJECT})
add_custom_target(perf
COMMAND ./${PROJECT} ../tests/perf1.mal
COMMAND ./${PROJECT} ../tests/perf2.mal
COMMAND ./${PROJECT} ../tests/perf3.mal)
add_dependencies(perf ${PROJECT})
Symlink
+1
View File
@@ -0,0 +1 @@
vendor/mal/impls/lib
Symlink
+1
View File
@@ -0,0 +1 @@
vendor/mal/impls/mal
+113 -9
View File
@@ -5,8 +5,9 @@
*/ */
#include <cstdint> // int64_t #include <cstdint> // int64_t
#include <memory> #include <memory> // std::static_pointer_cast
#include <string> #include <string>
#include <vector>
#include "ast.h" #include "ast.h"
#include "environment.h" #include "environment.h"
@@ -17,11 +18,39 @@
namespace blaze { namespace blaze {
Collection::Collection(const std::list<ValuePtr>& nodes) ValuePtr Value::withMeta(ValuePtr meta) const
{
return withMetaImpl(meta);
}
ValuePtr Value::meta() const
{
return (m_meta == nullptr) ? makePtr<Constant>() : m_meta;
}
// -----------------------------------------
Collection::Collection(const ValueVector& nodes)
: m_nodes(nodes) : m_nodes(nodes)
{ {
} }
Collection::Collection(ValueVectorIt begin, ValueVectorIt end)
: m_nodes(ValueVector(begin, end))
{
}
Collection::Collection(ValueVectorConstIt begin, ValueVectorConstIt end)
: m_nodes(ValueVector(begin, end))
{
}
Collection::Collection(const Collection& that, ValuePtr meta)
: Value(meta)
, m_nodes(that.m_nodes)
{
}
void Collection::add(ValuePtr node) void Collection::add(ValuePtr node)
{ {
if (node == nullptr) { if (node == nullptr) {
@@ -31,20 +60,56 @@ void Collection::add(ValuePtr node)
m_nodes.push_back(node); m_nodes.push_back(node);
} }
ValueVector Collection::rest() const
{
auto start = (m_nodes.size() > 0) ? m_nodes.begin() + 1 : m_nodes.end();
return ValueVector(start, m_nodes.end());
}
// ----------------------------------------- // -----------------------------------------
List::List(const std::list<ValuePtr>& nodes) List::List(const ValueVector& nodes)
: Collection(nodes) : Collection(nodes)
{ {
} }
List::List(ValueVectorIt begin, ValueVectorIt end)
: Collection(begin, end)
{
}
List::List(ValueVectorConstIt begin, ValueVectorConstIt end)
: Collection(begin, end)
{
}
List::List(const List& that, ValuePtr meta)
: Collection(that, meta)
{
}
// ----------------------------------------- // -----------------------------------------
Vector::Vector(const std::list<ValuePtr>& nodes) Vector::Vector(const ValueVector& nodes)
: Collection(nodes) : Collection(nodes)
{ {
} }
Vector::Vector(ValueVectorIt begin, ValueVectorIt end)
: Collection(begin, end)
{
}
Vector::Vector(ValueVectorConstIt begin, ValueVectorConstIt end)
: Collection(begin, end)
{
}
Vector::Vector(const Vector& that, ValuePtr meta)
: Collection(that, meta)
{
}
// ----------------------------------------- // -----------------------------------------
HashMap::HashMap(const Elements& elements) HashMap::HashMap(const Elements& elements)
@@ -52,6 +117,12 @@ HashMap::HashMap(const Elements& elements)
{ {
} }
HashMap::HashMap(const HashMap& that, ValuePtr meta)
: Value(meta)
, m_elements(that.m_elements)
{
}
void HashMap::add(const std::string& key, ValuePtr value) void HashMap::add(const std::string& key, ValuePtr value)
{ {
if (value == nullptr) { if (value == nullptr) {
@@ -127,6 +198,11 @@ String::String(const std::string& data)
{ {
} }
String::String(char character)
: m_data(std::string(1, character))
{
}
// ----------------------------------------- // -----------------------------------------
Keyword::Keyword(const std::string& data) Keyword::Keyword(const std::string& data)
@@ -162,12 +238,26 @@ Symbol::Symbol(const std::string& symbol)
// ----------------------------------------- // -----------------------------------------
Callable::Callable(ValuePtr meta)
: Value(meta)
{
}
// -----------------------------------------
Function::Function(const std::string& name, FunctionType function) Function::Function(const std::string& name, FunctionType function)
: m_name(name) : m_name(name)
, m_function(function) , m_function(function)
{ {
} }
Function::Function(const Function& that, ValuePtr meta)
: Callable(meta)
, m_name(that.m_name)
, m_function(that.m_function)
{
}
// ----------------------------------------- // -----------------------------------------
Lambda::Lambda(const std::vector<std::string>& bindings, ValuePtr body, EnvironmentPtr env) Lambda::Lambda(const std::vector<std::string>& bindings, ValuePtr body, EnvironmentPtr env)
@@ -177,11 +267,25 @@ Lambda::Lambda(const std::vector<std::string>& bindings, ValuePtr body, Environm
{ {
} }
Lambda::Lambda(std::shared_ptr<Lambda> that, bool is_macro) Lambda::Lambda(const Lambda& that)
: m_bindings(that->m_bindings) : m_bindings(that.m_bindings)
, m_body(that->m_body) , m_body(that.m_body)
, m_env(that->m_env) , m_env(that.m_env)
, m_is_macro(is_macro) {
}
Lambda::Lambda(const Lambda& that, ValuePtr meta)
: Callable(meta)
, m_bindings(that.m_bindings)
, m_body(that.m_body)
, m_env(that.m_env)
{
}
// -----------------------------------------
Macro::Macro(const Lambda& that)
: Lambda(that)
{ {
} }
+99 -18
View File
@@ -24,10 +24,23 @@
namespace blaze { namespace blaze {
template<typename T, typename... Args>
std::shared_ptr<T> makePtr(Args&&... args)
{
return std::make_shared<T>(std::forward<Args>(args)...);
}
// -----------------------------------------
class Value { class Value {
public: public:
virtual ~Value() = default; virtual ~Value() = default;
virtual ValuePtr withMetaImpl(ValuePtr meta) const = 0;
ValuePtr withMeta(ValuePtr meta) const;
ValuePtr meta() const;
std::string className() const { return typeid(*this).name(); } std::string className() const { return typeid(*this).name(); }
template<typename T> template<typename T>
@@ -45,12 +58,33 @@ public:
virtual bool isCallable() const { return false; } virtual bool isCallable() const { return false; }
virtual bool isFunction() const { return false; } virtual bool isFunction() const { return false; }
virtual bool isLambda() const { return false; } virtual bool isLambda() const { return false; }
virtual bool isMacro() const { return false; }
virtual bool isAtom() const { return false; } virtual bool isAtom() const { return false; }
protected: protected:
Value() {} Value() {}
Value(ValuePtr meta)
: m_meta(meta)
{
}
ValuePtr m_meta;
}; };
#define WITH_META(Type) \
virtual ValuePtr withMetaImpl(ValuePtr meta) const override \
{ \
return makePtr<Type>(*this, meta); \
}
#define WITH_NO_META() \
virtual ValuePtr withMetaImpl(ValuePtr meta) const override \
{ \
(void)meta; \
return nullptr; \
}
// ----------------------------------------- // -----------------------------------------
template<typename T> template<typename T>
@@ -62,14 +96,21 @@ public:
void add(ValuePtr node); void add(ValuePtr node);
// TODO: rename size -> count
size_t size() const { return m_nodes.size(); } size_t size() const { return m_nodes.size(); }
bool empty() const { return m_nodes.size() == 0; } bool empty() const { return m_nodes.size() == 0; }
const std::list<ValuePtr>& nodes() const { return m_nodes; } ValuePtr front() const { return m_nodes.front(); }
ValueVector rest() const;
const ValueVector& nodes() const { return m_nodes; }
protected: protected:
Collection() = default; Collection() = default;
Collection(const std::list<ValuePtr>& nodes); Collection(const ValueVector& nodes);
Collection(ValueVectorIt begin, ValueVectorIt end);
Collection(ValueVectorConstIt begin, ValueVectorConstIt end);
Collection(const Collection& that, ValuePtr meta);
template<IsValue... Ts> template<IsValue... Ts>
Collection(std::shared_ptr<Ts>... nodes) Collection(std::shared_ptr<Ts>... nodes)
@@ -80,7 +121,7 @@ protected:
private: private:
virtual bool isCollection() const override { return true; } virtual bool isCollection() const override { return true; }
std::list<ValuePtr> m_nodes; ValueVector m_nodes;
}; };
// ----------------------------------------- // -----------------------------------------
@@ -89,7 +130,10 @@ private:
class List final : public Collection { class List final : public Collection {
public: public:
List() = default; List() = default;
List(const std::list<ValuePtr>& nodes); List(const ValueVector& nodes);
List(ValueVectorIt begin, ValueVectorIt end);
List(ValueVectorConstIt begin, ValueVectorConstIt end);
List(const List& that, ValuePtr meta);
template<IsValue... Ts> template<IsValue... Ts>
List(std::shared_ptr<Ts>... nodes) List(std::shared_ptr<Ts>... nodes)
@@ -99,6 +143,8 @@ public:
virtual ~List() = default; virtual ~List() = default;
WITH_META(List);
private: private:
virtual bool isList() const override { return true; } virtual bool isList() const override { return true; }
}; };
@@ -109,7 +155,10 @@ private:
class Vector final : public Collection { class Vector final : public Collection {
public: public:
Vector() = default; Vector() = default;
Vector(const std::list<ValuePtr>& nodes); Vector(const ValueVector& nodes);
Vector(ValueVectorIt begin, ValueVectorIt end);
Vector(ValueVectorConstIt begin, ValueVectorConstIt end);
Vector(const Vector& that, ValuePtr meta);
template<IsValue... Ts> template<IsValue... Ts>
Vector(std::shared_ptr<Ts>... nodes) Vector(std::shared_ptr<Ts>... nodes)
@@ -119,6 +168,8 @@ public:
virtual ~Vector() = default; virtual ~Vector() = default;
WITH_META(Vector);
private: private:
virtual bool isVector() const override { return true; } virtual bool isVector() const override { return true; }
}; };
@@ -132,6 +183,7 @@ public:
HashMap() = default; HashMap() = default;
HashMap(const Elements& elements); HashMap(const Elements& elements);
HashMap(const HashMap& that, ValuePtr meta);
virtual ~HashMap() = default; virtual ~HashMap() = default;
void add(const std::string& key, ValuePtr value); void add(const std::string& key, ValuePtr value);
@@ -147,6 +199,8 @@ public:
size_t size() const { return m_elements.size(); } size_t size() const { return m_elements.size(); }
bool empty() const { return m_elements.size() == 0; } bool empty() const { return m_elements.size() == 0; }
WITH_META(HashMap);
private: private:
virtual bool isHashMap() const override { return true; } virtual bool isHashMap() const override { return true; }
@@ -161,9 +215,13 @@ private:
class String final : public Value { class String final : public Value {
public: public:
String(const std::string& data); String(const std::string& data);
String(char character);
virtual ~String() = default; virtual ~String() = default;
const std::string& data() const { return m_data; } const std::string& data() const { return m_data; }
bool empty() const { return m_data.empty(); }
WITH_NO_META();
private: private:
virtual bool isString() const override { return true; } virtual bool isString() const override { return true; }
@@ -183,6 +241,8 @@ public:
const std::string& keyword() const { return m_data; } const std::string& keyword() const { return m_data; }
WITH_NO_META();
private: private:
const std::string m_data; const std::string m_data;
}; };
@@ -196,6 +256,8 @@ public:
int64_t number() const { return m_number; } int64_t number() const { return m_number; }
WITH_NO_META();
private: private:
virtual bool isNumber() const override { return true; } virtual bool isNumber() const override { return true; }
@@ -220,6 +282,8 @@ public:
State state() const { return m_state; } State state() const { return m_state; }
WITH_NO_META();
private: private:
virtual bool isConstant() const override { return true; } virtual bool isConstant() const override { return true; }
@@ -236,6 +300,8 @@ public:
const std::string& symbol() const { return m_symbol; } const std::string& symbol() const { return m_symbol; }
WITH_NO_META();
private: private:
virtual bool isSymbol() const override { return true; } virtual bool isSymbol() const override { return true; }
@@ -250,6 +316,7 @@ public:
protected: protected:
Callable() = default; Callable() = default;
Callable(ValuePtr meta);
private: private:
virtual bool isCallable() const override { return true; } virtual bool isCallable() const override { return true; }
@@ -257,16 +324,19 @@ private:
// ----------------------------------------- // -----------------------------------------
using FunctionType = std::function<ValuePtr(std::list<ValuePtr>)>; using FunctionType = std::function<ValuePtr(ValueVectorIt, ValueVectorIt)>;
class Function final : public Callable { class Function final : public Callable {
public: public:
Function(const std::string& name, FunctionType function); Function(const std::string& name, FunctionType function);
Function(const Function& that, ValuePtr meta);
virtual ~Function() = default; virtual ~Function() = default;
const std::string& name() const { return m_name; } const std::string& name() const { return m_name; }
FunctionType function() const { return m_function; } FunctionType function() const { return m_function; }
WITH_META(Function);
private: private:
virtual bool isFunction() const override { return true; } virtual bool isFunction() const override { return true; }
@@ -276,16 +346,18 @@ private:
// ----------------------------------------- // -----------------------------------------
class Lambda final : public Callable { class Lambda : public Callable {
public: public:
Lambda(const std::vector<std::string>& bindings, ValuePtr body, EnvironmentPtr env); Lambda(const std::vector<std::string>& bindings, ValuePtr body, EnvironmentPtr env);
Lambda(std::shared_ptr<Lambda> that, bool is_macro); Lambda(const Lambda& that);
Lambda(const Lambda& that, ValuePtr meta);
virtual ~Lambda() = default; virtual ~Lambda() = default;
const std::vector<std::string>& bindings() const { return m_bindings; } const std::vector<std::string>& bindings() const { return m_bindings; }
ValuePtr body() const { return m_body; } ValuePtr body() const { return m_body; }
EnvironmentPtr env() const { return m_env; } EnvironmentPtr env() const { return m_env; }
bool isMacro() const { return m_is_macro; }
WITH_META(Lambda);
private: private:
virtual bool isLambda() const override { return true; } virtual bool isLambda() const override { return true; }
@@ -293,7 +365,19 @@ private:
const std::vector<std::string> m_bindings; const std::vector<std::string> m_bindings;
const ValuePtr m_body; const ValuePtr m_body;
const EnvironmentPtr m_env; const EnvironmentPtr m_env;
const bool m_is_macro { false }; };
// -----------------------------------------
class Macro final : public Lambda {
public:
Macro(const Lambda& that);
WITH_NO_META();
private:
virtual bool isLambda() const override { return false; }
virtual bool isMacro() const override { return true; }
}; };
// ----------------------------------------- // -----------------------------------------
@@ -307,6 +391,8 @@ public:
ValuePtr reset(ValuePtr value) { return m_value = value; } ValuePtr reset(ValuePtr value) { return m_value = value; }
ValuePtr deref() const { return m_value; } ValuePtr deref() const { return m_value; }
WITH_NO_META();
private: private:
virtual bool isAtom() const override { return true; } virtual bool isAtom() const override { return true; }
@@ -315,14 +401,6 @@ private:
// ----------------------------------------- // -----------------------------------------
template<typename T, typename... Args>
std::shared_ptr<T> makePtr(Args&&... args)
{
return std::make_shared<T>(std::forward<Args>(args)...);
}
// -----------------------------------------
// clang-format off // clang-format off
template<> template<>
inline bool Value::fastIs<Collection>() const { return isCollection(); } inline bool Value::fastIs<Collection>() const { return isCollection(); }
@@ -360,6 +438,9 @@ inline bool Value::fastIs<Function>() const { return isFunction(); }
template<> template<>
inline bool Value::fastIs<Lambda>() const { return isLambda(); } inline bool Value::fastIs<Lambda>() const { return isLambda(); }
template<>
inline bool Value::fastIs<Macro>() const { return isMacro(); }
template<> template<>
inline bool Value::fastIs<Atom>() const { return isAtom(); } inline bool Value::fastIs<Atom>() const { return isAtom(); }
// clang-format on // clang-format on
+1 -1
View File
@@ -29,7 +29,7 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer)
return env; return env;
} }
EnvironmentPtr Environment::create(const ValuePtr lambda, const std::list<ValuePtr>& arguments) EnvironmentPtr Environment::create(const ValuePtr lambda, const ValueVector& arguments)
{ {
auto lambda_casted = std::static_pointer_cast<Lambda>(lambda); auto lambda_casted = std::static_pointer_cast<Lambda>(lambda);
auto env = create(lambda_casted->env()); auto env = create(lambda_casted->env());
+1 -1
View File
@@ -21,7 +21,7 @@ public:
// Factory functions instead of constructors because it can fail in the bindings/arguments case // Factory functions instead of constructors because it can fail in the bindings/arguments case
static EnvironmentPtr create(); static EnvironmentPtr create();
static EnvironmentPtr create(EnvironmentPtr outer); static EnvironmentPtr create(EnvironmentPtr outer);
static EnvironmentPtr create(const ValuePtr lambda, const std::list<ValuePtr>& arguments); static EnvironmentPtr create(const ValuePtr lambda, const ValueVector& arguments);
bool exists(const std::string& symbol); bool exists(const std::string& symbol);
ValuePtr set(const std::string& symbol, ValuePtr value); ValuePtr set(const std::string& symbol, ValuePtr value);
+21 -19
View File
@@ -22,7 +22,7 @@ namespace blaze {
static ValuePtr evalQuasiQuoteImpl(ValuePtr ast); static ValuePtr evalQuasiQuoteImpl(ValuePtr ast);
// (def! x 2) // (def! x 2)
ValuePtr Eval::evalDef(const std::list<ValuePtr>& nodes, EnvironmentPtr env) ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("def!", nodes.size(), 2); CHECK_ARG_COUNT_IS("def!", nodes.size(), 2);
@@ -44,7 +44,7 @@ ValuePtr Eval::evalDef(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
} }
// (defmacro! x (fn* (x) x)) // (defmacro! x (fn* (x) x))
ValuePtr Eval::evalDefMacro(const std::list<ValuePtr>& nodes, EnvironmentPtr env) ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("defmacro!", nodes.size(), 2); CHECK_ARG_COUNT_IS("defmacro!", nodes.size(), 2);
@@ -63,19 +63,21 @@ ValuePtr Eval::evalDefMacro(const std::list<ValuePtr>& nodes, EnvironmentPtr env
} }
// Modify existing environment // Modify existing environment
return env->set(symbol->symbol(), makePtr<Lambda>(lambda, true)); return env->set(symbol->symbol(), makePtr<Macro>(*lambda));
} }
// (fn* (x) x) // (fn* (x) x)
ValuePtr Eval::evalFn(const std::list<ValuePtr>& nodes, EnvironmentPtr env) ValuePtr Eval::evalFn(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("fn*", nodes.size(), 2); CHECK_ARG_COUNT_IS("fn*", nodes.size(), 2);
// First element needs to be a List or Vector // First element needs to be a List or Vector
VALUE_CAST(collection, Collection, nodes.front()); VALUE_CAST(collection, Collection, nodes.front());
const auto& collection_nodes = collection->nodes();
std::vector<std::string> bindings; std::vector<std::string> bindings;
for (auto node : collection->nodes()) { bindings.reserve(collection_nodes.size());
for (const auto& node : collection_nodes) {
// All nodes need to be a Symbol // All nodes need to be a Symbol
VALUE_CAST(symbol, Symbol, node); VALUE_CAST(symbol, Symbol, node);
bindings.push_back(symbol->symbol()); bindings.push_back(symbol->symbol());
@@ -86,7 +88,7 @@ ValuePtr Eval::evalFn(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
return makePtr<Lambda>(bindings, *std::next(nodes.begin()), env); return makePtr<Lambda>(bindings, *std::next(nodes.begin()), env);
} }
ValuePtr Eval::evalMacroExpand(const std::list<ValuePtr>& nodes, EnvironmentPtr env) ValuePtr Eval::evalMacroExpand(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("macroexpand", nodes.size(), 1); CHECK_ARG_COUNT_IS("macroexpand", nodes.size(), 1);
@@ -94,7 +96,7 @@ ValuePtr Eval::evalMacroExpand(const std::list<ValuePtr>& nodes, EnvironmentPtr
} }
// (quasiquoteexpand x) // (quasiquoteexpand x)
ValuePtr Eval::evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes) ValuePtr Eval::evalQuasiQuoteExpand(const ValueVector& nodes)
{ {
CHECK_ARG_COUNT_IS("quasiquoteexpand", nodes.size(), 1); CHECK_ARG_COUNT_IS("quasiquoteexpand", nodes.size(), 1);
@@ -102,7 +104,7 @@ ValuePtr Eval::evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes)
} }
// (quote x) // (quote x)
ValuePtr Eval::evalQuote(const std::list<ValuePtr>& nodes) ValuePtr Eval::evalQuote(const ValueVector& nodes)
{ {
CHECK_ARG_COUNT_IS("quote", nodes.size(), 1); CHECK_ARG_COUNT_IS("quote", nodes.size(), 1);
@@ -110,7 +112,7 @@ ValuePtr Eval::evalQuote(const std::list<ValuePtr>& nodes)
} }
// (do 1 2 3) // (do 1 2 3)
void Eval::evalDo(const std::list<ValuePtr>& nodes, EnvironmentPtr env) void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_AT_LEAST("do", nodes.size(), 1, void()); CHECK_ARG_COUNT_AT_LEAST("do", nodes.size(), 1, void());
@@ -128,7 +130,7 @@ void Eval::evalDo(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
} }
// (if x true false) // (if x true false)
void Eval::evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env) void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_BETWEEN("if", nodes.size(), 2, 3, void()); CHECK_ARG_COUNT_BETWEEN("if", nodes.size(), 2, 3, void());
@@ -152,13 +154,13 @@ void Eval::evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
} }
// (let* (x 1) x) // (let* (x 1) x)
void Eval::evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env) void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("let*", nodes.size(), 2, void()); CHECK_ARG_COUNT_IS("let*", nodes.size(), 2, void());
// First argument needs to be a List or Vector // First argument needs to be a List or Vector
VALUE_CAST(bindings, Collection, nodes.front(), void()); VALUE_CAST(bindings, Collection, nodes.front(), void());
auto binding_nodes = bindings->nodes(); const auto& binding_nodes = bindings->nodes();
// List or Vector needs to have an even number of elements // List or Vector needs to have an even number of elements
CHECK_ARG_COUNT_EVEN("bindings", binding_nodes.size(), void()); CHECK_ARG_COUNT_EVEN("bindings", binding_nodes.size(), void());
@@ -207,7 +209,7 @@ static ValuePtr startsWith(ValuePtr ast, const std::string& symbol)
return nullptr; return nullptr;
} }
auto nodes = std::static_pointer_cast<List>(ast)->nodes(); const auto& nodes = std::static_pointer_cast<List>(ast)->nodes();
if (nodes.empty() || !isSymbol(nodes.front(), symbol)) { if (nodes.empty() || !isSymbol(nodes.front(), symbol)) {
return nullptr; return nullptr;
@@ -243,11 +245,11 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast)
ValuePtr result = makePtr<List>(); ValuePtr result = makePtr<List>();
auto nodes = std::static_pointer_cast<Collection>(ast)->nodes(); const auto& nodes = std::static_pointer_cast<Collection>(ast)->nodes();
// `() or `(1 ~2 3) or `(1 ~@(list 2 2 2) 3) // `() or `(1 ~2 3) or `(1 ~@(list 2 2 2) 3)
for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) { for (auto it = nodes.crbegin(); it != nodes.crend(); ++it) {
const auto elt = *it; const auto& elt = *it;
const auto splice_unquote = startsWith(elt, "splice-unquote"); // (list 2 2 2) const auto splice_unquote = startsWith(elt, "splice-unquote"); // (list 2 2 2)
if (splice_unquote) { if (splice_unquote) {
@@ -269,7 +271,7 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast)
} }
// (quasiquote x) // (quasiquote x)
void Eval::evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env) void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_IS("quasiquote", nodes.size(), 1, void()); CHECK_ARG_COUNT_IS("quasiquote", nodes.size(), 1, void());
@@ -281,7 +283,7 @@ void Eval::evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
} }
// (try* x (catch* y z)) // (try* x (catch* y z))
void Eval::evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env) void Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1, void()); CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1, void());
@@ -299,7 +301,7 @@ void Eval::evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
Error::the().clearErrors(); Error::the().clearErrors();
VALUE_CAST(catch_list, List, nodes.back(), void()); VALUE_CAST(catch_list, List, nodes.back(), void());
auto catch_nodes = catch_list->nodes(); const auto& catch_nodes = catch_list->nodes();
CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2, void()); CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2, void());
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front(), void()); VALUE_CAST(catch_symbol, Symbol, catch_nodes.front(), void());
+22 -29
View File
@@ -79,10 +79,9 @@ ValuePtr Eval::evalImpl()
} }
// Special forms // Special forms
auto nodes = list->nodes(); if (is<Symbol>(list->front().get())) {
if (is<Symbol>(nodes.front().get())) { auto symbol = std::static_pointer_cast<Symbol>(list->front())->symbol();
auto symbol = std::static_pointer_cast<Symbol>(nodes.front())->symbol(); const auto& nodes = list->rest();
nodes.pop_front();
if (symbol == "def!") { if (symbol == "def!") {
return evalDef(nodes, env); return evalDef(nodes, env);
} }
@@ -131,16 +130,11 @@ ValuePtr Eval::evalImpl()
} }
// Regular list // Regular list
if (is<Lambda>(evaluated_list->nodes().front().get())) { if (is<Lambda>(evaluated_list->front().get())) {
auto evaluated_nodes = evaluated_list->nodes(); auto lambda = std::static_pointer_cast<Lambda>(evaluated_list->front());
// car
auto lambda = std::static_pointer_cast<Lambda>(evaluated_nodes.front());
// cdr
evaluated_nodes.pop_front();
m_ast_stack.push(lambda->body()); m_ast_stack.push(lambda->body());
m_env_stack.push(Environment::create(lambda, evaluated_nodes)); m_env_stack.push(Environment::create(lambda, evaluated_list->rest()));
continue; // TCO continue; // TCO
} }
@@ -167,8 +161,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
else if (is<Collection>(ast_raw_ptr)) { else if (is<Collection>(ast_raw_ptr)) {
std::shared_ptr<Collection> result = nullptr; std::shared_ptr<Collection> result = nullptr;
(is<List>(ast_raw_ptr)) ? result = makePtr<List>() : result = makePtr<Vector>(); (is<List>(ast_raw_ptr)) ? result = makePtr<List>() : result = makePtr<Vector>();
auto nodes = std::static_pointer_cast<Collection>(ast)->nodes(); const auto& nodes = std::static_pointer_cast<Collection>(ast)->nodes();
for (auto node : nodes) { for (const auto& node : nodes) {
m_ast_stack.push(node); m_ast_stack.push(node);
m_env_stack.push(env); m_env_stack.push(env);
ValuePtr eval_node = evalImpl(); ValuePtr eval_node = evalImpl();
@@ -181,8 +175,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
} }
else if (is<HashMap>(ast_raw_ptr)) { else if (is<HashMap>(ast_raw_ptr)) {
auto result = makePtr<HashMap>(); auto result = makePtr<HashMap>();
auto elements = std::static_pointer_cast<HashMap>(ast)->elements(); const auto& elements = std::static_pointer_cast<HashMap>(ast)->elements();
for (auto& element : elements) { for (const auto& element : elements) {
m_ast_stack.push(element.second); m_ast_stack.push(element.second);
m_env_stack.push(env); m_env_stack.push(env);
ValuePtr element_node = evalImpl(); ValuePtr element_node = evalImpl();
@@ -202,19 +196,22 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
// (x y z) // (x y z)
bool Eval::isMacroCall(ValuePtr ast, EnvironmentPtr env) bool Eval::isMacroCall(ValuePtr ast, EnvironmentPtr env)
{ {
if (!is<List>(ast.get())) { auto list = dynamic_cast<List*>(ast.get());
if (list == nullptr || list->empty()) {
return false; return false;
} }
auto nodes = std::static_pointer_cast<List>(ast)->nodes(); auto front = list->front().get();
if (nodes.size() == 0 || !is<Symbol>(nodes.front().get())) { if (!is<Symbol>(front)) {
return false; return false;
} }
auto value = env->get(std::static_pointer_cast<Symbol>(nodes.front())->symbol()); auto symbol = dynamic_cast<Symbol*>(front)->symbol();
auto value = env->get(symbol).get();
if (!is<Lambda>(value.get()) || !std::static_pointer_cast<Lambda>(value)->isMacro()) { if (!is<Macro>(value)) {
return false; return false;
} }
@@ -225,13 +222,12 @@ bool Eval::isMacroCall(ValuePtr ast, EnvironmentPtr env)
ValuePtr Eval::macroExpand(ValuePtr ast, EnvironmentPtr env) ValuePtr Eval::macroExpand(ValuePtr ast, EnvironmentPtr env)
{ {
while (isMacroCall(ast, env)) { while (isMacroCall(ast, env)) {
auto nodes = std::static_pointer_cast<List>(ast)->nodes(); auto list = std::static_pointer_cast<List>(ast);
auto value = env->get(std::static_pointer_cast<Symbol>(nodes.front())->symbol()); auto value = env->get(std::static_pointer_cast<Symbol>(list->front())->symbol());
auto lambda = std::static_pointer_cast<Lambda>(value); auto lambda = std::static_pointer_cast<Lambda>(value);
nodes.pop_front();
m_ast_stack.push(lambda->body()); m_ast_stack.push(lambda->body());
m_env_stack.push(Environment::create(lambda, nodes)); m_env_stack.push(Environment::create(lambda, list->rest()));
ast = evalImpl(); ast = evalImpl();
} }
@@ -253,12 +249,9 @@ ValuePtr Eval::apply(std::shared_ptr<List> evaluated_list)
return nullptr; return nullptr;
} }
// car
auto function = std::static_pointer_cast<Function>(nodes.front())->function(); auto function = std::static_pointer_cast<Function>(nodes.front())->function();
// cdr
nodes.pop_front();
return function(nodes); return function(nodes.begin() + 1, nodes.end());
} }
} // namespace blaze } // namespace blaze
+11 -11
View File
@@ -32,17 +32,17 @@ private:
bool isMacroCall(ValuePtr ast, EnvironmentPtr env); bool isMacroCall(ValuePtr ast, EnvironmentPtr env);
ValuePtr macroExpand(ValuePtr ast, EnvironmentPtr env); ValuePtr macroExpand(ValuePtr ast, EnvironmentPtr env);
ValuePtr evalDef(const std::list<ValuePtr>& nodes, EnvironmentPtr env); ValuePtr evalDef(const ValueVector& nodes, EnvironmentPtr env);
ValuePtr evalDefMacro(const std::list<ValuePtr>& nodes, EnvironmentPtr env); ValuePtr evalDefMacro(const ValueVector& nodes, EnvironmentPtr env);
ValuePtr evalFn(const std::list<ValuePtr>& nodes, EnvironmentPtr env); ValuePtr evalFn(const ValueVector& nodes, EnvironmentPtr env);
ValuePtr evalMacroExpand(const std::list<ValuePtr>& nodes, EnvironmentPtr env); ValuePtr evalMacroExpand(const ValueVector& nodes, EnvironmentPtr env);
ValuePtr evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes); ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
ValuePtr evalQuote(const std::list<ValuePtr>& nodes); ValuePtr evalQuote(const ValueVector& nodes);
void evalDo(const std::list<ValuePtr>& nodes, EnvironmentPtr env); void evalDo(const ValueVector& nodes, EnvironmentPtr env);
void evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env); void evalIf(const ValueVector& nodes, EnvironmentPtr env);
void evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env); void evalLet(const ValueVector& nodes, EnvironmentPtr env);
void evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env); void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env);
void evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env); void evalTry(const ValueVector& nodes, EnvironmentPtr env);
ValuePtr apply(std::shared_ptr<List> evaluated_list); ValuePtr apply(std::shared_ptr<List> evaluated_list);
+6 -1
View File
@@ -7,6 +7,7 @@
#pragma once #pragma once
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <vector>
namespace blaze { namespace blaze {
@@ -15,6 +16,9 @@ namespace blaze {
class Value; class Value;
typedef std::shared_ptr<Value> ValuePtr; typedef std::shared_ptr<Value> ValuePtr;
typedef std::vector<ValuePtr> ValueVector;
typedef ValueVector::iterator ValueVectorIt;
typedef ValueVector::const_iterator ValueVectorConstIt;
class Environment; class Environment;
typedef std::shared_ptr<Environment> EnvironmentPtr; typedef std::shared_ptr<Environment> EnvironmentPtr;
@@ -22,8 +26,9 @@ typedef std::shared_ptr<Environment> EnvironmentPtr;
// ----------------------------------------- // -----------------------------------------
// Functions // Functions
extern ValuePtr readline(const std::string& prompt);
extern ValuePtr read(std::string_view input); extern ValuePtr read(std::string_view input);
ValuePtr eval(ValuePtr ast, EnvironmentPtr env); extern ValuePtr eval(ValuePtr ast, EnvironmentPtr env);
extern void installFunctions(EnvironmentPtr env); extern void installFunctions(EnvironmentPtr env);
+371 -183
View File
@@ -4,8 +4,11 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <iterator> // std::advance #include <algorithm> // std::copy, std::reverse_copy
#include <memory> // std::static_pointer_cast #include <chrono> // std::chrono::sytem_clock
#include <cstdint> // int64_t
#include <iterator> // std::advance, std::distance, std::next, std::prev
#include <memory> // std::static_pointer_cast
#include <string> #include <string>
#include "ruc/file.h" #include "ruc/file.h"
@@ -36,10 +39,12 @@
static struct FUNCTION_STRUCT_NAME(unique) \ static struct FUNCTION_STRUCT_NAME(unique) \
FUNCTION_STRUCT_NAME(unique)( \ FUNCTION_STRUCT_NAME(unique)( \
symbol, \ symbol, \
[](std::list<ValuePtr> nodes) -> ValuePtr lambda); [](ValueVectorIt begin, ValueVectorIt end) -> ValuePtr lambda);
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda); #define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda);
#define SIZE() std::distance(begin, end)
namespace blaze { namespace blaze {
static std::unordered_map<std::string, FunctionType> s_functions; static std::unordered_map<std::string, FunctionType> s_functions;
@@ -49,8 +54,8 @@ ADD_FUNCTION(
{ {
int64_t result = 0; int64_t result = 0;
for (auto node : nodes) { for (auto it = begin; it != end; ++it) {
VALUE_CAST(number, Number, node); VALUE_CAST(number, Number, (*it));
result += number->number(); result += number->number();
} }
@@ -60,16 +65,16 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"-", "-",
{ {
if (nodes.size() == 0) { if (SIZE() == 0) {
return makePtr<Number>(0); return makePtr<Number>(0);
} }
// Start with the first number // Start with the first number
VALUE_CAST(number, Number, nodes.front()); VALUE_CAST(number, Number, (*begin));
int64_t result = number->number(); int64_t result = number->number();
// Skip the first node // Skip the first node
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { for (auto it = begin + 1; it != end; ++it) {
VALUE_CAST(number, Number, (*it)); VALUE_CAST(number, Number, (*it));
result -= number->number(); result -= number->number();
} }
@@ -82,8 +87,8 @@ ADD_FUNCTION(
{ {
int64_t result = 1; int64_t result = 1;
for (auto node : nodes) { for (auto it = begin; it != end; ++it) {
VALUE_CAST(number, Number, node); VALUE_CAST(number, Number, (*it));
result *= number->number(); result *= number->number();
} }
@@ -93,14 +98,14 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"/", "/",
{ {
CHECK_ARG_COUNT_AT_LEAST("/", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1);
// Start with the first number // Start with the first number
VALUE_CAST(number, Number, nodes.front()); VALUE_CAST(number, Number, (*begin));
double result = number->number(); double result = number->number();
// Skip the first node // Skip the first node
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { for (auto it = begin + 1; it != end; ++it) {
VALUE_CAST(number, Number, (*it)); VALUE_CAST(number, Number, (*it));
result /= number->number(); result /= number->number();
} }
@@ -114,14 +119,14 @@ ADD_FUNCTION(
{ \ { \
bool result = true; \ bool result = true; \
\ \
CHECK_ARG_COUNT_AT_LEAST(#operator, nodes.size(), 2); \ CHECK_ARG_COUNT_AT_LEAST(#operator, SIZE(), 2); \
\ \
/* Start with the first number */ \ /* Start with the first number */ \
VALUE_CAST(number_node, Number, nodes.front()); \ VALUE_CAST(number_node, Number, (*begin)); \
int64_t number = number_node->number(); \ int64_t number = number_node->number(); \
\ \
/* Skip the first node */ \ /* Skip the first node */ \
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \ for (auto it = begin + 1; it != end; ++it) { \
VALUE_CAST(current_number_node, Number, (*it)); \ VALUE_CAST(current_number_node, Number, (*it)); \
int64_t current_number = current_number_node->number(); \ int64_t current_number = current_number_node->number(); \
if (!(number operator current_number)) { \ if (!(number operator current_number)) { \
@@ -144,7 +149,7 @@ ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
ADD_FUNCTION( ADD_FUNCTION(
"list", "list",
{ {
return makePtr<List>(nodes); return makePtr<List>(begin, end);
}); });
ADD_FUNCTION( ADD_FUNCTION(
@@ -152,8 +157,8 @@ ADD_FUNCTION(
{ {
bool result = true; bool result = true;
for (auto node : nodes) { for (auto it = begin; it != end; ++it) {
VALUE_CAST(collection, Collection, node); VALUE_CAST(collection, Collection, (*it));
if (!collection->empty()) { if (!collection->empty()) {
result = false; result = false;
break; break;
@@ -167,19 +172,17 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"count", "count",
{ {
CHECK_ARG_COUNT_IS("count", nodes.size(), 1); CHECK_ARG_COUNT_IS("count", SIZE(), 1);
auto first_argument = nodes.front();
size_t result = 0; size_t result = 0;
if (is<Constant>(first_argument.get()) && std::static_pointer_cast<Constant>(nodes.front())->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>(first_argument.get())) { else if (is<Collection>(begin->get())) {
result = std::static_pointer_cast<Collection>(first_argument)->size(); result = std::static_pointer_cast<Collection>(*begin)->size();
} }
else { else {
Error::the().add(format("wrong argument type: Collection, '{}'", first_argument)); Error::the().add(format("wrong argument type: Collection, '{}'", *begin));
return nullptr; return nullptr;
} }
@@ -194,10 +197,10 @@ ADD_FUNCTION(
std::string result; \ std::string result; \
\ \
Printer printer; \ Printer printer; \
for (auto it = nodes.begin(); it != nodes.end(); ++it) { \ for (auto it = begin; it != end; ++it) { \
result += format("{}", printer.printNoErrorCheck(*it, print_readably)); \ result += format("{}", printer.printNoErrorCheck(*it, print_readably)); \
\ \
if (!isLast(it, nodes)) { \ if (it != end && std::next(it) != end) { \
result += concatenation; \ result += concatenation; \
} \ } \
} \ } \
@@ -211,10 +214,10 @@ ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
#define PRINTER_PRINT(print_readably) \ #define PRINTER_PRINT(print_readably) \
{ \ { \
Printer printer; \ Printer printer; \
for (auto it = nodes.begin(); it != nodes.end(); ++it) { \ for (auto it = begin; it != end; ++it) { \
print("{}", printer.printNoErrorCheck(*it, print_readably)); \ print("{}", printer.printNoErrorCheck(*it, print_readably)); \
\ \
if (!isLast(it, nodes)) { \ if (it != end && std::next(it) != end) { \
print(" "); \ print(" "); \
} \ } \
} \ } \
@@ -231,21 +234,21 @@ ADD_FUNCTION("println", PRINTER_PRINT(false));
ADD_FUNCTION( ADD_FUNCTION(
"=", "=",
{ {
CHECK_ARG_COUNT_AT_LEAST("=", nodes.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_nodes = std::static_pointer_cast<Collection>(lhs)->nodes(); const auto& lhs_nodes = std::static_pointer_cast<Collection>(lhs)->nodes();
auto rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes(); const auto& rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes();
if (lhs_nodes.size() != rhs_nodes.size()) { if (lhs_nodes.size() != rhs_nodes.size()) {
return false; return false;
} }
auto lhs_it = lhs_nodes.begin(); auto lhs_it = lhs_nodes.cbegin();
auto rhs_it = rhs_nodes.begin(); auto rhs_it = rhs_nodes.cbegin();
for (; lhs_it != lhs_nodes.end(); ++lhs_it, ++rhs_it) { for (; lhs_it != lhs_nodes.end(); ++lhs_it, ++rhs_it) {
if (!equal(*lhs_it, *rhs_it)) { if (!equal(*lhs_it, *rhs_it)) {
return false; return false;
@@ -256,8 +259,8 @@ ADD_FUNCTION(
} }
if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) { if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) {
auto lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements(); const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements();
auto rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements(); const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements();
if (lhs_nodes.size() != rhs_nodes.size()) { if (lhs_nodes.size() != rhs_nodes.size()) {
return false; return false;
@@ -265,7 +268,7 @@ ADD_FUNCTION(
for (const auto& [key, value] : lhs_nodes) { for (const auto& [key, value] : lhs_nodes) {
auto it = rhs_nodes.find(key); auto it = rhs_nodes.find(key);
if (it == rhs_nodes.end() || !equal(value, it->second)) { if (it == rhs_nodes.cend() || !equal(value, it->second)) {
return false; return false;
} }
} }
@@ -298,9 +301,9 @@ ADD_FUNCTION(
}; };
bool result = true; bool result = true;
auto it = nodes.begin(); auto it = begin;
auto it_next = std::next(nodes.begin()); auto it_next = begin + 1;
for (; it_next != nodes.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;
@@ -313,9 +316,9 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"read-string", "read-string",
{ {
CHECK_ARG_COUNT_IS("read-string", nodes.size(), 1); CHECK_ARG_COUNT_IS("read-string", SIZE(), 1);
VALUE_CAST(node, String, nodes.front()); VALUE_CAST(node, String, (*begin));
std::string input = node->data(); std::string input = node->data();
return read(input); return read(input);
@@ -324,9 +327,9 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"slurp", "slurp",
{ {
CHECK_ARG_COUNT_IS("slurp", nodes.size(), 1); CHECK_ARG_COUNT_IS("slurp", SIZE(), 1);
VALUE_CAST(node, String, nodes.front()); VALUE_CAST(node, String, (*begin));
std::string path = node->data(); std::string path = node->data();
auto file = ruc::File(path); auto file = ruc::File(path);
@@ -337,27 +340,27 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"eval", "eval",
{ {
CHECK_ARG_COUNT_IS("eval", nodes.size(), 1); CHECK_ARG_COUNT_IS("eval", SIZE(), 1);
return eval(nodes.front(), nullptr); return eval(*begin, nullptr);
}); });
// (atom 1) // (atom 1)
ADD_FUNCTION( ADD_FUNCTION(
"atom", "atom",
{ {
CHECK_ARG_COUNT_IS("atom", nodes.size(), 1); CHECK_ARG_COUNT_IS("atom", SIZE(), 1);
return makePtr<Atom>(nodes.front()); return makePtr<Atom>(*begin);
}); });
// (deref myatom) // (deref myatom)
ADD_FUNCTION( ADD_FUNCTION(
"deref", "deref",
{ {
CHECK_ARG_COUNT_IS("deref", nodes.size(), 1); CHECK_ARG_COUNT_IS("deref", SIZE(), 1);
VALUE_CAST(atom, Atom, nodes.front()); VALUE_CAST(atom, Atom, (*begin));
return atom->deref(); return atom->deref();
}); });
@@ -366,10 +369,10 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"reset!", "reset!",
{ {
CHECK_ARG_COUNT_IS("reset!", nodes.size(), 2); CHECK_ARG_COUNT_IS("reset!", SIZE(), 2);
VALUE_CAST(atom, Atom, nodes.front()); VALUE_CAST(atom, Atom, (*begin));
auto value = *std::next(nodes.begin()); auto value = *(begin + 1);
atom->reset(value); atom->reset(value);
@@ -380,26 +383,26 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"swap!", "swap!",
{ {
CHECK_ARG_COUNT_AT_LEAST("swap!", nodes.size(), 2); CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2);
VALUE_CAST(atom, Atom, nodes.front()); VALUE_CAST(atom, Atom, (*begin));
auto callable = *std::next(nodes.begin()); VALUE_CAST(callable, Callable, (*(begin + 1)));
IS_VALUE(Callable, callable);
// Remove atom and function from the argument list, add atom value // Remove atom and function from the argument list, add atom value
nodes.pop_front(); begin += 2;
nodes.pop_front(); auto arguments = ValueVector(end - begin + 1);
nodes.push_front(atom->deref()); arguments[0] = atom->deref();
std::copy(begin, end, arguments.begin() + 1);
ValuePtr value = nullptr; ValuePtr value = nullptr;
if (is<Function>(callable.get())) { if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function(); auto function = std::static_pointer_cast<Function>(callable)->function();
value = function(nodes); value = function(arguments.begin(), arguments.end());
} }
else { else {
auto lambda = std::static_pointer_cast<Lambda>(callable); auto lambda = std::static_pointer_cast<Lambda>(callable);
value = eval(lambda->body(), Environment::create(lambda, nodes)); value = eval(lambda->body(), Environment::create(lambda, arguments));
} }
return atom->reset(value); return atom->reset(value);
@@ -409,42 +412,53 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"cons", "cons",
{ {
CHECK_ARG_COUNT_IS("cons", nodes.size(), 2); CHECK_ARG_COUNT_IS("cons", SIZE(), 2);
VALUE_CAST(collection, Collection, (*std::next(nodes.begin()))); ValuePtr first = *begin;
begin++;
auto result_nodes = collection->nodes(); VALUE_CAST(collection, Collection, (*begin));
result_nodes.push_front(nodes.front()); const auto& collection_nodes = collection->nodes();
return makePtr<List>(result_nodes); ValueVector* result_nodes = new 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)) // (concat (list 1) (list 2 3)) -> (1 2 3)
ADD_FUNCTION( ADD_FUNCTION(
"concat", "concat",
{ {
std::list<ValuePtr> result_nodes; size_t count = 0;
for (auto it = begin; it != end; ++it) {
for (auto node : nodes) { VALUE_CAST(collection, Collection, (*it));
VALUE_CAST(collection, Collection, node); count += collection->size();
auto argument_nodes = collection->nodes();
result_nodes.splice(result_nodes.end(), argument_nodes);
} }
return makePtr<List>(result_nodes); auto result_nodes = new ValueVector(count);
size_t offset = 0;
for (auto it = begin; it != end; ++it) {
const auto& collection_nodes = std::static_pointer_cast<Collection>(*it)->nodes();
std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes->begin() + offset);
offset += collection_nodes.size();
}
return makePtr<List>(*result_nodes);
}); });
// (vec (list 1 2 3)) // (vec (list 1 2 3))
ADD_FUNCTION( ADD_FUNCTION(
"vec", "vec",
{ {
CHECK_ARG_COUNT_IS("vec", nodes.size(), 1); CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
if (is<Vector>(nodes.front().get())) { if (is<Vector>(begin->get())) {
return nodes.front(); return *begin;
} }
VALUE_CAST(collection, Collection, nodes.front()); VALUE_CAST(collection, Collection, (*begin));
return makePtr<Vector>(collection->nodes()); return makePtr<Vector>(collection->nodes());
}); });
@@ -453,10 +467,10 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"nth", "nth",
{ {
CHECK_ARG_COUNT_IS("nth", nodes.size(), 2); CHECK_ARG_COUNT_IS("nth", SIZE(), 2);
VALUE_CAST(collection, Collection, nodes.front()); VALUE_CAST(collection, Collection, (*begin));
VALUE_CAST(number_node, Number, (*std::next(nodes.begin()))); VALUE_CAST(number_node, Number, (*(begin + 1)));
auto collection_nodes = collection->nodes(); auto collection_nodes = collection->nodes();
auto index = (size_t)number_node->number(); auto index = (size_t)number_node->number();
@@ -473,70 +487,66 @@ ADD_FUNCTION(
return *result; return *result;
}); });
// (first (list 1 2 3)) // (first (list 1 2 3)) -> 1
ADD_FUNCTION( ADD_FUNCTION(
"first", "first",
{ {
CHECK_ARG_COUNT_IS("first", nodes.size(), 1); CHECK_ARG_COUNT_IS("first", SIZE(), 1);
if (is<Constant>(nodes.front().get()) if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) { && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>(); return makePtr<Constant>();
} }
VALUE_CAST(collection, Collection, nodes.front()); VALUE_CAST(collection, Collection, (*begin));
auto collection_nodes = collection->nodes();
return (collection_nodes.empty()) ? makePtr<Constant>() : collection_nodes.front(); return (collection->empty()) ? makePtr<Constant>() : collection->front();
}); });
// (rest (list 1 2 3)) // (rest (list 1 2 3))
ADD_FUNCTION( ADD_FUNCTION(
"rest", "rest",
{ {
CHECK_ARG_COUNT_IS("rest", nodes.size(), 1); CHECK_ARG_COUNT_IS("rest", SIZE(), 1);
if (is<Constant>(nodes.front().get()) if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) { && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<List>(); return makePtr<List>();
} }
VALUE_CAST(collection, Collection, nodes.front()); VALUE_CAST(collection, Collection, (*begin));
auto collection_nodes = collection->nodes();
if (collection_nodes.size() > 0) {
collection_nodes.pop_front();
}
return makePtr<List>(collection_nodes); return makePtr<List>(collection->rest());
}); });
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) // (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4)
ADD_FUNCTION( ADD_FUNCTION(
"apply", "apply",
{ {
CHECK_ARG_COUNT_AT_LEAST("apply", nodes.size(), 2); CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2);
auto callable = nodes.front(); auto callable = *begin;
IS_VALUE(Callable, callable); IS_VALUE(Callable, callable);
VALUE_CAST(collection, Collection, nodes.back()); VALUE_CAST(collection, Collection, (*std::prev(end)));
// Remove function and list from the arguments ValueVector arguments(begin + 1, end - 1);
nodes.pop_front(); arguments.reserve(arguments.size() + collection->size());
nodes.pop_back();
// Append list nodes to the argument leftovers // Append list nodes to the argument leftovers
auto collection_nodes = collection->nodes(); auto nodes = collection->nodes();
nodes.splice(nodes.end(), collection_nodes); for (const auto& node : nodes) {
arguments.push_back(node);
}
ValuePtr value = nullptr; ValuePtr value = nullptr;
if (is<Function>(callable.get())) { if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function(); auto function = std::static_pointer_cast<Function>(callable)->function();
value = function(nodes); value = function(arguments.begin(), arguments.end());
} }
else { else {
auto lambda = std::static_pointer_cast<Lambda>(callable); auto lambda = std::static_pointer_cast<Lambda>(callable);
value = eval(lambda->body(), Environment::create(lambda, nodes)); value = eval(lambda->body(), Environment::create(lambda, arguments));
} }
return value; return value;
@@ -546,23 +556,24 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"map", "map",
{ {
CHECK_ARG_COUNT_IS("map", nodes.size(), 2); CHECK_ARG_COUNT_IS("map", SIZE(), 2);
VALUE_CAST(callable, Callable, nodes.front()); VALUE_CAST(callable, Callable, (*begin));
VALUE_CAST(collection, Collection, nodes.back()); VALUE_CAST(collection, Collection, (*(begin + 1)));
auto collection_nodes = collection->nodes(); const auto& collection_nodes = collection->nodes();
auto result = makePtr<List>(); auto result = makePtr<List>();
if (is<Function>(callable.get())) { if (is<Function>(callable.get())) {
auto function = std::static_pointer_cast<Function>(callable)->function(); auto function = std::static_pointer_cast<Function>(callable)->function();
for (auto node : collection_nodes) { for (const auto& node : collection_nodes) {
result->add(function({ node })); auto arguments = ValueVector { node };
result->add(function(arguments.begin(), arguments.end()));
} }
} }
else { else {
auto lambda = std::static_pointer_cast<Lambda>(callable); auto lambda = std::static_pointer_cast<Lambda>(callable);
for (auto node : collection_nodes) { for (const auto& node : collection_nodes) {
result->add(eval(lambda->body(), Environment::create(lambda, { node }))); result->add(eval(lambda->body(), Environment::create(lambda, { node })));
} }
} }
@@ -574,22 +585,22 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"throw", "throw",
{ {
CHECK_ARG_COUNT_IS("throw", nodes.size(), 1); CHECK_ARG_COUNT_IS("throw", SIZE(), 1);
Error::the().add(nodes.front()); Error::the().add(*begin);
return nullptr; return nullptr;
}) })
// ----------------------------------------- // -----------------------------------------
#define IS_CONSTANT(name, constant) \ #define IS_CONSTANT(name, constant) \
{ \ { \
CHECK_ARG_COUNT_IS(name, nodes.size(), 1); \ CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
\ \
return makePtr<Constant>( \ return makePtr<Constant>( \
is<Constant>(nodes.front().get()) \ is<Constant>(begin->get()) \
&& std::static_pointer_cast<Constant>(nodes.front())->state() == constant); \ && std::static_pointer_cast<Constant>(*begin)->state() == constant); \
} }
// (nil? nil) // (nil? nil)
@@ -599,22 +610,22 @@ ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False));
// ----------------------------------------- // -----------------------------------------
#define IS_TYPE(type) \ #define IS_TYPE(type) \
{ \ { \
bool result = true; \ bool result = true; \
\ \
if (nodes.size() == 0) { \ if (SIZE() == 0) { \
result = false; \ result = false; \
} \ } \
\ \
for (auto node : nodes) { \ for (auto it = begin; it != end; ++it) { \
if (!is<type>(node.get())) { \ if (!is<type>(it->get())) { \
result = false; \ result = false; \
break; \ break; \
} \ } \
} \ } \
\ \
return makePtr<Constant>(result); \ return makePtr<Constant>(result); \
} }
// (symbol? 'foo) // (symbol? 'foo)
@@ -622,23 +633,63 @@ 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("sequential?", IS_TYPE(Collection)); ADD_FUNCTION("sequential?", IS_TYPE(Collection));
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(
"fn?",
{
bool result = true;
if (SIZE() == 0) {
result = false;
}
for (auto it = begin; it != end; ++it) {
if (!is<Callable>(it->get()) || is<Macro>(it->get())) {
result = false;
break;
}
}
return makePtr<Constant>(result);
});
ADD_FUNCTION(
"macro?",
{
bool result = true;
if (SIZE() == 0) {
result = false;
}
for (auto it = begin; it != end; ++it) {
if (!is<Macro>(it->get())) {
result = false;
break;
}
}
return makePtr<Constant>(result);
});
// ----------------------------------------- // -----------------------------------------
#define STRING_TO_TYPE(name, type) \ #define STRING_TO_TYPE(name, type) \
{ \ { \
CHECK_ARG_COUNT_IS(name, nodes.size(), 1); \ CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
\ \
if (is<type>(nodes.front().get())) { \ if (is<type>(begin->get())) { \
return nodes.front(); \ return *begin; \
} \ } \
\ \
VALUE_CAST(stringValue, String, nodes.front()); \ VALUE_CAST(stringValue, String, (*begin)); \
\ \
return makePtr<type>(stringValue->data()); \ return makePtr<type>(stringValue->data()); \
} }
// (symbol "foo") // (symbol "foo")
@@ -652,8 +703,8 @@ ADD_FUNCTION(
{ {
auto result = makePtr<Vector>(); auto result = makePtr<Vector>();
for (auto node : nodes) { for (auto it = begin; it != end; ++it) {
result->add(node); result->add(*it);
} }
return result; return result;
@@ -662,11 +713,11 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"hash-map", "hash-map",
{ {
CHECK_ARG_COUNT_EVEN("hash-map", nodes.size()); CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
auto result = makePtr<HashMap>(); auto result = makePtr<HashMap>();
for (auto it = nodes.begin(); it != nodes.end(); std::advance(it, 2)) { for (auto it = begin; it != end; std::advance(it, 2)) {
result->add(*it, *(std::next(it))); result->add(*it, *(std::next(it)));
} }
@@ -677,16 +728,16 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"assoc", "assoc",
{ {
CHECK_ARG_COUNT_AT_LEAST("assoc", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1);
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
nodes.pop_front(); begin++;
CHECK_ARG_COUNT_EVEN("assoc", nodes.size()); CHECK_ARG_COUNT_EVEN("assoc", SIZE());
auto result = makePtr<HashMap>(hash_map->elements()); auto result = makePtr<HashMap>(hash_map->elements());
for (auto it = nodes.begin(); it != nodes.end(); std::advance(it, 2)) { for (auto it = begin; it != end; std::advance(it, 2)) {
result->add(*it, *(std::next(it))); result->add(*it, *(std::next(it)));
} }
@@ -696,63 +747,62 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"dissoc", "dissoc",
{ {
CHECK_ARG_COUNT_AT_LEAST("dissoc", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1);
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
nodes.pop_front(); begin++;
auto result = makePtr<HashMap>(hash_map->elements()); auto result = makePtr<HashMap>(hash_map->elements());
for (auto node : nodes) { for (auto it = begin; it != end; ++it) {
result->remove(node); result->remove(*it);
} }
return result; return result;
}); });
// (get {:kw "value"} :kw) // (get {:kw "value"} :kw) -> "value"
ADD_FUNCTION( ADD_FUNCTION(
"get", "get",
{ {
CHECK_ARG_COUNT_AT_LEAST("get", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
if (is<Constant>(nodes.front().get()) if (is<Constant>(begin->get())
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) { && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) {
return makePtr<Constant>(); return makePtr<Constant>();
} }
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
nodes.pop_front(); begin++;
if (nodes.size() == 0) { if (SIZE() == 0) {
return makePtr<Constant>(); return makePtr<Constant>();
} }
auto result = hash_map->get(nodes.front()); auto result = hash_map->get(*begin);
return (result) ? result : makePtr<Constant>(); return (result) ? result : makePtr<Constant>();
}); });
ADD_FUNCTION( ADD_FUNCTION(
"contains?", "contains?",
{ {
CHECK_ARG_COUNT_AT_LEAST("contains?", nodes.size(), 1); CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
nodes.pop_front();
if (nodes.size() == 0) { if (SIZE() == 0) {
return makePtr<Constant>(false); return makePtr<Constant>(false);
} }
return makePtr<Constant>(hash_map->exists(nodes.front())); return makePtr<Constant>(hash_map->exists(*(begin + 1)));
}); });
ADD_FUNCTION( ADD_FUNCTION(
"keys", "keys",
{ {
CHECK_ARG_COUNT_AT_LEAST("keys", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1);
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
auto result = makePtr<List>(); auto result = makePtr<List>();
@@ -772,9 +822,9 @@ ADD_FUNCTION(
ADD_FUNCTION( ADD_FUNCTION(
"vals", "vals",
{ {
CHECK_ARG_COUNT_AT_LEAST("vals", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1);
VALUE_CAST(hash_map, HashMap, nodes.front()); VALUE_CAST(hash_map, HashMap, (*begin));
auto result = makePtr<List>(); auto result = makePtr<List>();
@@ -786,6 +836,144 @@ ADD_FUNCTION(
return result; return result;
}); });
ADD_FUNCTION(
"readline",
{
CHECK_ARG_COUNT_IS("readline", SIZE(), 1);
VALUE_CAST(prompt, String, (*begin));
return readline(prompt->data());
});
ADD_FUNCTION(
"time-ms",
{
CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0);
int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
return makePtr<Number>(elapsed);
});
// (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<Collection>(front_raw_ptr) && // List / Vector
!is<HashMap>(front_raw_ptr) && // HashMap
!is<Callable>(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<Collection>(front_raw_ptr) && // List / Vector
!is<HashMap>(front_raw_ptr) && // HashMap
!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));
});
// (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->nodes();
size_t collection_count = collection_nodes.size();
size_t argument_count = SIZE();
ValueVector* nodes = new 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);
}
std::copy(collection_nodes.begin(), collection_nodes.end(), nodes->begin());
std::copy(begin, end, nodes->begin() + collection_count);
return makePtr<Vector>(*nodes);
});
// (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>();
}
if (is<Collection>(front_raw_ptr)) {
auto collection = std::static_pointer_cast<Collection>(front);
if (collection->empty()) {
return makePtr<Constant>();
}
if (is<List>(front_raw_ptr)) {
return front;
}
return makePtr<List>(collection->nodes());
}
if (is<String>(front_raw_ptr)) {
auto string = std::static_pointer_cast<String>(front);
if (string->empty()) {
return makePtr<Constant>();
}
auto result = makePtr<List>();
const auto& data = string->data();
for (const auto& character : data) {
result->add(makePtr<String>(character));
}
return result;
}
Error::the().add(format("wrong argument type: Collection or String, {}", front));
return nullptr;
});
// ----------------------------------------- // -----------------------------------------
void installFunctions(EnvironmentPtr env) void installFunctions(EnvironmentPtr env)
+5 -2
View File
@@ -139,8 +139,11 @@ void Printer::printImpl(ValuePtr node, bool print_readably)
} }
else if (is<Lambda>(node_raw_ptr)) { else if (is<Lambda>(node_raw_ptr)) {
printSpacing(); printSpacing();
auto lambda = std::static_pointer_cast<Lambda>(node); m_print += format("#<user-function>({:p})", node_raw_ptr);
m_print += format("#<user-{}>({:p})", (lambda->isMacro()) ? "macro" : "function", node_raw_ptr); }
else if (is<Macro>(node_raw_ptr)) {
printSpacing();
m_print += format("#<user-macro>({:p})", node_raw_ptr);
} }
else if (is<Atom>(node_raw_ptr)) { else if (is<Atom>(node_raw_ptr)) {
printSpacing(); printSpacing();
+24 -9
View File
@@ -13,6 +13,7 @@
#include <string_view> #include <string_view>
#include "ruc/format/color.h" #include "ruc/format/color.h"
#include "ruc/format/print.h"
#include "readline.h" #include "readline.h"
@@ -22,13 +23,7 @@ Readline::Readline(bool pretty_print, std::string_view history_path)
: m_pretty_print(pretty_print) : m_pretty_print(pretty_print)
, m_history_path(tilde_expand(history_path.data())) , m_history_path(tilde_expand(history_path.data()))
{ {
if (!pretty_print) { m_prompt = createPrompt("user> ");
m_prompt = "user> ";
}
else {
m_prompt = format(fg(ruc::format::TerminalColor::Blue), "user>");
m_prompt += format(" \033[1m");
}
read_history(m_history_path); read_history(m_history_path);
} }
@@ -40,9 +35,24 @@ Readline::~Readline()
// ----------------------------------------- // -----------------------------------------
bool Readline::get(std::string& output) std::string Readline::createPrompt(const std::string& prompt)
{ {
char* line = readline(m_prompt.c_str()); if (!m_pretty_print) {
return prompt;
}
return format(fg(ruc::format::TerminalColor::Blue), "{}", prompt)
+ format("\033[1m");
}
bool Readline::get(std::string& output, const std::string& prompt)
{
char* line = readline(prompt.c_str());
if (m_pretty_print) {
print("\033[0m");
}
if (line == nullptr) { if (line == nullptr) {
return false; return false;
} }
@@ -57,4 +67,9 @@ bool Readline::get(std::string& output)
return true; return true;
} }
bool Readline::get(std::string& output)
{
return get(output, m_prompt);
}
} // namespace blaze } // namespace blaze
+5 -1
View File
@@ -15,15 +15,19 @@ namespace blaze {
class Readline { class Readline {
public: public:
Readline() = default;
Readline(bool pretty_print, std::string_view history_path); Readline(bool pretty_print, std::string_view history_path);
virtual ~Readline(); virtual ~Readline();
std::string createPrompt(const std::string& prompt);
bool get(std::string& output, const std::string& prompt);
bool get(std::string& output); bool get(std::string& output);
private: private:
bool m_pretty_print { false }; bool m_pretty_print { false };
std::string m_prompt;
char* m_history_path; char* m_history_path;
std::string m_prompt;
}; };
} // namespace blaze } // namespace blaze
+3 -2
View File
@@ -5,7 +5,6 @@
#include "forward.h" #include "forward.h"
#if 0
auto read(std::string_view data) -> std::string_view auto read(std::string_view data) -> std::string_view
{ {
return data; return data;
@@ -57,5 +56,7 @@ auto eval(ValuePtr, EnvironmentPtr) -> ValuePtr
return {}; return {};
} }
// Added to keep the linker happy at step A
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze } // namespace blaze
#endif
+5 -2
View File
@@ -15,7 +15,6 @@
#include "reader.h" #include "reader.h"
#include "settings.h" #include "settings.h"
#if 0
namespace blaze { namespace blaze {
auto read(std::string_view input) -> ValuePtr auto read(std::string_view input) -> ValuePtr
@@ -108,4 +107,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -17,7 +17,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
namespace blaze { namespace blaze {
@@ -112,4 +111,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -17,7 +17,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
namespace blaze { namespace blaze {
@@ -112,4 +111,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -17,7 +17,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
static auto cleanup(int signal) -> void; static auto cleanup(int signal) -> void;
@@ -129,4 +128,8 @@ static auto print(blaze::ValuePtr exp) -> std::string
return printer.print(exp, true); return printer.print(exp, true);
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -23,7 +23,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
static auto cleanup(int signal) -> void; static auto cleanup(int signal) -> void;
@@ -135,4 +134,8 @@ static auto print(blaze::ValuePtr exp) -> std::string
return printer.print(exp, true); return printer.print(exp, true);
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -24,7 +24,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
namespace blaze { namespace blaze {
static EnvironmentPtr s_outer_env = Environment::create(); static EnvironmentPtr s_outer_env = Environment::create();
@@ -156,4 +155,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -24,7 +24,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
namespace blaze { namespace blaze {
static EnvironmentPtr s_outer_env = Environment::create(); static EnvironmentPtr s_outer_env = Environment::create();
@@ -156,4 +155,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -2
View File
@@ -24,7 +24,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
namespace blaze { namespace blaze {
static EnvironmentPtr s_outer_env = Environment::create(); static EnvironmentPtr s_outer_env = Environment::create();
@@ -163,4 +162,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+5 -3
View File
@@ -24,7 +24,6 @@
#include "readline.h" #include "readline.h"
#include "settings.h" #include "settings.h"
#if 0
namespace blaze { namespace blaze {
static EnvironmentPtr s_outer_env = Environment::create(); static EnvironmentPtr s_outer_env = Environment::create();
@@ -126,7 +125,6 @@ auto main(int argc, char* argv[]) -> int
arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr);
arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr);
arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes);
// TODO: Add overload for addArgument(std::vector<std::string_view>)
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);
@@ -167,4 +165,8 @@ auto main(int argc, char* argv[]) -> int
return 0; return 0;
} }
#endif
// Added to keep the linker happy at step A
namespace blaze {
ValuePtr readline(const std::string&) { return nullptr; }
} // namespace blaze
+181
View File
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <csignal> // std::signal
#include <cstdlib> // std::exit
#include <string>
#include <string_view>
#include <vector>
#include "ruc/argparser.h"
#include "ruc/format/color.h"
#include "ast.h"
#include "environment.h"
#include "error.h"
#include "eval.h"
#include "forward.h"
#include "lexer.h"
#include "printer.h"
#include "reader.h"
#include "readline.h"
#include "settings.h"
#if 1
namespace blaze {
static blaze::Readline s_readline;
static EnvironmentPtr s_outer_env = Environment::create();
static auto cleanup(int signal) -> void
{
print("\033[0m\n");
std::exit(signal);
}
auto readline(const std::string& prompt) -> ValuePtr
{
std::string input;
if (s_readline.get(input, s_readline.createPrompt(prompt))) {
return makePtr<String>(input);
}
return makePtr<Constant>();
}
auto read(std::string_view input) -> ValuePtr
{
Lexer lexer(input);
lexer.tokenize();
if (Settings::the().get("dump-lexer") == "1") {
lexer.dump();
}
Reader reader(std::move(lexer.tokens()));
reader.read();
if (Settings::the().get("dump-reader") == "1") {
reader.dump();
}
return reader.node();
}
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr
{
if (env == nullptr) {
env = s_outer_env;
}
Eval eval(ast, env);
eval.eval();
return eval.ast();
}
static auto print(ValuePtr exp) -> std::string
{
Printer printer;
return printer.print(exp, true);
}
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string
{
Error::the().clearErrors();
Error::the().setInput(input);
return print(eval(read(input), env));
}
static std::string_view lambdaTable[] = {
"(def! not (fn* (cond) (if cond false true)))",
"(def! load-file (fn* (filename) \
(eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))",
"(defmacro! cond (fn* (& xs) \
(if (> (count xs) 0) \
(list 'if (first xs) \
(if (> (count xs) 1) \
(nth xs 1) \
(throw \"odd number of forms to cond\")) \
(cons 'cond (rest (rest xs)))))))",
"(def! *host-language* \"C++\")",
};
static auto installLambdas(EnvironmentPtr env) -> void
{
for (auto function : lambdaTable) {
rep(function, env);
}
}
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void
{
auto list = makePtr<List>();
if (arguments.size() > 1) {
for (auto it = arguments.begin() + 1; it != arguments.end(); ++it) {
list->add(makePtr<String>(*it));
}
}
env->set("*ARGV*", list);
}
} // namespace blaze
auto main(int argc, char* argv[]) -> int
{
bool dump_lexer = false;
bool dump_reader = false;
bool pretty_print = false;
std::string_view history_path = "~/.blaze-history";
std::vector<std::string> arguments;
// CLI arguments
ruc::ArgParser arg_parser;
arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr);
arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr);
arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr);
arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes);
// TODO: Add overload for addArgument(std::vector<std::string_view>)
arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No);
arg_parser.parse(argc, argv);
// Set settings
blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0");
blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0");
blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0");
// Signal callbacks
std::signal(SIGINT, blaze::cleanup);
std::signal(SIGTERM, blaze::cleanup);
installFunctions(blaze::s_outer_env);
installLambdas(blaze::s_outer_env);
makeArgv(blaze::s_outer_env, arguments);
if (arguments.size() > 0) {
rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env);
return 0;
}
rep("(println (str \"Mal [\" *host-language* \"]\"))", blaze::s_outer_env);
blaze::s_readline = blaze::Readline(pretty_print, history_path);
std::string input;
while (blaze::s_readline.get(input)) {
std::string output = rep(input, blaze::s_outer_env);
if (output.length() > 0) {
print("{}\n", output);
}
}
if (pretty_print) {
print("\033[0m");
}
return 0;
}
#endif