Eval: Add special form while
This commit is contained in:
@@ -185,6 +185,11 @@ Keyword::Keyword(const std::string& data)
|
||||
{
|
||||
}
|
||||
|
||||
Keyword::Keyword(int64_t number)
|
||||
: m_data(std::string(1, 0x7f) + std::to_string(number)) // 127
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
Number::Number(int64_t number)
|
||||
|
||||
@@ -238,6 +238,7 @@ private:
|
||||
class Keyword final : public Value {
|
||||
public:
|
||||
Keyword(const std::string& data);
|
||||
Keyword(int64_t number);
|
||||
virtual ~Keyword() = default;
|
||||
|
||||
virtual bool isKeyword() const override { return true; }
|
||||
|
||||
@@ -331,6 +331,39 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
// (while true body...)
|
||||
void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
|
||||
{
|
||||
CHECK_ARG_COUNT_AT_LEAST("while", nodes.size(), 2, void());
|
||||
|
||||
// Condition
|
||||
ValuePtr predicate = *nodes.begin();
|
||||
|
||||
// Printer p;
|
||||
|
||||
m_ast = predicate;
|
||||
m_env = env;
|
||||
ValuePtr condition = evalImpl();
|
||||
while (!is<Constant>(condition.get())
|
||||
|| std::static_pointer_cast<Constant>(condition)->state() == Constant::True) {
|
||||
for (auto it = nodes.begin() + 1; it != nodes.end(); ++it) {
|
||||
m_ast = *it;
|
||||
m_env = env;
|
||||
evalImpl();
|
||||
}
|
||||
|
||||
m_ast = predicate;
|
||||
m_env = env;
|
||||
condition = evalImpl();
|
||||
|
||||
// print("{}\n", p.print(condition));
|
||||
}
|
||||
|
||||
m_ast = makePtr<Constant>();
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
@@ -109,6 +109,10 @@ ValuePtr Eval::evalImpl()
|
||||
evalQuasiQuote(nodes, env);
|
||||
continue; // TCO
|
||||
}
|
||||
if (symbol == "while") {
|
||||
evalWhile(nodes, env);
|
||||
continue; // TCO
|
||||
}
|
||||
}
|
||||
|
||||
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
||||
|
||||
@@ -44,6 +44,7 @@ private:
|
||||
void evalIf(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalLet(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env);
|
||||
void evalWhile(const ValueVector& nodes, EnvironmentPtr env);
|
||||
|
||||
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
||||
|
||||
|
||||
+133
-19
@@ -10,6 +10,7 @@
|
||||
#include <iterator> // std::advance, std::distance, std::next, std::prev
|
||||
#include <memory> // std::static_pointer_cast
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "ruc/file.h"
|
||||
#include "ruc/format/format.h"
|
||||
@@ -24,7 +25,7 @@
|
||||
|
||||
// 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.
|
||||
// Also, the counter macro is used to make the struct names unique.
|
||||
|
||||
#define FUNCTION_STRUCT_NAME(unique) __functionStruct##unique
|
||||
|
||||
@@ -41,7 +42,7 @@
|
||||
symbol, \
|
||||
[](ValueVectorConstIt begin, ValueVectorConstIt end) -> ValuePtr lambda);
|
||||
|
||||
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda);
|
||||
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__COUNTER__, symbol, lambda);
|
||||
|
||||
#define SIZE() std::distance(begin, end)
|
||||
|
||||
@@ -113,6 +114,18 @@ ADD_FUNCTION(
|
||||
return makePtr<Number>((int64_t)result);
|
||||
});
|
||||
|
||||
// (% 5 2) -> 1
|
||||
ADD_FUNCTION(
|
||||
"%",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("/", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(divide, Number, (*begin));
|
||||
VALUE_CAST(by, Number, (*(begin + 1)));
|
||||
|
||||
return makePtr<Number>(divide->number() % by->number());
|
||||
});
|
||||
|
||||
// // -----------------------------------------
|
||||
|
||||
#define NUMBER_COMPARE(operator) \
|
||||
@@ -146,12 +159,14 @@ ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// (list 1 2) -> (1 2)
|
||||
ADD_FUNCTION(
|
||||
"list",
|
||||
{
|
||||
return makePtr<List>(begin, end);
|
||||
});
|
||||
|
||||
// (empty?)
|
||||
ADD_FUNCTION(
|
||||
"empty?",
|
||||
{
|
||||
@@ -230,6 +245,8 @@ ADD_FUNCTION("println", PRINTER_PRINT(false));
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// (= 1 1) -> true
|
||||
// (= "foo" "foo") -> true
|
||||
ADD_FUNCTION(
|
||||
"=",
|
||||
{
|
||||
@@ -447,6 +464,32 @@ ADD_FUNCTION(
|
||||
return makePtr<List>(result_nodes);
|
||||
});
|
||||
|
||||
// (set-nth-element (list 1 2 3) 1 "foo") -> (1 "foo" 3)
|
||||
ADD_FUNCTION(
|
||||
"set-nth-element",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3);
|
||||
|
||||
VALUE_CAST(collection, Collection, (*begin));
|
||||
|
||||
VALUE_CAST(number_node, Number, (*(begin + 1)));
|
||||
auto index = static_cast<size_t>(number_node->number() < 0 ? 0 : number_node->number());
|
||||
|
||||
auto value = *(begin + 2);
|
||||
|
||||
auto collection_nodes = collection->nodesCopy();
|
||||
if (index >= collection->size()) { // Enlarge list if index out of bounds
|
||||
collection_nodes.resize(index + 1, makePtr<Constant>());
|
||||
}
|
||||
collection_nodes[index] = value;
|
||||
|
||||
if (is<Vector>(begin->get())) {
|
||||
return makePtr<Vector>(collection_nodes);
|
||||
}
|
||||
|
||||
return makePtr<List>(collection_nodes);
|
||||
});
|
||||
|
||||
// (vec (list 1 2 3))
|
||||
ADD_FUNCTION(
|
||||
"vec",
|
||||
@@ -462,7 +505,7 @@ ADD_FUNCTION(
|
||||
return makePtr<Vector>(collection->nodesCopy());
|
||||
});
|
||||
|
||||
// (nth (list 1 2 3) 0)
|
||||
// (nth (list 1 2 3) 0) -> 1
|
||||
ADD_FUNCTION(
|
||||
"nth",
|
||||
{
|
||||
@@ -497,7 +540,7 @@ ADD_FUNCTION(
|
||||
return (collection->empty()) ? makePtr<Constant>() : collection->front();
|
||||
});
|
||||
|
||||
// (rest (list 1 2 3))
|
||||
// (rest (list 1 2 3)) -> (2 3)
|
||||
ADD_FUNCTION(
|
||||
"rest",
|
||||
{
|
||||
@@ -673,22 +716,41 @@ ADD_FUNCTION(
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
#define STRING_TO_TYPE(name, type) \
|
||||
{ \
|
||||
CHECK_ARG_COUNT_IS(name, SIZE(), 1); \
|
||||
\
|
||||
if (is<type>(begin->get())) { \
|
||||
return *begin; \
|
||||
} \
|
||||
\
|
||||
VALUE_CAST(stringValue, String, (*begin)); \
|
||||
\
|
||||
return makePtr<type>(stringValue->data()); \
|
||||
}
|
||||
// (symbol "foo") -> foo
|
||||
ADD_FUNCTION(
|
||||
"symbol",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
|
||||
|
||||
// (symbol "foo")
|
||||
ADD_FUNCTION("symbol", STRING_TO_TYPE("symbol", Symbol));
|
||||
ADD_FUNCTION("keyword", STRING_TO_TYPE("keyword", Keyword));
|
||||
if (is<Symbol>(begin->get())) {
|
||||
return *begin;
|
||||
}
|
||||
|
||||
VALUE_CAST(stringValue, String, (*begin));
|
||||
|
||||
return makePtr<Symbol>(stringValue->data());
|
||||
});
|
||||
|
||||
// (keyword "foo") -> :foo
|
||||
// (keyword 123) -> :123
|
||||
ADD_FUNCTION(
|
||||
"keyword",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
|
||||
|
||||
if (is<Keyword>(begin->get())) {
|
||||
return *begin;
|
||||
}
|
||||
else if (is<Number>(begin->get())) {
|
||||
VALUE_CAST(numberValue, Number, (*begin));
|
||||
|
||||
return makePtr<Keyword>(numberValue->number());
|
||||
}
|
||||
|
||||
VALUE_CAST(stringValue, String, (*begin));
|
||||
|
||||
return makePtr<Keyword>(stringValue->data());
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
@@ -978,6 +1040,58 @@ ADD_FUNCTION(
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// (make-list 4 nil) -> (nil nil nil nil)
|
||||
ADD_FUNCTION(
|
||||
"make-list",
|
||||
{
|
||||
CHECK_ARG_COUNT_IS("make-list", SIZE(), 2);
|
||||
|
||||
VALUE_CAST(number, Number, (*begin));
|
||||
auto count = static_cast<size_t>(number->number() < 0 ? 0 : number->number());
|
||||
auto value = *std::next(begin);
|
||||
|
||||
auto nodes = ValueVector(count);
|
||||
if (is<Atom>(value.get())) {
|
||||
auto atom = std::static_pointer_cast<Atom>(value);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
nodes[i] = makePtr<Atom>(atom);
|
||||
}
|
||||
}
|
||||
// else if (is<Collection>(value.get())) {
|
||||
// for (size_t i = 0; i < count; ++i) {
|
||||
// auto nodes = std::static_pointer_cast<Collection>(value)->nodesCopy();
|
||||
// if (is<Vector>(value.get())) {
|
||||
// makePtr<Vector>(nodes);
|
||||
// continue;
|
||||
// }
|
||||
// nodes[i] = makePtr<List>(nodes);
|
||||
// }
|
||||
// }
|
||||
// else if (is<Constant>(value.get())) {
|
||||
// for (size_t i = 0; i < count; ++i) {
|
||||
// auto constant = std::static_pointer_cast<Constant>(value);
|
||||
// nodes[i] = makePtr<Constant>(constant);
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO:
|
||||
// Atom
|
||||
// Collection
|
||||
// Constant
|
||||
// Function
|
||||
// HashMap
|
||||
// Keyword
|
||||
// Lambda
|
||||
// List
|
||||
// Macro
|
||||
// Number
|
||||
// String
|
||||
// Symbol
|
||||
// Vector
|
||||
|
||||
return makePtr<List>(std::move(nodes));
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void installFunctions(EnvironmentPtr env)
|
||||
|
||||
Reference in New Issue
Block a user