Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,11 @@

build/
cmake-build-*/
CMakeUserPresets.json
.idea
.vs
.vs

# Added by the agentic bootstrap: byproducts of the hooks it installs.
__pycache__/
*.py[cod]
.agents/**/*.bootstrap-tmp
6 changes: 2 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
cmake_minimum_required(VERSION 3.26)
project(cura-formulae-engine)

include(CTest)

find_package(standardprojectsettings REQUIRED)
option(ENABLE_TESTS "Build with unit test" ON)
option(EXTENSIVE_WARNINGS "Build with all warnings" ON)
option(ENABLE_APPS "Build apps example" ON)

if (ENABLE_TESTS AND NOT BUILD_TESTING)
message(STATUS "ENABLE_TESTS is ON, forcing BUILD_TESTING=ON so CTest can discover tests")
if (ENABLE_TESTS)
set(BUILD_TESTING ON CACHE BOOL "Enable CTest" FORCE)
include(CTest)
endif ()

find_package(spdlog REQUIRED)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,4 @@ General Public License ever published by the Free Software Foundation.
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
Library.
1 change: 0 additions & 1 deletion apps/cmdline_parser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ if (${EXTENSIVE_WARNINGS})
endif ()

target_link_libraries(cmdline_parser PUBLIC cura-formulae-engine foonathan::lexy range-v3::range-v3)

67 changes: 31 additions & 36 deletions apps/cmdline_parser/cmdline_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,37 @@
#include <string>
#include <string_view>

