22 changed files with 1313 additions and 1114 deletions
			
			
		@ -0,0 +1,139 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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,119 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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,265 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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 = 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) = (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,132 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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(>=)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (= 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<List>(lhs.get()) || is<Vector>(lhs.get())) | 
				
			||||||
 | 
							        && (is<List>(rhs.get()) || is<Vector>(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; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								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); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,49 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (symbol "foo")  -> foo
 | 
				
			||||||
 | 
					ADD_FUNCTION( | 
				
			||||||
 | 
						"symbol", | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is<Symbol>(begin->get())) { | 
				
			||||||
 | 
								return *begin; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VALUE_CAST(stringValue, String, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return makePtr<Symbol>(stringValue->data()); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (keyword "foo") -> :foo
 | 
				
			||||||
 | 
					// (keyword 123)   -> :123
 | 
				
			||||||
 | 
					ADD_FUNCTION( | 
				
			||||||
 | 
						"keyword", | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							CHECK_ARG_COUNT_IS("symbol", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is<Keyword>(begin->get())) { | 
				
			||||||
 | 
								return *begin; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							else if (is<Number>(begin->get())) { | 
				
			||||||
 | 
								VALUE_CAST(numberValue, Number, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return makePtr<Keyword>(numberValue->number()); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VALUE_CAST(stringValue, String, (*begin)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return makePtr<Keyword>(stringValue->data()); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,56 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iterator> // std::next | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/format/print.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "printer.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,53 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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,81 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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 = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return atom->reset(value); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,91 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint> // int64_t | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (% 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,71 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <chrono>  // std::chrono::sytem_clock | 
				
			||||||
 | 
					#include <cstddef> // size_t | 
				
			||||||
 | 
					#include <cstdint> // int64_t | 
				
			||||||
 | 
					#include <memory>  // std::static_pointer_cast | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "error.h" | 
				
			||||||
 | 
					#include "forward.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (count '(1 2 3)) -> 3
 | 
				
			||||||
 | 
					// (count [1 2 3]) -> 3
 | 
				
			||||||
 | 
					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); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// (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,132 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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,63 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ruc/file.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ast.h" | 
				
			||||||
 | 
					#include "env/macro.h" | 
				
			||||||
 | 
					#include "util.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace blaze { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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 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 readline(prompt->data()); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// REPL eval
 | 
				
			||||||
 | 
					ADD_FUNCTION( | 
				
			||||||
 | 
						"eval", | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							CHECK_ARG_COUNT_IS("eval", SIZE(), 1); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return eval(*begin, nullptr); | 
				
			||||||
 | 
						}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace blaze
 | 
				
			||||||
@ -0,0 +1,32 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2023 Riyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unordered_map> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "env/environment.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 counter macro 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)   \
 | 
				
			||||||
 | 
							{                                                      \
 | 
				
			||||||
 | 
								Environment::registerFunction(__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(__COUNTER__, symbol, lambda); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIZE() std::distance(begin, end) | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue