Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb4ccc5822 | ||
|
|
8aa540c4e5 | ||
|
|
e09f168d4f | ||
|
|
6980d28b36 | ||
|
|
2a16f5ddf5 | ||
|
|
f89e73d44a | ||
|
|
c8b1e6dc81 |
@@ -115,3 +115,7 @@ 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 env STEP=step_env MAL_IMPL=js ../vendor/mal/runtest.py --deferrable --optional ../vendor/mal/tests/step8_macros.mal -- ./${PROJECT})
|
||||||
add_dependencies(test8 ${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})
|
||||||
|
add_dependencies(test9 ${PROJECT})
|
||||||
|
|||||||
+76
-6
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "error.h"
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
#include "printer.h"
|
#include "printer.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@@ -46,13 +47,77 @@ Vector::Vector(const std::list<ValuePtr>& nodes)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
|
HashMap::HashMap(const Elements& elements)
|
||||||
|
: m_elements(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) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_elements.emplace(key, value);
|
m_elements.insert_or_assign(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HashMap::add(ValuePtr key, ValuePtr value)
|
||||||
|
{
|
||||||
|
if (key == nullptr || value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_elements.insert_or_assign(getKeyString(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HashMap::remove(const std::string& key)
|
||||||
|
{
|
||||||
|
m_elements.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HashMap::remove(ValuePtr key)
|
||||||
|
{
|
||||||
|
if (key == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_elements.erase(getKeyString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HashMap::exists(const std::string& key)
|
||||||
|
{
|
||||||
|
return m_elements.find(key) != m_elements.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HashMap::exists(ValuePtr key)
|
||||||
|
{
|
||||||
|
return exists(getKeyString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr HashMap::get(const std::string& key)
|
||||||
|
{
|
||||||
|
if (!exists(key)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_elements[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
ValuePtr HashMap::get(ValuePtr key)
|
||||||
|
{
|
||||||
|
return get(getKeyString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HashMap::getKeyString(ValuePtr key)
|
||||||
|
{
|
||||||
|
if (!is<String>(key.get()) && !is<Keyword>(key.get())) {
|
||||||
|
Error::the().add(format("wrong argument type: string or keyword, {}", key));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return is<String>(key.get())
|
||||||
|
? std::static_pointer_cast<String>(key)->data()
|
||||||
|
: std::static_pointer_cast<Keyword>(key)->keyword();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -65,7 +130,7 @@ String::String(const std::string& data)
|
|||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
Keyword::Keyword(const std::string& data)
|
Keyword::Keyword(const std::string& data)
|
||||||
: m_data(data)
|
: m_data(std::string(1, 0x7f) + data) // 127
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,15 +143,20 @@ Number::Number(int64_t number)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
Symbol::Symbol(const std::string& symbol)
|
Constant::Constant(State state)
|
||||||
: m_symbol(symbol)
|
: m_state(state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Constant::Constant(bool state)
|
||||||
|
: m_state(state ? Constant::True : Constant::False)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
Constant::Constant(State state)
|
Symbol::Symbol(const std::string& symbol)
|
||||||
: m_state(state)
|
: m_symbol(symbol)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
#include <cstdint> // int64_t, uint8_t
|
#include <cstdint> // int64_t, uint8_t
|
||||||
#include <functional> // std::function
|
#include <functional> // std::function
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <map>
|
||||||
#include <memory> // std::shared_ptr
|
#include <memory> // std::shared_ptr
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <typeinfo> // typeid
|
#include <typeinfo> // typeid
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ruc/format/formatter.h"
|
#include "ruc/format/formatter.h"
|
||||||
@@ -128,19 +128,31 @@ private:
|
|||||||
// {}
|
// {}
|
||||||
class HashMap final : public Value {
|
class HashMap final : public Value {
|
||||||
public:
|
public:
|
||||||
|
using Elements = std::map<std::string, ValuePtr>;
|
||||||
|
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
|
HashMap(const Elements& elements);
|
||||||
virtual ~HashMap() = default;
|
virtual ~HashMap() = default;
|
||||||
|
|
||||||
void add(const std::string& key, ValuePtr value);
|
void add(const std::string& key, ValuePtr value);
|
||||||
|
void add(ValuePtr key, ValuePtr value);
|
||||||
|
void remove(const std::string& key);
|
||||||
|
void remove(ValuePtr key);
|
||||||
|
|
||||||
const std::unordered_map<std::string, ValuePtr>& elements() const { return m_elements; }
|
bool exists(const std::string& key);
|
||||||
|
bool exists(ValuePtr key);
|
||||||
|
ValuePtr get(const std::string& key);
|
||||||
|
ValuePtr get(ValuePtr key);
|
||||||
|
const Elements& elements() const { return m_elements; }
|
||||||
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; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool isHashMap() const override { return true; }
|
virtual bool isHashMap() const override { return true; }
|
||||||
|
|
||||||
std::unordered_map<std::string, ValuePtr> m_elements;
|
std::string getKeyString(ValuePtr key);
|
||||||
|
|
||||||
|
Elements m_elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -201,7 +213,9 @@ public:
|
|||||||
False,
|
False,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Constant() = default;
|
||||||
Constant(State state);
|
Constant(State state);
|
||||||
|
Constant(bool state);
|
||||||
virtual ~Constant() = default;
|
virtual ~Constant() = default;
|
||||||
|
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
@@ -209,7 +223,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
virtual bool isConstant() const override { return true; }
|
virtual bool isConstant() const override { return true; }
|
||||||
|
|
||||||
const State m_state;
|
const State m_state { State::Nil };
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer)
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnvironmentPtr Environment::create(const ValuePtr lambda, std::list<ValuePtr> arguments)
|
EnvironmentPtr Environment::create(const ValuePtr lambda, const std::list<ValuePtr>& 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, std::list<ValuePtr> arguments);
|
static EnvironmentPtr create(const ValuePtr lambda, const std::list<ValuePtr>& 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);
|
||||||
|
|||||||
+7
-1
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "ruc/singleton.h"
|
#include "ruc/singleton.h"
|
||||||
|
|
||||||
|
#include "forward.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
@@ -23,23 +24,28 @@ public:
|
|||||||
{
|
{
|
||||||
m_token_errors.clear();
|
m_token_errors.clear();
|
||||||
m_other_errors.clear();
|
m_other_errors.clear();
|
||||||
|
m_exceptions.clear();
|
||||||
}
|
}
|
||||||
void add(Token error) { m_token_errors.push_back(error); }
|
void add(Token error) { m_token_errors.push_back(error); }
|
||||||
void add(const std::string& error) { m_other_errors.push_back(error); }
|
void add(const std::string& error) { m_other_errors.push_back(error); }
|
||||||
|
void add(ValuePtr error) { m_exceptions.push_back(error); }
|
||||||
|
|
||||||
bool hasTokenError() { return m_token_errors.size() > 0; }
|
bool hasTokenError() { return m_token_errors.size() > 0; }
|
||||||
bool hasOtherError() { return m_other_errors.size() > 0; }
|
bool hasOtherError() { return m_other_errors.size() > 0; }
|
||||||
bool hasAnyError() { return hasTokenError() || hasOtherError(); }
|
bool hasException() { return m_exceptions.size() > 0; }
|
||||||
|
bool hasAnyError() { return hasTokenError() || hasOtherError() || hasException(); }
|
||||||
|
|
||||||
void setInput(std::string_view input) { m_input = input; }
|
void setInput(std::string_view input) { m_input = input; }
|
||||||
|
|
||||||
Token tokenError() const { return m_token_errors[0]; }
|
Token tokenError() const { return m_token_errors[0]; }
|
||||||
const std::string& otherError() const { return m_other_errors[0]; }
|
const std::string& otherError() const { return m_other_errors[0]; }
|
||||||
|
ValuePtr exception() const { return m_exceptions[0]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string_view m_input;
|
std::string_view m_input;
|
||||||
std::vector<Token> m_token_errors;
|
std::vector<Token> m_token_errors;
|
||||||
std::vector<std::string> m_other_errors;
|
std::vector<std::string> m_other_errors;
|
||||||
|
std::vector<ValuePtr> m_exceptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <iterator> // std::next, std::prev
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
#include "environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
@@ -277,6 +280,51 @@ void Eval::evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
return; // TCO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (try* x (catch* y z))
|
||||||
|
void Eval::evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1, void());
|
||||||
|
|
||||||
|
// Try 'x'
|
||||||
|
m_ast_stack.push(nodes.front());
|
||||||
|
m_env_stack.push(env);
|
||||||
|
auto result = evalImpl();
|
||||||
|
|
||||||
|
// Catch
|
||||||
|
if (nodes.size() == 2 && (Error::the().hasOtherError() || Error::the().hasException())) {
|
||||||
|
// Get the exception
|
||||||
|
auto error = (Error::the().hasOtherError())
|
||||||
|
? makePtr<String>(Error::the().otherError())
|
||||||
|
: Error::the().exception();
|
||||||
|
Error::the().clearErrors();
|
||||||
|
|
||||||
|
VALUE_CAST(catch_list, List, nodes.back(), void());
|
||||||
|
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());
|
||||||
|
if (catch_symbol->symbol() != "catch*") {
|
||||||
|
Error::the().add("catch block must begin with catch*");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())), void());
|
||||||
|
|
||||||
|
// Create new Environment that binds 'y' to the value of the exception
|
||||||
|
auto catch_env = Environment::create(env);
|
||||||
|
catch_env->set(catch_binding->symbol(), error);
|
||||||
|
|
||||||
|
// Evaluate 'z' using the new Environment
|
||||||
|
m_ast_stack.push(catch_nodes.back());
|
||||||
|
m_env_stack.push(catch_env);
|
||||||
|
return; // TCO
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ast_stack.push(result);
|
||||||
|
m_env_stack.push(env);
|
||||||
|
return; // TCO
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ ValuePtr Eval::evalImpl()
|
|||||||
EnvironmentPtr env = nullptr;
|
EnvironmentPtr env = nullptr;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (Error::the().hasAnyError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ast_stack.size() == 0) {
|
if (m_ast_stack.size() == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -114,6 +118,10 @@ ValuePtr Eval::evalImpl()
|
|||||||
evalQuasiQuote(nodes, env);
|
evalQuasiQuote(nodes, env);
|
||||||
continue; // TCO
|
continue; // TCO
|
||||||
}
|
}
|
||||||
|
if (symbol == "try*") {
|
||||||
|
evalTry(nodes, env);
|
||||||
|
continue; // TCO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ private:
|
|||||||
void evalIf(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 evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||||
void evalQuasiQuote(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 apply(std::shared_ptr<List> evaluated_list);
|
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
||||||
|
|
||||||
|
|||||||
+290
-48
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <iterator> // std::advance
|
||||||
#include <memory> // std::static_pointer_cast
|
#include <memory> // std::static_pointer_cast
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -146,25 +147,6 @@ ADD_FUNCTION(
|
|||||||
return makePtr<List>(nodes);
|
return makePtr<List>(nodes);
|
||||||
});
|
});
|
||||||
|
|
||||||
ADD_FUNCTION(
|
|
||||||
"list?",
|
|
||||||
{
|
|
||||||
bool result = true;
|
|
||||||
|
|
||||||
if (nodes.size() == 0) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto node : nodes) {
|
|
||||||
if (!is<List>(node.get())) {
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return makePtr<Constant>((result) ? Constant::True : Constant::False);
|
|
||||||
});
|
|
||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"empty?",
|
"empty?",
|
||||||
{
|
{
|
||||||
@@ -238,7 +220,7 @@ ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
|
|||||||
} \
|
} \
|
||||||
print("\n"); \
|
print("\n"); \
|
||||||
\
|
\
|
||||||
return makePtr<Constant>(Constant::Nil); \
|
return makePtr<Constant>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_FUNCTION("prn", PRINTER_PRINT(true));
|
ADD_FUNCTION("prn", PRINTER_PRINT(true));
|
||||||
@@ -369,26 +351,6 @@ ADD_FUNCTION(
|
|||||||
return makePtr<Atom>(nodes.front());
|
return makePtr<Atom>(nodes.front());
|
||||||
});
|
});
|
||||||
|
|
||||||
// (atom? myatom 2 "foo")
|
|
||||||
ADD_FUNCTION(
|
|
||||||
"atom?",
|
|
||||||
{
|
|
||||||
bool result = true;
|
|
||||||
|
|
||||||
if (nodes.size() == 0) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto node : nodes) {
|
|
||||||
if (!is<Atom>(node.get())) {
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return makePtr<Constant>((result) ? Constant::True : Constant::False);
|
|
||||||
});
|
|
||||||
|
|
||||||
// (deref myatom)
|
// (deref myatom)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"deref",
|
"deref",
|
||||||
@@ -414,7 +376,7 @@ ADD_FUNCTION(
|
|||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// (swap! myatom (fn* [x] (+ 1 x)))
|
// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"swap!",
|
"swap!",
|
||||||
{
|
{
|
||||||
@@ -422,8 +384,8 @@ ADD_FUNCTION(
|
|||||||
|
|
||||||
VALUE_CAST(atom, Atom, nodes.front());
|
VALUE_CAST(atom, Atom, nodes.front());
|
||||||
|
|
||||||
auto second_argument = *std::next(nodes.begin());
|
auto callable = *std::next(nodes.begin());
|
||||||
IS_VALUE(Callable, second_argument);
|
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();
|
nodes.pop_front();
|
||||||
@@ -431,12 +393,12 @@ ADD_FUNCTION(
|
|||||||
nodes.push_front(atom->deref());
|
nodes.push_front(atom->deref());
|
||||||
|
|
||||||
ValuePtr value = nullptr;
|
ValuePtr value = nullptr;
|
||||||
if (is<Function>(second_argument.get())) {
|
if (is<Function>(callable.get())) {
|
||||||
auto function = std::static_pointer_cast<Function>(second_argument)->function();
|
auto function = std::static_pointer_cast<Function>(callable)->function();
|
||||||
value = function(nodes);
|
value = function(nodes);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto lambda = std::static_pointer_cast<Lambda>(second_argument);
|
auto lambda = std::static_pointer_cast<Lambda>(callable);
|
||||||
value = eval(lambda->body(), Environment::create(lambda, nodes));
|
value = eval(lambda->body(), Environment::create(lambda, nodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +440,10 @@ ADD_FUNCTION(
|
|||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("vec", nodes.size(), 1);
|
CHECK_ARG_COUNT_IS("vec", nodes.size(), 1);
|
||||||
|
|
||||||
|
if (is<Vector>(nodes.front().get())) {
|
||||||
|
return nodes.front();
|
||||||
|
}
|
||||||
|
|
||||||
VALUE_CAST(collection, Collection, nodes.front());
|
VALUE_CAST(collection, Collection, nodes.front());
|
||||||
|
|
||||||
return makePtr<Vector>(collection->nodes());
|
return makePtr<Vector>(collection->nodes());
|
||||||
@@ -515,13 +481,13 @@ ADD_FUNCTION(
|
|||||||
|
|
||||||
if (is<Constant>(nodes.front().get())
|
if (is<Constant>(nodes.front().get())
|
||||||
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) {
|
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) {
|
||||||
return makePtr<Constant>(Constant::Nil);
|
return makePtr<Constant>();
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE_CAST(collection, Collection, nodes.front());
|
VALUE_CAST(collection, Collection, nodes.front());
|
||||||
auto collection_nodes = collection->nodes();
|
auto collection_nodes = collection->nodes();
|
||||||
|
|
||||||
return (collection_nodes.empty()) ? makePtr<Constant>(Constant::Nil) : collection_nodes.front();
|
return (collection_nodes.empty()) ? makePtr<Constant>() : collection_nodes.front();
|
||||||
});
|
});
|
||||||
|
|
||||||
// (rest (list 1 2 3))
|
// (rest (list 1 2 3))
|
||||||
@@ -544,6 +510,282 @@ ADD_FUNCTION(
|
|||||||
return makePtr<List>(collection_nodes);
|
return makePtr<List>(collection_nodes);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4)
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"apply",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("apply", nodes.size(), 2);
|
||||||
|
|
||||||
|
auto callable = nodes.front();
|
||||||
|
IS_VALUE(Callable, callable);
|
||||||
|
|
||||||
|
VALUE_CAST(collection, Collection, nodes.back());
|
||||||
|
|
||||||
|
// Remove function and list from the arguments
|
||||||
|
nodes.pop_front();
|
||||||
|
nodes.pop_back();
|
||||||
|
|
||||||
|
// Append list nodes to the argument leftovers
|
||||||
|
auto collection_nodes = collection->nodes();
|
||||||
|
nodes.splice(nodes.end(), collection_nodes);
|
||||||
|
|
||||||
|
ValuePtr value = nullptr;
|
||||||
|
if (is<Function>(callable.get())) {
|
||||||
|
auto function = std::static_pointer_cast<Function>(callable)->function();
|
||||||
|
value = function(nodes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto lambda = std::static_pointer_cast<Lambda>(callable);
|
||||||
|
value = eval(lambda->body(), Environment::create(lambda, nodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// (map (fn* (x) (* x 2)) (list 1 2 3))
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"map",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_IS("map", nodes.size(), 2);
|
||||||
|
|
||||||
|
VALUE_CAST(callable, Callable, nodes.front());
|
||||||
|
VALUE_CAST(collection, Collection, nodes.back());
|
||||||
|
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 }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto lambda = std::static_pointer_cast<Lambda>(callable);
|
||||||
|
for (auto node : collection_nodes) {
|
||||||
|
result->add(eval(lambda->body(), Environment::create(lambda, { node })));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// (throw x)
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"throw",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_IS("throw", nodes.size(), 1);
|
||||||
|
|
||||||
|
Error::the().add(nodes.front());
|
||||||
|
|
||||||
|
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); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// (nil? nil)
|
||||||
|
ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil));
|
||||||
|
ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True));
|
||||||
|
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); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// (symbol? 'foo)
|
||||||
|
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("sequential?", IS_TYPE(Collection));
|
||||||
|
ADD_FUNCTION("symbol?", IS_TYPE(Symbol));
|
||||||
|
ADD_FUNCTION("vector?", IS_TYPE(Vector));
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
#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()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// (symbol "foo")
|
||||||
|
ADD_FUNCTION("symbol", STRING_TO_TYPE("symbol", Symbol));
|
||||||
|
ADD_FUNCTION("keyword", STRING_TO_TYPE("keyword", Keyword));
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"vector",
|
||||||
|
{
|
||||||
|
auto result = makePtr<Vector>();
|
||||||
|
|
||||||
|
for (auto node : nodes) {
|
||||||
|
result->add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"hash-map",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_EVEN("hash-map", nodes.size());
|
||||||
|
|
||||||
|
auto result = makePtr<HashMap>();
|
||||||
|
|
||||||
|
for (auto it = nodes.begin(); it != nodes.end(); std::advance(it, 2)) {
|
||||||
|
result->add(*it, *(std::next(it)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// (assoc {:a 1 :b 2} :a 3 :c 1)
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"assoc",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("assoc", nodes.size(), 1);
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
nodes.pop_front();
|
||||||
|
|
||||||
|
CHECK_ARG_COUNT_EVEN("assoc", nodes.size());
|
||||||
|
|
||||||
|
auto result = makePtr<HashMap>(hash_map->elements());
|
||||||
|
|
||||||
|
for (auto it = nodes.begin(); it != nodes.end(); std::advance(it, 2)) {
|
||||||
|
result->add(*it, *(std::next(it)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"dissoc",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("dissoc", nodes.size(), 1);
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
nodes.pop_front();
|
||||||
|
|
||||||
|
auto result = makePtr<HashMap>(hash_map->elements());
|
||||||
|
|
||||||
|
for (auto node : nodes) {
|
||||||
|
result->remove(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// (get {:kw "value"} :kw)
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"get",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("get", nodes.size(), 1);
|
||||||
|
|
||||||
|
if (is<Constant>(nodes.front().get())
|
||||||
|
&& std::static_pointer_cast<Constant>(nodes.front())->state() == Constant::Nil) {
|
||||||
|
return makePtr<Constant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
nodes.pop_front();
|
||||||
|
|
||||||
|
if (nodes.size() == 0) {
|
||||||
|
return makePtr<Constant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = hash_map->get(nodes.front());
|
||||||
|
return (result) ? result : makePtr<Constant>();
|
||||||
|
});
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"contains?",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("contains?", nodes.size(), 1);
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
nodes.pop_front();
|
||||||
|
|
||||||
|
if (nodes.size() == 0) {
|
||||||
|
return makePtr<Constant>(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return makePtr<Constant>(hash_map->exists(nodes.front()));
|
||||||
|
});
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"keys",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("keys", nodes.size(), 1);
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
|
||||||
|
auto result = makePtr<List>();
|
||||||
|
|
||||||
|
auto elements = hash_map->elements();
|
||||||
|
for (auto pair : elements) {
|
||||||
|
if (pair.first.front() == 0x7f) { // 127
|
||||||
|
result->add(makePtr<Keyword>(pair.first.substr(1)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result->add(makePtr<String>(pair.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"vals",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("vals", nodes.size(), 1);
|
||||||
|
|
||||||
|
VALUE_CAST(hash_map, HashMap, nodes.front());
|
||||||
|
|
||||||
|
auto result = makePtr<List>();
|
||||||
|
|
||||||
|
auto elements = hash_map->elements();
|
||||||
|
for (auto pair : elements) {
|
||||||
|
result->add(pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
void installFunctions(EnvironmentPtr env)
|
void installFunctions(EnvironmentPtr env)
|
||||||
|
|||||||
@@ -170,7 +170,6 @@ bool Lexer::consumeKeyword()
|
|||||||
{
|
{
|
||||||
size_t column = m_column;
|
size_t column = m_column;
|
||||||
std::string keyword;
|
std::string keyword;
|
||||||
keyword += 0x7f; // 127
|
|
||||||
|
|
||||||
ignore(); // :
|
ignore(); // :
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ void Printer::printError()
|
|||||||
std::string error = Error::the().otherError();
|
std::string error = Error::the().otherError();
|
||||||
m_print += format("{}", error);
|
m_print += format("{}", error);
|
||||||
}
|
}
|
||||||
|
else if (Error::the().hasException()) {
|
||||||
|
ValuePtr error = Error::the().exception();
|
||||||
|
m_print += format("{}", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+2
-4
@@ -191,14 +191,12 @@ ValuePtr Reader::readHashMap()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is<String>(key.get()) && !is<Keyword>(key.get())) {
|
if (!is<String>(key.get()) && !is<Keyword>(key.get())) {
|
||||||
Error::the().add(format("{} is not a string or keyword", key));
|
Error::the().add(format("wrong argument type: string or keyword, {}", key));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = readImpl();
|
auto value = readImpl();
|
||||||
|
hash_map->add(key, value);
|
||||||
std::string keyString = is<String>(key.get()) ? std::static_pointer_cast<String>(key)->data() : std::static_pointer_cast<Keyword>(key)->keyword();
|
|
||||||
hash_map->add(keyString, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!consumeSpecific(Token { .type = Token::Type::BraceClose })) { // }
|
if (!consumeSpecific(Token { .type = Token::Type::BraceClose })) { // }
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "readline.h"
|
#include "readline.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
static EnvironmentPtr s_outer_env = Environment::create();
|
static EnvironmentPtr s_outer_env = Environment::create();
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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 EnvironmentPtr s_outer_env = Environment::create();
|
||||||
|
|
||||||
|
static auto cleanup(int signal) -> void
|
||||||
|
{
|
||||||
|
print("\033[0m\n");
|
||||||
|
std::exit(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))))))",
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
blaze::Readline readline(pretty_print, history_path);
|
||||||
|
|
||||||
|
std::string input;
|
||||||
|
while (readline.get(input)) {
|
||||||
|
if (pretty_print) {
|
||||||
|
print("\033[0m");
|
||||||
|
}
|
||||||
|
print("{}\n", rep(input, blaze::s_outer_env));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pretty_print) {
|
||||||
|
print("\033[0m");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user