int main(int argc, const char** argv)
{
spdlog::set_level(spdlog::level::info);
spdlog::info("Formula REPL, type 'exit' to quit.");

while (true)
{
std::cout << "> ";
std::string command;
std::getline(std::cin, command);
if (command == "exit")
{
break;
}

const auto input = std::string_view(command.begin(), command.end());
auto message = CuraFormulaeEngine::parser::parse(input);

if (!message.has_value())
{
spdlog::warn("Failed to parse input.");
continue;
}

const auto& expr = message.value();
const auto eval_result = expr.evaluate(&CuraFormulaeEngine::env::std_env);

if (!eval_result.has_value())
{
spdlog::warn("Expr {} results in eval error", expr.toString());
continue;
}

const auto& eval = eval_result.value();
spdlog::info("{} = {}", expr.toString(), eval.toString());
int main(int argc, const char **argv) {
spdlog::set_level(spdlog::level::info);
spdlog::info("Formula REPL, type 'exit' to quit.");

while (true) {
std::cout << "> ";
std::string command;
std::getline(std::cin, command);
if (command == "exit") {
break;
}

return 0;
const auto input = std::string_view(command.begin(), command.end());
auto message = CuraFormulaeEngine::parser::parse(input);

if (!message.has_value()) {
spdlog::warn("Failed to parse input.");
continue;
}

const auto &expr = message.value();
const auto eval_result = expr.evaluate(&CuraFormulaeEngine::env::std_env);

if (!eval_result.has_value()) {
spdlog::warn("Expr {} results in eval error", expr.toString());
continue;
}

const auto &eval = eval_result.value();
spdlog::info("{} = {}", expr.toString(), eval.toString());
}

return 0;
}
201 changes: 100 additions & 101 deletions include/cura-formulae-engine/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

#include "cura-formulae-engine/eval.h"

namespace CuraFormulaeEngine::eval
{
namespace CuraFormulaeEngine::eval {

enum class Error;

Expand All @@ -19,146 +18,146 @@ using Result = zeus::expected<Value, Error>;

} // namespace CuraFormulaeEngine::eval

namespace CuraFormulaeEngine::env
{
namespace CuraFormulaeEngine::env {

class Environment
{
class Environment {
public:
virtual ~Environment() = default;
virtual ~Environment() = default;

[[nodiscard]] virtual std::optional<eval::Value> get(const std::string& key) const = 0;
[[nodiscard]] virtual bool has(const std::string& key) const = 0;
[[nodiscard]] virtual std::unordered_map<std::string, eval::Value> getAll() const = 0;
[[nodiscard]] virtual std::optional<eval::Value>
get(const std::string &key) const = 0;
[[nodiscard]] virtual bool has(const std::string &key) const = 0;
[[nodiscard]] virtual std::unordered_map<std::string, eval::Value>
getAll() const = 0;
};

class EnvironmentMap : public Environment
{
class EnvironmentMap : public Environment {
private:
std::unordered_map<std::string, eval::Value> environment_ = {};
std::unordered_map<std::string, eval::Value> environment_ = {};

public:
EnvironmentMap() = default;
explicit EnvironmentMap(const std::unordered_map<std::string, eval::Value>& map)
: environment_(map)
{
}
~EnvironmentMap() override = default;
EnvironmentMap() = default;
explicit EnvironmentMap(
const std::unordered_map<std::string, eval::Value> &map)
: environment_(map) {}
~EnvironmentMap() override = default;

[[nodiscard]] std::optional<eval::Value> get(const std::string& key) const noexcept override;
[[nodiscard]] std::optional<eval::Value>
get(const std::string &key) const noexcept override;

[[nodiscard]] bool has(const std::string& key) const noexcept override;
[[nodiscard]] bool has(const std::string &key) const noexcept override;

[[nodiscard]] std::unordered_map<std::string, eval::Value> getAll() const noexcept override;
[[nodiscard]] std::unordered_map<std::string, eval::Value>
getAll() const noexcept override;

bool erase(const std::string& key) noexcept;
bool erase(const std::string &key) noexcept;

void set(const std::string& key, const eval::Value& value) noexcept;
void set(const std::string &key, const eval::Value &value) noexcept;

void add(const std::unordered_map<std::string, eval::Value>& values);
void add(const std::unordered_map<std::string, eval::Value> &values);

[[nodiscard]] EnvironmentMap clone() const noexcept;
[[nodiscard]] EnvironmentMap clone() const noexcept;
};

class ChainableEnvironment : public Environment
{
class ChainableEnvironment : public Environment {
private:
const Environment* shadow_environment_{ nullptr };
const Environment *shadow_environment_{nullptr};

public:
explicit ChainableEnvironment(const Environment* shadow_environment = nullptr)
: shadow_environment_(shadow_environment)
{
}
~ChainableEnvironment() override = default;
explicit ChainableEnvironment(const Environment *shadow_environment = nullptr)
: shadow_environment_(shadow_environment) {}
~ChainableEnvironment() override = default;

[[nodiscard]] std::optional<eval::Value> get(const std::string& key) const noexcept override final;
[[nodiscard]] std::optional<eval::Value>
get(const std::string &key) const noexcept override final;

[[nodiscard]] bool has(const std::string& key) const noexcept override final;
[[nodiscard]] bool has(const std::string &key) const noexcept override final;

[[nodiscard]] std::unordered_map<std::string, eval::Value> getAll() const noexcept override final;
[[nodiscard]] std::unordered_map<std::string, eval::Value>
getAll() const noexcept override final;

protected:
[[nodiscard]] virtual std::optional<eval::Value> getImpl(const std::string& key) const noexcept = 0;
[[nodiscard]] virtual std::optional<eval::Value>
getImpl(const std::string &key) const noexcept = 0;

[[nodiscard]] virtual bool hasImpl(const std::string& key) const noexcept = 0;
[[nodiscard]] virtual bool hasImpl(const std::string &key) const noexcept = 0;

[[nodiscard]] virtual std::unordered_map<std::string, eval::Value> getAllImpl() const noexcept = 0;
[[nodiscard]] virtual std::unordered_map<std::string, eval::Value>
getAllImpl() const noexcept = 0;
};

class LocalEnvironment : public ChainableEnvironment
{
class LocalEnvironment : public ChainableEnvironment {
private:
EnvironmentMap local_environment_;
EnvironmentMap local_environment_;

public:
explicit LocalEnvironment(const Environment* shadow_environment = nullptr)
: ChainableEnvironment(shadow_environment)
{
}
~LocalEnvironment() override = default;
explicit LocalEnvironment(const Environment *shadow_environment = nullptr)
: ChainableEnvironment(shadow_environment) {}
~LocalEnvironment() override = default;

[[nodiscard]] std::optional<eval::Value> getImpl(const std::string& key) const noexcept override;
[[nodiscard]] std::optional<eval::Value>
getImpl(const std::string &key) const noexcept override;

[[nodiscard]] bool hasImpl(const std::string& key) const noexcept override;
[[nodiscard]] bool hasImpl(const std::string &key) const noexcept override;

[[nodiscard]] std::unordered_map<std::string, eval::Value> getAllImpl() const noexcept override;
[[nodiscard]] std::unordered_map<std::string, eval::Value>
getAllImpl() const noexcept override;

void set(const std::string& key, const eval::Value& value);
void set(const std::string &key, const eval::Value &value);

void add(const std::unordered_map<std::string, eval::Value>& values);
void add(const std::unordered_map<std::string, eval::Value> &values);
};

} // namespace CuraFormulaeEngine::env

namespace CuraFormulaeEngine::ast
{

struct Expr
{
Expr() = default;
Expr(const Expr&) = default;
Expr(Expr&&) = default;
Expr& operator=(const Expr&) = default;
Expr& operator=(Expr&&) = default;
virtual ~Expr() = default;

/**
* @brief Evaluates the expression in the given environment.
*
* @param environment The environment to evaluate the expression in.
* @return eval_result The result of the evaluation.
*/
[[nodiscard]] virtual eval::Result evaluate(const env::Environment* environment) const = 0;

/**
* @brief Returns the set of free variables in the expression.
*
* @return std::unordered_set<std::string> The set of free variables.
*/
[[nodiscard]] virtual std::unordered_set<std::string> freeVariables() const = 0;

/**
* @brief Returns a string representation of the expression.
*
* @return std::string The string representation.
*/
[[nodiscard]] virtual std::string toString() const = 0;

/**
* @brief Returns a deep copy of the expression.
*
* @return true if the expressions are equal, false otherwise.
*/
[[nodiscard]] virtual bool deepEq(const Expr& other) const = 0;

/**
* @brief Traverses the expression tree and applies the visitor function to
* each node.
*
* @param visitor The visitor function to apply to each node.
*/
virtual void visitAll(std::function<void(const Expr&)> visitor) const = 0;
namespace CuraFormulaeEngine::ast {

struct Expr {
Expr() = default;
Expr(const Expr &) = default;
Expr(Expr &&) = default;
Expr &operator=(const Expr &) = default;
Expr &operator=(Expr &&) = default;
virtual ~Expr() = default;

/**
* @brief Evaluates the expression in the given environment.
*
* @param environment The environment to evaluate the expression in.
* @return eval_result The result of the evaluation.
*/
[[nodiscard]] virtual eval::Result
evaluate(const env::Environment *environment) const = 0;

/**
* @brief Returns the set of free variables in the expression.
*
* @return std::unordered_set<std::string> The set of free variables.
*/
[[nodiscard]] virtual std::unordered_set<std::string>
freeVariables() const = 0;

/**
* @brief Returns a string representation of the expression.
*
* @return std::string The string representation.
*/
[[nodiscard]] virtual std::string toString() const = 0;

/**
* @brief Returns a deep copy of the expression.
*
* @return true if the expressions are equal, false otherwise.
*/
[[nodiscard]] virtual bool deepEq(const Expr &other) const = 0;

/**
* @brief Traverses the expression tree and applies the visitor function to
* each node.
*
* @param visitor The visitor function to apply to each node.
*/
virtual void visitAll(std::function<void(const Expr &)> visitor) const = 0;
};

} // namespace CuraFormulaeEngine::ast
Loading