Browse Source

Eval: Add special form while

master
Riyyi 1 year ago
parent
commit
80b25f8c21
  1. 5
      src/ast.cpp
  2. 1
      src/ast.h
  3. 33
      src/eval-special-form.cpp
  4. 4
      src/eval.cpp
  5. 1
      src/eval.h
  6. 152
      src/functions.cpp

5
src/ast.cpp

@ -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)

1
src/ast.h

@ -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; }

33
src/eval-special-form.cpp

@ -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

4
src/eval.cpp

@ -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));

1
src/eval.h

@ -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);

152
src/functions.cpp

@ -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)

Loading…
Cancel
Save