Compare commits
	
		
			21 Commits 
		
	
	
		
			3aa99d0045
			...
			11f0553b5a
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								 | 
						11f0553b5a | 2 years ago | 
| 
							
							
								 | 
						705e80ad6b | 2 years ago | 
| 
							
							
								 | 
						4cc2acc8a0 | 2 years ago | 
| 
							
							
								 | 
						f5dc1168eb | 2 years ago | 
| 
							
							
								 | 
						536e55e75a | 2 years ago | 
| 
							
							
								 | 
						25871cd5d5 | 2 years ago | 
| 
							
							
								 | 
						929fb5d645 | 2 years ago | 
| 
							
							
								 | 
						9db041946e | 2 years ago | 
| 
							
							
								 | 
						b74f3448b2 | 2 years ago | 
| 
							
							
								 | 
						b727f7147e | 2 years ago | 
| 
							
							
								 | 
						c6c6d69e73 | 2 years ago | 
| 
							
							
								 | 
						bb6f3e7496 | 2 years ago | 
| 
							
							
								 | 
						1915621427 | 2 years ago | 
| 
							
							
								 | 
						9895195410 | 2 years ago | 
| 
							
							
								 | 
						e8206d762c | 2 years ago | 
| 
							
							
								 | 
						b65482eb68 | 2 years ago | 
| 
							
							
								 | 
						67b982fd4c | 2 years ago | 
| 
							
							
								 | 
						d3a50abfbc | 2 years ago | 
| 
							
							
								 | 
						80b25f8c21 | 2 years ago | 
| 
							
							
								 | 
						0d43512ea9 | 2 years ago | 
| 
							
							
								 | 
						fa4bd63dca | 2 years ago | 
				 54 changed files with 2941 additions and 2948 deletions
			
			
		@ -0,0 +1 @@ | 
				
			|||||||
 | 
					file(COPY ${CMAKE_CURRENT_LIST_DIR}/../lisp DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) | 
				
			||||||
