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
|
||||
|
||||
# Set project name
|
||||
set(PROJECT "blaze")
|
||||
set(PROJECT "stepA_mal")
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(BLAZE_STANDALONE TRUE)
|
||||
@@ -64,11 +64,26 @@ add_subdirectory("vendor/ruc")
|
||||
|
||||
# Define source files
|
||||
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})
|
||||
target_include_directories(${PROJECT} PRIVATE
|
||||
"src")
|
||||
target_link_libraries(${PROJECT} readline ruc)
|
||||
function(add_step TARGET_NAME MAIN_PATH)
|
||||
add_executable(${TARGET_NAME} ${PROJECT_SOURCES} ${MAIN_PATH})
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "src")
|
||||
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
|
||||
@@ -81,41 +96,51 @@ add_custom_target(run
|
||||
# Test targets
|
||||
|
||||
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_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_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_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_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_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_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_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_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_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_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 <memory>
|
||||
#include <memory> // std::static_pointer_cast
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ast.h"
|
||||
#include "environment.h"
|
||||
@@ -17,11 +18,39 @@
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (node == nullptr) {
|
||||
@@ -31,20 +60,56 @@ void Collection::add(ValuePtr 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)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
@@ -162,12 +238,26 @@ Symbol::Symbol(const std::string& symbol)
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
Callable::Callable(ValuePtr meta)
|
||||
: Value(meta)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
Function::Function(const std::string& name, FunctionType function)
|
||||
: m_name(name)
|
||||
, 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)
|
||||
@@ -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)
|
||||
: m_bindings(that->m_bindings)
|
||||
, m_body(that->m_body)
|
||||
, m_env(that->m_env)
|
||||
, m_is_macro(is_macro)
|
||||
Lambda::Lambda(const Lambda& that)
|
||||
: m_bindings(that.m_bindings)
|
||||
, m_body(that.m_body)
|
||||
, m_env(that.m_env)
|
||||
{
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
template<typename T, typename... Args>
|
||||
std::shared_ptr<T> makePtr(Args&&... args)
|
||||
{
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
class Value {
|
||||
public:
|
||||
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(); }
|
||||
|
||||
template<typename T>
|
||||
@@ -45,12 +58,33 @@ public:
|
||||
virtual bool isCallable() const { return false; }
|
||||
virtual bool isFunction() const { return false; }
|
||||
virtual bool isLambda() const { return false; }
|
||||
virtual bool isMacro() const { return false; }
|
||||
virtual bool isAtom() const { return false; }
|
||||
|
||||
protected:
|
||||
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>
|
||||
@@ -62,14 +96,21 @@ public:
|
||||
|
||||
void add(ValuePtr node);
|
||||
|
||||
// TODO: rename size -> count
|
||||
size_t size() const { return m_nodes.size(); }
|
||||
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:
|
||||
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>
|
||||
Collection(std::shared_ptr<Ts>... nodes)
|
||||
@@ -80,7 +121,7 @@ protected:
|
||||
private:
|
||||
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 {
|
||||
public:
|
||||
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>
|
||||
List(std::shared_ptr<Ts>... nodes)
|
||||
@@ -99,6 +143,8 @@ public:
|
||||
|
||||
virtual ~List() = default;
|
||||
|
||||
WITH_META(List);
|
||||
|
||||
private:
|
||||
virtual bool isList() const override { return true; }
|
||||
};
|
||||
@@ -109,7 +155,10 @@ private:
|
||||
class Vector final : public Collection {
|
||||
public:
|
||||
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>
|
||||
Vector(std::shared_ptr<Ts>... nodes)
|
||||
@@ -119,6 +168,8 @@ public:
|
||||
|
||||
virtual ~Vector() = default;
|
||||
|
||||
WITH_META(Vector);
|
||||
|
||||
private:
|
||||
virtual bool isVector() const override { return true; }
|
||||
};
|
||||
@@ -132,6 +183,7 @@ public:
|
||||
|
||||
HashMap() = default;
|
||||
HashMap(const Elements& elements);
|
||||
HashMap(const HashMap& that, ValuePtr meta);
|
||||
virtual ~HashMap() = default;
|
||||
|
||||
void add(const std::string& key, ValuePtr value);
|
||||
@@ -147,6 +199,8 @@ public:
|
||||
size_t size() const { return m_elements.size(); }
|
||||
bool empty() const { return m_elements.size() == 0; }
|
||||
|
||||
WITH_META(HashMap);
|
||||
|
||||
private:
|
||||
virtual bool isHashMap() const override { return true; }
|
||||
|
||||
@@ -161,9 +215,13 @@ private:
|
||||
class String final : public Value {
|
||||
public:
|
||||
String(const std::string& data);
|
||||
String(char character);
|
||||
virtual ~String() = default;
|
||||
|
||||
const std::string& data() const { return m_data; }
|
||||
bool empty() const { return m_data.empty(); }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
virtual bool isString() const override { return true; }
|
||||
@@ -183,6 +241,8 @@ public:
|
||||
|
||||
const std::string& keyword() const { return m_data; }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
const std::string m_data;
|
||||
};
|
||||
@@ -196,6 +256,8 @@ public:
|
||||
|
||||
int64_t number() const { return m_number; }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
virtual bool isNumber() const override { return true; }
|
||||
|
||||
@@ -220,6 +282,8 @@ public:
|
||||
|
||||
State state() const { return m_state; }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
virtual bool isConstant() const override { return true; }
|
||||
|
||||
@@ -236,6 +300,8 @@ public:
|
||||
|
||||
const std::string& symbol() const { return m_symbol; }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
virtual bool isSymbol() const override { return true; }
|
||||
|
||||
@@ -250,6 +316,7 @@ public:
|
||||
|
||||
protected:
|
||||
Callable() = default;
|
||||
Callable(ValuePtr meta);
|
||||
|
||||
private:
|
||||
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 {
|
||||
public:
|
||||
Function(const std::string& name, FunctionType function);
|
||||
Function(const Function& that, ValuePtr meta);
|
||||
virtual ~Function() = default;
|
||||
|
||||
const std::string& name() const { return m_name; }
|
||||
FunctionType function() const { return m_function; }
|
||||
|
||||
WITH_META(Function);
|
||||
|
||||
private:
|
||||
virtual bool isFunction() const override { return true; }
|
||||
|
||||
@@ -276,16 +346,18 @@ private:
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
class Lambda final : public Callable {
|
||||
class Lambda : public Callable {
|
||||
public:
|
||||
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;
|
||||
|
||||
const std::vector<std::string>& bindings() const { return m_bindings; }
|
||||
ValuePtr body() const { return m_body; }
|
||||
EnvironmentPtr env() const { return m_env; }
|
||||
bool isMacro() const { return m_is_macro; }
|
||||
|
||||
WITH_META(Lambda);
|
||||
|
||||
private:
|
||||
virtual bool isLambda() const override { return true; }
|
||||
@@ -293,7 +365,19 @@ private:
|
||||
const std::vector<std::string> m_bindings;
|
||||
const ValuePtr m_body;
|
||||
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 deref() const { return m_value; }
|
||||
|
||||
WITH_NO_META();
|
||||
|
||||
private:
|
||||
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
|
||||
template<>
|
||||
inline bool Value::fastIs<Collection>() const { return isCollection(); }
|
||||
@@ -360,6 +438,9 @@ inline bool Value::fastIs<Function>() const { return isFunction(); }
|
||||
template<>
|
||||
inline bool Value::fastIs<Lambda>() const { return isLambda(); }
|
||||
|
||||
template<>
|
||||
inline bool Value::fastIs<Macro>() const { return isMacro(); }
|
||||
|
||||
template<>
|
||||
inline bool Value::fastIs<Atom>() const { return isAtom(); }
|
||||
// clang-format on
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer)
|
||||
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 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
|
||||
static EnvironmentPtr create();
|
||||
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);
|
||||
ValuePtr set(const std::string& symbol, ValuePtr value);
|
||||
|
||||
+21
-19
@@ -22,7 +22,7 @@ namespace blaze {
|
||||
static ValuePtr evalQuasiQuoteImpl(ValuePtr ast);
|
||||
|
||||
// (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);
|
||||
|
||||
@@ -44,7 +44,7 @@ ValuePtr Eval::evalDef(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||
}
|
||||
|
||||
// (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);
|
||||
|
||||
@@ -63,19 +63,21 @@ ValuePtr Eval::evalDefMacro(const std::list<ValuePtr>& nodes, EnvironmentPtr env
|
||||
}
|
||||
|
||||
// Modify existing environment
|
||||
return env->set(symbol->symbol(), makePtr<Lambda>(lambda, true));
|
||||
return env->set(symbol->symbol(), makePtr<Macro>(*lambda));
|
||||
}
|
||||
|
||||
// (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);
|
||||
|
||||
// First element needs to be a List or Vector
|
||||
VALUE_CAST(collection, Collection, nodes.front());
|
||||
const auto& collection_nodes = collection->nodes();
|
||||
|
||||
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
|
||||
VALUE_CAST(symbol, Symbol, node);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -94,7 +96,7 @@ ValuePtr Eval::evalMacroExpand(const std::list<ValuePtr>& nodes, EnvironmentPtr
|
||||
}
|
||||
|
||||
// (quasiquoteexpand x)
|
||||
ValuePtr Eval::evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes)
|
||||
ValuePtr Eval::evalQuasiQuoteExpand(const ValueVector& nodes)
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("quasiquoteexpand", nodes.size(), 1);
|
||||
|
||||
@@ -102,7 +104,7 @@ ValuePtr Eval::evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes)
|
||||
}
|
||||
|
||||
// (quote x)
|
||||
ValuePtr Eval::evalQuote(const std::list<ValuePtr>& nodes)
|
||||
ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("quote", nodes.size(), 1);
|
||||
|
||||
@@ -110,7 +112,7 @@ ValuePtr Eval::evalQuote(const std::list<ValuePtr>& nodes)
|
||||
}
|
||||
|
||||
// (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());
|
||||
|
||||
@@ -128,7 +130,7 @@ void Eval::evalDo(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||
}
|
||||
|
||||
// (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());
|
||||
|
||||
@@ -152,13 +154,13 @@ void Eval::evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||
}
|
||||
|
||||
// (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());
|
||||
|
||||
// First argument needs to be a List or Vector
|
||||
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
|
||||
CHECK_ARG_COUNT_EVEN("bindings", binding_nodes.size(), void());
|
||||
@@ -207,7 +209,7 @@ static ValuePtr startsWith(ValuePtr ast, const std::string& symbol)
|
||||
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)) {
|
||||
return nullptr;
|
||||
@@ -243,11 +245,11 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast)
|
||||
|
||||
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)
|
||||
for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
|
||||
const auto elt = *it;
|
||||
for (auto it = nodes.crbegin(); it != nodes.crend(); ++it) {
|
||||
const auto& elt = *it;
|
||||
|
||||
const auto splice_unquote = startsWith(elt, "splice-unquote"); // (list 2 2 2)
|
||||
if (splice_unquote) {
|
||||
@@ -269,7 +271,7 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast)
|
||||
}
|
||||
|
||||
// (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());
|
||||
|
||||
@@ -281,7 +283,7 @@ void Eval::evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||
}
|
||||
|
||||
// (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());
|
||||
|
||||
@@ -299,7 +301,7 @@ void Eval::evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||
Error::the().clearErrors();
|
||||
|
||||
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());
|
||||
|
||||
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front(), void());
|
||||
|
||||
+22
-29
@@ -79,10 +79,9 @@ ValuePtr Eval::evalImpl()
|
||||
}
|
||||
|
||||
// Special forms
|
||||
auto nodes = list->nodes();
|
||||
if (is<Symbol>(nodes.front().get())) {
|
||||
auto symbol = std::static_pointer_cast<Symbol>(nodes.front())->symbol();
|
||||
nodes.pop_front();
|
||||
if (is<Symbol>(list->front().get())) {
|
||||
auto symbol = std::static_pointer_cast<Symbol>(list->front())->symbol();
|
||||
const auto& nodes = list->rest();
|
||||
if (symbol == "def!") {
|
||||
return evalDef(nodes, env);
|
||||
}
|
||||
@@ -131,16 +130,11 @@ ValuePtr Eval::evalImpl()
|
||||
}
|
||||
|
||||
// Regular list
|
||||
if (is<Lambda>(evaluated_list->nodes().front().get())) {
|
||||
auto evaluated_nodes = evaluated_list->nodes();
|
||||
|
||||
// car
|
||||
auto lambda = std::static_pointer_cast<Lambda>(evaluated_nodes.front());
|
||||
// cdr
|
||||
evaluated_nodes.pop_front();
|
||||
if (is<Lambda>(evaluated_list->front().get())) {
|
||||
auto lambda = std::static_pointer_cast<Lambda>(evaluated_list->front());
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -167,8 +161,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
|
||||
else if (is<Collection>(ast_raw_ptr)) {
|
||||
std::shared_ptr<Collection> result = nullptr;
|
||||
(is<List>(ast_raw_ptr)) ? result = makePtr<List>() : result = makePtr<Vector>();
|
||||
auto nodes = std::static_pointer_cast<Collection>(ast)->nodes();
|
||||
for (auto node : nodes) {
|
||||
const auto& nodes = std::static_pointer_cast<Collection>(ast)->nodes();
|
||||
for (const auto& node : nodes) {
|
||||
m_ast_stack.push(node);
|
||||
m_env_stack.push(env);
|
||||
ValuePtr eval_node = evalImpl();
|
||||
@@ -181,8 +175,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
|
||||
}
|
||||
else if (is<HashMap>(ast_raw_ptr)) {
|
||||
auto result = makePtr<HashMap>();
|
||||
auto elements = std::static_pointer_cast<HashMap>(ast)->elements();
|
||||
for (auto& element : elements) {
|
||||
const auto& elements = std::static_pointer_cast<HashMap>(ast)->elements();
|
||||
for (const auto& element : elements) {
|
||||
m_ast_stack.push(element.second);
|
||||
m_env_stack.push(env);
|
||||
ValuePtr element_node = evalImpl();
|
||||
@@ -202,19 +196,22 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
|
||||
// (x y z)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -225,13 +222,12 @@ bool Eval::isMacroCall(ValuePtr ast, EnvironmentPtr env)
|
||||
ValuePtr Eval::macroExpand(ValuePtr ast, EnvironmentPtr env)
|
||||
{
|
||||
while (isMacroCall(ast, env)) {
|
||||
auto nodes = std::static_pointer_cast<List>(ast)->nodes();
|
||||
auto value = env->get(std::static_pointer_cast<Symbol>(nodes.front())->symbol());
|
||||
auto list = std::static_pointer_cast<List>(ast);
|
||||
auto value = env->get(std::static_pointer_cast<Symbol>(list->front())->symbol());
|
||||
auto lambda = std::static_pointer_cast<Lambda>(value);
|
||||
nodes.pop_front();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -253,12 +249,9 @@ ValuePtr Eval::apply(std::shared_ptr<List> evaluated_list)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// car
|
||||
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
|
||||
|
||||
+11
-11
@@ -32,17 +32,17 @@ private:
|
||||
bool isMacroCall(ValuePtr ast, EnvironmentPtr env);
|
||||
ValuePtr macroExpand(ValuePtr ast, EnvironmentPtr env);
|
||||
|
||||
ValuePtr evalDef(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalDefMacro(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalFn(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalMacroExpand(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalQuasiQuoteExpand(const std::list<ValuePtr>& nodes);
|
||||
ValuePtr evalQuote(const std::list<ValuePtr>& nodes);
|
||||
void evalDo(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
void evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
void evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
void evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
void evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalDef(const ValueVector& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalDefMacro(const ValueVector& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalFn(const ValueVector& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalMacroExpand(const ValueVector& nodes, EnvironmentPtr env);
|
||||
ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
|
||||
ValuePtr evalQuote(const ValueVector& nodes);
|
||||
void evalDo(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalIf(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalLet(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalTry(const ValueVector& nodes, EnvironmentPtr env);
|
||||
|
||||
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
||||
|
||||
|
||||
+6
-1
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <vector>
|
||||
|
||||
namespace blaze {
|
||||
|
||||
@@ -15,6 +16,9 @@ namespace blaze {
|
||||
|
||||
class Value;
|
||||
typedef std::shared_ptr<Value> ValuePtr;
|
||||
typedef std::vector<ValuePtr> ValueVector;
|
||||
typedef ValueVector::iterator ValueVectorIt;
|
||||
typedef ValueVector::const_iterator ValueVectorConstIt;
|
||||
|
||||
class Environment;
|
||||
typedef std::shared_ptr<Environment> EnvironmentPtr;
|
||||
@@ -22,8 +26,9 @@ typedef std::shared_ptr<Environment> EnvironmentPtr;
|
||||
// -----------------------------------------
|
||||
// Functions
|
||||
|
||||
extern ValuePtr readline(const std::string& prompt);
|
||||
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);
|
||||
|
||||
|
||||
+371
-183
@@ -4,8 +4,11 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <iterator> // std::advance
|
||||
#include <memory> // std::static_pointer_cast
|
||||
#include <algorithm> // std::copy, std::reverse_copy
|
||||
#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 "ruc/file.h"
|
||||
@@ -36,10 +39,12 @@
|
||||
static struct FUNCTION_STRUCT_NAME(unique) \
|
||||
FUNCTION_STRUCT_NAME(unique)( \
|
||||
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 SIZE() std::distance(begin, end)
|
||||
|
||||
namespace blaze {
|
||||
|
||||
static std::unordered_map<std::string, FunctionType> s_functions;
|
||||
@@ -49,8 +54,8 @@ ADD_FUNCTION(
|
||||
{
|
||||
int64_t result = 0;
|
||||
|
||||
for (auto node : nodes) {
|
||||
VALUE_CAST(number, Number, node);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
VALUE_CAST(number, Number, (*it));
|
||||
result += number->number();
|
||||
}
|
||||
|
||||
@@ -60,16 +65,16 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"-",
|
||||
{
|
||||
if (nodes.size() == 0) {
|
||||
if (SIZE() == 0) {
|
||||
return makePtr<Number>(0);
|
||||
}
|
||||
|
||||
// Start with the first number
|
||||
VALUE_CAST(number, Number, nodes.front());
|
||||
VALUE_CAST(number, Number, (*begin));
|
||||
int64_t result = number->number();
|
||||
|
||||
// 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));
|
||||
result -= number->number();
|
||||
}
|
||||
@@ -82,8 +87,8 @@ ADD_FUNCTION(
|
||||
{
|
||||
int64_t result = 1;
|
||||
|
||||
for (auto node : nodes) {
|
||||
VALUE_CAST(number, Number, node);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
VALUE_CAST(number, Number, (*it));
|
||||
result *= number->number();
|
||||
}
|
||||
|
||||
@@ -93,14 +98,14 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"/",
|
||||
{
|
||||
CHECK_ARG_COUNT_AT_LEAST("/", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1);
|
||||
|
||||
// Start with the first number
|
||||
VALUE_CAST(number, Number, nodes.front());
|
||||
VALUE_CAST(number, Number, (*begin));
|
||||
double result = number->number();
|
||||
|
||||
// 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));
|
||||
result /= number->number();
|
||||
}
|
||||
@@ -114,14 +119,14 @@ ADD_FUNCTION(
|
||||
{ \
|
||||
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 */ \
|
||||
VALUE_CAST(number_node, Number, nodes.front()); \
|
||||
VALUE_CAST(number_node, Number, (*begin)); \
|
||||
int64_t number = number_node->number(); \
|
||||
\
|
||||
/* 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)); \
|
||||
int64_t current_number = current_number_node->number(); \
|
||||
if (!(number operator current_number)) { \
|
||||
@@ -144,7 +149,7 @@ ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
|
||||
ADD_FUNCTION(
|
||||
"list",
|
||||
{
|
||||
return makePtr<List>(nodes);
|
||||
return makePtr<List>(begin, end);
|
||||
});
|
||||
|
||||
ADD_FUNCTION(
|
||||
@@ -152,8 +157,8 @@ ADD_FUNCTION(
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto node : nodes) {
|
||||
VALUE_CAST(collection, Collection, node);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
VALUE_CAST(collection, Collection, (*it));
|
||||
if (!collection->empty()) {
|
||||
result = false;
|
||||
break;
|
||||
@@ -167,19 +172,17 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"count",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("count", nodes.size(), 1);
|
||||
|
||||
auto first_argument = nodes.front();
|
||||
CHECK_ARG_COUNT_IS("count", SIZE(), 1);
|
||||
|
||||
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
|
||||
}
|
||||
else if (is<Collection>(first_argument.get())) {
|
||||
result = std::static_pointer_cast<Collection>(first_argument)->size();
|
||||
else if (is<Collection>(begin->get())) {
|
||||
result = std::static_pointer_cast<Collection>(*begin)->size();
|
||||
}
|
||||
else {
|
||||
Error::the().add(format("wrong argument type: Collection, '{}'", first_argument));
|
||||
Error::the().add(format("wrong argument type: Collection, '{}'", *begin));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -194,10 +197,10 @@ ADD_FUNCTION(
|
||||
std::string result; \
|
||||
\
|
||||
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)); \
|
||||
\
|
||||
if (!isLast(it, nodes)) { \
|
||||
if (it != end && std::next(it) != end) { \
|
||||
result += concatenation; \
|
||||
} \
|
||||
} \
|
||||
@@ -211,10 +214,10 @@ ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
|
||||
#define PRINTER_PRINT(print_readably) \
|
||||
{ \
|
||||
Printer printer; \
|
||||
for (auto it = nodes.begin(); it != nodes.end(); ++it) { \
|
||||
for (auto it = begin; it != end; ++it) { \
|
||||
print("{}", printer.printNoErrorCheck(*it, print_readably)); \
|
||||
\
|
||||
if (!isLast(it, nodes)) { \
|
||||
if (it != end && std::next(it) != end) { \
|
||||
print(" "); \
|
||||
} \
|
||||
} \
|
||||
@@ -231,21 +234,21 @@ ADD_FUNCTION("println", PRINTER_PRINT(false));
|
||||
ADD_FUNCTION(
|
||||
"=",
|
||||
{
|
||||
CHECK_ARG_COUNT_AT_LEAST("=", nodes.size(), 2);
|
||||
CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2);
|
||||
|
||||
std::function<bool(ValuePtr, ValuePtr)> equal =
|
||||
[&equal](ValuePtr lhs, ValuePtr rhs) -> bool {
|
||||
if ((is<List>(lhs.get()) || is<Vector>(lhs.get()))
|
||||
&& (is<List>(rhs.get()) || is<Vector>(rhs.get()))) {
|
||||
auto lhs_nodes = std::static_pointer_cast<Collection>(lhs)->nodes();
|
||||
auto rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes();
|
||||
const auto& lhs_nodes = std::static_pointer_cast<Collection>(lhs)->nodes();
|
||||
const auto& rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes();
|
||||
|
||||
if (lhs_nodes.size() != rhs_nodes.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lhs_it = lhs_nodes.begin();
|
||||
auto rhs_it = rhs_nodes.begin();
|
||||
auto lhs_it = lhs_nodes.cbegin();
|
||||
auto rhs_it = rhs_nodes.cbegin();
|
||||
for (; lhs_it != lhs_nodes.end(); ++lhs_it, ++rhs_it) {
|
||||
if (!equal(*lhs_it, *rhs_it)) {
|
||||
return false;
|
||||
@@ -256,8 +259,8 @@ ADD_FUNCTION(
|
||||
}
|
||||
|
||||
if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) {
|
||||
auto lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements();
|
||||
auto rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements();
|
||||
const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements();
|
||||
const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements();
|
||||
|
||||
if (lhs_nodes.size() != rhs_nodes.size()) {
|
||||
return false;
|
||||
@@ -265,7 +268,7 @@ ADD_FUNCTION(
|
||||
|
||||
for (const auto& [key, value] : lhs_nodes) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -298,9 +301,9 @@ ADD_FUNCTION(
|
||||
};
|
||||
|
||||
bool result = true;
|
||||
auto it = nodes.begin();
|
||||
auto it_next = std::next(nodes.begin());
|
||||
for (; it_next != nodes.end(); ++it, ++it_next) {
|
||||
auto it = begin;
|
||||
auto it_next = begin + 1;
|
||||
for (; it_next != end; ++it, ++it_next) {
|
||||
if (!equal(*it, *it_next)) {
|
||||
result = false;
|
||||
break;
|
||||
@@ -313,9 +316,9 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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();
|
||||
|
||||
return read(input);
|
||||
@@ -324,9 +327,9 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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();
|
||||
|
||||
auto file = ruc::File(path);
|
||||
@@ -337,27 +340,27 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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)
|
||||
ADD_FUNCTION(
|
||||
"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)
|
||||
ADD_FUNCTION(
|
||||
"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();
|
||||
});
|
||||
@@ -366,10 +369,10 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"reset!",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("reset!", nodes.size(), 2);
|
||||
CHECK_ARG_COUNT_IS("reset!", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(atom, Atom, nodes.front());
|
||||
auto value = *std::next(nodes.begin());
|
||||
VALUE_CAST(atom, Atom, (*begin));
|
||||
auto value = *(begin + 1);
|
||||
|
||||
atom->reset(value);
|
||||
|
||||
@@ -380,26 +383,26 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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());
|
||||
IS_VALUE(Callable, callable);
|
||||
VALUE_CAST(callable, Callable, (*(begin + 1)));
|
||||
|
||||
// Remove atom and function from the argument list, add atom value
|
||||
nodes.pop_front();
|
||||
nodes.pop_front();
|
||||
nodes.push_front(atom->deref());
|
||||
begin += 2;
|
||||
auto arguments = ValueVector(end - begin + 1);
|
||||
arguments[0] = atom->deref();
|
||||
std::copy(begin, end, arguments.begin() + 1);
|
||||
|
||||
ValuePtr value = nullptr;
|
||||
if (is<Function>(callable.get())) {
|
||||
auto function = std::static_pointer_cast<Function>(callable)->function();
|
||||
value = function(nodes);
|
||||
value = function(arguments.begin(), arguments.end());
|
||||
}
|
||||
else {
|
||||
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);
|
||||
@@ -409,42 +412,53 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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();
|
||||
result_nodes.push_front(nodes.front());
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
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(
|
||||
"concat",
|
||||
{
|
||||
std::list<ValuePtr> result_nodes;
|
||||
|
||||
for (auto node : nodes) {
|
||||
VALUE_CAST(collection, Collection, node);
|
||||
auto argument_nodes = collection->nodes();
|
||||
result_nodes.splice(result_nodes.end(), argument_nodes);
|
||||
size_t count = 0;
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
VALUE_CAST(collection, Collection, (*it));
|
||||
count += collection->size();
|
||||
}
|
||||
|
||||
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))
|
||||
ADD_FUNCTION(
|
||||
"vec",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("vec", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
|
||||
|
||||
if (is<Vector>(nodes.front().get())) {
|
||||
return nodes.front();
|
||||
if (is<Vector>(begin->get())) {
|
||||
return *begin;
|
||||
}
|
||||
|
||||
VALUE_CAST(collection, Collection, nodes.front());
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
|
||||
return makePtr<Vector>(collection->nodes());
|
||||
});
|
||||
@@ -453,10 +467,10 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"nth",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("nth", nodes.size(), 2);
|
||||
CHECK_ARG_COUNT_IS("nth", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(collection, Collection, nodes.front());
|
||||
VALUE_CAST(number_node, Number, (*std::next(nodes.begin())));
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
VALUE_CAST(number_node, Number, (*(begin + 1)));
|
||||
auto collection_nodes = collection->nodes();
|
||||
auto index = (size_t)number_node->number();
|
||||
|
||||
@@ -473,70 +487,66 @@ ADD_FUNCTION(
|
||||
return *result;
|
||||
});
|
||||
|
||||
// (first (list 1 2 3))
|
||||
// (first (list 1 2 3)) -> 1
|
||||
ADD_FUNCTION(
|
||||
"first",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("first", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_IS("first", SIZE(), 1);
|
||||
|
||||
if (is<Constant>(nodes.front().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) {
|
||||
return makePtr<Constant>();
|
||||
}
|
||||
|
||||
VALUE_CAST(collection, Collection, nodes.front());
|
||||
auto collection_nodes = collection->nodes();
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
|
||||
return (collection_nodes.empty()) ? makePtr<Constant>() : collection_nodes.front();
|
||||
return (collection->empty()) ? makePtr<Constant>() : collection->front();
|
||||
});
|
||||
|
||||
// (rest (list 1 2 3))
|
||||
ADD_FUNCTION(
|
||||
"rest",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("rest", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_IS("rest", SIZE(), 1);
|
||||
|
||||
if (is<Constant>(nodes.front().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) {
|
||||
return makePtr<List>();
|
||||
}
|
||||
|
||||
VALUE_CAST(collection, Collection, nodes.front());
|
||||
auto collection_nodes = collection->nodes();
|
||||
if (collection_nodes.size() > 0) {
|
||||
collection_nodes.pop_front();
|
||||
}
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
|
||||
return makePtr<List>(collection_nodes);
|
||||
return makePtr<List>(collection->rest());
|
||||
});
|
||||
|
||||
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4)
|
||||
ADD_FUNCTION(
|
||||
"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);
|
||||
|
||||
VALUE_CAST(collection, Collection, nodes.back());
|
||||
VALUE_CAST(collection, Collection, (*std::prev(end)));
|
||||
|
||||
// Remove function and list from the arguments
|
||||
nodes.pop_front();
|
||||
nodes.pop_back();
|
||||
ValueVector arguments(begin + 1, end - 1);
|
||||
arguments.reserve(arguments.size() + collection->size());
|
||||
|
||||
// Append list nodes to the argument leftovers
|
||||
auto collection_nodes = collection->nodes();
|
||||
nodes.splice(nodes.end(), collection_nodes);
|
||||
auto nodes = collection->nodes();
|
||||
for (const auto& node : nodes) {
|
||||
arguments.push_back(node);
|
||||
}
|
||||
|
||||
ValuePtr value = nullptr;
|
||||
if (is<Function>(callable.get())) {
|
||||
auto function = std::static_pointer_cast<Function>(callable)->function();
|
||||
value = function(nodes);
|
||||
value = function(arguments.begin(), arguments.end());
|
||||
}
|
||||
else {
|
||||
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;
|
||||
@@ -546,23 +556,24 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"map",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("map", nodes.size(), 2);
|
||||
CHECK_ARG_COUNT_IS("map", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(callable, Callable, nodes.front());
|
||||
VALUE_CAST(collection, Collection, nodes.back());
|
||||
auto collection_nodes = collection->nodes();
|
||||
VALUE_CAST(callable, Callable, (*begin));
|
||||
VALUE_CAST(collection, Collection, (*(begin + 1)));
|
||||
const auto& collection_nodes = collection->nodes();
|
||||
|
||||
auto result = makePtr<List>();
|
||||
|
||||
if (is<Function>(callable.get())) {
|
||||
auto function = std::static_pointer_cast<Function>(callable)->function();
|
||||
for (auto node : collection_nodes) {
|
||||
result->add(function({ node }));
|
||||
for (const auto& node : collection_nodes) {
|
||||
auto arguments = ValueVector { node };
|
||||
result->add(function(arguments.begin(), arguments.end()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
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 })));
|
||||
}
|
||||
}
|
||||
@@ -574,22 +585,22 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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;
|
||||
})
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
#define IS_CONSTANT(name, constant) \
|
||||
{ \
|
||||
CHECK_ARG_COUNT_IS(name, nodes.size(), 1); \
|
||||
\
|
||||
return makePtr<Constant>( \
|
||||
is<Constant>(nodes.front().get()) \
|
||||
&& std::static_pointer_cast<Constant>(nodes.front())->state() == constant); \
|
||||
#define IS_CONSTANT(name, constant) \
|
||||
{ \
|
||||
CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
|
||||
\
|
||||
return makePtr<Constant>( \
|
||||
is<Constant>(begin->get()) \
|
||||
&& std::static_pointer_cast<Constant>(*begin)->state() == constant); \
|
||||
}
|
||||
|
||||
// (nil? nil)
|
||||
@@ -599,22 +610,22 @@ ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False));
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
#define IS_TYPE(type) \
|
||||
{ \
|
||||
bool result = true; \
|
||||
\
|
||||
if (nodes.size() == 0) { \
|
||||
result = false; \
|
||||
} \
|
||||
\
|
||||
for (auto node : nodes) { \
|
||||
if (!is<type>(node.get())) { \
|
||||
result = false; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return makePtr<Constant>(result); \
|
||||
#define IS_TYPE(type) \
|
||||
{ \
|
||||
bool result = true; \
|
||||
\
|
||||
if (SIZE() == 0) { \
|
||||
result = false; \
|
||||
} \
|
||||
\
|
||||
for (auto it = begin; it != end; ++it) { \
|
||||
if (!is<type>(it->get())) { \
|
||||
result = false; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return makePtr<Constant>(result); \
|
||||
}
|
||||
|
||||
// (symbol? 'foo)
|
||||
@@ -622,23 +633,63 @@ ADD_FUNCTION("atom?", IS_TYPE(Atom));
|
||||
ADD_FUNCTION("keyword?", IS_TYPE(Keyword));
|
||||
ADD_FUNCTION("list?", IS_TYPE(List));
|
||||
ADD_FUNCTION("map?", IS_TYPE(HashMap));
|
||||
ADD_FUNCTION("number?", IS_TYPE(Number));
|
||||
ADD_FUNCTION("sequential?", IS_TYPE(Collection));
|
||||
ADD_FUNCTION("string?", IS_TYPE(String));
|
||||
ADD_FUNCTION("symbol?", IS_TYPE(Symbol));
|
||||
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) \
|
||||
{ \
|
||||
CHECK_ARG_COUNT_IS(name, nodes.size(), 1); \
|
||||
\
|
||||
if (is<type>(nodes.front().get())) { \
|
||||
return nodes.front(); \
|
||||
} \
|
||||
\
|
||||
VALUE_CAST(stringValue, String, nodes.front()); \
|
||||
\
|
||||
return makePtr<type>(stringValue->data()); \
|
||||
#define STRING_TO_TYPE(name, type) \
|
||||
{ \
|
||||
CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
|
||||
\
|
||||
if (is<type>(begin->get())) { \
|
||||
return *begin; \
|
||||
} \
|
||||
\
|
||||
VALUE_CAST(stringValue, String, (*begin)); \
|
||||
\
|
||||
return makePtr<type>(stringValue->data()); \
|
||||
}
|
||||
|
||||
// (symbol "foo")
|
||||
@@ -652,8 +703,8 @@ ADD_FUNCTION(
|
||||
{
|
||||
auto result = makePtr<Vector>();
|
||||
|
||||
for (auto node : nodes) {
|
||||
result->add(node);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
result->add(*it);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -662,11 +713,11 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"hash-map",
|
||||
{
|
||||
CHECK_ARG_COUNT_EVEN("hash-map", nodes.size());
|
||||
CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
@@ -677,16 +728,16 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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());
|
||||
nodes.pop_front();
|
||||
VALUE_CAST(hash_map, HashMap, (*begin));
|
||||
begin++;
|
||||
|
||||
CHECK_ARG_COUNT_EVEN("assoc", nodes.size());
|
||||
CHECK_ARG_COUNT_EVEN("assoc", SIZE());
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
@@ -696,63 +747,62 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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());
|
||||
nodes.pop_front();
|
||||
VALUE_CAST(hash_map, HashMap, (*begin));
|
||||
begin++;
|
||||
|
||||
auto result = makePtr<HashMap>(hash_map->elements());
|
||||
|
||||
for (auto node : nodes) {
|
||||
result->remove(node);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
result->remove(*it);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
// (get {:kw "value"} :kw)
|
||||
// (get {:kw "value"} :kw) -> "value"
|
||||
ADD_FUNCTION(
|
||||
"get",
|
||||
{
|
||||
CHECK_ARG_COUNT_AT_LEAST("get", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
|
||||
|
||||
if (is<Constant>(nodes.front().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) {
|
||||
return makePtr<Constant>();
|
||||
}
|
||||
|
||||
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||
nodes.pop_front();
|
||||
VALUE_CAST(hash_map, HashMap, (*begin));
|
||||
begin++;
|
||||
|
||||
if (nodes.size() == 0) {
|
||||
if (SIZE() == 0) {
|
||||
return makePtr<Constant>();
|
||||
}
|
||||
|
||||
auto result = hash_map->get(nodes.front());
|
||||
auto result = hash_map->get(*begin);
|
||||
return (result) ? result : makePtr<Constant>();
|
||||
});
|
||||
|
||||
ADD_FUNCTION(
|
||||
"contains?",
|
||||
{
|
||||
CHECK_ARG_COUNT_AT_LEAST("contains?", nodes.size(), 1);
|
||||
CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||
nodes.pop_front();
|
||||
VALUE_CAST(hash_map, HashMap, (*begin));
|
||||
|
||||
if (nodes.size() == 0) {
|
||||
if (SIZE() == 0) {
|
||||
return makePtr<Constant>(false);
|
||||
}
|
||||
|
||||
return makePtr<Constant>(hash_map->exists(nodes.front()));
|
||||
return makePtr<Constant>(hash_map->exists(*(begin + 1)));
|
||||
});
|
||||
|
||||
ADD_FUNCTION(
|
||||
"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>();
|
||||
|
||||
@@ -772,9 +822,9 @@ ADD_FUNCTION(
|
||||
ADD_FUNCTION(
|
||||
"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>();
|
||||
|
||||
@@ -786,6 +836,144 @@ ADD_FUNCTION(
|
||||
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)
|
||||
|
||||
+5
-2
@@ -139,8 +139,11 @@ void Printer::printImpl(ValuePtr node, bool print_readably)
|
||||
}
|
||||
else if (is<Lambda>(node_raw_ptr)) {
|
||||
printSpacing();
|
||||
auto lambda = std::static_pointer_cast<Lambda>(node);
|
||||
m_print += format("#<user-{}>({:p})", (lambda->isMacro()) ? "macro" : "function", node_raw_ptr);
|
||||
m_print += format("#<user-function>({:p})", 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)) {
|
||||
printSpacing();
|
||||
|
||||
+24
-9
@@ -13,6 +13,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include "ruc/format/color.h"
|
||||
#include "ruc/format/print.h"
|
||||
|
||||
#include "readline.h"
|
||||
|
||||
@@ -22,13 +23,7 @@ Readline::Readline(bool pretty_print, std::string_view history_path)
|
||||
: m_pretty_print(pretty_print)
|
||||
, m_history_path(tilde_expand(history_path.data()))
|
||||
{
|
||||
if (!pretty_print) {
|
||||
m_prompt = "user> ";
|
||||
}
|
||||
else {
|
||||
m_prompt = format(fg(ruc::format::TerminalColor::Blue), "user>");
|
||||
m_prompt += format(" \033[1m");
|
||||
}
|
||||
m_prompt = createPrompt("user> ");
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
@@ -57,4 +67,9 @@ bool Readline::get(std::string& output)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Readline::get(std::string& output)
|
||||
{
|
||||
return get(output, m_prompt);
|
||||
}
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
+5
-1
@@ -15,15 +15,19 @@ namespace blaze {
|
||||
|
||||
class Readline {
|
||||
public:
|
||||
Readline() = default;
|
||||
Readline(bool pretty_print, std::string_view history_path);
|
||||
virtual ~Readline();
|
||||
|
||||
std::string createPrompt(const std::string& prompt);
|
||||
|
||||
bool get(std::string& output, const std::string& prompt);
|
||||
bool get(std::string& output);
|
||||
|
||||
private:
|
||||
bool m_pretty_print { false };
|
||||
std::string m_prompt;
|
||||
char* m_history_path;
|
||||
std::string m_prompt;
|
||||
};
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
+3
-2
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
#if 0
|
||||
auto read(std::string_view data) -> std::string_view
|
||||
{
|
||||
return data;
|
||||
@@ -57,5 +56,7 @@ auto eval(ValuePtr, EnvironmentPtr) -> ValuePtr
|
||||
return {};
|
||||
}
|
||||
|
||||
// Added to keep the linker happy at step A
|
||||
ValuePtr readline(const std::string&) { return nullptr; }
|
||||
|
||||
} // namespace blaze
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "reader.h"
|
||||
#include "settings.h"
|
||||
|
||||
#if 0
|
||||
namespace blaze {
|
||||
|
||||
auto read(std::string_view input) -> ValuePtr
|
||||
@@ -108,4 +107,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
|
||||
|
||||
namespace blaze {
|
||||
@@ -112,4 +111,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
|
||||
|
||||
namespace blaze {
|
||||
@@ -112,4 +111,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
|
||||
|
||||
static auto cleanup(int signal) -> void;
|
||||
@@ -129,4 +128,8 @@ static auto print(blaze::ValuePtr exp) -> std::string
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
|
||||
|
||||
static auto cleanup(int signal) -> void;
|
||||
@@ -135,4 +134,8 @@ static auto print(blaze::ValuePtr exp) -> std::string
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
namespace blaze {
|
||||
|
||||
static EnvironmentPtr s_outer_env = Environment::create();
|
||||
@@ -156,4 +155,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
namespace blaze {
|
||||
|
||||
static EnvironmentPtr s_outer_env = Environment::create();
|
||||
@@ -156,4 +155,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
namespace blaze {
|
||||
|
||||
static EnvironmentPtr s_outer_env = Environment::create();
|
||||
@@ -163,4 +162,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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 "settings.h"
|
||||
|
||||
#if 0
|
||||
namespace blaze {
|
||||
|
||||
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(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);
|
||||
|
||||
@@ -167,4 +165,8 @@ auto main(int argc, char* argv[]) -> int
|
||||
|
||||
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