Skip to content

Commit 292342f

Browse files
authored
Merge pull request #1 from Ultimaker/CURA-12556
Split formula engine from curator
2 parents 365dc95 + 2b3afe9 commit 292342f

127 files changed

Lines changed: 7904 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
*.obj
9+
10+
# Precompiled Headers
11+
*.gch
12+
*.pch
13+
14+
# Compiled Dynamic libraries
15+
*.so
16+
*.dylib
17+
*.dll
18+
19+
# Fortran module files
20+
*.mod
21+
*.smod
22+
23+
# Compiled Static libraries
24+
*.lai
25+
*.la
26+
*.a
27+
*.lib
28+
29+
# Executables
30+
*.exe
31+
*.out
32+
*.app
33+
34+
build/
35+
cmake-build-*/
36+
.idea
37+
.vs

CMakeLists.txt

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
cmake_minimum_required(VERSION 3.26)
2+
project(cura-formulae-engine)
3+
4+
find_package(standardprojectsettings REQUIRED)
5+
option(ENABLE_TESTS "Build with unit test" ON)
6+
option(EXTENSIVE_WARNINGS "Build with all warnings" ON)
7+
option(ENABLE_APPS "Build apps example" ON)
8+
9+
find_package(spdlog REQUIRED)
10+
find_package(lexy REQUIRED)
11+
find_package(zeus_expected REQUIRED)
12+
find_package(range-v3 REQUIRED)
13+
14+
set(CMAKE_CXX_STANDARD 20)
15+
set(CMAKE_CXX_EXTENSIONS OFF)
16+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
17+
18+
if (NOT DEFINED CURA_FORMULA_VERSION_VERSION)
19+
message(FATAL_ERROR "CURA_FORMULA_VERSION_VERSION is not defined!")
20+
endif ()
21+
message(STATUS "Configuring CuraFormuleaEngine version: ${CURA_FORMULA_VERSION_VERSION}")
22+
23+
set(CURA_FORMULAE_ENGINE__SRC
24+
src/eval.cpp
25+
src/env/abs.cpp
26+
src/env/map.cpp
27+
src/env/math_ceil.cpp
28+
src/env/math_cos.cpp
29+
src/env/math_degrees.cpp
30+
src/env/math_floor.cpp
31+
src/env/math_log.cpp
32+
src/env/math_radians.cpp
33+
src/env/math_sin.cpp
34+
src/env/math_sqrt.cpp
35+
src/env/math_tan.cpp
36+
src/env/max.cpp
37+
src/env/min.cpp
38+
src/env/round.cpp
39+
src/env/str.cpp
40+
src/env/sum.cpp
41+
src/env/all.cpp
42+
src/env/any.cpp
43+
src/env/float_fn.cpp
44+
src/env/int_fn.cpp
45+
src/env/len.cpp
46+
src/env/math_atan.cpp
47+
src/env/env.cpp
48+
src/ast/ast.cpp
49+
src/ast/unary_expr/unary_expr.cpp
50+
src/ast/unary_expr/neg_expr.cpp
51+
src/ast/unary_expr/not_expr.cpp
52+
src/ast/comp_chain_expr.cpp
53+
src/ast/condition_expr.cpp
54+
src/ast/expr_ptr.cpp
55+
src/ast/fn_application_expr.cpp
56+
src/ast/index_expr.cpp
57+
src/ast/list_comprehension_expr.cpp
58+
src/ast/list_expr.cpp
59+
src/ast/slice_expr.cpp
60+
src/ast/tuple_expr.cpp
61+
src/ast/variable_expr.cpp
62+
src/parser/parser.cpp
63+
src/ast/binary_expr/binary_expr.cpp
64+
src/ast/binary_expr/add_expr.cpp
65+
src/ast/binary_expr/sub_expr.cpp
66+
src/ast/binary_expr/div_expr.cpp
67+
src/ast/binary_expr/mod_expr.cpp
68+
src/ast/binary_expr/mul_expr.cpp
69+
src/ast/binary_expr/or_expr.cpp
70+
src/ast/binary_expr/pow_expr.cpp
71+
src/ast/binary_expr/and_expr.cpp
72+
src/ast/primary_expr/string_expr.cpp
73+
)
74+
75+
add_library(cura-formulae-engine SHARED ${CURA_FORMULAE_ENGINE__SRC})
76+
77+
target_link_libraries(cura-formulae-engine
78+
PUBLIC
79+
fmt::fmt
80+
spdlog::spdlog
81+
foonathan::lexy
82+
zeus::expected
83+
range-v3::range-v3
84+
)
85+
86+
target_compile_definitions(cura-formulae-engine
87+
INTERFACE
88+
CURA_FORMULA_VERSION_VERSION="${CURA_FORMULA_VERSION_VERSION}"
89+
)
90+
91+
target_include_directories(
92+
cura-formulae-engine
93+
PUBLIC
94+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
95+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
96+
PRIVATE
97+
${CMAKE_CURRENT_SOURCE_DIR}/src
98+
)
99+
100+
if (ENABLE_APPS)
101+
add_subdirectory(apps)
102+
endif ()
103+
104+
if (${EXTENSIVE_WARNINGS})
105+
set_project_warnings(cura-formulae-engine)
106+
endif ()
107+
108+
if (ENABLE_TESTS)
109+
add_subdirectory(tests)
110+
endif ()

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Cura Formulae Engine
2+
3+
Cura Formulae Engine is a library designed to parse and evaluate Cura setting-expressions. These (python-like) expressions can be written to express complex logic for 3D printing settings and internal dependencies between settings.
4+
5+
An example expression could be:
6+
7+
```python
8+
min_layer_time if min_layer_time > 0 else 0
9+
```
10+
11+
## Build
12+
13+
Building Cura Formulae Engine requires Conan and CMake. You can use the following commands to build the project:
14+
15+
```shell
16+
conan install . --build=missing --update
17+
source build/Release/generators/conanbuild.sh
18+
cmake --preset conan-release
19+
cmake --build --preset conan-release
20+
```
21+
22+
Some additional CMake presets are available for different build configurations. You can specify these configurations by appending the following options to the `conan install` command:
23+
- tests: `-c tools.build:skip_test=False`
24+
- extensive warnings: `-o enable_extensive_warnings="True"`
25+
- with applications: `-o with_apps="True"`

