/* * Copyright (C) 2023 Riyi * * SPDX-License-Identifier: MIT */ #include // std::static_pointer_cast #include #include "ruc/format/color.h" #include "ruc/format/format.h" #include "ast.h" #include "environment.h" #include "error.h" #include "printer.h" #include "types.h" #include "util.h" namespace blaze { void GlobalEnvironment::add() { auto add = [](std::span nodes) -> ASTNodePtr { int64_t result = 0; for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong argument type: number, '{}'", node)); return nullptr; } result += std::static_pointer_cast(node)->number(); } return makePtr(result); }; m_values.emplace("+", makePtr(add)); } void GlobalEnvironment::sub() { auto sub = [](std::span nodes) -> ASTNodePtr { if (nodes.size() == 0) { return makePtr(0); } for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong argument type: number, '{}'", node)); return nullptr; } } // Start with the first number int64_t result = std::static_pointer_cast(nodes[0])->number(); // Skip the first node for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { result -= std::static_pointer_cast(*it)->number(); } return makePtr(result); }; m_values.emplace("-", makePtr(sub)); } void GlobalEnvironment::mul() { auto mul = [](std::span nodes) -> ASTNodePtr { int64_t result = 1; for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong argument type: number, '{}'", node)); return nullptr; } result *= std::static_pointer_cast(node)->number(); } return makePtr(result); }; m_values.emplace("*", makePtr(mul)); } void GlobalEnvironment::div() { auto div = [this](std::span nodes) -> ASTNodePtr { if (nodes.size() == 0) { Error::the().addError(format("wrong number of arguments: {}, 0", m_current_key)); return nullptr; } for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); return nullptr; } } // Start with the first number double result = std::static_pointer_cast(nodes[0])->number(); // Skip the first node for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { result /= std::static_pointer_cast(*it)->number(); } return makePtr((int64_t)result); }; m_values.emplace("/", makePtr(div)); } // ----------------------------------------- #define NUMBER_COMPARE(symbol, comparison_symbol) \ auto lambda = [this](std::span nodes) -> ASTNodePtr { \ bool result = true; \ \ if (nodes.size() < 2) { \ Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); \ return nullptr; \ } \ \ for (auto node : nodes) { \ if (!is(node.get())) { \ Error::the().addError(format("wrong argument type: number, '{}'", node)); \ return nullptr; \ } \ } \ \ /* Start with the first number */ \ int64_t number = std::static_pointer_cast(nodes[0])->number(); \ \ /* Skip the first node */ \ for (auto it = std::next(nodes.begin()); it != nodes.end(); ++it) { \ int64_t current_number = std::static_pointer_cast(*it)->number(); \ if (number comparison_symbol current_number) { \ result = false; \ break; \ } \ number = current_number; \ } \ \ return makePtr((result) ? Value::True : Value::False); \ }; \ \ m_values.emplace(symbol, makePtr(lambda)); void GlobalEnvironment::lt() { NUMBER_COMPARE("<", >=); } void GlobalEnvironment::lte() { NUMBER_COMPARE("<=", >); } void GlobalEnvironment::gt() { NUMBER_COMPARE(">", <=); } void GlobalEnvironment::gte() { NUMBER_COMPARE(">=", <); } // ----------------------------------------- void GlobalEnvironment::list() { auto list = [](std::span nodes) -> ASTNodePtr { auto list = makePtr(); for (auto node : nodes) { list->addNode(node); } return list; }; m_values.emplace("list", makePtr(list)); } void GlobalEnvironment::isList() { auto is_list = [](std::span nodes) -> ASTNodePtr { bool result = true; for (auto node : nodes) { if (!is(node.get())) { result = false; break; } } return makePtr((result) ? Value::True : Value::False); }; m_values.emplace("list?", makePtr(is_list)); } void GlobalEnvironment::isEmpty() { auto is_empty = [](std::span nodes) -> ASTNodePtr { bool result = true; for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong argument type: list, '{}'", node)); return nullptr; } if (!std::static_pointer_cast(node)->empty()) { result = false; break; } } return makePtr((result) ? Value::True : Value::False); }; m_values.emplace("empty?", makePtr(is_empty)); } void GlobalEnvironment::count() { auto count = [this](std::span nodes) -> ASTNodePtr { if (nodes.size() > 1) { Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); return nullptr; } size_t result = 0; for (auto node : nodes) { if (!is(node.get())) { Error::the().addError(format("wrong argument type: list, '{}'", node)); return nullptr; } result = std::static_pointer_cast(node)->size(); } // FIXME: Add numeric_limits check for implicit cast: size_t > int64_t return makePtr((int64_t)result); }; m_values.emplace("count", makePtr(count)); } // ----------------------------------------- #define PRINTER_STRING(symbol, concatenation, print_readably) \ auto lambda = [](std::span nodes) -> ASTNodePtr { \ std::string result; \ \ Printer printer; \ for (auto it = nodes.begin(); it != nodes.end(); ++it) { \ result += format("{}", printer.printNoErrorCheck(*it, print_readably)); \ \ if (!isLast(it, nodes)) { \ result += concatenation; \ } \ } \ \ return makePtr(result); \ }; \ \ m_values.emplace(symbol, makePtr(lambda)); void GlobalEnvironment::str() { PRINTER_STRING("str", "", false); } void GlobalEnvironment::prStr() { PRINTER_STRING("pr-str", " ", true); } #define PRINTER_PRINT(symbol, print_readably) \ auto lambda = [](std::span nodes) -> ASTNodePtr { \ Printer printer; \ for (auto it = nodes.begin(); it != nodes.end(); ++it) { \ print("{}", printer.printNoErrorCheck(*it, print_readably)); \ \ if (!isLast(it, nodes)) { \ print(" "); \ } \ } \ print("\n"); \ \ return makePtr(Value::Nil); \ }; \ \ m_values.emplace(symbol, makePtr(lambda)); void GlobalEnvironment::prn() { PRINTER_PRINT("prn", true); } void GlobalEnvironment::println() { PRINTER_PRINT("println", false); } // ----------------------------------------- void GlobalEnvironment::equal() { auto lambda = [this](std::span nodes) -> ASTNodePtr { if (nodes.size() < 2) { Error::the().addError(format("wrong number of arguments: {}, {}", m_current_key, nodes.size() - 1)); return nullptr; } std::function equal = [&equal](ASTNodePtr lhs, ASTNodePtr rhs) -> bool { if ((is(lhs.get()) && is(rhs.get())) || (is(lhs.get()) && is(rhs.get()))) { auto lhs_nodes = std::static_pointer_cast(lhs)->nodes(); auto rhs_nodes = std::static_pointer_cast(rhs)->nodes(); if (lhs_nodes.size() != rhs_nodes.size()) { return false; } for (size_t i = 0; i < lhs_nodes.size(); ++i) { if (!equal(lhs_nodes[i], rhs_nodes[i])) { return false; } } return true; } if (is(lhs.get()) && is(rhs.get())) { auto lhs_nodes = std::static_pointer_cast(lhs)->elements(); auto rhs_nodes = std::static_pointer_cast(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.end() || !equal(value, it->second)) { return false; } } return true; } if (is(lhs.get()) && is(rhs.get()) && std::static_pointer_cast(lhs)->data() == std::static_pointer_cast(rhs)->data()) { return true; } if (is(lhs.get()) && is(rhs.get()) && std::static_pointer_cast(lhs)->keyword() == std::static_pointer_cast(rhs)->keyword()) { return true; } if (is(lhs.get()) && is(rhs.get()) && std::static_pointer_cast(lhs)->number() == std::static_pointer_cast(rhs)->number()) { return true; } if (is(lhs.get()) && is(rhs.get()) && std::static_pointer_cast(lhs)->state() == std::static_pointer_cast(rhs)->state()) { return true; } if (is(lhs.get()) && is(rhs.get()) && std::static_pointer_cast(lhs)->symbol() == std::static_pointer_cast(rhs)->symbol()) { return true; } return false; }; bool result = true; for (size_t i = 0; i < nodes.size() - 1; ++i) { if (!equal(nodes[i], nodes[i + 1])) { result = false; break; } } return makePtr((result) ? Value::True : Value::False); }; m_values.emplace("=", makePtr(lambda)); } } // namespace blaze