Compare commits
7
Commits
1e76d4599a
...
826af24561
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
826af24561 | ||
|
|
c53c0af5a2 | ||
|
|
14367fa5a7 | ||
|
|
e47b338984 | ||
|
|
30b120befc | ||
|
|
90d6ff7d18 | ||
|
|
a60859acc4 |
+15
-4
@@ -9,12 +9,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
#include "environment.h"
|
||||||
|
#include "forward.h"
|
||||||
#include "printer.h"
|
#include "printer.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
void Collection::addNode(ASTNodePtr node)
|
void Collection::add(ASTNodePtr node)
|
||||||
{
|
{
|
||||||
m_nodes.push_back(node);
|
m_nodes.push_back(node);
|
||||||
}
|
}
|
||||||
@@ -63,8 +65,18 @@ Value::Value(State state)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
Function::Function(Lambda lambda)
|
Function::Function(const std::string& name, FunctionType function)
|
||||||
: m_lambda(lambda)
|
: m_name(name)
|
||||||
|
, m_function(function)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
Lambda::Lambda(std::vector<std::string> bindings, ASTNodePtr body, EnvironmentPtr env)
|
||||||
|
: m_bindings(bindings)
|
||||||
|
, m_body(body)
|
||||||
|
, m_env(env)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +86,6 @@ Function::Function(Lambda lambda)
|
|||||||
|
|
||||||
void Formatter<blaze::ASTNodePtr>::format(Builder& builder, blaze::ASTNodePtr value) const
|
void Formatter<blaze::ASTNodePtr>::format(Builder& builder, blaze::ASTNodePtr value) const
|
||||||
{
|
{
|
||||||
// printf("ASDJASJKDASJKDNAJK\n");
|
|
||||||
blaze::Printer printer;
|
blaze::Printer printer;
|
||||||
return Formatter<std::string>::format(builder, printer.printNoErrorCheck(value));
|
return Formatter<std::string>::format(builder, printer.printNoErrorCheck(value));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <typeinfo> // typeid
|
#include <typeinfo> // typeid
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ruc/format/formatter.h"
|
#include "ruc/format/formatter.h"
|
||||||
|
|
||||||
namespace blaze {
|
#include "forward.h"
|
||||||
|
|
||||||
class ASTNode;
|
namespace blaze {
|
||||||
typedef std::shared_ptr<ASTNode> ASTNodePtr;
|
|
||||||
|
|
||||||
class ASTNode {
|
class ASTNode {
|
||||||
public:
|
public:
|
||||||
@@ -42,6 +42,7 @@ public:
|
|||||||
virtual bool isValue() const { return false; }
|
virtual bool isValue() const { return false; }
|
||||||
virtual bool isSymbol() const { return false; }
|
virtual bool isSymbol() const { return false; }
|
||||||
virtual bool isFunction() const { return false; }
|
virtual bool isFunction() const { return false; }
|
||||||
|
virtual bool isLambda() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ASTNode() {}
|
ASTNode() {}
|
||||||
@@ -55,7 +56,7 @@ public:
|
|||||||
|
|
||||||
virtual bool isCollection() const override { return true; }
|
virtual bool isCollection() const override { return true; }
|
||||||
|
|
||||||
void addNode(ASTNodePtr node);
|
void add(ASTNodePtr node);
|
||||||
|
|
||||||
const std::list<ASTNodePtr>& nodes() const { return m_nodes; }
|
const std::list<ASTNodePtr>& nodes() const { return m_nodes; }
|
||||||
size_t size() const { return m_nodes.size(); }
|
size_t size() const { return m_nodes.size(); }
|
||||||
@@ -76,7 +77,6 @@ public:
|
|||||||
List() = default;
|
List() = default;
|
||||||
virtual ~List() = default;
|
virtual ~List() = default;
|
||||||
|
|
||||||
virtual bool isCollection() const override { return false; }
|
|
||||||
virtual bool isList() const override { return true; }
|
virtual bool isList() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,7 +88,6 @@ public:
|
|||||||
Vector() = default;
|
Vector() = default;
|
||||||
virtual ~Vector() = default;
|
virtual ~Vector() = default;
|
||||||
|
|
||||||
virtual bool isCollection() const override { return false; }
|
|
||||||
virtual bool isVector() const override { return true; }
|
virtual bool isVector() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,19 +198,40 @@ private:
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
using Lambda = std::function<ASTNodePtr(std::list<ASTNodePtr>)>;
|
using FunctionType = std::function<ASTNodePtr(std::list<ASTNodePtr>)>;
|
||||||
|
|
||||||
class Function final : public ASTNode {
|
class Function final : public ASTNode {
|
||||||
public:
|
public:
|
||||||
explicit Function(Lambda lambda);
|
explicit Function(const std::string& name, FunctionType function);
|
||||||
virtual ~Function() = default;
|
virtual ~Function() = default;
|
||||||
|
|
||||||
virtual bool isFunction() const override { return true; }
|
virtual bool isFunction() const override { return true; }
|
||||||
|
|
||||||
Lambda lambda() const { return m_lambda; }
|
const std::string& name() const { return m_name; }
|
||||||
|
FunctionType function() const { return m_function; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Lambda m_lambda;
|
const std::string m_name;
|
||||||
|
FunctionType m_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
class Lambda final : public ASTNode {
|
||||||
|
public:
|
||||||
|
Lambda(std::vector<std::string> bindings, ASTNodePtr body, EnvironmentPtr env);
|
||||||
|
virtual ~Lambda() = default;
|
||||||
|
|
||||||
|
virtual bool isLambda() const override { return true; }
|
||||||
|
|
||||||
|
std::vector<std::string> bindings() const { return m_bindings; }
|
||||||
|
ASTNodePtr body() const { return m_body; }
|
||||||
|
EnvironmentPtr env() const { return m_env; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_bindings;
|
||||||
|
ASTNodePtr m_body;
|
||||||
|
EnvironmentPtr m_env;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -254,6 +274,9 @@ inline bool ASTNode::fastIs<Symbol>() const { return isSymbol(); }
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline bool ASTNode::fastIs<Function>() const { return isFunction(); }
|
inline bool ASTNode::fastIs<Function>() const { return isFunction(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool ASTNode::fastIs<Lambda>() const { return isLambda(); }
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+55
-32
@@ -4,16 +4,68 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ruc/format/print.h"
|
#include <memory> // std::static_pointer_cast
|
||||||
|
|
||||||
|
#include "ruc/format/format.h"
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "forward.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
Environment::Environment(EnvironmentPtr outer)
|
EnvironmentPtr Environment::create()
|
||||||
: m_outer(outer)
|
|
||||||
{
|
{
|
||||||
|
return std::shared_ptr<Environment>(new Environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvironmentPtr Environment::create(EnvironmentPtr outer)
|
||||||
|
{
|
||||||
|
auto env = create();
|
||||||
|
|
||||||
|
env->m_outer = outer;
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvironmentPtr Environment::create(const ASTNodePtr lambda, std::list<ASTNodePtr> arguments)
|
||||||
|
{
|
||||||
|
auto lambda_casted = std::static_pointer_cast<Lambda>(lambda);
|
||||||
|
auto env = create(lambda_casted->env());
|
||||||
|
auto bindings = lambda_casted->bindings();
|
||||||
|
|
||||||
|
auto it = arguments.begin();
|
||||||
|
for (size_t i = 0; i < bindings.size(); ++i, ++it) {
|
||||||
|
if (bindings[i] == "&") {
|
||||||
|
if (i + 2 != bindings.size()) {
|
||||||
|
Error::the().add(format("invalid function: {}", lambda));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto list = makePtr<List>();
|
||||||
|
for (; it != arguments.end(); ++it) {
|
||||||
|
list->add(*it);
|
||||||
|
}
|
||||||
|
env->set(bindings[i + 1], list);
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == arguments.end()) {
|
||||||
|
Error::the().add(format("wrong number of arguments: {}, {}", lambda, arguments.size()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->set(bindings[i], *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != arguments.end()) {
|
||||||
|
Error::the().add(format("wrong number of arguments: {}, {}", lambda, arguments.size()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -36,8 +88,6 @@ ASTNodePtr Environment::set(const std::string& symbol, ASTNodePtr value)
|
|||||||
|
|
||||||
ASTNodePtr Environment::get(const std::string& symbol)
|
ASTNodePtr Environment::get(const std::string& symbol)
|
||||||
{
|
{
|
||||||
m_current_key = symbol;
|
|
||||||
|
|
||||||
if (exists(symbol)) {
|
if (exists(symbol)) {
|
||||||
return m_values[symbol];
|
return m_values[symbol];
|
||||||
}
|
}
|
||||||
@@ -49,31 +99,4 @@ ASTNodePtr Environment::get(const std::string& symbol)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
GlobalEnvironment::GlobalEnvironment()
|
|
||||||
{
|
|
||||||
add();
|
|
||||||
sub();
|
|
||||||
mul();
|
|
||||||
div();
|
|
||||||
|
|
||||||
lt();
|
|
||||||
lte();
|
|
||||||
gt();
|
|
||||||
gte();
|
|
||||||
|
|
||||||
list();
|
|
||||||
isList();
|
|
||||||
isEmpty();
|
|
||||||
count();
|
|
||||||
|
|
||||||
str();
|
|
||||||
prStr();
|
|
||||||
prn();
|
|
||||||
println();
|
|
||||||
|
|
||||||
equal();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+10
-37
@@ -6,59 +6,32 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "ast.h"
|
#include "forward.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
class Environment;
|
|
||||||
typedef std::shared_ptr<Environment> EnvironmentPtr;
|
|
||||||
|
|
||||||
class Environment {
|
class Environment {
|
||||||
public:
|
public:
|
||||||
Environment() = default;
|
|
||||||
Environment(EnvironmentPtr outer);
|
|
||||||
virtual ~Environment() = default;
|
virtual ~Environment() = default;
|
||||||
|
|
||||||
|
// 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 ASTNodePtr lambda, std::list<ASTNodePtr> arguments);
|
||||||
|
|
||||||
bool exists(const std::string& symbol);
|
bool exists(const std::string& symbol);
|
||||||
ASTNodePtr set(const std::string& symbol, ASTNodePtr value);
|
ASTNodePtr set(const std::string& symbol, ASTNodePtr value);
|
||||||
ASTNodePtr get(const std::string& symbol);
|
ASTNodePtr get(const std::string& symbol);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_current_key;
|
Environment() {}
|
||||||
std::unordered_map<std::string, ASTNodePtr> m_values;
|
|
||||||
EnvironmentPtr m_outer { nullptr };
|
EnvironmentPtr m_outer { nullptr };
|
||||||
};
|
std::unordered_map<std::string, ASTNodePtr> m_values;
|
||||||
|
|
||||||
class GlobalEnvironment final : public Environment {
|
|
||||||
public:
|
|
||||||
GlobalEnvironment();
|
|
||||||
virtual ~GlobalEnvironment() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void add(); // +
|
|
||||||
void sub(); // -
|
|
||||||
void mul(); // *
|
|
||||||
void div(); // /
|
|
||||||
|
|
||||||
void lt(); // <
|
|
||||||
void lte(); // <=
|
|
||||||
void gt(); // >
|
|
||||||
void gte(); // >=
|
|
||||||
|
|
||||||
void list(); // list
|
|
||||||
void isList(); // list?
|
|
||||||
void isEmpty(); // empty?
|
|
||||||
void count(); // count
|
|
||||||
|
|
||||||
void str(); // str
|
|
||||||
void prStr(); // pr-str
|
|
||||||
void prn(); // prn
|
|
||||||
void println(); // println
|
|
||||||
|
|
||||||
void equal(); // =
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@ public:
|
|||||||
m_token_errors.clear();
|
m_token_errors.clear();
|
||||||
m_other_errors.clear();
|
m_other_errors.clear();
|
||||||
}
|
}
|
||||||
void addError(Token error) { m_token_errors.push_back(error); }
|
void add(Token error) { m_token_errors.push_back(error); }
|
||||||
void addError(const std::string& error) { m_other_errors.push_back(error); }
|
void add(const std::string& error) { m_other_errors.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; }
|
||||||
|
|||||||
+73
-25
@@ -14,7 +14,7 @@
|
|||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "ruc/meta/assert.h"
|
#include "forward.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
@@ -63,6 +63,9 @@ ASTNodePtr Eval::evalImpl(ASTNodePtr ast, EnvironmentPtr env)
|
|||||||
if (symbol == "if") {
|
if (symbol == "if") {
|
||||||
return evalIf(nodes, env);
|
return evalIf(nodes, env);
|
||||||
}
|
}
|
||||||
|
if (symbol == "fn*") {
|
||||||
|
return evalFn(nodes, env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function call
|
// Function call
|
||||||
@@ -79,7 +82,7 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
|
|||||||
if (is<Symbol>(ast_raw_ptr)) {
|
if (is<Symbol>(ast_raw_ptr)) {
|
||||||
auto result = env->get(std::static_pointer_cast<Symbol>(ast)->symbol());
|
auto result = env->get(std::static_pointer_cast<Symbol>(ast)->symbol());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
Error::the().addError(format("'{}' not found", ast));
|
Error::the().add(format("'{}' not found", ast));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -92,7 +95,7 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
|
|||||||
if (eval_node == nullptr) {
|
if (eval_node == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
result->addNode(eval_node);
|
result->add(eval_node);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
|
|||||||
if (eval_node == nullptr) {
|
if (eval_node == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
result->addNode(eval_node);
|
result->add(eval_node);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -127,7 +130,7 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
|
|||||||
ASTNodePtr Eval::evalDef(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
ASTNodePtr Eval::evalDef(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
if (nodes.size() != 2) {
|
if (nodes.size() != 2) {
|
||||||
Error::the().addError(format("wrong number of arguments: def!, {}", nodes.size()));
|
Error::the().add(format("wrong number of arguments: def!, {}", nodes.size()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +139,7 @@ ASTNodePtr Eval::evalDef(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
|
|
||||||
// First element needs to be a Symbol
|
// First element needs to be a Symbol
|
||||||
if (!is<Symbol>(first_argument.get())) {
|
if (!is<Symbol>(first_argument.get())) {
|
||||||
Error::the().addError(format("wrong type argument: symbol, {}", first_argument));
|
Error::the().add(format("wrong argument type: symbol, {}", first_argument));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +158,7 @@ ASTNodePtr Eval::evalDef(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
ASTNodePtr Eval::evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
ASTNodePtr Eval::evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
if (nodes.size() != 2) {
|
if (nodes.size() != 2) {
|
||||||
Error::the().addError(format("wrong number of arguments: let*, {}", nodes.size()));
|
Error::the().add(format("wrong number of arguments: let*, {}", nodes.size()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,36 +166,30 @@ ASTNodePtr Eval::evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
auto second_argument = *std::next(nodes.begin());
|
auto second_argument = *std::next(nodes.begin());
|
||||||
|
|
||||||
// First argument needs to be a List or Vector
|
// First argument needs to be a List or Vector
|
||||||
if (!is<List>(first_argument.get()) && !is<Vector>(first_argument.get())) {
|
if (!is<Collection>(first_argument.get())) {
|
||||||
Error::the().addError(format("wrong argument type: list, '{}'", first_argument));
|
Error::the().add(format("wrong argument type: collection, '{}'", first_argument));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the nodes out of the List or Vector
|
// Get the nodes out of the List or Vector
|
||||||
std::list<ASTNodePtr> binding_nodes;
|
std::list<ASTNodePtr> binding_nodes;
|
||||||
if (is<List>(first_argument.get())) {
|
auto bindings = std::static_pointer_cast<Collection>(first_argument);
|
||||||
auto bindings = std::static_pointer_cast<List>(first_argument);
|
|
||||||
binding_nodes = bindings->nodes();
|
binding_nodes = bindings->nodes();
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto bindings = std::static_pointer_cast<Vector>(first_argument);
|
|
||||||
binding_nodes = bindings->nodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
// List or Vector needs to have an even number of elements
|
// List or Vector needs to have an even number of elements
|
||||||
size_t count = binding_nodes.size();
|
size_t count = binding_nodes.size();
|
||||||
if (count % 2 != 0) {
|
if (count % 2 != 0) {
|
||||||
Error::the().addError(format("wrong number of arguments: {}, {}", "let* bindings", count));
|
Error::the().add(format("wrong number of arguments: {}, {}", "let* bindings", count));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new environment
|
// Create new environment
|
||||||
auto let_env = makePtr<Environment>(env);
|
auto let_env = Environment::create(env);
|
||||||
|
|
||||||
for (auto it = binding_nodes.begin(); it != binding_nodes.end(); std::advance(it, 2)) {
|
for (auto it = binding_nodes.begin(); it != binding_nodes.end(); std::advance(it, 2)) {
|
||||||
// First element needs to be a Symbol
|
// First element needs to be a Symbol
|
||||||
if (!is<Symbol>(*it->get())) {
|
if (!is<Symbol>(*it->get())) {
|
||||||
Error::the().addError(format("wrong argument type: symbol, '{}'", *it));
|
Error::the().add(format("wrong argument type: symbol, '{}'", *it));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +206,7 @@ ASTNodePtr Eval::evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
ASTNodePtr Eval::evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
ASTNodePtr Eval::evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
if (nodes.size() == 0) {
|
if (nodes.size() == 0) {
|
||||||
Error::the().addError(format("wrong number of arguments: do, {}", nodes.size()));
|
Error::the().add(format("wrong number of arguments: do, {}", nodes.size()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +222,7 @@ ASTNodePtr Eval::evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
ASTNodePtr Eval::evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
ASTNodePtr Eval::evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
if (nodes.size() != 2 && nodes.size() != 3) {
|
if (nodes.size() != 2 && nodes.size() != 3) {
|
||||||
Error::the().addError(format("wrong number of arguments: if, {}", nodes.size()));
|
Error::the().add(format("wrong number of arguments: if, {}", nodes.size()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +240,42 @@ ASTNodePtr Eval::evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ARG_COUNT_CHECK(name, size, comparison) \
|
||||||
|
if (size comparison) { \
|
||||||
|
Error::the().add(format("wrong number of arguments: {}, {}", name, size)); \
|
||||||
|
return nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AST_CHECK(type, value) \
|
||||||
|
if (!is<type>(value.get())) { \
|
||||||
|
Error::the().add(format("wrong argument type: {}, {}", #type, value)); \
|
||||||
|
return nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AST_CAST(type, value, variable) \
|
||||||
|
AST_CHECK(type, value) \
|
||||||
|
auto variable = std::static_pointer_cast<type>(value);
|
||||||
|
|
||||||
|
ASTNodePtr Eval::evalFn(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env)
|
||||||
|
{
|
||||||
|
ARG_COUNT_CHECK("fn*", nodes.size(), != 2);
|
||||||
|
|
||||||
|
auto first_argument = *nodes.begin();
|
||||||
|
auto second_argument = *std::next(nodes.begin());
|
||||||
|
|
||||||
|
// First element needs to be a List or Vector
|
||||||
|
AST_CAST(Collection, first_argument, collection);
|
||||||
|
|
||||||
|
std::vector<std::string> bindings;
|
||||||
|
for (auto node : collection->nodes()) {
|
||||||
|
// All nodes need to be a Symbol
|
||||||
|
AST_CAST(Symbol, node, symbol);
|
||||||
|
bindings.push_back(symbol->symbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
return makePtr<Lambda>(bindings, second_argument, env);
|
||||||
|
}
|
||||||
|
|
||||||
ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list)
|
ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list)
|
||||||
{
|
{
|
||||||
if (evaluated_list == nullptr) {
|
if (evaluated_list == nullptr) {
|
||||||
@@ -251,17 +284,32 @@ ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list)
|
|||||||
|
|
||||||
auto nodes = evaluated_list->nodes();
|
auto nodes = evaluated_list->nodes();
|
||||||
|
|
||||||
if (!is<Function>(nodes.front().get())) {
|
if (!is<Function>(nodes.front().get()) && !is<Lambda>(nodes.front().get())) {
|
||||||
Error::the().addError(format("invalid function: {}", nodes.front()));
|
Error::the().add(format("invalid function: {}", nodes.front()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function
|
||||||
|
|
||||||
|
if (is<Function>(nodes.front().get())) {
|
||||||
// car
|
// car
|
||||||
auto lambda = std::static_pointer_cast<Function>(nodes.front())->lambda();
|
auto function = std::static_pointer_cast<Function>(nodes.front())->function();
|
||||||
// cdr
|
// cdr
|
||||||
nodes.pop_front();
|
nodes.pop_front();
|
||||||
|
|
||||||
return lambda(nodes);
|
return function(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambda
|
||||||
|
|
||||||
|
// car
|
||||||
|
auto lambda = std::static_pointer_cast<Lambda>(nodes.front());
|
||||||
|
// cdr
|
||||||
|
nodes.pop_front();
|
||||||
|
|
||||||
|
auto lambda_env = Environment::create(lambda, nodes);
|
||||||
|
|
||||||
|
return evalImpl(lambda->body(), lambda_env);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+4
-1
@@ -8,11 +8,13 @@
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "ast.h"
|
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "forward.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
|
class List;
|
||||||
|
|
||||||
class Eval {
|
class Eval {
|
||||||
public:
|
public:
|
||||||
Eval(ASTNodePtr ast, EnvironmentPtr env);
|
Eval(ASTNodePtr ast, EnvironmentPtr env);
|
||||||
@@ -29,6 +31,7 @@ private:
|
|||||||
ASTNodePtr evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
ASTNodePtr evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
||||||
ASTNodePtr evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
ASTNodePtr evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
||||||
ASTNodePtr evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
ASTNodePtr evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
||||||
|
ASTNodePtr evalFn(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env);
|
||||||
ASTNodePtr apply(std::shared_ptr<List> evaluated_list);
|
ASTNodePtr apply(std::shared_ptr<List> evaluated_list);
|
||||||
|
|
||||||
ASTNodePtr m_ast;
|
ASTNodePtr m_ast;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
|
|
||||||
|
namespace blaze {
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// Types
|
||||||
|
|
||||||
|
class ASTNode;
|
||||||
|
typedef std::shared_ptr<ASTNode> ASTNodePtr;
|
||||||
|
|
||||||
|
class Environment;
|
||||||
|
typedef std::shared_ptr<Environment> EnvironmentPtr;
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
extern void installFunctions(EnvironmentPtr env);
|
||||||
|
|
||||||
|
} // namespace blaze
|
||||||
+107
-140
@@ -7,26 +7,49 @@
|
|||||||
#include <memory> // std::static_pointer_cast
|
#include <memory> // std::static_pointer_cast
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ruc/format/color.h"
|
|
||||||
#include "ruc/format/format.h"
|
#include "ruc/format/format.h"
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "forward.h"
|
||||||
#include "printer.h"
|
#include "printer.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
// At the top-level you cant invoke any function, but you can create variables.
|
||||||
|
// Using a struct's constructor you can work around this limitation.
|
||||||
|
// Also the line number in the file is used to make the struct names unique.
|
||||||
|
|
||||||
|
#define FUNCTION_STRUCT_NAME(unique) __functionStruct##unique
|
||||||
|
|
||||||
|
#define ADD_FUNCTION_IMPL(unique, symbol, lambda) \
|
||||||
|
struct FUNCTION_STRUCT_NAME(unique) { \
|
||||||
|
FUNCTION_STRUCT_NAME(unique) \
|
||||||
|
(std::string __symbol, FunctionType __lambda) \
|
||||||
|
{ \
|
||||||
|
s_functions.emplace(__symbol, __lambda); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
static struct FUNCTION_STRUCT_NAME(unique) \
|
||||||
|
FUNCTION_STRUCT_NAME(unique)( \
|
||||||
|
symbol, \
|
||||||
|
[](std::list<ASTNodePtr> nodes) -> ASTNodePtr lambda);
|
||||||
|
|
||||||
|
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda);
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
void GlobalEnvironment::add()
|
static std::unordered_map<std::string, FunctionType> s_functions;
|
||||||
{
|
|
||||||
auto add = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
ADD_FUNCTION(
|
||||||
|
"+",
|
||||||
|
{
|
||||||
int64_t result = 0;
|
int64_t result = 0;
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
if (!is<Number>(node.get())) {
|
if (!is<Number>(node.get())) {
|
||||||
Error::the().addError(format("wrong argument type: number, '{}'", node));
|
Error::the().add(format("wrong argument type: number, '{}'", node));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,21 +57,18 @@ void GlobalEnvironment::add()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Number>(result);
|
return makePtr<Number>(result);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("+", makePtr<Function>(add));
|
ADD_FUNCTION(
|
||||||
}
|
"-",
|
||||||
|
{
|
||||||
void GlobalEnvironment::sub()
|
|
||||||
{
|
|
||||||
auto sub = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
if (nodes.size() == 0) {
|
if (nodes.size() == 0) {
|
||||||
return makePtr<Number>(0);
|
return makePtr<Number>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
if (!is<Number>(node.get())) {
|
if (!is<Number>(node.get())) {
|
||||||
Error::the().addError(format("wrong argument type: number, '{}'", node));
|
Error::the().add(format("wrong argument type: number, '{}'", node));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,19 +82,16 @@ void GlobalEnvironment::sub()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Number>(result);
|
return makePtr<Number>(result);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("-", makePtr<Function>(sub));
|
ADD_FUNCTION(
|
||||||
}
|
"*",
|
||||||
|
{
|
||||||
void GlobalEnvironment::mul()
|
|
||||||
{
|
|
||||||
auto mul = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
int64_t result = 1;
|
int64_t result = 1;
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
if (!is<Number>(node.get())) {
|
if (!is<Number>(node.get())) {
|
||||||
Error::the().addError(format("wrong argument type: number, '{}'", node));
|
Error::the().add(format("wrong argument type: number, '{}'", node));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,22 +99,19 @@ void GlobalEnvironment::mul()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Number>(result);
|
return makePtr<Number>(result);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("*", makePtr<Function>(mul));
|
ADD_FUNCTION(
|
||||||
}
|
"/",
|
||||||
|
{
|
||||||
void GlobalEnvironment::div()
|
|
||||||
{
|
|
||||||
auto div = [this](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
if (nodes.size() == 0) {
|
if (nodes.size() == 0) {
|
||||||
Error::the().addError(format("wrong number of arguments: {}, 0", m_current_key));
|
Error::the().add(format("wrong number of arguments: /, 0"));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
if (!is<Number>(node.get())) {
|
if (!is<Number>(node.get())) {
|
||||||
Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node));
|
Error::the().add(format("wrong argument type: number, '{}'", node));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,25 +125,22 @@ void GlobalEnvironment::div()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Number>((int64_t)result);
|
return makePtr<Number>((int64_t)result);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("/", makePtr<Function>(div));
|
// // -----------------------------------------
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
#define NUMBER_COMPARE(operator) \
|
||||||
|
{ \
|
||||||
#define NUMBER_COMPARE(symbol, comparison_symbol) \
|
|
||||||
auto lambda = [this](std::list<ASTNodePtr> nodes) -> ASTNodePtr { \
|
|
||||||
bool result = true; \
|
bool result = true; \
|
||||||
\
|
\
|
||||||
if (nodes.size() < 2) { \
|
if (nodes.size() < 2) { \
|
||||||
Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); \
|
Error::the().add(format("wrong number of arguments: {}, {}", #operator, nodes.size() - 1)); \
|
||||||
return nullptr; \
|
return nullptr; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
for (auto node : nodes) { \
|
for (auto node : nodes) { \
|
||||||
if (!is<Number>(node.get())) { \
|
if (!is<Number>(node.get())) { \
|
||||||
Error::the().addError(format("wrong argument type: number, '{}'", node)); \
|
Error::the().add(format("wrong argument type: number, '{}'", node)); \
|
||||||
return nullptr; \
|
return nullptr; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@@ -140,7 +151,7 @@ void GlobalEnvironment::div()
|
|||||||
/* Skip the first node */ \
|
/* Skip the first node */ \
|
||||||
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \
|
for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \
|
||||||
int64_t current_number = std::static_pointer_cast<Number>(*it)->number(); \
|
int64_t current_number = std::static_pointer_cast<Number>(*it)->number(); \
|
||||||
if (number comparison_symbol current_number) { \
|
if (!(number operator current_number)) { \
|
||||||
result = false; \
|
result = false; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
@@ -148,50 +159,30 @@ void GlobalEnvironment::div()
|
|||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return makePtr<Value>((result) ? Value::True : Value::False); \
|
return makePtr<Value>((result) ? Value::True : Value::False); \
|
||||||
}; \
|
}
|
||||||
\
|
|
||||||
m_values.emplace(symbol, makePtr<Function>(lambda));
|
|
||||||
|
|
||||||
void GlobalEnvironment::lt()
|
ADD_FUNCTION("<", NUMBER_COMPARE(<));
|
||||||
{
|
ADD_FUNCTION("<=", NUMBER_COMPARE(<=));
|
||||||
NUMBER_COMPARE("<", >=);
|
ADD_FUNCTION(">", NUMBER_COMPARE(>));
|
||||||
}
|
ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
|
||||||
|
|
||||||
void GlobalEnvironment::lte()
|
|
||||||
{
|
|
||||||
NUMBER_COMPARE("<=", >);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalEnvironment::gt()
|
|
||||||
{
|
|
||||||
NUMBER_COMPARE(">", <=);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalEnvironment::gte()
|
|
||||||
{
|
|
||||||
NUMBER_COMPARE(">=", <);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
void GlobalEnvironment::list()
|
ADD_FUNCTION(
|
||||||
{
|
"list",
|
||||||
auto list = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
{
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
list->addNode(node);
|
list->add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("list", makePtr<Function>(list));
|
ADD_FUNCTION(
|
||||||
}
|
"list?",
|
||||||
|
{
|
||||||
void GlobalEnvironment::isList()
|
|
||||||
{
|
|
||||||
auto is_list = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
@@ -202,68 +193,58 @@ void GlobalEnvironment::isList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("list?", makePtr<Function>(is_list));
|
ADD_FUNCTION(
|
||||||
}
|
"empty?",
|
||||||
|
{
|
||||||
void GlobalEnvironment::isEmpty()
|
|
||||||
{
|
|
||||||
auto is_empty = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
if (!is<List>(node.get())) {
|
if (!is<Collection>(node.get())) {
|
||||||
Error::the().addError(format("wrong argument type: list, '{}'", node));
|
Error::the().add(format("wrong argument type: collection, '{}'", node));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::static_pointer_cast<List>(node)->empty()) {
|
if (!std::static_pointer_cast<Collection>(node)->empty()) {
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("empty?", makePtr<Function>(is_empty));
|
ADD_FUNCTION(
|
||||||
}
|
"count",
|
||||||
|
{
|
||||||
void GlobalEnvironment::count()
|
|
||||||
{
|
|
||||||
auto count = [this](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
|
||||||
if (nodes.size() != 1) {
|
if (nodes.size() != 1) {
|
||||||
Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1));
|
Error::the().add(format("wrong number of arguments: count, {}", nodes.size() - 1));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto first_argument = nodes.front();
|
||||||
|
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
if (is<Value>(nodes.front().get()) && std::static_pointer_cast<Value>(nodes.front())->state() == Value::Nil) {
|
if (is<Value>(first_argument.get()) && std::static_pointer_cast<Value>(nodes.front())->state() == Value::Nil) {
|
||||||
// result = 0
|
// result = 0
|
||||||
}
|
}
|
||||||
else if (!is<List>(nodes.front().get())) {
|
else if (is<Collection>(first_argument.get())) {
|
||||||
result = std::static_pointer_cast<List>(nodes.front())->size();
|
result = std::static_pointer_cast<Collection>(first_argument)->size();
|
||||||
}
|
|
||||||
else if (!is<Vector>(nodes.front().get())) {
|
|
||||||
result = std::static_pointer_cast<Vector>(nodes.front())->size();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Error::the().addError(format("wrong argument type: list, '{}'", nodes));
|
Error::the().add(format("wrong argument type: collection, '{}'", first_argument));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Add numeric_limits check for implicit cast: size_t > int64_t
|
// FIXME: Add numeric_limits check for implicit cast: size_t > int64_t
|
||||||
return makePtr<Number>((int64_t)result);
|
return makePtr<Number>((int64_t)result);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("count", makePtr<Function>(count));
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
#define PRINTER_STRING(symbol, concatenation, print_readably) \
|
#define PRINTER_STRING(print_readably, concatenation) \
|
||||||
auto lambda = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr { \
|
{ \
|
||||||
std::string result; \
|
std::string result; \
|
||||||
\
|
\
|
||||||
Printer printer; \
|
Printer printer; \
|
||||||
@@ -276,22 +257,13 @@ void GlobalEnvironment::count()
|
|||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return makePtr<String>(result); \
|
return makePtr<String>(result); \
|
||||||
}; \
|
}
|
||||||
\
|
|
||||||
m_values.emplace(symbol, makePtr<Function>(lambda));
|
|
||||||
|
|
||||||
void GlobalEnvironment::str()
|
ADD_FUNCTION("str", PRINTER_STRING(false, ""));
|
||||||
{
|
ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
|
||||||
PRINTER_STRING("str", "", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalEnvironment::prStr()
|
#define PRINTER_PRINT(print_readably) \
|
||||||
{
|
{ \
|
||||||
PRINTER_STRING("pr-str", " ", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PRINTER_PRINT(symbol, print_readably) \
|
|
||||||
auto lambda = [](std::list<ASTNodePtr> nodes) -> ASTNodePtr { \
|
|
||||||
Printer printer; \
|
Printer printer; \
|
||||||
for (auto it = nodes.begin(); it != nodes.end(); ++it) { \
|
for (auto it = nodes.begin(); it != nodes.end(); ++it) { \
|
||||||
print("{}", printer.printNoErrorCheck(*it, print_readably)); \
|
print("{}", printer.printNoErrorCheck(*it, print_readably)); \
|
||||||
@@ -303,36 +275,27 @@ void GlobalEnvironment::prStr()
|
|||||||
print("\n"); \
|
print("\n"); \
|
||||||
\
|
\
|
||||||
return makePtr<Value>(Value::Nil); \
|
return makePtr<Value>(Value::Nil); \
|
||||||
}; \
|
}
|
||||||
\
|
|
||||||
m_values.emplace(symbol, makePtr<Function>(lambda));
|
|
||||||
|
|
||||||
void GlobalEnvironment::prn()
|
ADD_FUNCTION("prn", PRINTER_PRINT(true));
|
||||||
{
|
ADD_FUNCTION("println", PRINTER_PRINT(false));
|
||||||
PRINTER_PRINT("prn", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalEnvironment::println()
|
|
||||||
{
|
|
||||||
PRINTER_PRINT("println", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
void GlobalEnvironment::equal()
|
ADD_FUNCTION(
|
||||||
{
|
"=",
|
||||||
auto lambda = [this](std::list<ASTNodePtr> nodes) -> ASTNodePtr {
|
{
|
||||||
if (nodes.size() < 2) {
|
if (nodes.size() < 2) {
|
||||||
Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1));
|
Error::the().add(format("wrong number of arguments: =, {}", nodes.size() - 1));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<bool(ASTNodePtr, ASTNodePtr)> equal =
|
std::function<bool(ASTNodePtr, ASTNodePtr)> equal =
|
||||||
[&equal](ASTNodePtr lhs, ASTNodePtr rhs) -> bool {
|
[&equal](ASTNodePtr lhs, ASTNodePtr rhs) -> bool {
|
||||||
if ((is<List>(lhs.get()) && is<List>(rhs.get()))
|
if ((is<List>(lhs.get()) || is<Vector>(lhs.get()))
|
||||||
|| (is<Vector>(lhs.get()) && is<Vector>(rhs.get()))) {
|
&& (is<List>(rhs.get()) || is<Vector>(rhs.get()))) {
|
||||||
auto lhs_nodes = std::static_pointer_cast<List>(lhs)->nodes();
|
auto lhs_nodes = std::static_pointer_cast<Collection>(lhs)->nodes();
|
||||||
auto rhs_nodes = std::static_pointer_cast<List>(rhs)->nodes();
|
auto rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes();
|
||||||
|
|
||||||
if (lhs_nodes.size() != rhs_nodes.size()) {
|
if (lhs_nodes.size() != rhs_nodes.size()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -402,9 +365,13 @@ void GlobalEnvironment::equal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return makePtr<Value>((result) ? Value::True : Value::False);
|
return makePtr<Value>((result) ? Value::True : Value::False);
|
||||||
};
|
});
|
||||||
|
|
||||||
m_values.emplace("=", makePtr<Function>(lambda));
|
void installFunctions(EnvironmentPtr env)
|
||||||
|
{
|
||||||
|
for (const auto& [name, lambda] : s_functions) {
|
||||||
|
env->set(name, makePtr<Function>(name, lambda));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+1
-1
@@ -160,7 +160,7 @@ bool Lexer::consumeString()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (character != '"') {
|
if (character != '"') {
|
||||||
Error::the().addError({ Token::Type::Error, m_line, column, "expected '\"', got EOF" });
|
Error::the().add({ Token::Type::Error, m_line, column, "expected '\"', got EOF" });
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tokens.push_back({ Token::Type::String, m_line, column, text });
|
m_tokens.push_back({ Token::Type::String, m_line, column, text });
|
||||||
|
|||||||
+14
-18
@@ -71,29 +71,17 @@ void Printer::printImpl(ASTNodePtr node, bool print_readably)
|
|||||||
};
|
};
|
||||||
|
|
||||||
ASTNode* node_raw_ptr = node.get();
|
ASTNode* node_raw_ptr = node.get();
|
||||||
if (is<List>(node_raw_ptr)) {
|
if (is<Collection>(node_raw_ptr)) {
|
||||||
printSpacing();
|
printSpacing();
|
||||||
m_print += '(';
|
m_print += (is<List>(node_raw_ptr)) ? '(' : '[';
|
||||||
m_first_node = false;
|
m_first_node = false;
|
||||||
m_previous_node_is_list = true;
|
m_previous_node_is_list = true;
|
||||||
auto nodes = std::static_pointer_cast<List>(node)->nodes();
|
auto nodes = std::static_pointer_cast<Collection>(node)->nodes();
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
printImpl(node);
|
printImpl(node, print_readably);
|
||||||
m_previous_node_is_list = false;
|
m_previous_node_is_list = false;
|
||||||
}
|
}
|
||||||
m_print += ')';
|
m_print += (is<List>(node_raw_ptr)) ? ')' : ']';
|
||||||
}
|
|
||||||
else if (is<Vector>(node_raw_ptr)) {
|
|
||||||
printSpacing();
|
|
||||||
m_print += '[';
|
|
||||||
m_first_node = false;
|
|
||||||
m_previous_node_is_list = true;
|
|
||||||
auto nodes = std::static_pointer_cast<Vector>(node)->nodes();
|
|
||||||
for (auto node : nodes) {
|
|
||||||
printImpl(node);
|
|
||||||
m_previous_node_is_list = false;
|
|
||||||
}
|
|
||||||
m_print += ']';
|
|
||||||
}
|
}
|
||||||
else if (is<HashMap>(node_raw_ptr)) {
|
else if (is<HashMap>(node_raw_ptr)) {
|
||||||
printSpacing();
|
printSpacing();
|
||||||
@@ -103,7 +91,7 @@ void Printer::printImpl(ASTNodePtr node, bool print_readably)
|
|||||||
auto elements = std::static_pointer_cast<HashMap>(node)->elements();
|
auto elements = std::static_pointer_cast<HashMap>(node)->elements();
|
||||||
for (auto it = elements.begin(); it != elements.end(); ++it) {
|
for (auto it = elements.begin(); it != elements.end(); ++it) {
|
||||||
m_print += format("{} ", it->first.front() == 0x7f ? ":" + it->first.substr(1) : it->first); // 127
|
m_print += format("{} ", it->first.front() == 0x7f ? ":" + it->first.substr(1) : it->first); // 127
|
||||||
printImpl(it->second);
|
printImpl(it->second, print_readably);
|
||||||
|
|
||||||
if (isLast(it, elements)) {
|
if (isLast(it, elements)) {
|
||||||
m_print += ' ';
|
m_print += ' ';
|
||||||
@@ -145,6 +133,14 @@ void Printer::printImpl(ASTNodePtr node, bool print_readably)
|
|||||||
printSpacing();
|
printSpacing();
|
||||||
m_print += format("{}", std::static_pointer_cast<Symbol>(node)->symbol());
|
m_print += format("{}", std::static_pointer_cast<Symbol>(node)->symbol());
|
||||||
}
|
}
|
||||||
|
else if (is<Function>(node_raw_ptr)) {
|
||||||
|
printSpacing();
|
||||||
|
m_print += format("#<builtin-function>({})", std::static_pointer_cast<Function>(node)->name());
|
||||||
|
}
|
||||||
|
else if (is<Lambda>(node_raw_ptr)) {
|
||||||
|
printSpacing();
|
||||||
|
m_print += format("#<user-function>({:p})", node_raw_ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Printer::printError()
|
void Printer::printError()
|
||||||
|
|||||||
+33
-33
@@ -50,7 +50,7 @@ void Reader::read()
|
|||||||
case Token::Type::Comment:
|
case Token::Type::Comment:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Error::the().addError("more than one sexp in input");
|
Error::the().add("more than one sexp in input");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -70,21 +70,21 @@ ASTNodePtr Reader::readImpl()
|
|||||||
return readList();
|
return readList();
|
||||||
break;
|
break;
|
||||||
case Token::Type::ParenClose: // )
|
case Token::Type::ParenClose: // )
|
||||||
Error::the().addError("invalid read syntax: ')'");
|
Error::the().add("invalid read syntax: ')'");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
case Token::Type::BracketOpen: // [
|
case Token::Type::BracketOpen: // [
|
||||||
return readVector();
|
return readVector();
|
||||||
break;
|
break;
|
||||||
case Token::Type::BracketClose: // ]
|
case Token::Type::BracketClose: // ]
|
||||||
Error::the().addError("invalid read syntax: ']'");
|
Error::the().add("invalid read syntax: ']'");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
case Token::Type::BraceOpen: // {
|
case Token::Type::BraceOpen: // {
|
||||||
return readHashMap();
|
return readHashMap();
|
||||||
break;
|
break;
|
||||||
case Token::Type::BraceClose: // }
|
case Token::Type::BraceClose: // }
|
||||||
Error::the().addError("invalid read syntax: '}'");
|
Error::the().add("invalid read syntax: '}'");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
case Token::Type::Quote: // '
|
case Token::Type::Quote: // '
|
||||||
@@ -129,13 +129,13 @@ ASTNodePtr Reader::readSpliceUnquote()
|
|||||||
ignore(); // ~@
|
ignore(); // ~@
|
||||||
|
|
||||||
if (isEOF()) {
|
if (isEOF()) {
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("splice-unquote"));
|
list->add(makePtr<Symbol>("splice-unquote"));
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -146,11 +146,11 @@ ASTNodePtr Reader::readList()
|
|||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
while (!isEOF() && peek().type != Token::Type::ParenClose) {
|
while (!isEOF() && peek().type != Token::Type::ParenClose) {
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!consumeSpecific(Token { .type = Token::Type::ParenClose })) { // )
|
if (!consumeSpecific(Token { .type = Token::Type::ParenClose })) { // )
|
||||||
Error::the().addError("expected ')', got EOF");
|
Error::the().add("expected ')', got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +163,11 @@ ASTNodePtr Reader::readVector()
|
|||||||
|
|
||||||
auto vector = makePtr<Vector>();
|
auto vector = makePtr<Vector>();
|
||||||
while (!isEOF() && peek().type != Token::Type::BracketClose) {
|
while (!isEOF() && peek().type != Token::Type::BracketClose) {
|
||||||
vector->addNode(readImpl());
|
vector->add(readImpl());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!consumeSpecific(Token { .type = Token::Type::BracketClose })) { // ]
|
if (!consumeSpecific(Token { .type = Token::Type::BracketClose })) { // ]
|
||||||
Error::the().addError("expected ']', got EOF");
|
Error::the().add("expected ']', got EOF");
|
||||||
}
|
}
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
@@ -187,12 +187,12 @@ ASTNodePtr Reader::readHashMap()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key == nullptr || value == nullptr) {
|
if (key == nullptr || value == nullptr) {
|
||||||
Error::the().addError("hash-map requires an even-sized list");
|
Error::the().add("hash-map requires an even-sized list");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is<String>(key.get()) && !is<Keyword>(key.get())) {
|
if (!is<String>(key.get()) && !is<Keyword>(key.get())) {
|
||||||
Error::the().addError(format("{} is not a string or keyword", key));
|
Error::the().add(format("{} is not a string or keyword", key));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ ASTNodePtr Reader::readHashMap()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!consumeSpecific(Token { .type = Token::Type::BraceClose })) { // }
|
if (!consumeSpecific(Token { .type = Token::Type::BraceClose })) { // }
|
||||||
Error::the().addError("expected '}', got EOF");
|
Error::the().add("expected '}', got EOF");
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash_map;
|
return hash_map;
|
||||||
@@ -212,13 +212,13 @@ ASTNodePtr Reader::readQuote()
|
|||||||
ignore(); // '
|
ignore(); // '
|
||||||
|
|
||||||
if (isEOF()) {
|
if (isEOF()) {
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("quote"));
|
list->add(makePtr<Symbol>("quote"));
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -228,13 +228,13 @@ ASTNodePtr Reader::readQuasiQuote()
|
|||||||
ignore(); // `
|
ignore(); // `
|
||||||
|
|
||||||
if (isEOF()) {
|
if (isEOF()) {
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("quasiquote"));
|
list->add(makePtr<Symbol>("quasiquote"));
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -244,13 +244,13 @@ ASTNodePtr Reader::readUnquote()
|
|||||||
ignore(); // ~
|
ignore(); // ~
|
||||||
|
|
||||||
if (isEOF()) {
|
if (isEOF()) {
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("unquote"));
|
list->add(makePtr<Symbol>("unquote"));
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -261,17 +261,17 @@ ASTNodePtr Reader::readWithMeta()
|
|||||||
|
|
||||||
ignore(); // first token
|
ignore(); // first token
|
||||||
if (isEOF()) { // second token
|
if (isEOF()) { // second token
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
retreat();
|
retreat();
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("with-meta"));
|
list->add(makePtr<Symbol>("with-meta"));
|
||||||
ASTNodePtr first = readImpl();
|
ASTNodePtr first = readImpl();
|
||||||
ASTNodePtr second = readImpl();
|
ASTNodePtr second = readImpl();
|
||||||
list->addNode(second);
|
list->add(second);
|
||||||
list->addNode(first);
|
list->add(first);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -281,13 +281,13 @@ ASTNodePtr Reader::readDeref()
|
|||||||
ignore(); // @
|
ignore(); // @
|
||||||
|
|
||||||
if (isEOF()) {
|
if (isEOF()) {
|
||||||
Error::the().addError("expected form, got EOF");
|
Error::the().add("expected form, got EOF");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = makePtr<List>();
|
auto list = makePtr<List>();
|
||||||
list->addNode(makePtr<Symbol>("deref"));
|
list->add(makePtr<Symbol>("deref"));
|
||||||
list->addNode(readImpl());
|
list->add(readImpl());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -377,12 +377,12 @@ void Reader::dumpImpl(ASTNodePtr node)
|
|||||||
std::string indentation = std::string(m_indentation * 2, ' ');
|
std::string indentation = std::string(m_indentation * 2, ' ');
|
||||||
|
|
||||||
ASTNode* node_raw_ptr = node.get();
|
ASTNode* node_raw_ptr = node.get();
|
||||||
if (is<List>(node_raw_ptr)) {
|
if (is<Collection>(node_raw_ptr)) {
|
||||||
auto nodes = std::static_pointer_cast<List>(node)->nodes();
|
auto nodes = std::static_pointer_cast<List>(node)->nodes();
|
||||||
print("{}", indentation);
|
print("{}", indentation);
|
||||||
print(fg(ruc::format::TerminalColor::Blue), "ListContainer");
|
print(fg(ruc::format::TerminalColor::Blue), "{}Container", (is<List>(node_raw_ptr)) ? "List" : "Vector");
|
||||||
print(" <");
|
print(" <");
|
||||||
print(fg(ruc::format::TerminalColor::Blue), "()");
|
print(fg(ruc::format::TerminalColor::Blue), "{}", (is<List>(node_raw_ptr)) ? "()" : "{}");
|
||||||
print(">\n");
|
print(">\n");
|
||||||
m_indentation++;
|
m_indentation++;
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
|
|||||||
+69
-47
@@ -10,6 +10,7 @@
|
|||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
|
#include "forward.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "printer.h"
|
#include "printer.h"
|
||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
@@ -17,53 +18,14 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
static blaze::EnvironmentPtr env = blaze::makePtr<blaze::GlobalEnvironment>();
|
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create();
|
||||||
|
|
||||||
auto read(std::string_view input) -> blaze::ASTNodePtr
|
static auto cleanup(int signal) -> void;
|
||||||
{
|
static auto installLambdas(blaze::EnvironmentPtr env) -> void;
|
||||||
blaze::Lexer lexer(input);
|
static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string;
|
||||||
lexer.tokenize();
|
static auto read(std::string_view input) -> blaze::ASTNodePtr;
|
||||||
if (blaze::Settings::the().get("dump-lexer") == "1") {
|
static auto eval(blaze::ASTNodePtr ast, blaze::EnvironmentPtr env) -> blaze::ASTNodePtr;
|
||||||
lexer.dump();
|
static auto print(blaze::ASTNodePtr exp) -> std::string;
|
||||||
}
|
|
||||||
|
|
||||||
blaze::Reader reader(std::move(lexer.tokens()));
|
|
||||||
reader.read();
|
|
||||||
if (blaze::Settings::the().get("dump-reader") == "1") {
|
|
||||||
reader.dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.node();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto eval(blaze::ASTNodePtr ast) -> blaze::ASTNodePtr
|
|
||||||
{
|
|
||||||
blaze::Eval eval(ast, env);
|
|
||||||
eval.eval();
|
|
||||||
|
|
||||||
return eval.ast();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto print(blaze::ASTNodePtr exp) -> std::string
|
|
||||||
{
|
|
||||||
blaze::Printer printer;
|
|
||||||
|
|
||||||
return printer.print(exp, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rep(std::string_view input) -> std::string
|
|
||||||
{
|
|
||||||
blaze::Error::the().clearErrors();
|
|
||||||
blaze::Error::the().setInput(input);
|
|
||||||
|
|
||||||
return print(eval(read(input)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto cleanup(int signal) -> void
|
|
||||||
{
|
|
||||||
print("\033[0m\n");
|
|
||||||
std::exit(signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto main(int argc, char* argv[]) -> int
|
auto main(int argc, char* argv[]) -> int
|
||||||
{
|
{
|
||||||
@@ -89,6 +51,9 @@ auto main(int argc, char* argv[]) -> int
|
|||||||
std::signal(SIGINT, cleanup);
|
std::signal(SIGINT, cleanup);
|
||||||
std::signal(SIGTERM, cleanup);
|
std::signal(SIGTERM, cleanup);
|
||||||
|
|
||||||
|
installFunctions(s_outer_env);
|
||||||
|
installLambdas(s_outer_env);
|
||||||
|
|
||||||
blaze::Readline readline(pretty_print, history_path);
|
blaze::Readline readline(pretty_print, history_path);
|
||||||
|
|
||||||
std::string input;
|
std::string input;
|
||||||
@@ -96,7 +61,7 @@ auto main(int argc, char* argv[]) -> int
|
|||||||
if (pretty_print) {
|
if (pretty_print) {
|
||||||
print("\033[0m");
|
print("\033[0m");
|
||||||
}
|
}
|
||||||
print("{}\n", rep(input));
|
print("{}\n", rep(input, s_outer_env));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pretty_print) {
|
if (pretty_print) {
|
||||||
@@ -105,4 +70,61 @@ auto main(int argc, char* argv[]) -> int
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto cleanup(int signal) -> void
|
||||||
|
{
|
||||||
|
print("\033[0m\n");
|
||||||
|
std::exit(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string_view lambdaTable[] = {
|
||||||
|
"(def! not (fn* (cond) (if cond false true)))",
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto installLambdas(blaze::EnvironmentPtr env) -> void
|
||||||
|
{
|
||||||
|
for (auto function : lambdaTable) {
|
||||||
|
rep(function, env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string
|
||||||
|
{
|
||||||
|
blaze::Error::the().clearErrors();
|
||||||
|
blaze::Error::the().setInput(input);
|
||||||
|
|
||||||
|
return print(eval(read(input), env));
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto read(std::string_view input) -> blaze::ASTNodePtr
|
||||||
|
{
|
||||||
|
blaze::Lexer lexer(input);
|
||||||
|
lexer.tokenize();
|
||||||
|
if (blaze::Settings::the().get("dump-lexer") == "1") {
|
||||||
|
lexer.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
blaze::Reader reader(std::move(lexer.tokens()));
|
||||||
|
reader.read();
|
||||||
|
if (blaze::Settings::the().get("dump-reader") == "1") {
|
||||||
|
reader.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.node();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto eval(blaze::ASTNodePtr ast, blaze::EnvironmentPtr env) -> blaze::ASTNodePtr
|
||||||
|
{
|
||||||
|
blaze::Eval eval(ast, env);
|
||||||
|
eval.eval();
|
||||||
|
|
||||||
|
return eval.ast();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto print(blaze::ASTNodePtr exp) -> std::string
|
||||||
|
{
|
||||||
|
blaze::Printer printer;
|
||||||
|
|
||||||
|
return printer.print(exp, true);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user