apps/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add_subdirectory(cmdline_parser)

apps/cmdline_parser/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
add_executable(cmdline_parser
2+
cmdline_parser.cpp
3+
)
4+
if (MSVC)
5+
target_compile_options(cmdline_parser PRIVATE /bigobj)
6+
endif ()
7+
8+
enable_sanitizers(cmdline_parser)
9+
if (${EXTENSIVE_WARNINGS})
10+
set_project_warnings(cmdline_parser)
11+
endif ()
12+
13+
target_link_libraries(cmdline_parser PUBLIC cura-formulae-engine foonathan::lexy range-v3::range-v3)
14+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <cura-formulae-engine/cura-formulae-engine.h>
2+
#include <spdlog/spdlog.h>
3+
4+
#include <iostream>
5+
#include <string>
6+
#include <string_view>
7+
8+
int main(int argc, const char** argv)
9+
{
10+
spdlog::set_level(spdlog::level::info);
11+
spdlog::info("Formula REPL, type 'exit' to quit.");
12+
13+
while (true)
14+
{
15+
std::cout << "> ";
16+
std::string command;
17+
std::getline(std::cin, command);
18+
if (command == "exit")
19+
{
20+
break;
21+
}
22+
23+
const auto input = std::string_view(command.begin(), command.end());
24+
auto message = CuraFormulaeEngine::parser::parse(input);
25+
26+
if (!message.has_value())
27+
{
28+
spdlog::warn("Failed to parse input.");
29+
continue;
30+
}
31+
32+
const auto& expr = message.value();
33+
const auto eval_result = expr.evaluate(&CuraFormulaeEngine::env::std_env);
34+
35+
if (!eval_result.has_value())
36+
{
37+
spdlog::warn("Expr {} results in eval error", expr.toString());
38+
continue;
39+
}
40+
41+
const auto& eval = eval_result.value();
42+
spdlog::info("{} = {}", expr.toString(), eval.toString());
43+
}
44+
45+
return 0;
46+
}

conandata.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version: "1.0.0"