@ -0,0 +1,12 @@ | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					(defmacro! cond (fn* [& xs] | 
				
			||||||
 | 
					  (if (> (count xs) 0) | 
				
			||||||
 | 
					      (list 'if (first xs) | 
				
			||||||
 | 
					        (if (> (count xs) 1) | 
				
			||||||
 | 
					            (nth xs 1) | 
				
			||||||
 | 
					          (throw "odd number of forms to cond")) | 
				
			||||||
 | 
						    (cons 'cond (rest (rest xs))))))) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Local Variables: | 
				
			||||||
 | 
					;; eval: (emacs-lisp-mode) | 
				
			||||||
 | 
					;; End: | 
				
			||||||
@ -0,0 +1,14 @@ | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					(defmacro! defmacro | 
				
			||||||
 | 
					  (fn* [name args & body] | 
				
			||||||
 | 
					    `(defmacro! ~name (fn* ~args ~@body)))) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defmacro defn [name args & body] | 
				
			||||||
 | 
					  `(def! ~name (fn* ~args ~@body))) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defmacro def [name & body] | 
				
			||||||
 | 
					  `(def! ~name ~@body)) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Local Variables: | 
				
			||||||
 | 
					;; eval: (emacs-lisp-mode) | 
				
			||||||
 | 
					;; End: | 
				
			||||||
@ -0,0 +1,12 @@ | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					(defn load-file [file] | 
				
			||||||
 | 
					  "Load the Lisp file named FILE." | 
				
			||||||
 | 
					  (eval (read-string (str "(do " (slurp file) "\nnil)")))) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defn load [file] | 
				
			||||||
 | 
					  "Load the Lisp file named FILE." | 
				
			||||||
 | 
					  (eval (read-string (str "(let* [] (do " (slurp file) "))")))) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Local Variables: | 
				
			||||||
 | 
					;; eval: (emacs-lisp-mode) | 
				
			||||||
 | 
					;; End: | 
				
			||||||
@ -0,0 +1,6 @@ | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					(def *host-language* "C++") | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Local Variables: | 
				
			||||||
 | 
					;; eval: (emacs-lisp-mode) | 
				
			||||||
 | 
					;; End: | 
				
			||||||
@ -0,0 +1,8 @@ | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					(defn not [object] | 
				
			||||||
 | 
					  "Return true if OBJECT is nil or false, and return false otherwise." | 
				
			||||||
 | 
					  (if object false true)) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;; Local Variables: | 
				
			||||||
 | 
					;; eval: (emacs-lisp-mode) | 
				
			||||||
 | 
					;; End: | 
				
			||||||
@ -0,0 +1,174 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <filesystem> | 
				
			||||||
 | 
					#include <iterator> // std::distance | 
				
			||||||
 | 
					#include <memory>   // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/file.h" | 
				
			||||||
 | 
					#include "ruc/format/format.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					#include "error.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<FunctionParts> Environment::s_function_parts; | 
				
			||||||
 | 
					std::vector<std::string> Environment::s_lambdas; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EnvironmentPtr Environment::create() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						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 ValuePtr lambda, ValueVector&& 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 nodes = ValueVector(); | 
				
			||||||
 | 
								for (; it != arguments.end(); ++it) { | 
				
			||||||
 | 
									nodes.push_back(*it); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								env->set(bindings[i + 1], makePtr<List>(nodes)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadFunctions() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						loadCollectionAccess(); | 
				
			||||||
 | 
						loadCollectionConstructor(); | 
				
			||||||
 | 
						loadCollectionModify(); | 
				
			||||||
 | 
						loadCompare(); | 
				
			||||||
 | 
						loadConvert(); | 
				
			||||||
 | 
						loadFormat(); | 
				
			||||||
 | 
						loadMeta(); | 
				
			||||||
 | 
						loadMutable(); | 
				
			||||||
 | 
						loadOperators(); | 
				
			||||||
 | 
						loadOther(); | 
				
			||||||
 | 
						loadPredicate(); | 
				
			||||||
 | 
						loadRepl(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Load std files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::filesystem::path std = "./lisp"; | 
				
			||||||
 | 
						if (!std::filesystem::exists(std) || !std::filesystem::is_directory(std)) { | 
				
			||||||
 | 
							return; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						s_lambdas.reserve(std::distance(std::filesystem::directory_iterator(std), {})); | 
				
			||||||
 | 
						for (const auto& entry : std::filesystem::directory_iterator(std)) { | 
				
			||||||
 | 
							if (!std::filesystem::is_regular_file(entry.path()) | 
				
			||||||
 | 
							    || entry.path().extension().string() != ".bl") { | 
				
			||||||
 | 
								continue; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::filesystem::path filename = entry.path().filename(); | 
				
			||||||
 | 
							ruc::File file((std / filename).string()); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// The init will be added to the front and executed first
 | 
				
			||||||
 | 
							if (filename.string() == "init.bl") { | 
				
			||||||
 | 
								s_lambdas.emplace(s_lambdas.begin(), file.data()); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else { | 
				
			||||||
 | 
								s_lambdas.push_back(file.data()); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::registerFunction(FunctionParts function_parts) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						s_function_parts.push_back(function_parts); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::installFunctions(EnvironmentPtr env) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						for (const auto& function_parts : s_function_parts) { | 
				
			||||||
 | 
							env->set(std::string(function_parts.name), | 
				
			||||||
 | 
							         makePtr<Function>( | 
				
			||||||
 | 
										 function_parts.name, | 
				
			||||||
 | 
										 function_parts.signature, | 
				
			||||||
 | 
										 function_parts.documentation, | 
				
			||||||
 | 
										 function_parts.function)); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						for (const auto& lambda : s_lambdas) { | 
				
			||||||
 | 
							// Ensure all s-exprs are run with (do)
 | 
				
			||||||
 | 
							Repl::eval(Repl::read("(do " + lambda + ")"), env); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Environment::exists(std::string_view symbol) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						return m_values.find(std::string(symbol)) != m_values.end(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ValuePtr Environment::set(std::string_view symbol, ValuePtr value) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						if (exists(symbol)) { | 
				
			||||||
 | 
							m_values.erase(std::string(symbol)); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_values.emplace(symbol, value); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return value; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ValuePtr Environment::get(std::string_view symbol) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						if (exists(symbol)) { | 
				
			||||||
 | 
							return m_values[std::string(symbol)]; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (m_outer) { | 
				
			||||||
 | 
							return m_outer->get(symbol); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,68 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <list> | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					#include <unordered_map> | 
				
			||||||
 | 
					#include <vector> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// All of these combined become a Function in the Environment
 | 
				
			||||||
 | 
					struct FunctionParts { | 
				
			||||||
 | 
						std::string_view name; | 
				
			||||||
 | 
						std::string_view signature; | 
				
			||||||
 | 
						std::string_view documentation; | 
				
			||||||
 | 
						FunctionType function; | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Environment { | 
				
			||||||
 | 
					public: | 
				
			||||||
 | 
						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 ValuePtr lambda, ValueVector&& arguments); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void loadFunctions(); | 
				
			||||||
 | 
						static void registerFunction(FunctionParts function_parts); | 
				
			||||||
 | 
						static void installFunctions(EnvironmentPtr env); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool exists(std::string_view symbol); | 
				
			||||||
 | 
						ValuePtr set(std::string_view symbol, ValuePtr value); | 
				
			||||||
 | 
						ValuePtr get(std::string_view symbol); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private: | 
				
			||||||
 | 
						Environment() {} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Outer environment native functions, "Core"
 | 
				
			||||||
 | 
						static void loadCollectionAccess(); | 
				
			||||||
 | 
						static void loadCollectionConstructor(); | 
				
			||||||
 | 
						static void loadCollectionModify(); | 
				
			||||||
 | 
						static void loadCompare(); | 
				
			||||||
 | 
						static void loadConvert(); | 
				
			||||||
 | 
						static void loadFormat(); | 
				
			||||||
 | 
						static void loadMeta(); | 
				
			||||||
 | 
						static void loadMutable(); | 
				
			||||||
 | 
						static void loadOperators(); | 
				
			||||||
 | 
						static void loadOther(); | 
				
			||||||
 | 
						static void loadPredicate(); | 
				
			||||||
 | 
						static void loadRepl(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EnvironmentPtr m_outer { nullptr }; | 
				
			||||||
 | 
						std::unordered_map<std::string, ValuePtr> m_values; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static std::vector<FunctionParts> s_function_parts; | 
				
			||||||
 | 
						static std::vector<std::string> s_lambdas; | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,185 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstddef> // size_t | 
				
			||||||
 | 
					#include <memory>  // std:static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadCollectionAccess() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (count '(1 2 3))        -> 3
 | 
				
			||||||
 | 
						// (count [1 2 3])         -> 3
 | 
				
			||||||
 | 
						// (count {:foo 2 :bar 3}) -> 2
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"count", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("count", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t result = 0; | 
				
			||||||
 | 
								if (is<Constant>(begin->get()) && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
				
			||||||
 | 
									// result = 0
 | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else if (is<Collection>(begin->get())) { | 
				
			||||||
 | 
									result = std::static_pointer_cast<Collection>(*begin)->size(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else if (is<HashMap>(begin->get())) { | 
				
			||||||
 | 
									result = std::static_pointer_cast<HashMap>(*begin)->size(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else { | 
				
			||||||
 | 
									Error::the().add(::format("wrong argument type: Collection, '{}'", *begin)); | 
				
			||||||
 | 
									return nullptr; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// FIXME: Add numeric_limits check for implicit cast: size_t > int64_t
 | 
				
			||||||
 | 
								return makePtr<Number>((int64_t)result); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (first (list 1 2 3)) -> 1
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"first", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("first", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Constant>(begin->get()) | 
				
			||||||
 | 
							        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
				
			||||||
 | 
									return makePtr<Constant>(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (collection->empty()) ? makePtr<Constant>() : collection->front(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (nth (list 1 2 3) 0) -> 1
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"nth", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("nth", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
								VALUE_CAST(number_node, Number, (*(begin + 1))); | 
				
			||||||
 | 
								auto collection_nodes = collection->nodesRead(); | 
				
			||||||
 | 
								auto index = static_cast<size_t>(number_node->number()); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (number_node->number() < 0 || index >= collection_nodes.size()) { | 
				
			||||||
 | 
									Error::the().add("index is out of range"); | 
				
			||||||
 | 
									return nullptr; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return collection_nodes[index]; | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (rest (list 1 2 3)) -> (2 3)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"rest", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("rest", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Constant>(begin->get()) | 
				
			||||||
 | 
							        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
				
			||||||
 | 
									return makePtr<List>(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(collection->rest()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (get {:kw "value"} :kw) -> "value"
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"get", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Constant>(begin->get()) | 
				
			||||||
 | 
							        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
				
			||||||
 | 
									return makePtr<Constant>(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
								begin++; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (SIZE() == 0) { | 
				
			||||||
 | 
									return makePtr<Constant>(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto result = hash_map->get(*begin); | 
				
			||||||
 | 
								return (result) ? result : makePtr<Constant>(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (keys {"foo" 3 :bar 5}) -> ("foo" :bar)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"keys", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t count = hash_map->size(); | 
				
			||||||
 | 
								auto nodes = ValueVector(count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t i = 0; | 
				
			||||||
 | 
								auto elements = hash_map->elements(); | 
				
			||||||
 | 
								for (auto pair : elements) { | 
				
			||||||
 | 
									if (pair.first.front() == 0x7f) { // 127
 | 
				
			||||||
 | 
										nodes.at(i) = makePtr<Keyword>(pair.first.substr(1)); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									else { | 
				
			||||||
 | 
										nodes.at(i) = makePtr<String>(pair.first); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									i++; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (vals {"foo" 3 :bar 5}) -> (3 5)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"vals", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t count = hash_map->size(); | 
				
			||||||
 | 
								auto nodes = ValueVector(count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t i = 0; | 
				
			||||||
 | 
								auto elements = hash_map->elements(); | 
				
			||||||
 | 
								for (auto pair : elements) { | 
				
			||||||
 | 
									nodes.at(i) = pair.second; | 
				
			||||||
 | 
									i++; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,132 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstddef> // size_t | 
				
			||||||
 | 
					#include <memory>  // std:static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadCollectionConstructor() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (list 1 2) -> (1 2)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"list", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								return makePtr<List>(begin, end); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (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)); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (vec (list 1 2 3))
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"vec", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("vec", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Vector>(begin->get())) { | 
				
			||||||
 | 
									return *begin; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Vector>(collection->nodesCopy()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (vector 1 2 3) -> [1 2 3]
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"vector", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								auto result = makePtr<Vector>(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Vector>(begin, end); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10}
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"hash-map", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_EVEN("hash-map", SIZE()); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Elements elements; | 
				
			||||||
 | 
								for (auto it = begin; it != end; std::advance(it, 2)) { | 
				
			||||||
 | 
									const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
 | 
				
			||||||
 | 
									elements.insert_or_assign(HashMap::getKeyString(*it), value); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<HashMap>(elements); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,287 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm> // std::copy, std::reverse_copy | 
				
			||||||
 | 
					#include <cstddef>   // size_t | 
				
			||||||
 | 
					#include <memory>    // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadCollectionModify() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"apply", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto callable = *begin; | 
				
			||||||
 | 
								IS_VALUE(Callable, callable); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*std::prev(end))); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto arguments = ValueVector(begin + 1, end - 1); | 
				
			||||||
 | 
								arguments.reserve(arguments.size() + collection->size()); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Append list nodes to the argument leftovers
 | 
				
			||||||
 | 
								auto nodes = collection->nodesRead(); | 
				
			||||||
 | 
								for (const auto& node : nodes) { | 
				
			||||||
 | 
									arguments.push_back(node); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ValuePtr value = nullptr; | 
				
			||||||
 | 
								if (is<Function>(callable.get())) { | 
				
			||||||
 | 
									auto function = std::static_pointer_cast<Function>(callable)->function(); | 
				
			||||||
 | 
									value = function(arguments.begin(), arguments.end()); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else { | 
				
			||||||
 | 
									auto lambda = std::static_pointer_cast<Lambda>(callable); | 
				
			||||||
 | 
									value = Repl::eval(lambda->body(), Environment::create(lambda, std::move(arguments))); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return value; | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (cons 1 (list 2 3))
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"cons", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("cons", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ValuePtr first = *begin; | 
				
			||||||
 | 
								begin++; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
								const auto& collection_nodes = collection->nodesRead(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto result_nodes = ValueVector(collection_nodes.size() + 1); | 
				
			||||||
 | 
								result_nodes.at(0) = first; | 
				
			||||||
 | 
								std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(result_nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (concat (list 1) (list 2 3)) -> (1 2 3)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"concat", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								size_t count = 0; | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									VALUE_CAST(collection, Collection, (*it)); | 
				
			||||||
 | 
									count += collection->size(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto result_nodes = ValueVector(count); | 
				
			||||||
 | 
								size_t offset = 0; | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									const auto& collection_nodes = std::static_pointer_cast<Collection>(*it)->nodesRead(); | 
				
			||||||
 | 
									std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset); | 
				
			||||||
 | 
									offset += collection_nodes.size(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(result_nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (conj '(1 2 3) 4 5 6) -> (6 5 4 1 2 3)
 | 
				
			||||||
 | 
						// (conj [1 2 3] 4 5 6)  -> [1 2 3 4 5 6]
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"conj", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*begin)); | 
				
			||||||
 | 
								begin++; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const auto& collection_nodes = collection->nodesRead(); | 
				
			||||||
 | 
								size_t collection_count = collection_nodes.size(); | 
				
			||||||
 | 
								size_t argument_count = SIZE(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto nodes = ValueVector(argument_count + collection_count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<List>(collection.get())) { | 
				
			||||||
 | 
									std::reverse_copy(begin, end, nodes.begin()); | 
				
			||||||
 | 
									std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return makePtr<List>(nodes); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin()); | 
				
			||||||
 | 
								std::copy(begin, end, nodes.begin() + collection_count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Vector>(nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"map", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("map", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(callable, Callable, (*begin)); | 
				
			||||||
 | 
								VALUE_CAST(collection, Collection, (*(begin + 1))); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								size_t count = collection->size(); | 
				
			||||||
 | 
								auto nodes = ValueVector(count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Function>(callable.get())) { | 
				
			||||||
 | 
									auto function = std::static_pointer_cast<Function>(callable)->function(); | 
				
			||||||
 | 
									for (size_t i = 0; i < count; ++i) { | 
				
			||||||
 | 
										nodes.at(i) = function(collection->begin() + i, collection->begin() + i + 1); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else { | 
				
			||||||
 | 
									auto lambda = std::static_pointer_cast<Lambda>(callable); | 
				
			||||||
 | 
									auto collection_nodes = collection->nodesRead(); | 
				
			||||||
 | 
									for (size_t i = 0; i < count; ++i) { | 
				
			||||||
 | 
										nodes.at(i) = (Repl::eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<List>(nodes); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"set-nth", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								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); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (seq '(1 2 3)) -> (1 2 3)
 | 
				
			||||||
 | 
						// (seq [1 2 3])  -> (1 2 3)
 | 
				
			||||||
 | 
						// (seq "foo")    -> ("f" "o" "o")
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"seq", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("seq", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto front = *begin; | 
				
			||||||
 | 
								Value* front_raw_ptr = front.get(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Constant>(front_raw_ptr) && std::static_pointer_cast<Constant>(front)->state() == Constant::Nil) { | 
				
			||||||
 | 
									return makePtr<Constant>(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								if (is<Collection>(front_raw_ptr)) { | 
				
			||||||
 | 
									auto collection = std::static_pointer_cast<Collection>(front); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (collection->empty()) { | 
				
			||||||
 | 
										return makePtr<Constant>(); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (is<List>(front_raw_ptr)) { | 
				
			||||||
 | 
										return front; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return makePtr<List>(collection->nodesCopy()); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								if (is<String>(front_raw_ptr)) { | 
				
			||||||
 | 
									auto string = std::static_pointer_cast<String>(front); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (string->empty()) { | 
				
			||||||
 | 
										return makePtr<Constant>(); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									size_t count = string->size(); | 
				
			||||||
 | 
									auto nodes = ValueVector(count); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const auto& data = string->data(); | 
				
			||||||
 | 
									for (size_t i = 0; i < count; ++i) { | 
				
			||||||
 | 
										nodes.at(i) = makePtr<String>(data[i]); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return makePtr<List>(nodes); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Error::the().add(::format("wrong argument type: Collection or String, {}", front)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return nullptr; | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1}
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"assoc", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
								begin++; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								CHECK_ARG_COUNT_EVEN("assoc", SIZE()); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Elements elements(hash_map->elements()); | 
				
			||||||
 | 
								for (auto it = begin; it != end; std::advance(it, 2)) { | 
				
			||||||
 | 
									const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
 | 
				
			||||||
 | 
									elements.insert_or_assign(HashMap::getKeyString(*it), value); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<HashMap>(elements); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2}
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"dissoc", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
								begin++; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Elements elements(hash_map->elements()); | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									elements.erase(HashMap::getKeyString(*it)); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<HashMap>(elements); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,166 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>    // int64_t | 
				
			||||||
 | 
					#include <functional> // std::function | 
				
			||||||
 | 
					#include <memory>     // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadCompare() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					#define NUMBER_COMPARE(operator)                                                             \ | 
				
			||||||
 | 
						{                                                                                        \
 | 
				
			||||||
 | 
							CHECK_ARG_COUNT_AT_LEAST(#operator, SIZE(), 2);                                      \
 | 
				
			||||||
 | 
					                                                                                             \
 | 
				
			||||||
 | 
							bool result = true;                                                                  \
 | 
				
			||||||
 | 
					                                                                                             \
 | 
				
			||||||
 | 
							int64_t number = 0;                                                                  \
 | 
				
			||||||
 | 
							double decimal = 0;                                                                  \
 | 
				
			||||||
 | 
							bool current_numeric_is_number = false;                                              \
 | 
				
			||||||
 | 
					                                                                                             \
 | 
				
			||||||
 | 
							/* Start with the first number */                                                    \
 | 
				
			||||||
 | 
							IS_VALUE(Numeric, (*begin));                                                         \
 | 
				
			||||||
 | 
							if (is<Number>(begin->get())) {                                                      \
 | 
				
			||||||
 | 
								number = std::static_pointer_cast<Number>(*begin)->number();                     \
 | 
				
			||||||
 | 
								current_numeric_is_number = true;                                                \
 | 
				
			||||||
 | 
							}                                                                                    \
 | 
				
			||||||
 | 
							else {                                                                               \
 | 
				
			||||||
 | 
								decimal = std::static_pointer_cast<Decimal>(*begin)->decimal();                  \
 | 
				
			||||||
 | 
								current_numeric_is_number = false;                                               \
 | 
				
			||||||
 | 
							}                                                                                    \
 | 
				
			||||||
 | 
					                                                                                             \
 | 
				
			||||||
 | 
							/* Skip the first node */                                                            \
 | 
				
			||||||
 | 
							for (auto it = begin + 1; it != end; ++it) {                                         \
 | 
				
			||||||
 | 
								IS_VALUE(Numeric, (*it));                                                        \
 | 
				
			||||||
 | 
								if (is<Number>(*it->get())) {                                                    \
 | 
				
			||||||
 | 
									int64_t it_number = std::static_pointer_cast<Number>(*it)->number();         \
 | 
				
			||||||
 | 
									if (!((current_numeric_is_number ? number : decimal) operator it_number)) {  \
 | 
				
			||||||
 | 
										result = false;                                                          \
 | 
				
			||||||
 | 
										break;                                                                   \
 | 
				
			||||||
 | 
									}                                                                            \
 | 
				
			||||||
 | 
									number = it_number;                                                          \
 | 
				
			||||||
 | 
									current_numeric_is_number = true;                                            \
 | 
				
			||||||
 | 
								}                                                                                \
 | 
				
			||||||
 | 
								else {                                                                           \
 | 
				
			||||||
 | 
									double it_decimal = std::static_pointer_cast<Decimal>(*it)->decimal();       \
 | 
				
			||||||
 | 
									if (!((current_numeric_is_number ? number : decimal) operator it_decimal)) { \
 | 
				
			||||||
 | 
										result = false;                                                          \
 | 
				
			||||||
 | 
										break;                                                                   \
 | 
				
			||||||
 | 
									}                                                                            \
 | 
				
			||||||
 | 
									decimal = it_decimal;                                                        \
 | 
				
			||||||
 | 
									current_numeric_is_number = false;                                           \
 | 
				
			||||||
 | 
								}                                                                                \
 | 
				
			||||||
 | 
							}                                                                                    \
 | 
				
			||||||
 | 
					                                                                                             \
 | 
				
			||||||
 | 
							return makePtr<Constant>((result) ? Constant::True : Constant::False);               \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION("<", "", "", NUMBER_COMPARE(<)); | 
				
			||||||
 | 
						ADD_FUNCTION("<=", "", "", NUMBER_COMPARE(<=)); | 
				
			||||||
 | 
						ADD_FUNCTION(">", "", "", NUMBER_COMPARE(>)); | 
				
			||||||
 | 
						ADD_FUNCTION(">=", "", "", NUMBER_COMPARE(>=)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (= 1 1)         -> true
 | 
				
			||||||
 | 
						// (= "foo" "foo") -> true
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"=", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::function<bool(ValuePtr, ValuePtr)> equal = | 
				
			||||||
 | 
									[&equal](ValuePtr lhs, ValuePtr rhs) -> bool { | 
				
			||||||
 | 
									if (is<Collection>(lhs.get()) && is<Collection>(rhs.get())) { | 
				
			||||||
 | 
										auto lhs_collection = std::static_pointer_cast<Collection>(lhs); | 
				
			||||||
 | 
										auto rhs_collection = std::static_pointer_cast<Collection>(rhs); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (lhs_collection->size() != rhs_collection->size()) { | 
				
			||||||
 | 
											return false; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										auto lhs_it = lhs_collection->begin(); | 
				
			||||||
 | 
										auto rhs_it = rhs_collection->begin(); | 
				
			||||||
 | 
										for (; lhs_it != lhs_collection->end(); ++lhs_it, ++rhs_it) { | 
				
			||||||
 | 
											if (!equal(*lhs_it, *rhs_it)) { | 
				
			||||||
 | 
												return false; | 
				
			||||||
 | 
											} | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) { | 
				
			||||||
 | 
										const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements(); | 
				
			||||||
 | 
										const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (lhs_nodes.size() != rhs_nodes.size()) { | 
				
			||||||
 | 
											return false; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for (const auto& [key, value] : lhs_nodes) { | 
				
			||||||
 | 
											auto it = rhs_nodes.find(key); | 
				
			||||||
 | 
											if (it == rhs_nodes.cend() || !equal(value, it->second)) { | 
				
			||||||
 | 
												return false; | 
				
			||||||
 | 
											} | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (is<String>(lhs.get()) && is<String>(rhs.get()) | 
				
			||||||
 | 
								        && std::static_pointer_cast<String>(lhs)->data() == std::static_pointer_cast<String>(rhs)->data()) { | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									if (is<Keyword>(lhs.get()) && is<Keyword>(rhs.get()) | 
				
			||||||
 | 
								        && std::static_pointer_cast<Keyword>(lhs)->keyword() == std::static_pointer_cast<Keyword>(rhs)->keyword()) { | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									// clang-format off
 | 
				
			||||||
 | 
									if (is<Numeric>(lhs.get()) && is<Numeric>(rhs.get()) | 
				
			||||||
 | 
									    && (is<Number>(lhs.get()) | 
				
			||||||
 | 
									    	? std::static_pointer_cast<Number>(lhs)->number() | 
				
			||||||
 | 
									        : std::static_pointer_cast<Decimal>(lhs)->decimal()) | 
				
			||||||
 | 
									    == (is<Number>(rhs.get()) | 
				
			||||||
 | 
								        	? std::static_pointer_cast<Number>(rhs)->number() | 
				
			||||||
 | 
									        : std::static_pointer_cast<Decimal>(rhs)->decimal())) { | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									// clang-format on
 | 
				
			||||||
 | 
									if (is<Constant>(lhs.get()) && is<Constant>(rhs.get()) | 
				
			||||||
 | 
								        && std::static_pointer_cast<Constant>(lhs)->state() == std::static_pointer_cast<Constant>(rhs)->state()) { | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
									if (is<Symbol>(lhs.get()) && is<Symbol>(rhs.get()) | 
				
			||||||
 | 
								        && std::static_pointer_cast<Symbol>(lhs)->symbol() == std::static_pointer_cast<Symbol>(rhs)->symbol()) { | 
				
			||||||
 | 
										return true; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return false; | 
				
			||||||
 | 
								}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool result = true; | 
				
			||||||
 | 
								auto it = begin; | 
				
			||||||
 | 
								auto it_next = begin + 1; | 
				
			||||||
 | 
								for (; it_next != end; ++it, ++it_next) { | 
				
			||||||
 | 
									if (!equal(*it, *it_next)) { | 
				
			||||||
 | 
										result = false; | 
				
			||||||
 | 
										break; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Constant>((result) ? Constant::True : Constant::False); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,149 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <charconv> // std::from_chars, std::to_chars | 
				
			||||||
 | 
					#include <memory> | 
				
			||||||
 | 
					#include <system_error> // std::errc | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadConvert() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (number-to-string 123) -> "123"
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"number-to-string", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("number-to-string", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IS_VALUE(Numeric, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								char result[32]; | 
				
			||||||
 | 
								auto conversion = std::to_chars(result, | 
				
			||||||
 | 
							                                    result + sizeof(result), | 
				
			||||||
 | 
							                                    is<Number>(begin->get()) | 
				
			||||||
 | 
							                                        ? std::static_pointer_cast<Number>(*begin)->number() | 
				
			||||||
 | 
							                                        : std::static_pointer_cast<Decimal>(*begin)->decimal()); | 
				
			||||||
 | 
								if (conversion.ec != std::errc()) { | 
				
			||||||
 | 
									return makePtr<Constant>(Constant::Nil); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<String>(std::string(result, conversion.ptr - result)); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (string-to-char "123") -> 49
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"string-to-char", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("string-to-char", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(string_value, String, (*begin)); | 
				
			||||||
 | 
								std::string data = string_value->data(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Number>(data.c_str()[0]); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (string-to-number "123") -> 123
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"string-to-number", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("string-to-number", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(string_value, String, (*begin)); | 
				
			||||||
 | 
								std::string data = string_value->data(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (data.find('.') == std::string::npos) { | 
				
			||||||
 | 
									int64_t number; | 
				
			||||||
 | 
									auto conversion_number = std::from_chars(data.c_str(), data.c_str() + data.size(), number); | 
				
			||||||
 | 
									if (conversion_number.ec != std::errc()) { | 
				
			||||||
 | 
										return makePtr<Constant>(Constant::Nil); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return makePtr<Number>(number); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								double decimal; | 
				
			||||||
 | 
								auto conversion_decimal = std::from_chars(data.c_str(), data.c_str() + data.size(), decimal); | 
				
			||||||
 | 
								if (conversion_decimal.ec != std::errc()) { | 
				
			||||||
 | 
									return makePtr<Constant>(Constant::Nil); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Decimal>(decimal); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STRING_TO_COLLECTION(name, type)                    \ | 
				
			||||||
 | 
						{                                                       \
 | 
				
			||||||
 | 
							CHECK_ARG_COUNT_IS(name, SIZE(), 1);                \
 | 
				
			||||||
 | 
					                                                            \
 | 
				
			||||||
 | 
							VALUE_CAST(string_value, String, (*begin));         \
 | 
				
			||||||
 | 
							std::string data = string_value->data();            \
 | 
				
			||||||
 | 
					                                                            \
 | 
				
			||||||
 | 
							ValueVector nodes(data.size());                     \
 | 
				
			||||||
 | 
							for (size_t i = 0; i < data.size(); ++i) {          \
 | 
				
			||||||
 | 
								nodes.at(i) = makePtr<Number>(data.c_str()[i]); \
 | 
				
			||||||
 | 
							}                                                   \
 | 
				
			||||||
 | 
					                                                            \
 | 
				
			||||||
 | 
							return makePtr<type>(nodes);                        \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (string-to-list "foo")   -> (102 111 111)
 | 
				
			||||||
 | 
						// (string-to-vector "foo") -> [102 111 111]
 | 
				
			||||||
 | 
						ADD_FUNCTION("string-to-list", "", "", STRING_TO_COLLECTION("string-to-list", List)); | 
				
			||||||
 | 
						ADD_FUNCTION("string-to-vector", "", "", STRING_TO_COLLECTION("string-to-vector", Vector)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (symbol "foo")  -> foo
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"symbol", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Symbol>(begin->get())) { | 
				
			||||||
 | 
									return *begin; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(string_value, String, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Symbol>(string_value->data()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (keyword "foo") -> :foo
 | 
				
			||||||
 | 
						// (keyword 123)   -> :123
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"keyword", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("keyword", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is<Keyword>(begin->get())) { | 
				
			||||||
 | 
									return *begin; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else if (is<Number>(begin->get())) { | 
				
			||||||
 | 
									VALUE_CAST(number_value, Number, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return makePtr<Keyword>(number_value->number()); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(string_value, String, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Keyword>(string_value->data()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,75 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iterator> // std::next | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "reader.h" | 
				
			||||||
 | 
					#include "ruc/format/print.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "printer.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadFormat() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					#define PRINTER_STRING(print_readably, concatenation)                                 \ | 
				
			||||||
 | 
						{                                                                                 \
 | 
				
			||||||
 | 
							std::string result;                                                           \
 | 
				
			||||||
 | 
					                                                                                      \
 | 
				
			||||||
 | 
							Printer printer;                                                              \
 | 
				
			||||||
 | 
							for (auto it = begin; it != end; ++it) {                                      \
 | 
				
			||||||
 | 
								result += ::format("{}", printer.printNoErrorCheck(*it, print_readably)); \
 | 
				
			||||||
 | 
					                                                                                      \
 | 
				
			||||||
 | 
								if (it != end && std::next(it) != end) {                                  \
 | 
				
			||||||
 | 
									result += concatenation;                                              \
 | 
				
			||||||
 | 
								}                                                                         \
 | 
				
			||||||
 | 
							}                                                                             \
 | 
				
			||||||
 | 
					                                                                                      \
 | 
				
			||||||
 | 
							return makePtr<String>(result);                                               \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION("str", "", "", PRINTER_STRING(false, "")); | 
				
			||||||
 | 
						ADD_FUNCTION("pr-str", "", "", PRINTER_STRING(true, " ")); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PRINTER_PRINT(print_readably)                                    \ | 
				
			||||||
 | 
						{                                                                    \
 | 
				
			||||||
 | 
							Printer printer;                                                 \
 | 
				
			||||||
 | 
							for (auto it = begin; it != end; ++it) {                         \
 | 
				
			||||||
 | 
								print("{}", printer.printNoErrorCheck(*it, print_readably)); \
 | 
				
			||||||
 | 
					                                                                         \
 | 
				
			||||||
 | 
								if (it != end && std::next(it) != end) {                     \
 | 
				
			||||||
 | 
									print(" ");                                              \
 | 
				
			||||||
 | 
								}                                                            \
 | 
				
			||||||
 | 
							}                                                                \
 | 
				
			||||||
 | 
							print("\n");                                                     \
 | 
				
			||||||
 | 
					                                                                         \
 | 
				
			||||||
 | 
							return makePtr<Constant>();                                      \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION("prn", "", "", PRINTER_PRINT(true)); | 
				
			||||||
 | 
						ADD_FUNCTION("println", "", "", PRINTER_PRINT(false)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"dump", | 
				
			||||||
 | 
							"arg", | 
				
			||||||
 | 
							"Print AST of the value ARG.", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("dump", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Reader reader; | 
				
			||||||
 | 
								reader.dump(*begin); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return nullptr; | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,60 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "error.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadMeta() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (meta [1 2 3])
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"meta", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("meta", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto front = *begin; | 
				
			||||||
 | 
								Value* front_raw_ptr = begin->get(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!is<Collection>(front_raw_ptr) && // List / Vector
 | 
				
			||||||
 | 
							        !is<HashMap>(front_raw_ptr) &&    // HashMap
 | 
				
			||||||
 | 
							        !is<Callable>(front_raw_ptr)) {   // Function / Lambda
 | 
				
			||||||
 | 
									Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); | 
				
			||||||
 | 
									return nullptr; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return front->meta(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (with-meta [1 2 3] "some metadata")
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"with-meta", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto front = *begin; | 
				
			||||||
 | 
								Value* front_raw_ptr = begin->get(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!is<Collection>(front_raw_ptr) && // List / Vector
 | 
				
			||||||
 | 
							        !is<HashMap>(front_raw_ptr) &&    // HashMap
 | 
				
			||||||
 | 
							        !is<Callable>(front_raw_ptr)) {   // Function / Lambda
 | 
				
			||||||
 | 
									Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); | 
				
			||||||
 | 
									return nullptr; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return front->withMeta(*(begin + 1)); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,93 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm> // std::copy | 
				
			||||||
 | 
					#include <memory>    // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadMutable() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (atom 1)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"atom", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("atom", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Atom>(*begin); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (deref myatom)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"deref", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("deref", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(atom, Atom, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return atom->deref(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (reset! myatom 2)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"reset!", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("reset!", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(atom, Atom, (*begin)); | 
				
			||||||
 | 
								auto value = *(begin + 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								atom->reset(value); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return value; | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"swap!", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(atom, Atom, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(callable, Callable, (*(begin + 1))); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Remove atom and function from the argument list, add atom value
 | 
				
			||||||
 | 
								begin += 2; | 
				
			||||||
 | 
								auto arguments = ValueVector(SIZE() + 1); | 
				
			||||||
 | 
								arguments[0] = atom->deref(); | 
				
			||||||
 | 
								std::copy(begin, end, arguments.begin() + 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ValuePtr value = nullptr; | 
				
			||||||
 | 
								if (is<Function>(callable.get())) { | 
				
			||||||
 | 
									auto function = std::static_pointer_cast<Function>(callable)->function(); | 
				
			||||||
 | 
									value = function(arguments.begin(), arguments.end()); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								else { | 
				
			||||||
 | 
									auto lambda = std::static_pointer_cast<Lambda>(callable); | 
				
			||||||
 | 
									value = Repl::eval(lambda->body(), Environment::create(lambda, std::move(arguments))); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return atom->reset(value); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,166 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint> // int64_t | 
				
			||||||
 | 
					#include <memory>  // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadOperators() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					#define APPLY_NUMBER_OR_DECIMAL(it, apply)                                   \ | 
				
			||||||
 | 
						IS_VALUE(Numeric, (*it));                                                \
 | 
				
			||||||
 | 
						if (is<Number>(it->get())) {                                             \
 | 
				
			||||||
 | 
							auto it_numeric = std::static_pointer_cast<Number>(*it)->number();   \
 | 
				
			||||||
 | 
							do {                                                                 \
 | 
				
			||||||
 | 
								apply                                                            \
 | 
				
			||||||
 | 
							} while (0);                                                         \
 | 
				
			||||||
 | 
						}                                                                        \
 | 
				
			||||||
 | 
						else {                                                                   \
 | 
				
			||||||
 | 
							return_decimal = true;                                               \
 | 
				
			||||||
 | 
							auto it_numeric = std::static_pointer_cast<Decimal>(*it)->decimal(); \
 | 
				
			||||||
 | 
							do {                                                                 \
 | 
				
			||||||
 | 
								apply                                                            \
 | 
				
			||||||
 | 
							} while (0);                                                         \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RETURN_NUMBER_OR_DECIMAL()      \ | 
				
			||||||
 | 
						if (!return_decimal) {              \
 | 
				
			||||||
 | 
							return makePtr<Number>(number); \
 | 
				
			||||||
 | 
						}                                   \
 | 
				
			||||||
 | 
						return makePtr<Decimal>(decimal); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"+", | 
				
			||||||
 | 
							"number...", | 
				
			||||||
 | 
							"Return the sum of any amount of arguments, where NUMBER is of type number.", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								bool return_decimal = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int64_t number = 0; | 
				
			||||||
 | 
								double decimal = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									APPLY_NUMBER_OR_DECIMAL(it, { | 
				
			||||||
 | 
										number += it_numeric; | 
				
			||||||
 | 
										decimal += it_numeric; | 
				
			||||||
 | 
									}); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RETURN_NUMBER_OR_DECIMAL(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"-", | 
				
			||||||
 | 
							"[number] subtract...", | 
				
			||||||
 | 
							R"(Negate NUMBER or SUBTRACT numbers and return the result. | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With one arg, negates it. With more than one arg, | 
				
			||||||
 | 
					subtracts all but the first from the first.)", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								size_t length = SIZE(); | 
				
			||||||
 | 
								if (length == 0) { | 
				
			||||||
 | 
									return makePtr<Number>(0); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool return_decimal = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int64_t number = 0; | 
				
			||||||
 | 
								double decimal = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Start with the first number
 | 
				
			||||||
 | 
								APPLY_NUMBER_OR_DECIMAL(begin, { | 
				
			||||||
 | 
									number = it_numeric; | 
				
			||||||
 | 
									decimal = it_numeric; | 
				
			||||||
 | 
								}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Return negative on single argument
 | 
				
			||||||
 | 
								if (length == 1) { | 
				
			||||||
 | 
									number = -number; | 
				
			||||||
 | 
									decimal = -decimal; | 
				
			||||||
 | 
									RETURN_NUMBER_OR_DECIMAL(); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Skip the first node
 | 
				
			||||||
 | 
								for (auto it = begin + 1; it != end; ++it) { | 
				
			||||||
 | 
									APPLY_NUMBER_OR_DECIMAL(it, { | 
				
			||||||
 | 
										number -= it_numeric; | 
				
			||||||
 | 
										decimal -= it_numeric; | 
				
			||||||
 | 
									}); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RETURN_NUMBER_OR_DECIMAL(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"*", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								bool return_decimal = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int64_t number = 1; | 
				
			||||||
 | 
								double decimal = 1; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									APPLY_NUMBER_OR_DECIMAL(it, { | 
				
			||||||
 | 
										number *= it_numeric; | 
				
			||||||
 | 
										decimal *= it_numeric; | 
				
			||||||
 | 
									}); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RETURN_NUMBER_OR_DECIMAL(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"/", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool return_decimal = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int64_t number = 0; | 
				
			||||||
 | 
								double decimal = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Start with the first number
 | 
				
			||||||
 | 
								APPLY_NUMBER_OR_DECIMAL(begin, { | 
				
			||||||
 | 
									number = it_numeric; | 
				
			||||||
 | 
									decimal = it_numeric; | 
				
			||||||
 | 
								}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Skip the first node
 | 
				
			||||||
 | 
								for (auto it = begin + 1; it != end; ++it) { | 
				
			||||||
 | 
									APPLY_NUMBER_OR_DECIMAL(it, { | 
				
			||||||
 | 
										number /= it_numeric; | 
				
			||||||
 | 
										decimal /= it_numeric; | 
				
			||||||
 | 
									}); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RETURN_NUMBER_OR_DECIMAL(); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (% 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()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,51 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <chrono>  // std::chrono::sytem_clock | 
				
			||||||
 | 
					#include <cstdint> // int64_t | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "error.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadOther() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// (throw x)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"throw", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("throw", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Error::the().add(*begin); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return nullptr; | 
				
			||||||
 | 
							}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (time-ms)
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"time-ms", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( | 
				
			||||||
 | 
													  std::chrono::system_clock::now().time_since_epoch()) | 
				
			||||||
 | 
							                          .count(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Number>(elapsed); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,143 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadPredicate() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					#define IS_CONSTANT(name, constant)                                              \ | 
				
			||||||
 | 
						{                                                                            \
 | 
				
			||||||
 | 
							CHECK_ARG_COUNT_IS(name, SIZE(), 1);                                     \
 | 
				
			||||||
 | 
					                                                                                 \
 | 
				
			||||||
 | 
							return makePtr<Constant>(                                                \
 | 
				
			||||||
 | 
								is<Constant>(begin->get())                                           \
 | 
				
			||||||
 | 
								&& std::static_pointer_cast<Constant>(*begin)->state() == constant); \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (nil? nil)
 | 
				
			||||||
 | 
						ADD_FUNCTION("nil?", "", "", IS_CONSTANT("nil?", Constant::Nil)); | 
				
			||||||
 | 
						ADD_FUNCTION("true?", "", "", IS_CONSTANT("true?", Constant::True)); | 
				
			||||||
 | 
						ADD_FUNCTION("false?", "", "", IS_CONSTANT("false?", Constant::False)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IS_TYPE(type)                            \ | 
				
			||||||
 | 
						{                                            \
 | 
				
			||||||
 | 
							bool result = true;                      \
 | 
				
			||||||
 | 
					                                                 \
 | 
				
			||||||
 | 
							if (SIZE() == 0) {                       \
 | 
				
			||||||
 | 
								result = false;                      \
 | 
				
			||||||
 | 
							}                                        \
 | 
				
			||||||
 | 
					                                                 \
 | 
				
			||||||
 | 
							for (auto it = begin; it != end; ++it) { \
 | 
				
			||||||
 | 
								if (!is<type>(it->get())) {          \
 | 
				
			||||||
 | 
									result = false;                  \
 | 
				
			||||||
 | 
									break;                           \
 | 
				
			||||||
 | 
								}                                    \
 | 
				
			||||||
 | 
							}                                        \
 | 
				
			||||||
 | 
					                                                 \
 | 
				
			||||||
 | 
							return makePtr<Constant>(result);        \
 | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (symbol? 'foo)
 | 
				
			||||||
 | 
						ADD_FUNCTION("atom?", "", "", IS_TYPE(Atom)); | 
				
			||||||
 | 
						ADD_FUNCTION("keyword?", "", "", IS_TYPE(Keyword)); | 
				
			||||||
 | 
						ADD_FUNCTION("list?", "", "", IS_TYPE(List)); | 
				
			||||||
 | 
						ADD_FUNCTION("map?", "", "", IS_TYPE(HashMap)); | 
				
			||||||
 | 
						ADD_FUNCTION("number?", "", "", IS_TYPE(Number)); | 
				
			||||||
 | 
						ADD_FUNCTION("sequential?", "", "", IS_TYPE(Collection)); | 
				
			||||||
 | 
						ADD_FUNCTION("string?", "", "", IS_TYPE(String)); | 
				
			||||||
 | 
						ADD_FUNCTION("symbol?", "", "", IS_TYPE(Symbol)); | 
				
			||||||
 | 
						ADD_FUNCTION("vector?", "", "", IS_TYPE(Vector)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"fn?", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								bool result = true; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (SIZE() == 0) { | 
				
			||||||
 | 
									result = false; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									if (!is<Callable>(it->get()) || is<Macro>(it->get())) { | 
				
			||||||
 | 
										result = false; | 
				
			||||||
 | 
										break; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Constant>(result); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"macro?", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								bool result = true; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (SIZE() == 0) { | 
				
			||||||
 | 
									result = false; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									if (!is<Macro>(it->get())) { | 
				
			||||||
 | 
										result = false; | 
				
			||||||
 | 
										break; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Constant>(result); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (contains? {:foo 5} :foo)   -> true
 | 
				
			||||||
 | 
						// (contains? {"bar" 5} "foo") -> false
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"contains?", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("contains?", SIZE(), 2); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(hash_map, HashMap, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (SIZE() == 0) { | 
				
			||||||
 | 
									return makePtr<Constant>(false); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Constant>(hash_map->exists(*(begin + 1))); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// (empty? '() '())       -> true
 | 
				
			||||||
 | 
						// (empty? [] [1 2 3] []) -> false
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"empty?", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								bool result = true; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto it = begin; it != end; ++it) { | 
				
			||||||
 | 
									VALUE_CAST(collection, Collection, (*it)); | 
				
			||||||
 | 
									if (!collection->empty()) { | 
				
			||||||
 | 
										result = false; | 
				
			||||||
 | 
										break; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Constant>((result) ? Constant::True : Constant::False); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,75 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/file.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Environment::loadRepl() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						// REPL reader
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"read-string", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("read-string", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(node, String, (*begin)); | 
				
			||||||
 | 
								std::string input = node->data(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return Repl::read(input); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Read file contents
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"slurp", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("slurp", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(node, String, (*begin)); | 
				
			||||||
 | 
								std::string path = node->data(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto file = ruc::File(path); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<String>(file.data()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Prompt readline
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"readline", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("readline", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VALUE_CAST(prompt, String, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return Repl::readline(prompt->data()); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// REPL eval
 | 
				
			||||||
 | 
						ADD_FUNCTION( | 
				
			||||||
 | 
							"eval", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							"", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								CHECK_ARG_COUNT_IS("eval", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return Repl::eval(*begin, nullptr); | 
				
			||||||
 | 
							}); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,18 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unordered_map> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADD_FUNCTION(name, signature, documentation, lambda) \ | 
				
			||||||
 | 
						Environment::registerFunction(                           \
 | 
				
			||||||
 | 
							{ name,                                              \
 | 
				
			||||||
 | 
						      signature,                                         \
 | 
				
			||||||
 | 
						      documentation,                                     \
 | 
				
			||||||
 | 
						      [](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda }); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIZE() std::distance(begin, end) | 
				
			||||||
@ -1,102 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory> // std::static_pointer_cast | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/format/format.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EnvironmentPtr Environment::create() | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	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 ValuePtr lambda, const ValueVector& 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 nodes = ValueVector(); | 
					 | 
				
			||||||
			for (; it != arguments.end(); ++it) { | 
					 | 
				
			||||||
				nodes.push_back(*it); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			env->set(bindings[i + 1], makePtr<List>(nodes)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			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; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Environment::exists(const std::string& symbol) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return m_values.find(symbol) != m_values.end(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ValuePtr Environment::set(const std::string& symbol, ValuePtr value) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (exists(symbol)) { | 
					 | 
				
			||||||
		m_values.erase(symbol); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_values.emplace(symbol, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return value; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ValuePtr Environment::get(const std::string& symbol) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (exists(symbol)) { | 
					 | 
				
			||||||
		return m_values[symbol]; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (m_outer) { | 
					 | 
				
			||||||
		return m_outer->get(symbol); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nullptr; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,37 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <list> | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <unordered_map> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Environment { | 
					 | 
				
			||||||
public: | 
					 | 
				
			||||||
	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 ValuePtr lambda, const ValueVector& arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool exists(const std::string& symbol); | 
					 | 
				
			||||||
	ValuePtr set(const std::string& symbol, ValuePtr value); | 
					 | 
				
			||||||
	ValuePtr get(const std::string& symbol); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected: | 
					 | 
				
			||||||
	Environment() {} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EnvironmentPtr m_outer { nullptr }; | 
					 | 
				
			||||||
	std::unordered_map<std::string, ValuePtr> m_values; | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,992 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <algorithm> // std::copy, std::reverse_copy | 
					 | 
				
			||||||
#include <chrono>    // std::chrono::sytem_clock | 
					 | 
				
			||||||
#include <cstdint>   // int64_t | 
					 | 
				
			||||||
#include <iterator>  // std::advance, std::distance, std::next, std::prev | 
					 | 
				
			||||||
#include <memory>    // std::static_pointer_cast | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/file.h" | 
					 | 
				
			||||||
#include "ruc/format/format.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "types.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)                         \
 | 
					 | 
				
			||||||
		(const std::string& __symbol, FunctionType __lambda) \
 | 
					 | 
				
			||||||
		{                                                    \
 | 
					 | 
				
			||||||
			s_functions.emplace(__symbol, __lambda);         \
 | 
					 | 
				
			||||||
		}                                                    \
 | 
					 | 
				
			||||||
	};                                                       \
 | 
					 | 
				
			||||||
	static struct FUNCTION_STRUCT_NAME(unique)               \
 | 
					 | 
				
			||||||
		FUNCTION_STRUCT_NAME(unique)(                        \
 | 
					 | 
				
			||||||
			symbol,                                          \
 | 
					 | 
				
			||||||
			[](ValueVectorConstIt begin, ValueVectorConstIt end) -> ValuePtr lambda); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define ADD_FUNCTION(symbol, lambda) ADD_FUNCTION_IMPL(__LINE__, symbol, lambda); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SIZE() std::distance(begin, end) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::unordered_map<std::string, FunctionType> s_functions; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"+", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		int64_t result = 0; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(number, Number, (*it)); | 
					 | 
				
			||||||
			result += number->number(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Number>(result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"-", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		if (SIZE() == 0) { | 
					 | 
				
			||||||
			return makePtr<Number>(0); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Start with the first number
 | 
					 | 
				
			||||||
		VALUE_CAST(number, Number, (*begin)); | 
					 | 
				
			||||||
		int64_t result = number->number(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Skip the first node
 | 
					 | 
				
			||||||
		for (auto it = begin + 1; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(number, Number, (*it)); | 
					 | 
				
			||||||
			result -= number->number(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Number>(result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"*", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		int64_t result = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(number, Number, (*it)); | 
					 | 
				
			||||||
			result *= number->number(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Number>(result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"/", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Start with the first number
 | 
					 | 
				
			||||||
		VALUE_CAST(number, Number, (*begin)); | 
					 | 
				
			||||||
		double result = number->number(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Skip the first node
 | 
					 | 
				
			||||||
		for (auto it = begin + 1; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(number, Number, (*it)); | 
					 | 
				
			||||||
			result /= number->number(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Number>((int64_t)result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// // -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NUMBER_COMPARE(operator)                                               \ | 
					 | 
				
			||||||
	{                                                                          \
 | 
					 | 
				
			||||||
		bool result = true;                                                    \
 | 
					 | 
				
			||||||
                                                                               \
 | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST(#operator, SIZE(), 2);                        \
 | 
					 | 
				
			||||||
                                                                               \
 | 
					 | 
				
			||||||
		/* Start with the first number */                                      \
 | 
					 | 
				
			||||||
		VALUE_CAST(number_node, Number, (*begin));                             \
 | 
					 | 
				
			||||||
		int64_t number = number_node->number();                                \
 | 
					 | 
				
			||||||
                                                                               \
 | 
					 | 
				
			||||||
		/* Skip the first node */                                              \
 | 
					 | 
				
			||||||
		for (auto it = begin + 1; it != end; ++it) {                           \
 | 
					 | 
				
			||||||
			VALUE_CAST(current_number_node, Number, (*it));                    \
 | 
					 | 
				
			||||||
			int64_t current_number = current_number_node->number();            \
 | 
					 | 
				
			||||||
			if (!(number operator current_number)) {                           \
 | 
					 | 
				
			||||||
				result = false;                                                \
 | 
					 | 
				
			||||||
				break;                                                         \
 | 
					 | 
				
			||||||
			}                                                                  \
 | 
					 | 
				
			||||||
			number = current_number;                                           \
 | 
					 | 
				
			||||||
		}                                                                      \
 | 
					 | 
				
			||||||
                                                                               \
 | 
					 | 
				
			||||||
		return makePtr<Constant>((result) ? Constant::True : Constant::False); \
 | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION("<", NUMBER_COMPARE(<)); | 
					 | 
				
			||||||
ADD_FUNCTION("<=", NUMBER_COMPARE(<=)); | 
					 | 
				
			||||||
ADD_FUNCTION(">", NUMBER_COMPARE(>)); | 
					 | 
				
			||||||
ADD_FUNCTION(">=", NUMBER_COMPARE(>=)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"list", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		return makePtr<List>(begin, end); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"empty?", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		bool result = true; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(collection, Collection, (*it)); | 
					 | 
				
			||||||
			if (!collection->empty()) { | 
					 | 
				
			||||||
				result = false; | 
					 | 
				
			||||||
				break; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Constant>((result) ? Constant::True : Constant::False); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"count", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("count", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t result = 0; | 
					 | 
				
			||||||
		if (is<Constant>(begin->get()) && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
					 | 
				
			||||||
			// result = 0
 | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else if (is<Collection>(begin->get())) { | 
					 | 
				
			||||||
			result = std::static_pointer_cast<Collection>(*begin)->size(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else { | 
					 | 
				
			||||||
			Error::the().add(::format("wrong argument type: Collection, '{}'", *begin)); | 
					 | 
				
			||||||
			return nullptr; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// FIXME: Add numeric_limits check for implicit cast: size_t > int64_t
 | 
					 | 
				
			||||||
		return makePtr<Number>((int64_t)result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PRINTER_STRING(print_readably, concatenation)                                 \ | 
					 | 
				
			||||||
	{                                                                                 \
 | 
					 | 
				
			||||||
		std::string result;                                                           \
 | 
					 | 
				
			||||||
                                                                                      \
 | 
					 | 
				
			||||||
		Printer printer;                                                              \
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) {                                      \
 | 
					 | 
				
			||||||
			result += ::format("{}", printer.printNoErrorCheck(*it, print_readably)); \
 | 
					 | 
				
			||||||
                                                                                      \
 | 
					 | 
				
			||||||
			if (it != end && std::next(it) != end) {                                  \
 | 
					 | 
				
			||||||
				result += concatenation;                                              \
 | 
					 | 
				
			||||||
			}                                                                         \
 | 
					 | 
				
			||||||
		}                                                                             \
 | 
					 | 
				
			||||||
                                                                                      \
 | 
					 | 
				
			||||||
		return makePtr<String>(result);                                               \
 | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION("str", PRINTER_STRING(false, "")); | 
					 | 
				
			||||||
ADD_FUNCTION("pr-str", PRINTER_STRING(true, " ")); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PRINTER_PRINT(print_readably)                                    \ | 
					 | 
				
			||||||
	{                                                                    \
 | 
					 | 
				
			||||||
		Printer printer;                                                 \
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) {                         \
 | 
					 | 
				
			||||||
			print("{}", printer.printNoErrorCheck(*it, print_readably)); \
 | 
					 | 
				
			||||||
                                                                         \
 | 
					 | 
				
			||||||
			if (it != end && std::next(it) != end) {                     \
 | 
					 | 
				
			||||||
				print(" ");                                              \
 | 
					 | 
				
			||||||
			}                                                            \
 | 
					 | 
				
			||||||
		}                                                                \
 | 
					 | 
				
			||||||
		print("\n");                                                     \
 | 
					 | 
				
			||||||
                                                                         \
 | 
					 | 
				
			||||||
		return makePtr<Constant>();                                      \
 | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION("prn", PRINTER_PRINT(true)); | 
					 | 
				
			||||||
ADD_FUNCTION("println", PRINTER_PRINT(false)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"=", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::function<bool(ValuePtr, ValuePtr)> equal = | 
					 | 
				
			||||||
			[&equal](ValuePtr lhs, ValuePtr rhs) -> bool { | 
					 | 
				
			||||||
			if ((is<List>(lhs.get()) || is<Vector>(lhs.get())) | 
					 | 
				
			||||||
		        && (is<List>(rhs.get()) || is<Vector>(rhs.get()))) { | 
					 | 
				
			||||||
				const auto& lhs_nodes = std::static_pointer_cast<Collection>(lhs)->nodes(); | 
					 | 
				
			||||||
				const auto& rhs_nodes = std::static_pointer_cast<Collection>(rhs)->nodes(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (lhs_nodes.size() != rhs_nodes.size()) { | 
					 | 
				
			||||||
					return false; | 
					 | 
				
			||||||
				} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				auto lhs_it = lhs_nodes.cbegin(); | 
					 | 
				
			||||||
				auto rhs_it = rhs_nodes.cbegin(); | 
					 | 
				
			||||||
				for (; lhs_it != lhs_nodes.end(); ++lhs_it, ++rhs_it) { | 
					 | 
				
			||||||
					if (!equal(*lhs_it, *rhs_it)) { | 
					 | 
				
			||||||
						return false; | 
					 | 
				
			||||||
					} | 
					 | 
				
			||||||
				} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (is<HashMap>(lhs.get()) && is<HashMap>(rhs.get())) { | 
					 | 
				
			||||||
				const auto& lhs_nodes = std::static_pointer_cast<HashMap>(lhs)->elements(); | 
					 | 
				
			||||||
				const auto& rhs_nodes = std::static_pointer_cast<HashMap>(rhs)->elements(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (lhs_nodes.size() != rhs_nodes.size()) { | 
					 | 
				
			||||||
					return false; | 
					 | 
				
			||||||
				} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				for (const auto& [key, value] : lhs_nodes) { | 
					 | 
				
			||||||
					auto it = rhs_nodes.find(key); | 
					 | 
				
			||||||
					if (it == rhs_nodes.cend() || !equal(value, it->second)) { | 
					 | 
				
			||||||
						return false; | 
					 | 
				
			||||||
					} | 
					 | 
				
			||||||
				} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (is<String>(lhs.get()) && is<String>(rhs.get()) | 
					 | 
				
			||||||
		        && std::static_pointer_cast<String>(lhs)->data() == std::static_pointer_cast<String>(rhs)->data()) { | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			if (is<Keyword>(lhs.get()) && is<Keyword>(rhs.get()) | 
					 | 
				
			||||||
		        && std::static_pointer_cast<Keyword>(lhs)->keyword() == std::static_pointer_cast<Keyword>(rhs)->keyword()) { | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			if (is<Number>(lhs.get()) && is<Number>(rhs.get()) | 
					 | 
				
			||||||
		        && std::static_pointer_cast<Number>(lhs)->number() == std::static_pointer_cast<Number>(rhs)->number()) { | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			if (is<Constant>(lhs.get()) && is<Constant>(rhs.get()) | 
					 | 
				
			||||||
		        && std::static_pointer_cast<Constant>(lhs)->state() == std::static_pointer_cast<Constant>(rhs)->state()) { | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			if (is<Symbol>(lhs.get()) && is<Symbol>(rhs.get()) | 
					 | 
				
			||||||
		        && std::static_pointer_cast<Symbol>(lhs)->symbol() == std::static_pointer_cast<Symbol>(rhs)->symbol()) { | 
					 | 
				
			||||||
				return true; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return false; | 
					 | 
				
			||||||
		}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool result = true; | 
					 | 
				
			||||||
		auto it = begin; | 
					 | 
				
			||||||
		auto it_next = begin + 1; | 
					 | 
				
			||||||
		for (; it_next != end; ++it, ++it_next) { | 
					 | 
				
			||||||
			if (!equal(*it, *it_next)) { | 
					 | 
				
			||||||
				result = false; | 
					 | 
				
			||||||
				break; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Constant>((result) ? Constant::True : Constant::False); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"read-string", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("read-string", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(node, String, (*begin)); | 
					 | 
				
			||||||
		std::string input = node->data(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return read(input); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"slurp", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("slurp", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(node, String, (*begin)); | 
					 | 
				
			||||||
		std::string path = node->data(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto file = ruc::File(path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<String>(file.data()); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"eval", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("eval", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return eval(*begin, nullptr); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (atom 1)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"atom", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("atom", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Atom>(*begin); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (deref myatom)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"deref", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("deref", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(atom, Atom, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return atom->deref(); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (reset! myatom 2)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"reset!", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("reset!", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(atom, Atom, (*begin)); | 
					 | 
				
			||||||
		auto value = *(begin + 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		atom->reset(value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return value; | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"swap!", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(atom, Atom, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(callable, Callable, (*(begin + 1))); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Remove atom and function from the argument list, add atom value
 | 
					 | 
				
			||||||
		begin += 2; | 
					 | 
				
			||||||
		auto arguments = ValueVector(end - begin + 1); | 
					 | 
				
			||||||
		arguments[0] = atom->deref(); | 
					 | 
				
			||||||
		std::copy(begin, end, arguments.begin() + 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ValuePtr value = nullptr; | 
					 | 
				
			||||||
		if (is<Function>(callable.get())) { | 
					 | 
				
			||||||
			auto function = std::static_pointer_cast<Function>(callable)->function(); | 
					 | 
				
			||||||
			value = function(arguments.begin(), arguments.end()); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else { | 
					 | 
				
			||||||
			auto lambda = std::static_pointer_cast<Lambda>(callable); | 
					 | 
				
			||||||
			value = eval(lambda->body(), Environment::create(lambda, arguments)); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return atom->reset(value); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (cons 1 (list 2 3))
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"cons", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("cons", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ValuePtr first = *begin; | 
					 | 
				
			||||||
		begin++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
		const auto& collection_nodes = collection->nodes(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto result_nodes = ValueVector(collection_nodes.size() + 1); | 
					 | 
				
			||||||
		result_nodes.at(0) = first; | 
					 | 
				
			||||||
		std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(result_nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (concat (list 1) (list 2 3)) -> (1 2 3)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"concat", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		size_t count = 0; | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			VALUE_CAST(collection, Collection, (*it)); | 
					 | 
				
			||||||
			count += collection->size(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto result_nodes = ValueVector(count); | 
					 | 
				
			||||||
		size_t offset = 0; | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			const auto& collection_nodes = std::static_pointer_cast<Collection>(*it)->nodes(); | 
					 | 
				
			||||||
			std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset); | 
					 | 
				
			||||||
			offset += collection_nodes.size(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(result_nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (vec (list 1 2 3))
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"vec", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("vec", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Vector>(begin->get())) { | 
					 | 
				
			||||||
			return *begin; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Vector>(collection->nodes()); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (nth (list 1 2 3) 0)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"nth", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("nth", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
		VALUE_CAST(number_node, Number, (*(begin + 1))); | 
					 | 
				
			||||||
		auto collection_nodes = collection->nodes(); | 
					 | 
				
			||||||
		auto index = (size_t)number_node->number(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (number_node->number() < 0 || index >= collection_nodes.size()) { | 
					 | 
				
			||||||
			Error::the().add("index is out of range"); | 
					 | 
				
			||||||
			return nullptr; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto result = collection_nodes.begin(); | 
					 | 
				
			||||||
		for (size_t i = 0; i < index; ++i) { | 
					 | 
				
			||||||
			result++; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return *result; | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (first (list 1 2 3)) -> 1
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"first", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("first", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Constant>(begin->get()) | 
					 | 
				
			||||||
	        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
					 | 
				
			||||||
			return makePtr<Constant>(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return (collection->empty()) ? makePtr<Constant>() : collection->front(); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (rest (list 1 2 3))
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"rest", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("rest", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Constant>(begin->get()) | 
					 | 
				
			||||||
	        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
					 | 
				
			||||||
			return makePtr<List>(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(collection->rest()); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"apply", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto callable = *begin; | 
					 | 
				
			||||||
		IS_VALUE(Callable, callable); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*std::prev(end))); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto arguments = ValueVector(begin + 1, end - 1); | 
					 | 
				
			||||||
		arguments.reserve(arguments.size() + collection->size()); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Append list nodes to the argument leftovers
 | 
					 | 
				
			||||||
		auto nodes = collection->nodes(); | 
					 | 
				
			||||||
		for (const auto& node : nodes) { | 
					 | 
				
			||||||
			arguments.push_back(node); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ValuePtr value = nullptr; | 
					 | 
				
			||||||
		if (is<Function>(callable.get())) { | 
					 | 
				
			||||||
			auto function = std::static_pointer_cast<Function>(callable)->function(); | 
					 | 
				
			||||||
			value = function(arguments.begin(), arguments.end()); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else { | 
					 | 
				
			||||||
			auto lambda = std::static_pointer_cast<Lambda>(callable); | 
					 | 
				
			||||||
			value = eval(lambda->body(), Environment::create(lambda, arguments)); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return value; | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"map", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("map", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(callable, Callable, (*begin)); | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*(begin + 1))); | 
					 | 
				
			||||||
		const auto& collection_nodes = collection->nodes(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t count = collection->size(); | 
					 | 
				
			||||||
		auto nodes = ValueVector(count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Function>(callable.get())) { | 
					 | 
				
			||||||
			auto function = std::static_pointer_cast<Function>(callable)->function(); | 
					 | 
				
			||||||
			for (size_t i = 0; i < count; ++i) { | 
					 | 
				
			||||||
				nodes.at(i) = function(collection_nodes.begin() + i, collection_nodes.begin() + i + 1); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else { | 
					 | 
				
			||||||
			auto lambda = std::static_pointer_cast<Lambda>(callable); | 
					 | 
				
			||||||
			for (size_t i = 0; i < count; ++i) { | 
					 | 
				
			||||||
				nodes.at(i) = (eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (throw x)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"throw", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("throw", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Error::the().add(*begin); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nullptr; | 
					 | 
				
			||||||
	}) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define IS_CONSTANT(name, constant)                                              \ | 
					 | 
				
			||||||
	{                                                                            \
 | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS(name, SIZE(), 1);                                     \
 | 
					 | 
				
			||||||
                                                                                 \
 | 
					 | 
				
			||||||
		return makePtr<Constant>(                                                \
 | 
					 | 
				
			||||||
			is<Constant>(begin->get())                                           \
 | 
					 | 
				
			||||||
			&& std::static_pointer_cast<Constant>(*begin)->state() == constant); \
 | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (nil? nil)
 | 
					 | 
				
			||||||
ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil)); | 
					 | 
				
			||||||
ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True)); | 
					 | 
				
			||||||
ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define IS_TYPE(type)                            \ | 
					 | 
				
			||||||
	{                                            \
 | 
					 | 
				
			||||||
		bool result = true;                      \
 | 
					 | 
				
			||||||
                                                 \
 | 
					 | 
				
			||||||
		if (SIZE() == 0) {                       \
 | 
					 | 
				
			||||||
			result = false;                      \
 | 
					 | 
				
			||||||
		}                                        \
 | 
					 | 
				
			||||||
                                                 \
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { \
 | 
					 | 
				
			||||||
			if (!is<type>(it->get())) {          \
 | 
					 | 
				
			||||||
				result = false;                  \
 | 
					 | 
				
			||||||
				break;                           \
 | 
					 | 
				
			||||||
			}                                    \
 | 
					 | 
				
			||||||
		}                                        \
 | 
					 | 
				
			||||||
                                                 \
 | 
					 | 
				
			||||||
		return makePtr<Constant>(result);        \
 | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (symbol? 'foo)
 | 
					 | 
				
			||||||
ADD_FUNCTION("atom?", IS_TYPE(Atom)); | 
					 | 
				
			||||||
ADD_FUNCTION("keyword?", IS_TYPE(Keyword)); | 
					 | 
				
			||||||
ADD_FUNCTION("list?", IS_TYPE(List)); | 
					 | 
				
			||||||
ADD_FUNCTION("map?", IS_TYPE(HashMap)); | 
					 | 
				
			||||||
ADD_FUNCTION("number?", IS_TYPE(Number)); | 
					 | 
				
			||||||
ADD_FUNCTION("sequential?", IS_TYPE(Collection)); | 
					 | 
				
			||||||
ADD_FUNCTION("string?", IS_TYPE(String)); | 
					 | 
				
			||||||
ADD_FUNCTION("symbol?", IS_TYPE(Symbol)); | 
					 | 
				
			||||||
ADD_FUNCTION("vector?", IS_TYPE(Vector)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"fn?", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		bool result = true; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (SIZE() == 0) { | 
					 | 
				
			||||||
			result = false; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			if (!is<Callable>(it->get()) || is<Macro>(it->get())) { | 
					 | 
				
			||||||
				result = false; | 
					 | 
				
			||||||
				break; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Constant>(result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"macro?", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		bool result = true; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (SIZE() == 0) { | 
					 | 
				
			||||||
			result = false; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			if (!is<Macro>(it->get())) { | 
					 | 
				
			||||||
				result = false; | 
					 | 
				
			||||||
				break; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Constant>(result); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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")
 | 
					 | 
				
			||||||
ADD_FUNCTION("symbol", STRING_TO_TYPE("symbol", Symbol)); | 
					 | 
				
			||||||
ADD_FUNCTION("keyword", STRING_TO_TYPE("keyword", Keyword)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (vector 1 2 3) -> [1 2 3]
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"vector", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		auto result = makePtr<Vector>(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Vector>(begin, end); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10}
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"hash-map", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_EVEN("hash-map", SIZE()); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Elements elements; | 
					 | 
				
			||||||
		for (auto it = begin; it != end; std::advance(it, 2)) { | 
					 | 
				
			||||||
			const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
 | 
					 | 
				
			||||||
			elements.insert_or_assign(HashMap::getKeyString(*it), value); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<HashMap>(elements); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1}
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"assoc", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
		begin++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_EVEN("assoc", SIZE()); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Elements elements(hash_map->elements()); | 
					 | 
				
			||||||
		for (auto it = begin; it != end; std::advance(it, 2)) { | 
					 | 
				
			||||||
			const ValuePtr& value = *(std::next(it)); // temporary instance to get around const
 | 
					 | 
				
			||||||
			elements.insert_or_assign(HashMap::getKeyString(*it), value); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<HashMap>(elements); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2}
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"dissoc", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
		begin++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Elements elements(hash_map->elements()); | 
					 | 
				
			||||||
		for (auto it = begin; it != end; ++it) { | 
					 | 
				
			||||||
			elements.erase(HashMap::getKeyString(*it)); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<HashMap>(elements); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (get {:kw "value"} :kw) -> "value"
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"get", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Constant>(begin->get()) | 
					 | 
				
			||||||
	        && std::static_pointer_cast<Constant>(*begin)->state() == Constant::Nil) { | 
					 | 
				
			||||||
			return makePtr<Constant>(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
		begin++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (SIZE() == 0) { | 
					 | 
				
			||||||
			return makePtr<Constant>(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto result = hash_map->get(*begin); | 
					 | 
				
			||||||
		return (result) ? result : makePtr<Constant>(); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"contains?", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("contains?", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (SIZE() == 0) { | 
					 | 
				
			||||||
			return makePtr<Constant>(false); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Constant>(hash_map->exists(*(begin + 1))); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (keys {"foo" 3 :bar 5}) -> ("foo" :bar)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"keys", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t count = hash_map->size(); | 
					 | 
				
			||||||
		auto nodes = ValueVector(count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t i = 0; | 
					 | 
				
			||||||
		auto elements = hash_map->elements(); | 
					 | 
				
			||||||
		for (auto pair : elements) { | 
					 | 
				
			||||||
			if (pair.first.front() == 0x7f) { // 127
 | 
					 | 
				
			||||||
				nodes.at(i) = makePtr<Keyword>(pair.first.substr(1)); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			else { | 
					 | 
				
			||||||
				nodes.at(i) = makePtr<String>(pair.first); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
			i++; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (vals {"foo" 3 :bar 5}) -> (3 5)
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"vals", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(hash_map, HashMap, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t count = hash_map->size(); | 
					 | 
				
			||||||
		auto nodes = ValueVector(count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		size_t i = 0; | 
					 | 
				
			||||||
		auto elements = hash_map->elements(); | 
					 | 
				
			||||||
		for (auto pair : elements) { | 
					 | 
				
			||||||
			nodes.at(i) = pair.second; | 
					 | 
				
			||||||
			i++; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<List>(nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"readline", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("readline", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(prompt, String, (*begin)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return readline(prompt->data()); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"time-ms", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( | 
					 | 
				
			||||||
							  std::chrono::system_clock::now().time_since_epoch()) | 
					 | 
				
			||||||
	                          .count(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Number>(elapsed); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (meta [1 2 3])
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"meta", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("meta", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto front = *begin; | 
					 | 
				
			||||||
		Value* front_raw_ptr = begin->get(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!is<Collection>(front_raw_ptr) && // List / Vector
 | 
					 | 
				
			||||||
	        !is<HashMap>(front_raw_ptr) &&    // HashMap
 | 
					 | 
				
			||||||
	        !is<Callable>(front_raw_ptr)) {   // Function / Lambda
 | 
					 | 
				
			||||||
			Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); | 
					 | 
				
			||||||
			return nullptr; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return front->meta(); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (with-meta [1 2 3] "some metadata")
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"with-meta", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto front = *begin; | 
					 | 
				
			||||||
		Value* front_raw_ptr = begin->get(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!is<Collection>(front_raw_ptr) && // List / Vector
 | 
					 | 
				
			||||||
	        !is<HashMap>(front_raw_ptr) &&    // HashMap
 | 
					 | 
				
			||||||
	        !is<Callable>(front_raw_ptr)) {   // Function / Lambda
 | 
					 | 
				
			||||||
			Error::the().add(::format("wrong argument type: Collection, HashMap or Callable, {}", front)); | 
					 | 
				
			||||||
			return nullptr; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return front->withMeta(*(begin + 1)); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (conj '(1 2 3) 4 5 6) -> (6 5 4 1 2 3)
 | 
					 | 
				
			||||||
// (conj [1 2 3] 4 5 6)  -> [1 2 3 4 5 6]
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"conj", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VALUE_CAST(collection, Collection, (*begin)); | 
					 | 
				
			||||||
		begin++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto& collection_nodes = collection->nodes(); | 
					 | 
				
			||||||
		size_t collection_count = collection_nodes.size(); | 
					 | 
				
			||||||
		size_t argument_count = SIZE(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto nodes = ValueVector(argument_count + collection_count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<List>(collection.get())) { | 
					 | 
				
			||||||
			std::reverse_copy(begin, end, nodes.begin()); | 
					 | 
				
			||||||
			std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin() + argument_count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return makePtr<List>(nodes); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::copy(collection_nodes.begin(), collection_nodes.end(), nodes.begin()); | 
					 | 
				
			||||||
		std::copy(begin, end, nodes.begin() + collection_count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return makePtr<Vector>(nodes); | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// (seq '(1 2 3)) -> (1 2 3)
 | 
					 | 
				
			||||||
// (seq [1 2 3])  -> (1 2 3)
 | 
					 | 
				
			||||||
// (seq "foo")    -> ("f" "o" "o")
 | 
					 | 
				
			||||||
ADD_FUNCTION( | 
					 | 
				
			||||||
	"seq", | 
					 | 
				
			||||||
	{ | 
					 | 
				
			||||||
		CHECK_ARG_COUNT_IS("seq", SIZE(), 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto front = *begin; | 
					 | 
				
			||||||
		Value* front_raw_ptr = front.get(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is<Constant>(front_raw_ptr) && std::static_pointer_cast<Constant>(front)->state() == Constant::Nil) { | 
					 | 
				
			||||||
			return makePtr<Constant>(); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		if (is<Collection>(front_raw_ptr)) { | 
					 | 
				
			||||||
			auto collection = std::static_pointer_cast<Collection>(front); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (collection->empty()) { | 
					 | 
				
			||||||
				return makePtr<Constant>(); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (is<List>(front_raw_ptr)) { | 
					 | 
				
			||||||
				return front; | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return makePtr<List>(collection->nodes()); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		if (is<String>(front_raw_ptr)) { | 
					 | 
				
			||||||
			auto string = std::static_pointer_cast<String>(front); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (string->empty()) { | 
					 | 
				
			||||||
				return makePtr<Constant>(); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			size_t count = string->size(); | 
					 | 
				
			||||||
			auto nodes = ValueVector(count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			const auto& data = string->data(); | 
					 | 
				
			||||||
			for (size_t i = 0; i < count; ++i) { | 
					 | 
				
			||||||
				nodes.at(i) = makePtr<String>(data[i]); | 
					 | 
				
			||||||
			} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return makePtr<List>(nodes); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Error::the().add(::format("wrong argument type: Collection or String, {}", front)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nullptr; | 
					 | 
				
			||||||
	}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// -----------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void installFunctions(EnvironmentPtr env) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (const auto& [name, function] : s_functions) { | 
					 | 
				
			||||||
		env->set(name, makePtr<Function>(name, function)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -0,0 +1,22 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eval.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONCAT(a, b) CONCAT_IMPL(a, b) | 
				
			||||||
 | 
					#define CONCAT_IMPL(a, b) a##b | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define EVAL_FUNCTION_IMPL(name, signature, documentation, struct_name)    \ | 
				
			||||||
 | 
						struct struct_name {                                                   \
 | 
				
			||||||
 | 
							struct_name()                                                      \
 | 
				
			||||||
 | 
							{                                                                  \
 | 
				
			||||||
 | 
								Eval::registerSpecialForm({ name, signature, documentation }); \
 | 
				
			||||||
 | 
							}                                                                  \
 | 
				
			||||||
 | 
						};                                                                     \
 | 
				
			||||||
 | 
						static struct struct_name struct_name; // NOLINT(clang-diagnostic-unused-function)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define EVAL_FUNCTION(name, signature, documentation) \ | 
				
			||||||
 | 
						EVAL_FUNCTION_IMPL(name, signature, documentation, CONCAT(__EVAL_STRUCT_, __COUNTER__)) | 
				
			||||||
@ -0,0 +1,84 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <csignal> // std::signal | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					#include <string_view> | 
				
			||||||
 | 
					#include <vector> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/argparser.h" | 
				
			||||||
 | 
					#include "ruc/format/color.h" | 
				
			||||||
 | 
					#include "ruc/format/print.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					#include "settings.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto main(int argc, char* argv[]) -> int | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						bool dump_lexer = false; | 
				
			||||||
 | 
						bool dump_reader = false; | 
				
			||||||
 | 
						bool pretty_print = false; | 
				
			||||||
 | 
						std::string_view history_path = "~/.blaze-history"; | 
				
			||||||
 | 
						std::vector<std::string> arguments; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// CLI arguments
 | 
				
			||||||
 | 
						ruc::ArgParser arg_parser; | 
				
			||||||
 | 
						arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
				
			||||||
 | 
						arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
				
			||||||
 | 
						arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
				
			||||||
 | 
						arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
				
			||||||
 | 
						// TODO: Add overload for addArgument(std::vector<std::string_view>)
 | 
				
			||||||
 | 
						arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
				
			||||||
 | 
						arg_parser.parse(argc, argv); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set settings
 | 
				
			||||||
 | 
						g_outer_env->set("*DUMP-LEXER*", makePtr<Constant>(dump_lexer)); | 
				
			||||||
 | 
						g_outer_env->set("*DUMP-READER*", makePtr<Constant>(dump_reader)); | 
				
			||||||
 | 
						g_outer_env->set("*PRETTY-PRINT*", makePtr<Constant>(pretty_print)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Signal callbacks
 | 
				
			||||||
 | 
						std::signal(SIGINT, Repl::cleanup); | 
				
			||||||
 | 
						std::signal(SIGTERM, Repl::cleanup); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Environment::loadFunctions(); | 
				
			||||||
 | 
						Environment::installFunctions(g_outer_env); | 
				
			||||||
 | 
						Repl::makeArgv(g_outer_env, arguments); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (arguments.size() > 0) { | 
				
			||||||
 | 
							Repl::rep(format("(load-file \"{}\")", arguments.front()), g_outer_env); | 
				
			||||||
 | 
							return 0; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Repl::rep("(println (str \"Blaze [\" *host-language* \"]\"))", g_outer_env); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_readline = Readline(pretty_print, history_path); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string input; | 
				
			||||||
 | 
						while (g_readline.get(input)) { | 
				
			||||||
 | 
							std::string output = Repl::rep(input, g_outer_env); | 
				
			||||||
 | 
							if (output.length() > 0) { | 
				
			||||||
 | 
								print("{}\n", output); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pretty_print) { | 
				
			||||||
 | 
							print("\033[0m"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto main(int argc, char* argv[]) -> int | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						return blaze::main(argc, argv); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,100 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdlib> // std::exit | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					#include <string_view> | 
				
			||||||
 | 
					#include <vector> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/format/print.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "env/environment.h" | 
				
			||||||
 | 
					#include "error.h" | 
				
			||||||
 | 
					#include "eval.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "lexer.h" | 
				
			||||||
 | 
					#include "printer.h" | 
				
			||||||
 | 
					#include "reader.h" | 
				
			||||||
 | 
					#include "readline.h" | 
				
			||||||
 | 
					#include "repl.h" | 
				
			||||||
 | 
					#include "settings.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Readline g_readline; | 
				
			||||||
 | 
					EnvironmentPtr g_outer_env = Environment::create(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::cleanup(int signal) -> void | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						::print("\033[0m\n"); | 
				
			||||||
 | 
						std::exit(signal); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::readline(const std::string& prompt) -> ValuePtr | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						std::string input; | 
				
			||||||
 | 
						if (g_readline.get(input, g_readline.createPrompt(prompt))) { | 
				
			||||||
 | 
							return makePtr<String>(input); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return makePtr<Constant>(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::read(std::string_view input) -> ValuePtr | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Lexer lexer(input); | 
				
			||||||
 | 
						lexer.tokenize(); | 
				
			||||||
 | 
						if (Settings::the().getEnvBool("*DUMP-LEXER*")) { | 
				
			||||||
 | 
							lexer.dump(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Reader reader(std::move(lexer.tokens())); | 
				
			||||||
 | 
						reader.read(); | 
				
			||||||
 | 
						if (Settings::the().getEnvBool("*DUMP-READER*")) { | 
				
			||||||
 | 
							reader.dump(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return reader.node(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						if (env == nullptr) { | 
				
			||||||
 | 
							env = g_outer_env; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Eval eval(ast, env); | 
				
			||||||
 | 
						eval.eval(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return eval.ast(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::print(ValuePtr value) -> std::string | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Printer printer; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return printer.print(value, true); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::rep(std::string_view input, EnvironmentPtr env) -> std::string | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Error::the().clearErrors(); | 
				
			||||||
 | 
						Error::the().setInput(input); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return print(eval(read(input), env)); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto Repl::makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						size_t count = arguments.size(); | 
				
			||||||
 | 
						auto nodes = ValueVector(); | 
				
			||||||
 | 
						for (size_t i = 1; i < count; ++i) { | 
				
			||||||
 | 
							nodes.push_back(makePtr<String>(arguments[i])); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
						env->set("*ARGV*", makePtr<List>(nodes)); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,29 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					#include <string_view> | 
				
			||||||
 | 
					#include <vector> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "readline.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Repl { | 
				
			||||||
 | 
					public: | 
				
			||||||
 | 
						static auto cleanup(int signal) -> void; | 
				
			||||||
 | 
						static auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr; | 
				
			||||||
 | 
						static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void; | 
				
			||||||
 | 
						static auto print(ValuePtr value) -> std::string; | 
				
			||||||
 | 
						static auto read(std::string_view input) -> ValuePtr; | 
				
			||||||
 | 
						static auto readline(const std::string& prompt) -> ValuePtr; | 
				
			||||||
 | 
						static auto rep(std::string_view input, EnvironmentPtr env) -> std::string; | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -1,62 +0,0 @@ | 
				
			|||||||
#include <cstdio> | 
					 | 
				
			||||||
#include <iostream> // std::cin | 
					 | 
				
			||||||
#include <string>   // std::getline | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view data) -> std::string_view | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return data; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(std::string_view data) -> std::string_view | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return data; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto print(std::string_view data) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	printf("%s\n", data.data()); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto rep(std::string_view data) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print(eval(read(data))); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main() -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	while (true) { | 
					 | 
				
			||||||
		printf("user> "); | 
					 | 
				
			||||||
		std::string line; | 
					 | 
				
			||||||
		std::getline(std::cin, line); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Exit with Ctrl-D
 | 
					 | 
				
			||||||
		if (std::cin.eof() || std::cin.fail()) { | 
					 | 
				
			||||||
			break; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rep(line); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Below is needed for compilation
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return {}; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr, EnvironmentPtr) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return {}; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,114 +0,0 @@ | 
				
			|||||||
#include <csignal>  // std::signal | 
					 | 
				
			||||||
#include <cstdlib>  // std::exit | 
					 | 
				
			||||||
#include <iostream> // std::cin | 
					 | 
				
			||||||
#include <string>   // std::getline | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	return ast; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto print(blaze::ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Printer printer; | 
					 | 
				
			||||||
	return printer.print(exp); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto rep(std::string_view input) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Error::the().clearErrors(); | 
					 | 
				
			||||||
	blaze::Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	print("{}\n", print(blaze::eval(blaze::read(input), nullptr)).c_str()); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (true) { | 
					 | 
				
			||||||
		if (!pretty_print) { | 
					 | 
				
			||||||
			print("user> "); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		else { | 
					 | 
				
			||||||
			print(fg(ruc::format::TerminalColor::Blue), "user>"); | 
					 | 
				
			||||||
			print(" \033[1m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		std::string line; | 
					 | 
				
			||||||
		std::getline(std::cin, line); | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Exit with Ctrl-D
 | 
					 | 
				
			||||||
		if (std::cin.eof() || std::cin.fail()) { | 
					 | 
				
			||||||
			break; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rep(line); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,118 +0,0 @@ | 
				
			|||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto print(blaze::ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto rep(std::string_view input) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Error::the().clearErrors(); | 
					 | 
				
			||||||
	blaze::Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(blaze::eval(blaze::read(input), s_outer_env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.mal-history"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(s_outer_env); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,118 +0,0 @@ | 
				
			|||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto print(blaze::ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto rep(std::string_view input) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Error::the().clearErrors(); | 
					 | 
				
			||||||
	blaze::Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(blaze::eval(blaze::read(input), s_outer_env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.mal-history"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(s_outer_env); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,135 +0,0 @@ | 
				
			|||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void; | 
					 | 
				
			||||||
static auto installLambdas(blaze::EnvironmentPtr env) -> void; | 
					 | 
				
			||||||
static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string; | 
					 | 
				
			||||||
static auto print(blaze::ValuePtr exp) -> std::string; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.mal-history"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(s_outer_env); | 
					 | 
				
			||||||
	installLambdas(s_outer_env); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input, s_outer_env)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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(blaze::eval(blaze::read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(blaze::ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,141 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static blaze::EnvironmentPtr s_outer_env = blaze::Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void; | 
					 | 
				
			||||||
static auto installLambdas(blaze::EnvironmentPtr env) -> void; | 
					 | 
				
			||||||
static auto rep(std::string_view input, blaze::EnvironmentPtr env) -> std::string; | 
					 | 
				
			||||||
static auto print(blaze::ValuePtr exp) -> std::string; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.mal-history"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(s_outer_env); | 
					 | 
				
			||||||
	installLambdas(s_outer_env); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input, s_outer_env)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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(blaze::eval(blaze::read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(blaze::ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	blaze::Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,161 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
#include <vector> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static EnvironmentPtr s_outer_env = Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (env == nullptr) { | 
					 | 
				
			||||||
		env = s_outer_env; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Error::the().clearErrors(); | 
					 | 
				
			||||||
	Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(eval(read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::string_view lambdaTable[] = { | 
					 | 
				
			||||||
	"(def! not (fn* (cond) (if cond false true)))", | 
					 | 
				
			||||||
	"(def! load-file (fn* (filename) \
 | 
					 | 
				
			||||||
	    (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto installLambdas(EnvironmentPtr env) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (auto function : lambdaTable) { | 
					 | 
				
			||||||
		rep(function, env); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	size_t count = arguments.size(); | 
					 | 
				
			||||||
	auto nodes = ValueVector(); | 
					 | 
				
			||||||
	for (size_t i = 1; i < count; ++i) { | 
					 | 
				
			||||||
		nodes.push_back(makePtr<String>(arguments[i])); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	env->set("*ARGV*", makePtr<List>(nodes)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.blaze-history"; | 
					 | 
				
			||||||
	std::vector<std::string> arguments; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, blaze::cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, blaze::cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(blaze::s_outer_env); | 
					 | 
				
			||||||
	installLambdas(blaze::s_outer_env); | 
					 | 
				
			||||||
	makeArgv(blaze::s_outer_env, arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arguments.size() > 0) { | 
					 | 
				
			||||||
		rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input, blaze::s_outer_env)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,161 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
#include <vector> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static EnvironmentPtr s_outer_env = Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (env == nullptr) { | 
					 | 
				
			||||||
		env = s_outer_env; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Error::the().clearErrors(); | 
					 | 
				
			||||||
	Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(eval(read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::string_view lambdaTable[] = { | 
					 | 
				
			||||||
	"(def! not (fn* (cond) (if cond false true)))", | 
					 | 
				
			||||||
	"(def! load-file (fn* (filename) \
 | 
					 | 
				
			||||||
	    (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto installLambdas(EnvironmentPtr env) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (auto function : lambdaTable) { | 
					 | 
				
			||||||
		rep(function, env); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	size_t count = arguments.size(); | 
					 | 
				
			||||||
	auto nodes = ValueVector(); | 
					 | 
				
			||||||
	for (size_t i = 1; i < count; ++i) { | 
					 | 
				
			||||||
		nodes.push_back(makePtr<String>(arguments[i])); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	env->set("*ARGV*", makePtr<List>(nodes)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.blaze-history"; | 
					 | 
				
			||||||
	std::vector<std::string> arguments; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, blaze::cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, blaze::cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(blaze::s_outer_env); | 
					 | 
				
			||||||
	installLambdas(blaze::s_outer_env); | 
					 | 
				
			||||||
	makeArgv(blaze::s_outer_env, arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arguments.size() > 0) { | 
					 | 
				
			||||||
		rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input, blaze::s_outer_env)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,168 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
#include <vector> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static EnvironmentPtr s_outer_env = Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (env == nullptr) { | 
					 | 
				
			||||||
		env = s_outer_env; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Error::the().clearErrors(); | 
					 | 
				
			||||||
	Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(eval(read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::string_view lambdaTable[] = { | 
					 | 
				
			||||||
	"(def! not (fn* (cond) (if cond false true)))", | 
					 | 
				
			||||||
	"(def! load-file (fn* (filename) \
 | 
					 | 
				
			||||||
	   (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", | 
					 | 
				
			||||||
	"(defmacro! cond (fn* (& xs) \
 | 
					 | 
				
			||||||
	    (if (> (count xs) 0) \
 | 
					 | 
				
			||||||
	        (list 'if (first xs) \
 | 
					 | 
				
			||||||
	            (if (> (count xs) 1) \
 | 
					 | 
				
			||||||
	                (nth xs 1) \
 | 
					 | 
				
			||||||
	              (throw \"odd number of forms to cond\")) \
 | 
					 | 
				
			||||||
	          (cons 'cond (rest (rest xs)))))))", | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto installLambdas(EnvironmentPtr env) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (auto function : lambdaTable) { | 
					 | 
				
			||||||
		rep(function, env); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	size_t count = arguments.size(); | 
					 | 
				
			||||||
	auto nodes = ValueVector(); | 
					 | 
				
			||||||
	for (size_t i = 1; i < count; ++i) { | 
					 | 
				
			||||||
		nodes.push_back(makePtr<String>(arguments[i])); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	env->set("*ARGV*", makePtr<List>(nodes)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.blaze-history"; | 
					 | 
				
			||||||
	std::vector<std::string> arguments; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, blaze::cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, blaze::cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(blaze::s_outer_env); | 
					 | 
				
			||||||
	installLambdas(blaze::s_outer_env); | 
					 | 
				
			||||||
	makeArgv(blaze::s_outer_env, arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arguments.size() > 0) { | 
					 | 
				
			||||||
		rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		print("{}\n", rep(input, blaze::s_outer_env)); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,171 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
#include <vector> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static EnvironmentPtr s_outer_env = Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (env == nullptr) { | 
					 | 
				
			||||||
		env = s_outer_env; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Error::the().clearErrors(); | 
					 | 
				
			||||||
	Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(eval(read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::string_view lambdaTable[] = { | 
					 | 
				
			||||||
	"(def! not (fn* (cond) (if cond false true)))", | 
					 | 
				
			||||||
	"(def! load-file (fn* (filename) \
 | 
					 | 
				
			||||||
	   (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", | 
					 | 
				
			||||||
	"(defmacro! cond (fn* (& xs) \
 | 
					 | 
				
			||||||
	    (if (> (count xs) 0) \
 | 
					 | 
				
			||||||
	        (list 'if (first xs) \
 | 
					 | 
				
			||||||
	            (if (> (count xs) 1) \
 | 
					 | 
				
			||||||
	                (nth xs 1) \
 | 
					 | 
				
			||||||
	              (throw \"odd number of forms to cond\")) \
 | 
					 | 
				
			||||||
	          (cons 'cond (rest (rest xs)))))))", | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto installLambdas(EnvironmentPtr env) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (auto function : lambdaTable) { | 
					 | 
				
			||||||
		rep(function, env); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	size_t count = arguments.size(); | 
					 | 
				
			||||||
	auto nodes = ValueVector(); | 
					 | 
				
			||||||
	for (size_t i = 1; i < count; ++i) { | 
					 | 
				
			||||||
		nodes.push_back(makePtr<String>(arguments[i])); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	env->set("*ARGV*", makePtr<List>(nodes)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.blaze-history"; | 
					 | 
				
			||||||
	std::vector<std::string> arguments; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, blaze::cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, blaze::cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(blaze::s_outer_env); | 
					 | 
				
			||||||
	installLambdas(blaze::s_outer_env); | 
					 | 
				
			||||||
	makeArgv(blaze::s_outer_env, arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arguments.size() > 0) { | 
					 | 
				
			||||||
		rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::Readline readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (readline.get(input)) { | 
					 | 
				
			||||||
		if (pretty_print) { | 
					 | 
				
			||||||
			print("\033[0m"); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		std::string output = rep(input, blaze::s_outer_env); | 
					 | 
				
			||||||
		if (output.length() > 0) { | 
					 | 
				
			||||||
			print("{}\n", output); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Added to keep the linker happy at step A
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
ValuePtr readline(const std::string&) { return nullptr; } | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
@ -1,178 +0,0 @@ | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 Riyyi | 
					 | 
				
			||||||
 * | 
					 | 
				
			||||||
 * SPDX-License-Identifier: MIT | 
					 | 
				
			||||||
 */ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <csignal> // std::signal | 
					 | 
				
			||||||
#include <cstdlib> // std::exit | 
					 | 
				
			||||||
#include <string> | 
					 | 
				
			||||||
#include <string_view> | 
					 | 
				
			||||||
#include <vector> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ruc/argparser.h" | 
					 | 
				
			||||||
#include "ruc/format/color.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ast.h" | 
					 | 
				
			||||||
#include "environment.h" | 
					 | 
				
			||||||
#include "error.h" | 
					 | 
				
			||||||
#include "eval.h" | 
					 | 
				
			||||||
#include "forward.h" | 
					 | 
				
			||||||
#include "lexer.h" | 
					 | 
				
			||||||
#include "printer.h" | 
					 | 
				
			||||||
#include "reader.h" | 
					 | 
				
			||||||
#include "readline.h" | 
					 | 
				
			||||||
#include "settings.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace blaze { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static blaze::Readline s_readline; | 
					 | 
				
			||||||
static EnvironmentPtr s_outer_env = Environment::create(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto cleanup(int signal) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	print("\033[0m\n"); | 
					 | 
				
			||||||
	std::exit(signal); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto readline(const std::string& prompt) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	if (s_readline.get(input, s_readline.createPrompt(prompt))) { | 
					 | 
				
			||||||
		return makePtr<String>(input); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return makePtr<Constant>(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto read(std::string_view input) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Lexer lexer(input); | 
					 | 
				
			||||||
	lexer.tokenize(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-lexer") == "1") { | 
					 | 
				
			||||||
		lexer.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reader reader(std::move(lexer.tokens())); | 
					 | 
				
			||||||
	reader.read(); | 
					 | 
				
			||||||
	if (Settings::the().get("dump-reader") == "1") { | 
					 | 
				
			||||||
		reader.dump(); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return reader.node(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto eval(ValuePtr ast, EnvironmentPtr env) -> ValuePtr | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (env == nullptr) { | 
					 | 
				
			||||||
		env = s_outer_env; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Eval eval(ast, env); | 
					 | 
				
			||||||
	eval.eval(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval.ast(); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto print(ValuePtr exp) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Printer printer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return printer.print(exp, true); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto rep(std::string_view input, EnvironmentPtr env) -> std::string | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	Error::the().clearErrors(); | 
					 | 
				
			||||||
	Error::the().setInput(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return print(eval(read(input), env)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::string_view lambdaTable[] = { | 
					 | 
				
			||||||
	"(def! not (fn* (cond) (if cond false true)))", | 
					 | 
				
			||||||
	"(def! load-file (fn* (filename) \
 | 
					 | 
				
			||||||
	   (eval (read-string (str \"(do \" (slurp filename) \"\nnil)\")))))", | 
					 | 
				
			||||||
	"(defmacro! cond (fn* (& xs) \
 | 
					 | 
				
			||||||
	    (if (> (count xs) 0) \
 | 
					 | 
				
			||||||
	        (list 'if (first xs) \
 | 
					 | 
				
			||||||
	            (if (> (count xs) 1) \
 | 
					 | 
				
			||||||
	                (nth xs 1) \
 | 
					 | 
				
			||||||
	              (throw \"odd number of forms to cond\")) \
 | 
					 | 
				
			||||||
	          (cons 'cond (rest (rest xs)))))))", | 
					 | 
				
			||||||
	"(def! *host-language* \"C++\")", | 
					 | 
				
			||||||
}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto installLambdas(EnvironmentPtr env) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	for (auto function : lambdaTable) { | 
					 | 
				
			||||||
		rep(function, env); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static auto makeArgv(EnvironmentPtr env, std::vector<std::string> arguments) -> void | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	size_t count = arguments.size(); | 
					 | 
				
			||||||
	auto nodes = ValueVector(); | 
					 | 
				
			||||||
	for (size_t i = 1; i < count; ++i) { | 
					 | 
				
			||||||
		nodes.push_back(makePtr<String>(arguments[i])); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	env->set("*ARGV*", makePtr<List>(nodes)); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace blaze
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char* argv[]) -> int | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	bool dump_lexer = false; | 
					 | 
				
			||||||
	bool dump_reader = false; | 
					 | 
				
			||||||
	bool pretty_print = false; | 
					 | 
				
			||||||
	std::string_view history_path = "~/.blaze-history"; | 
					 | 
				
			||||||
	std::vector<std::string> arguments; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CLI arguments
 | 
					 | 
				
			||||||
	ruc::ArgParser arg_parser; | 
					 | 
				
			||||||
	arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); | 
					 | 
				
			||||||
	arg_parser.addOption(history_path, 'h', "history-path", nullptr, nullptr, nullptr, ruc::ArgParser::Required::Yes); | 
					 | 
				
			||||||
	// TODO: Add overload for addArgument(std::vector<std::string_view>)
 | 
					 | 
				
			||||||
	arg_parser.addArgument(arguments, "arguments", nullptr, nullptr, ruc::ArgParser::Required::No); | 
					 | 
				
			||||||
	arg_parser.parse(argc, argv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set settings
 | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-lexer", dump_lexer ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("dump-reader", dump_reader ? "1" : "0"); | 
					 | 
				
			||||||
	blaze::Settings::the().set("pretty-print", pretty_print ? "1" : "0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Signal callbacks
 | 
					 | 
				
			||||||
	std::signal(SIGINT, blaze::cleanup); | 
					 | 
				
			||||||
	std::signal(SIGTERM, blaze::cleanup); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	installFunctions(blaze::s_outer_env); | 
					 | 
				
			||||||
	installLambdas(blaze::s_outer_env); | 
					 | 
				
			||||||
	makeArgv(blaze::s_outer_env, arguments); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arguments.size() > 0) { | 
					 | 
				
			||||||
		rep(format("(load-file \"{}\")", arguments.front()), blaze::s_outer_env); | 
					 | 
				
			||||||
		return 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rep("(println (str \"Mal [\" *host-language* \"]\"))", blaze::s_outer_env); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blaze::s_readline = blaze::Readline(pretty_print, history_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string input; | 
					 | 
				
			||||||
	while (blaze::s_readline.get(input)) { | 
					 | 
				
			||||||
		std::string output = rep(input, blaze::s_outer_env); | 
					 | 
				
			||||||
		if (output.length() > 0) { | 
					 | 
				
			||||||
			print("{}\n", output); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pretty_print) { | 
					 | 
				
			||||||
		print("\033[0m"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue