|  |  |  | @ -27,105 +27,6 @@ Eval::Eval(ASTNodePtr ast, EnvironmentPtr env) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | // -----------------------------------------
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define EVAL_LET(ast, nodes, env)                                                                  \ | 
			
		
	
		
			
				
					|  |  |  |  | 	{                                                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (nodes.size() != 2) {                                                                   \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong number of arguments: let*, {}", nodes.size()));         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return nullptr;                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto first_argument = *nodes.begin();                                                      \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto second_argument = *std::next(nodes.begin());                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* First argument needs to be a List or Vector */                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!is<Collection>(first_argument.get())) {                                               \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong argument type: collection, '{}'", first_argument));     \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return nullptr;                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* Get the nodes out of the List or Vector */                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		std::list<ASTNodePtr> binding_nodes;                                                       \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto bindings = std::static_pointer_cast<Collection>(first_argument);                      \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		binding_nodes = bindings->nodes();                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* List or Vector needs to have an even number of elements */                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		size_t count = binding_nodes.size();                                                       \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (count % 2 != 0) {                                                                      \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong number of arguments: {}, {}", "let* bindings", count)); \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return nullptr;                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* Create new environment */                                                               \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto let_env = Environment::create(env);                                                   \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		for (auto it = binding_nodes.begin(); it != binding_nodes.end(); std::advance(it, 2)) {    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			/* First element needs to be a Symbol */                                               \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if (!is<Symbol>(*it->get())) {                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 				Error::the().add(format("wrong argument type: symbol, '{}'", *it));                \
 | 
			
		
	
		
			
				
					|  |  |  |  | 				return nullptr;                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			}                                                                                      \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			std::string key = std::static_pointer_cast<Symbol>(*it)->symbol();                     \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_ast_stack.push(*std::next(it));                                                      \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_env_stack.push(let_env);                                                             \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			ASTNodePtr value = evalImpl();                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			let_env->set(key, value);                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* TODO: Remove limitation of 3 arguments */                                               \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/*       Eval all values in this new env, return last sexp of the result */                \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(second_argument);                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(let_env);                                                                 \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		continue; /* TCO */                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define EVAL_DO(ast, nodes, env)                                                         \ | 
			
		
	
		
			
				
					|  |  |  |  | 	{                                                                                    \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (nodes.size() == 0) {                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong number of arguments: do, {}", nodes.size())); \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return nullptr;                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* Evaluate all nodes except the last */                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		for (auto it = nodes.begin(); it != std::prev(nodes.end(), 1); ++it) {           \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_ast_stack.push(*it);                                                       \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_env_stack.push(env);                                                       \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			evalImpl();                                                                  \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		/* Eval last node */                                                             \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(nodes.back());                                                  \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(env);                                                           \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		continue; /* TCO */                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define EVAL_IF(ast, nodes, env)                                                                                       \ | 
			
		
	
		
			
				
					|  |  |  |  | 	{                                                                                                                  \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (nodes.size() != 2 && nodes.size() != 3) {                                                                  \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong number of arguments: if, {}", nodes.size()));                               \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return nullptr;                                                                                            \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto first_argument = *nodes.begin();                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto second_argument = *std::next(nodes.begin());                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto third_argument = (nodes.size() == 3) ? *std::next(std::next(nodes.begin())) : makePtr<Value>(Value::Nil); \
 | 
			
		
	
		
			
				
					|  |  |  |  |                                                                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(first_argument);                                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(env);                                                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		auto first_evaluated = evalImpl();                                                                             \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!is<Value>(first_evaluated.get())                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		    || std::static_pointer_cast<Value>(first_evaluated)->state() == Value::True) {                             \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_ast_stack.push(second_argument);                                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_env_stack.push(env);                                                                                     \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			continue; /* TCO */                                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		else {                                                                                                         \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_ast_stack.push(third_argument);                                                                          \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			m_env_stack.push(env);                                                                                     \
 | 
			
		
	
		
			
				
					|  |  |  |  | 			continue; /* TCO */                                                                                        \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		}                                                                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void Eval::eval() | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	m_ast_stack = std::stack<ASTNodePtr>(); | 
			
		
	
	
		
			
				
					|  |  |  | @ -175,13 +76,16 @@ ASTNodePtr Eval::evalImpl() | 
			
		
	
		
			
				
					|  |  |  |  | 				return evalDef(nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			if (symbol == "let*") { | 
			
		
	
		
			
				
					|  |  |  |  | 				EVAL_LET(ast, nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				evalLet(nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				continue; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			if (symbol == "do") { | 
			
		
	
		
			
				
					|  |  |  |  | 				EVAL_DO(ast, nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				evalDo(nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				continue; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			if (symbol == "if") { | 
			
		
	
		
			
				
					|  |  |  |  | 				EVAL_IF(ast, nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				evalIf(nodes, env); | 
			
		
	
		
			
				
					|  |  |  |  | 				continue; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			if (symbol == "fn*") { | 
			
		
	
		
			
				
					|  |  |  |  | 				return evalFn(nodes, env); | 
			
		
	
	
		
			
				
					|  |  |  | @ -291,6 +195,104 @@ ASTNodePtr Eval::evalDef(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env) | 
			
		
	
		
			
				
					|  |  |  |  | 	return env->set(symbol, value); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void Eval::evalLet(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (nodes.size() != 2) { | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong number of arguments: let*, {}", nodes.size())); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	auto first_argument = *nodes.begin(); | 
			
		
	
		
			
				
					|  |  |  |  | 	auto second_argument = *std::next(nodes.begin()); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// First argument needs to be a List or Vector
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!is<Collection>(first_argument.get())) { | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong argument type: collection, '{}'", first_argument)); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// Get the nodes out of the List or Vector
 | 
			
		
	
		
			
				
					|  |  |  |  | 	std::list<ASTNodePtr> binding_nodes; | 
			
		
	
		
			
				
					|  |  |  |  | 	auto bindings = std::static_pointer_cast<Collection>(first_argument); | 
			
		
	
		
			
				
					|  |  |  |  | 	binding_nodes = bindings->nodes(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// List or Vector needs to have an even number of elements
 | 
			
		
	
		
			
				
					|  |  |  |  | 	size_t count = binding_nodes.size(); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (count % 2 != 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong number of arguments: {}, {}", "let* bindings", count)); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// Create new environment
 | 
			
		
	
		
			
				
					|  |  |  |  | 	auto let_env = Environment::create(env); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	for (auto it = binding_nodes.begin(); it != binding_nodes.end(); std::advance(it, 2)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// First element needs to be a Symbol
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!is<Symbol>(*it->get())) { | 
			
		
	
		
			
				
					|  |  |  |  | 			Error::the().add(format("wrong argument type: symbol, '{}'", *it)); | 
			
		
	
		
			
				
					|  |  |  |  | 			return; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		std::string key = std::static_pointer_cast<Symbol>(*it)->symbol(); | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(*std::next(it)); | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(let_env); | 
			
		
	
		
			
				
					|  |  |  |  | 		ASTNodePtr value = evalImpl(); | 
			
		
	
		
			
				
					|  |  |  |  | 		let_env->set(key, value); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// TODO: Remove limitation of 3 arguments
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// Eval all values in this new env, return last sexp of the result
 | 
			
		
	
		
			
				
					|  |  |  |  | 	m_ast_stack.push(second_argument); | 
			
		
	
		
			
				
					|  |  |  |  | 	m_env_stack.push(let_env); | 
			
		
	
		
			
				
					|  |  |  |  | 	return; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void Eval::evalDo(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (nodes.size() == 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong number of arguments: do, {}", nodes.size())); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// Evaluate all nodes except the last
 | 
			
		
	
		
			
				
					|  |  |  |  | 	for (auto it = nodes.begin(); it != std::prev(nodes.end(), 1); ++it) { | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(*it); | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(env); | 
			
		
	
		
			
				
					|  |  |  |  | 		evalImpl(); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// Eval last node
 | 
			
		
	
		
			
				
					|  |  |  |  | 	m_ast_stack.push(nodes.back()); | 
			
		
	
		
			
				
					|  |  |  |  | 	m_env_stack.push(env); | 
			
		
	
		
			
				
					|  |  |  |  | 	return; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void Eval::evalIf(const std::list<ASTNodePtr>& nodes, EnvironmentPtr env) | 
			
		
	
		
			
				
					|  |  |  |  | { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (nodes.size() != 2 && nodes.size() != 3) { | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong number of arguments: if, {}", nodes.size())); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	auto first_argument = *nodes.begin(); | 
			
		
	
		
			
				
					|  |  |  |  | 	auto second_argument = *std::next(nodes.begin()); | 
			
		
	
		
			
				
					|  |  |  |  | 	auto third_argument = (nodes.size() == 3) ? *std::next(std::next(nodes.begin())) : makePtr<Value>(Value::Nil); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	m_ast_stack.push(first_argument); | 
			
		
	
		
			
				
					|  |  |  |  | 	m_env_stack.push(env); | 
			
		
	
		
			
				
					|  |  |  |  | 	auto first_evaluated = evalImpl(); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!is<Value>(first_evaluated.get()) | 
			
		
	
		
			
				
					|  |  |  |  | 	    || std::static_pointer_cast<Value>(first_evaluated)->state() == Value::True) { | 
			
		
	
		
			
				
					|  |  |  |  | 		m_ast_stack.push(second_argument); | 
			
		
	
		
			
				
					|  |  |  |  | 		m_env_stack.push(env); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	m_ast_stack.push(third_argument); | 
			
		
	
		
			
				
					|  |  |  |  | 	m_env_stack.push(env); | 
			
		
	
		
			
				
					|  |  |  |  | 	return; // TCO
 | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #define ARG_COUNT_CHECK(name, comparison, size)                                    \ | 
			
		
	
		
			
				
					|  |  |  |  | 	if (comparison) {                                                              \
 | 
			
		
	
		
			
				
					|  |  |  |  | 		Error::the().add(format("wrong number of arguments: {}, {}", name, size)); \
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |