9 changed files with 412 additions and 144 deletions
			
			
		| @ -0,0 +1,62 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2023 Riyyi | ||||
|  * | ||||
|  * SPDX-License-Identifier: MIT | ||||
|  */ | ||||
| 
 | ||||
| #include "ruc/format/print.h" | ||||
| 
 | ||||
| #include "ast.h" | ||||
| #include "environment.h" | ||||
| 
 | ||||
| namespace blaze { | ||||
| 
 | ||||
| Environment::Environment(EnvironmentPtr outer) | ||||
| 	: m_outer(outer) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------
 | ||||
| 
 | ||||
| bool Environment::exists(const std::string& symbol) | ||||
| { | ||||
| 	return m_values.find(symbol) != m_values.end(); | ||||
| } | ||||
| 
 | ||||
| ASTNodePtr Environment::set(const std::string& symbol, ASTNodePtr value) | ||||
| { | ||||
| 	if (exists(symbol)) { | ||||
| 		m_values.erase(symbol); | ||||
| 	} | ||||
| 
 | ||||
| 	m_values.emplace(symbol, value); | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
| ASTNodePtr Environment::get(const std::string& symbol) | ||||
| { | ||||
| 	m_current_key = symbol; | ||||
| 
 | ||||
| 	if (exists(symbol)) { | ||||
| 		return m_values[symbol]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_outer) { | ||||
| 		return m_outer->get(symbol); | ||||
| 	} | ||||
| 
 | ||||
| 	return nullptr; | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------
 | ||||
| 
 | ||||
| GlobalEnvironment::GlobalEnvironment() | ||||
| { | ||||
| 	add(); | ||||
| 	sub(); | ||||
| 	mul(); | ||||
| 	div(); | ||||
| } | ||||
| 
 | ||||
| } // namespace blaze
 | ||||
| @ -0,0 +1,119 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2023 Riyi | ||||
|  * | ||||
|  * 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 "types.h" | ||||
| 
 | ||||
| namespace blaze { | ||||
| 
 | ||||
| void GlobalEnvironment::add() | ||||
| { | ||||
| 	auto add = [](std::span<ASTNodePtr> nodes) -> ASTNodePtr { | ||||
| 		int64_t result = 0; | ||||
| 
 | ||||
| 		for (auto node : nodes) { | ||||
| 			if (!is<Number>(node.get())) { | ||||
| 				Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 
 | ||||
| 			result += std::static_pointer_cast<Number>(node)->number(); | ||||
| 		} | ||||
| 
 | ||||
| 		return makePtr<Number>(result); | ||||
| 	}; | ||||
| 
 | ||||
| 	m_values.emplace("+", makePtr<Function>(add)); | ||||
| } | ||||
| 
 | ||||
| void GlobalEnvironment::sub() | ||||
| { | ||||
| 	auto sub = [](std::span<ASTNodePtr> nodes) -> ASTNodePtr { | ||||
| 		int64_t result = 0; | ||||
| 
 | ||||
| 		if (nodes.size() == 0) { | ||||
| 			return makePtr<Number>(0); | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto node : nodes) { | ||||
| 			if (!is<Number>(node.get())) { | ||||
| 				Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Start with the first number
 | ||||
| 		result += std::static_pointer_cast<Number>(nodes[0])->number(); | ||||
| 
 | ||||
| 		// Skip the first node
 | ||||
| 		for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { | ||||
| 			result -= std::static_pointer_cast<Number>(*it)->number(); | ||||
| 		} | ||||
| 
 | ||||
| 		return makePtr<Number>(result); | ||||
| 	}; | ||||
| 
 | ||||
| 	m_values.emplace("-", makePtr<Function>(sub)); | ||||
| } | ||||
| 
 | ||||
| void GlobalEnvironment::mul() | ||||
| { | ||||
| 	auto mul = [](std::span<ASTNodePtr> nodes) -> ASTNodePtr { | ||||
| 		int64_t result = 1; | ||||
| 
 | ||||
| 		for (auto node : nodes) { | ||||
| 			if (!is<Number>(node.get())) { | ||||
| 				Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 
 | ||||
| 			result *= std::static_pointer_cast<Number>(node)->number(); | ||||
| 		} | ||||
| 
 | ||||
| 		return makePtr<Number>(result); | ||||
| 	}; | ||||
| 
 | ||||
| 	m_values.emplace("*", makePtr<Function>(mul)); | ||||
| } | ||||
| 
 | ||||
| void GlobalEnvironment::div() | ||||
| { | ||||
| 	auto div = [this](std::span<ASTNodePtr> nodes) -> ASTNodePtr { | ||||
| 		double result = 0; | ||||
| 
 | ||||
| 		if (nodes.size() == 0) { | ||||
| 			Error::the().addError(format("wrong number of arguments: {}, 0", m_current_key)); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto node : nodes) { | ||||
| 			if (!is<Number>(node.get())) { | ||||
| 				Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Start with the first number
 | ||||
| 		result += std::static_pointer_cast<Number>(nodes[0])->number(); | ||||
| 
 | ||||
| 		// Skip the first node
 | ||||
| 		for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { | ||||
| 			result /= std::static_pointer_cast<Number>(*it)->number(); | ||||
| 		} | ||||
| 
 | ||||
| 		return makePtr<Number>((int64_t)result); | ||||
| 	}; | ||||
| 
 | ||||
| 	m_values.emplace("/", makePtr<Function>(div)); | ||||
| } | ||||
| 
 | ||||
| } // namespace blaze
 | ||||
| @ -0,0 +1,108 @@ | ||||
| #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 "lexer.h" | ||||
| #include "printer.h" | ||||
| #include "reader.h" | ||||
| #include "readline.h" | ||||
| #include "settings.h" | ||||
| 
 | ||||
| #if 1 | ||||
| static blaze::EnvironmentPtr env = blaze::makePtr<blaze::GlobalEnvironment>(); | ||||
| 
 | ||||
| auto read(std::string_view input) -> blaze::ASTNodePtr | ||||
| { | ||||
| 	blaze::Lexer lexer(input); | ||||
| 	lexer.tokenize(); | ||||
| 	if (blaze::Settings::the().get("dump-lexer") == "1") { | ||||
| 		lexer.dump(); | ||||
| 	} | ||||
| 
 | ||||
| 	blaze::Reader reader(std::move(lexer.tokens())); | ||||
| 	reader.read(); | ||||
| 	if (blaze::Settings::the().get("dump-reader") == "1") { | ||||
| 		reader.dump(); | ||||
| 	} | ||||
| 
 | ||||
| 	return reader.node(); | ||||
| } | ||||
| 
 | ||||
| auto eval(blaze::ASTNodePtr ast) -> blaze::ASTNodePtr | ||||
| { | ||||
| 	blaze::Eval eval(ast, env); | ||||
| 	eval.eval(); | ||||
| 
 | ||||
| 	return eval.ast(); | ||||
| } | ||||
| 
 | ||||
| auto print(blaze::ASTNodePtr 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(eval(read(input))); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| 	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; | ||||
| } | ||||
| #endif | ||||
					Loading…
					
					
				
		Reference in new issue