conanfile.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import os
2+
3+
from conan import ConanFile
4+
from conan.errors import ConanInvalidConfiguration, ConanException
5+
from conan.tools.build import check_min_cppstd
6+
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
7+
from conan.tools.env import VirtualRunEnv, VirtualBuildEnv, Environment
8+
from conan.tools.files import copy, update_conandata, AutoPackager
9+
from conan.tools.microsoft import check_min_vs, is_msvc_static_runtime, is_msvc
10+
from conan.tools.scm import Version
11+
12+
required_conan_version = ">=2.7"
13+
14+
class CuraFormulaeEngineConan(ConanFile):
15+
name = "cura-formulae-engine"
16+
author = "UltiMaker"
17+
url = "https://github.com/Ultimaker/CuraFormlaeEngine"
18+
homepage = "https://ultimaker.com"
19+
description = "Formulae parser and evaluator engine used in Ultimaker Cura"
20+
settings = "os", "compiler", "build_type", "arch"
21+
options = {
22+
"enable_extensive_warnings": [True, False],
23+
"with_apps": [True, False],
24+
}
25+
default_options = {
26+
"enable_extensive_warnings": False,
27+
"with_apps": False,
28+
}
29+
30+
def set_version(self):
31+
if not self.version:
32+
self.version = self.conan_data["version"]
33+
34+
@property
35+
def _min_cppstd(self):
36+
return 20
37+
38+
@property
39+
def _compilers_minimum_version(self):
40+
return {
41+
"gcc": "11",
42+
"clang": "14",
43+
"apple-clang": "13",
44+
"msvc": "192",
45+
"visual_studio": "17",
46+
}
47+
48+
def layout(self):
49+
cmake_layout(self)
50+
self.cpp.build.bin = []
51+
self.cpp.package.bin = []
52+
self.cpp.package.libs = ["cura-formulae-engine"]
53+
self.cpp.build.bindirs = []
54+
self.cpp.package.bindirs = ["bin"]
55+
self.cpp.package.includedirs = ["include"]
56+
57+
def requirements(self):
58+
self.requires("range-v3/[>=0.12.0]", transitive_headers=True)
59+
self.requires("spdlog/[>=1.14.1]", transitive_headers=True)
60+
self.requires("fmt/[>=11.0.2]", transitive_headers=True)
61+
self.requires("foonathan-lexy/[>=2022.12.1]@ultimaker/stable", transitive_headers=True)
62+
self.requires("zeus_expected/[>=1.1.1]", transitive_headers=True)
63+
64+
def build_requirements(self):
65+
self.test_requires("standardprojectsettings/[>=0.2.0]")
66+
if not self.conf.get("tools.build:skip_test", False, check_type=bool):
67+
self.test_requires("catch2/[>=3.4.0]")
68+
69+
def export(self):
70+
update_conandata(self, {"version": self.version})
71+
72+
def export_sources(self):
73+
copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder)
74+
copy(self, "*", os.path.join(self.recipe_folder, "src"), os.path.join(self.export_sources_folder, "src"))
75+
copy(self, "*", os.path.join(self.recipe_folder, "include"), os.path.join(self.export_sources_folder, "include"))
76+
copy(self, "*", os.path.join(self.recipe_folder, "tests"), os.path.join(self.export_sources_folder, "tests"))
77+
78+
def generate(self):
79+
tc = CMakeToolchain(self)
80+
tc.variables["ENABLE_APPS"] = self.options.with_apps
81+
tc.variables["EXTENSIVE_WARNINGS"] = self.options.enable_extensive_warnings
82+
tc.variables["CURA_FORMULA_VERSION_VERSION"] = f'{self.version}'
83+
tc.variables["ENABLE_TESTS"] = not self.conf.get("tools.build:skip_test", False, check_type=bool)
84+
85+
tc.variables["WITH_CLI"] = self.options.get_safe("with_cli", False)
86+
87+
if is_msvc(self):
88+
tc.variables["USE_MSVC_RUNTIME_LIBRARY_DLL"] = not is_msvc_static_runtime(self)
89+
90+
tc.generate()
91+
92+
tc = CMakeDeps(self)
93+
tc.generate()
94+
95+
tc = VirtualBuildEnv(self)
96+
tc.generate()
97+
98+
tc = VirtualRunEnv(self)
99+
tc.generate()
100+
101+
def build(self):
102+
cmake = CMake(self)
103+
cmake.configure()
104+
cmake.build()
105+
106+
def package(self):
107+
copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
108+
packager = AutoPackager(self)
109+
packager.run()

0 commit comments

Comments
 (0)