Compare commits
9
Commits
7d91ef9198
...
099cda8b86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
099cda8b86 | ||
|
|
4fff2b9aa2 | ||
|
|
63c31d7ccf | ||
|
|
12d6b8ec88 | ||
|
|
f796f9c685 | ||
|
|
86e1a630b8 | ||
|
|
d34ab1efab | ||
|
|
24eab1034e | ||
|
|
6e0fe3a2f5 |
+40
-15
@@ -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})
|
||||||
|
|||||||
+113
-9
@@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user