openscad-cpp-evaluator 1.28.6__tar.gz → 1.30.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/CLAUDE.md +24 -3
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/bindings/module.cpp +22 -3
- openscad_cpp_evaluator-1.30.0/include/openscad_cpp_evaluator/css_colors.hpp +20 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/evaluator.hpp +30 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/python/openscad_cpp_evaluator/__init__.py +9 -4
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/CMakeLists.txt +1 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/color.cpp +44 -17
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/bytecode_vm.cpp +1 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/csg_generate.cpp +1 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/css_colors.cpp +39 -31
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/debug_profile.cpp +1 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/user_calls.cpp +3 -0
- openscad_cpp_evaluator-1.30.0/src/xkcd_colors.cpp +967 -0
- openscad_cpp_evaluator-1.30.0/src/xkcd_colors.hpp +13 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_control_flow.cpp +99 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_csg_tree.cpp +4 -3
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_python_bindings.py +22 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_transforms.cpp +103 -30
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/uv.lock +1 -1
- openscad_cpp_evaluator-1.28.6/include/openscad_cpp_evaluator/css_colors.hpp +0 -19
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.30.0}/tools/cli/main.cpp +0 -0
|
@@ -819,9 +819,15 @@ grep for `ponytail:`.
|
|
|
819
819
|
geometric-correctness test in Phase 3, not a hypothetical.
|
|
820
820
|
- `include/openscad_cpp_evaluator/segments.hpp`, `src/builtins/segments.cpp` — `$fn`/`$fa`/`$fs` ->
|
|
821
821
|
circular-shape segment count (`fnSegments`/`fnSegmentsFromCtx`), used by sphere/cylinder/circle.
|
|
822
|
-
- `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp` —
|
|
823
|
-
|
|
824
|
-
|
|
822
|
+
- `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp`, `src/xkcd_colors.{hpp,cpp}` —
|
|
823
|
+
`parseColor`, OpenSCAD's `parse_color` (ColorUtil.cc): CSS Color Level 4 names (148, with
|
|
824
|
+
`rebeccapurple`) plus `transparent` (alpha 0), `"xkcd:<name>"` over the 949 xkcd survey names
|
|
825
|
+
(generated from OpenSCAD's `XkcdColors.h`, CC0), all case-insensitive, then strict `#rgb` /
|
|
826
|
+
`#rgba` / `#rrggbb` / `#rrggbbaa`. `color()` (`src/builtins/color.cpp`) follows `builtin_color`:
|
|
827
|
+
an unreadable string warns `Unable to parse color "…"` and sets NO colour (children keep their
|
|
828
|
+
own, or the outer one) -- it used to draw white; a list fills missing channels with 1 and warns
|
|
829
|
+
outside 0..1; a numeric `alpha` replaces any alpha, a 4-list's included (checked on the 2026.02.01
|
|
830
|
+
binary's 3MF export). `cssColor` (white fallback) is only for SVG/PDF export options.
|
|
825
831
|
- `src/builtins/{primitives_2d,primitives_3d,transforms,color,booleans,modifiers,control}.cpp` —
|
|
826
832
|
one file per builtin group, each a `ResolveFn`/`GenerateFn` pair (or a few, where several builtin
|
|
827
833
|
names share one pair — circle/square/polygon, translate/rotate/scale/mirror/multmatrix/resize,
|
|
@@ -1563,6 +1569,21 @@ than the current pause point). Ported identically (same qualifier syntax, same e
|
|
|
1563
1569
|
- `tools/cli/main.cpp` — a 3-line wrapper: builds `args` from `argv`, calls `runCli(args)` with the
|
|
1564
1570
|
real `std::cin`/`std::cout`/`std::cerr`, returns its exit code.
|
|
1565
1571
|
|
|
1572
|
+
## Cancel and the module recursion limit (#554)
|
|
1573
|
+
|
|
1574
|
+
- **`Evaluator::setCancelFlag(shared_ptr<atomic<bool>>)`** -- bound as `CancelSignal` /
|
|
1575
|
+
`Evaluator(cancel_signal=...)`. Once the flag is set, from any thread, evaluate() throws
|
|
1576
|
+
`EvalError("Render cancelled")` at its next check: the top of `checkDebug` (every interpreted
|
|
1577
|
+
statement and loop pass already calls it, hooks or not), `pollCancel()` every 1,024 VM
|
|
1578
|
+
instructions in `driveVm`, and each top-level node in `generateTreeImpl`. A single Manifold op
|
|
1579
|
+
already under way still finishes. Sticky, unlike `setFastContinueInterruptFlag`'s test-and-clear.
|
|
1580
|
+
A host's echo callback was the only way in before, so a script that printed nothing could not
|
|
1581
|
+
be stopped at all.
|
|
1582
|
+
- **`kMaxModuleCallDepth = 16384`** nested user module calls, checked in `enterUserCall` against
|
|
1583
|
+
`moduleCallDepth_` -- "Recursion detected calling module 'm'", OpenSCAD's wording. Functions
|
|
1584
|
+
keep `kMaxVmCallStackDepth` (1e6). `module m() { m(); }` went from 4.2 s / 3.3 GB to stopping
|
|
1585
|
+
at once; OpenSCAD 2026.02.01 stops the same script near 14,000.
|
|
1586
|
+
|
|
1566
1587
|
## Coverage
|
|
1567
1588
|
|
|
1568
1589
|
`Evaluator(coverage=true)` records which parts of a run's source actually executed and
|
|
@@ -503,10 +503,22 @@ nb::object coverageResultToPy(const std::optional<oscadeval::CoverageResult>& cr
|
|
|
503
503
|
return result;
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
+
// A render's Cancel: .request() from any thread makes the evaluate() it was
|
|
507
|
+
// passed to throw EvalError("Render cancelled") at its next check -- see
|
|
508
|
+
// Evaluator::setCancelFlag. One per render; it is never cleared.
|
|
509
|
+
class CancelSignal {
|
|
510
|
+
public:
|
|
511
|
+
void request() { flag_->store(true, std::memory_order_relaxed); }
|
|
512
|
+
const std::shared_ptr<std::atomic<bool>>& flag() const { return flag_; }
|
|
513
|
+
|
|
514
|
+
private:
|
|
515
|
+
std::shared_ptr<std::atomic<bool>> flag_ = std::make_shared<std::atomic<bool>>(false);
|
|
516
|
+
};
|
|
517
|
+
|
|
506
518
|
nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
507
519
|
std::shared_ptr<oscadeval::ManifoldCache> manifoldCache, bool profile,
|
|
508
520
|
bool generate, bool strictCommas, bool coverage, bool keepMinuendColor,
|
|
509
|
-
double flatPreviewHeight) {
|
|
521
|
+
double flatPreviewHeight, CancelSignal* cancelSignal) {
|
|
510
522
|
std::unordered_map<std::string, oscadeval::Value> vp = toViewportParams(viewportParams);
|
|
511
523
|
|
|
512
524
|
std::vector<oscadeval::ColoredBody> bodies;
|
|
@@ -535,6 +547,7 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
535
547
|
oscadeval::ResolvedUseScopes used = oscadeval::resolveUseScopes(program.nodes, path, logFn);
|
|
536
548
|
oscadeval::Evaluator ev(logFn, nullptr, manifoldCache, oscadeval::DebugHooks{}, profile, coverage);
|
|
537
549
|
ev.keepMinuendColor = keepMinuendColor;
|
|
550
|
+
if (cancelSignal) ev.setCancelFlag(cancelSignal->flag());
|
|
538
551
|
ev.setUsedFileGlobals(used.usedFileGlobals);
|
|
539
552
|
oscadeval::EvalContext ctx = oscadeval::EvalContext::makeRoot(used.rootScope.get());
|
|
540
553
|
std::vector<oscadeval::ColoredBody> raw = ev.evaluate(used.processedNodes, ctx, vp, generate);
|
|
@@ -924,6 +937,10 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
924
937
|
|
|
925
938
|
// See FastContinueSignal's own doc comment, above -- only a
|
|
926
939
|
// constructor and request() are ever called from Python.
|
|
940
|
+
nb::class_<CancelSignal>(m, "CancelSignal")
|
|
941
|
+
.def(nb::init<>())
|
|
942
|
+
.def("request", &CancelSignal::request);
|
|
943
|
+
|
|
927
944
|
nb::class_<FastContinueSignal>(m, "FastContinueSignal")
|
|
928
945
|
.def(nb::init<>())
|
|
929
946
|
.def("request", &FastContinueSignal::request);
|
|
@@ -993,7 +1010,7 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
993
1010
|
m.def("evaluate", &evaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("manifold_cache") = nullptr,
|
|
994
1011
|
nb::arg("profile") = false, nb::arg("generate") = true, nb::arg("strict_commas") = false,
|
|
995
1012
|
nb::arg("coverage") = false, nb::arg("keep_minuend_color") = false,
|
|
996
|
-
nb::arg("flat_preview_height") = oscadeval::kTopLevel2dHeight,
|
|
1013
|
+
nb::arg("flat_preview_height") = oscadeval::kTopLevel2dHeight, nb::arg("cancel_signal") = nullptr,
|
|
997
1014
|
"Evaluate a .scad file; return (bodies, echoes, id_to_node, csg_tree, profile_result, dyn, dyn_explicit, "
|
|
998
1015
|
"geometry, coverage_result).\n"
|
|
999
1016
|
"coverage=True records which statements, branch arms and bodies ran: coverage_result is a dict "
|
|
@@ -1006,7 +1023,9 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
1006
1023
|
"are populated.\n\n"
|
|
1007
1024
|
"strict_commas=True makes a trailing comma in a call argument list or a let/for "
|
|
1008
1025
|
"assignment list a syntax error, as OpenSCAD 2021.01 did. List literals and parameter "
|
|
1009
|
-
"declarations keep theirs, which 2021.01 accepted too
|
|
1026
|
+
"declarations keep theirs, which 2021.01 accepted too.\n\n"
|
|
1027
|
+
"cancel_signal: a CancelSignal whose request(), from any thread, stops this call with "
|
|
1028
|
+
"EvalError('Render cancelled') -- even for a script that prints nothing.");
|
|
1010
1029
|
m.def("parse_decls", &parseDecls, nb::arg("path"),
|
|
1011
1030
|
"Parse a .scad file; return top-level declaration (namespace, name, start, end, line, column, origin) tuples.");
|
|
1012
1031
|
m.def("strip_slivers", &stripSliversPy, nb::arg("verts"), nb::arg("tris"),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <array>
|
|
4
|
+
#include <optional>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
namespace oscadeval {
|
|
8
|
+
|
|
9
|
+
// A colour string as OpenSCAD's parse_color reads it (ColorUtil.cc):
|
|
10
|
+
// a CSS Color Level 4 name or OpenSCAD's "transparent" (alpha 0), an
|
|
11
|
+
// "xkcd:<name>" from the xkcd colour survey, all case-insensitive; else
|
|
12
|
+
// "#rgb", "#rgba", "#rrggbb" or "#rrggbbaa". Nothing if it is none of
|
|
13
|
+
// those -- color() then warns and leaves its children's colour alone.
|
|
14
|
+
std::optional<std::array<double, 4>> parseColor(const std::string& text);
|
|
15
|
+
|
|
16
|
+
// parseColor with the alpha replaced, and white for anything unparseable.
|
|
17
|
+
// For export options (SVG/PDF fill and stroke), which have no warning path.
|
|
18
|
+
std::array<double, 4> cssColor(const std::string& name, double alpha = 1.0);
|
|
19
|
+
|
|
20
|
+
} // namespace oscadeval
|
|
@@ -703,6 +703,23 @@ public:
|
|
|
703
703
|
fastContinueInterrupt_ = std::move(flag);
|
|
704
704
|
}
|
|
705
705
|
|
|
706
|
+
// A host's Cancel button. Set from any thread; the running evaluate()
|
|
707
|
+
// then throws EvalError("Render cancelled") at its next check: every
|
|
708
|
+
// interpreted statement and loop pass (checkDebug, which all of them
|
|
709
|
+
// already call), every 1024th VM instruction, and between top-level
|
|
710
|
+
// generate-pass nodes. A single Manifold operation already under way
|
|
711
|
+
// still runs to its end. Before this existed a host could only stop a
|
|
712
|
+
// script from its echo callback, so one that printed nothing ran to
|
|
713
|
+
// completion however long that took (#554). Sticky: never cleared here.
|
|
714
|
+
void setCancelFlag(std::shared_ptr<std::atomic<bool>> flag) { cancel_ = std::move(flag); }
|
|
715
|
+
void checkCancel() const {
|
|
716
|
+
if (cancel_ && cancel_->load(std::memory_order_relaxed)) throw EvalError("Render cancelled");
|
|
717
|
+
}
|
|
718
|
+
// The VM's per-instruction form: one relaxed load per 1024 instructions.
|
|
719
|
+
void pollCancel() {
|
|
720
|
+
if (cancel_ && (++cancelTicks_ & 0x3FF) == 0) checkCancel();
|
|
721
|
+
}
|
|
722
|
+
|
|
706
723
|
// Checks whether a debug pause should happen at `node` (via the
|
|
707
724
|
// injected DebugHooks::debugHook, if any -- a no-op otherwise),
|
|
708
725
|
// applying any `mods` the hook returns to `ctx.let_` and throwing
|
|
@@ -1759,6 +1776,16 @@ public:
|
|
|
1759
1776
|
// recalibrating for real.
|
|
1760
1777
|
static constexpr size_t kMaxVmCallStackDepth = 1'000'000;
|
|
1761
1778
|
|
|
1779
|
+
// Nested user MODULE calls, of any modules. Functions keep
|
|
1780
|
+
// kMaxVmCallStackDepth: a deep function recursion builds nothing, but a
|
|
1781
|
+
// module frame holds its whole subtree, so `module m() { m(); }` used
|
|
1782
|
+
// to run to a million frames and 3.3 GB before stopping. OpenSCAD stops
|
|
1783
|
+
// the same script at ~14,000 ("Recursion detected calling module"),
|
|
1784
|
+
// 45 MB; this is that order, and far past any real library (BOSL2
|
|
1785
|
+
// nests tens deep). Checked in enterUserCall, which every module call
|
|
1786
|
+
// -- interpreted or compiled -- goes through (#554).
|
|
1787
|
+
static constexpr int kMaxModuleCallDepth = 16384;
|
|
1788
|
+
|
|
1762
1789
|
// Counts native C++ nesting of driveVm itself -- NOT logical call
|
|
1763
1790
|
// depth (that's vmCallStack_.size()/callStack_.size(), both of which
|
|
1764
1791
|
// grow just as much for a pure VM-internal Op::CallModule hop, which
|
|
@@ -2074,6 +2101,9 @@ private:
|
|
|
2074
2101
|
// default) means hook-skippable mode, if ever engaged, can't be
|
|
2075
2102
|
// interrupted from outside a hook call.
|
|
2076
2103
|
std::shared_ptr<std::atomic<bool>> fastContinueInterrupt_;
|
|
2104
|
+
// See setCancelFlag. nullptr (the default): nothing can cancel.
|
|
2105
|
+
std::shared_ptr<std::atomic<bool>> cancel_;
|
|
2106
|
+
unsigned cancelTicks_ = 0;
|
|
2077
2107
|
// The root EvalContext resolveTree() was called with -- lets
|
|
2078
2108
|
// checkDebug()'s locals snapshot fall back to top-level script
|
|
2079
2109
|
// variables when paused inside a nested user call, the same way the
|
|
@@ -13,12 +13,12 @@ from dataclasses import dataclass, field
|
|
|
13
13
|
from typing import Optional
|
|
14
14
|
|
|
15
15
|
from . import _openscad_cpp_evaluator as _ext
|
|
16
|
-
from ._openscad_cpp_evaluator import FastContinueSignal, ManifoldCache
|
|
16
|
+
from ._openscad_cpp_evaluator import CancelSignal, FastContinueSignal, ManifoldCache
|
|
17
17
|
|
|
18
18
|
__all__ = [
|
|
19
19
|
"Evaluator", "ColoredBody", "EvalError", "ParseError", "OscObject", "parse", "to_renderable_bodies",
|
|
20
20
|
"ManifoldCache", "CallSiteProfile", "ProfileResult", "format_csg_tree", "bodies_from_dicts",
|
|
21
|
-
"FastContinueSignal", "parse_ast", "parse_ast_string", "format_source",
|
|
21
|
+
"CancelSignal", "FastContinueSignal", "parse_ast", "parse_ast_string", "format_source",
|
|
22
22
|
"check_mesh", "strip_slivers",
|
|
23
23
|
"export_model", "export_extensions", "list_fonts",
|
|
24
24
|
]
|
|
@@ -565,7 +565,7 @@ class Evaluator:
|
|
|
565
565
|
|
|
566
566
|
def __init__(self, echo_fn=None, debug_hook=None, error_break_fn=None, return_hook=None,
|
|
567
567
|
manifold_cache=None, profile=False, fast_continue_signal=None, coverage=False,
|
|
568
|
-
keep_minuend_color=False, flat_preview_height=1.0):
|
|
568
|
+
keep_minuend_color=False, flat_preview_height=1.0, cancel_signal=None):
|
|
569
569
|
self._echo_fn = echo_fn
|
|
570
570
|
self._debug_hook = debug_hook
|
|
571
571
|
self._error_break_fn = error_break_fn
|
|
@@ -574,6 +574,11 @@ class Evaluator:
|
|
|
574
574
|
self._profile = profile
|
|
575
575
|
self._fast_continue_signal = fast_continue_signal
|
|
576
576
|
self._coverage = coverage
|
|
577
|
+
# A CancelSignal: request() it from any thread and a running
|
|
578
|
+
# evaluate() raises EvalError("Render cancelled") -- the only way to
|
|
579
|
+
# stop a script that prints nothing. Plain path only; the debugger
|
|
580
|
+
# has its own stop.
|
|
581
|
+
self._cancel_signal = cancel_signal
|
|
577
582
|
# keep_minuend_color=True: difference() paints the faces a
|
|
578
583
|
# subtrahend exposes with the MINUEND's colour rather than the
|
|
579
584
|
# subtrahend's (or the cut green). A viewer option; see
|
|
@@ -640,7 +645,7 @@ class Evaluator:
|
|
|
640
645
|
dyn_explicit, geometry, coverage_result) = _ext.evaluate(
|
|
641
646
|
source_path, vp, self._manifold_cache, self._profile, generate,
|
|
642
647
|
strict_commas, self._coverage, self._keep_minuend_color,
|
|
643
|
-
self._flat_preview_height)
|
|
648
|
+
self._flat_preview_height, self._cancel_signal)
|
|
644
649
|
# The evaluated bodies, still on the C++ side. Stashed like
|
|
645
650
|
# csg_tree/profile_result rather than returned, so
|
|
646
651
|
# evaluate()'s own 2-tuple result is unchanged -- callers
|
|
@@ -1,38 +1,63 @@
|
|
|
1
1
|
#include "builtins.hpp"
|
|
2
2
|
|
|
3
|
+
#include <cstdio>
|
|
4
|
+
|
|
3
5
|
#include "openscad_cpp_evaluator/call_args.hpp"
|
|
4
6
|
#include "openscad_cpp_evaluator/css_colors.hpp"
|
|
5
7
|
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
6
8
|
|
|
7
9
|
namespace oscadeval {
|
|
8
10
|
|
|
9
|
-
// color(c
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// color(c, alpha), as OpenSCAD's builtin_color (ColorNode.cc):
|
|
12
|
+
// - a string goes through parseColor (CSS / "xkcd:" names, hex with or
|
|
13
|
+
// without alpha); one it cannot read warns "Unable to parse color" and
|
|
14
|
+
// leaves the children's colour alone -- inherited from outside, not reset;
|
|
15
|
+
// - a list fills [r, g, b, a] in order, 1.0 for any it lacks, warning on a
|
|
16
|
+
// component outside 0..1;
|
|
17
|
+
// - a numeric `alpha` then replaces the alpha of whatever `c` gave -- even a
|
|
18
|
+
// 4-element list's, and even "#rrggbbaa"'s -- warning when outside 0..1;
|
|
19
|
+
// - anything else for `c`, or no `c` at all, sets no colour (OpenSCAD's
|
|
20
|
+
// unset Color4f is (-1,-1,-1,-1), which is not a colour).
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
std::string oneDecimal(double v) {
|
|
24
|
+
char buf[64];
|
|
25
|
+
std::snprintf(buf, sizeof buf, "%.1f", v);
|
|
26
|
+
return buf;
|
|
27
|
+
}
|
|
28
|
+
} // namespace
|
|
14
29
|
|
|
15
30
|
BuiltinWrapParams computeColorParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
|
|
16
31
|
auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
|
|
17
|
-
const Value
|
|
18
|
-
|
|
19
|
-
Value cArg = getArg(args, 0, "c", defaultC);
|
|
20
|
-
const double alpha = toDoubleLenient(getArg(args, 1, "alpha", Value{1.0}));
|
|
32
|
+
const Value cArg = getArg(args, 0, "c");
|
|
33
|
+
const Value alphaArg = getArg(args, 1, "alpha");
|
|
21
34
|
|
|
22
|
-
std::array<double, 4
|
|
35
|
+
std::optional<std::array<double, 4>> rgba;
|
|
23
36
|
if (const std::string* s = std::get_if<std::string>(&cArg)) {
|
|
24
|
-
rgba =
|
|
37
|
+
rgba = parseColor(*s);
|
|
38
|
+
if (!rgba) ev.warn("Unable to parse color \"" + *s + "\"", &node.position());
|
|
25
39
|
} else if (const ListPtr* l = std::get_if<ListPtr>(&cArg); l && *l) {
|
|
26
40
|
const auto& items = (*l)->items;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
std::array<double, 4> c{1.0, 1.0, 1.0, 1.0};
|
|
42
|
+
for (size_t i = 0; i < 4; ++i) {
|
|
43
|
+
if (i < items.size()) c[i] = toDoubleLenient(items[i]);
|
|
44
|
+
if (c[i] > 1 || c[i] < 0)
|
|
45
|
+
ev.warn("color() expects numbers between 0.0 and 1.0. Value of " + oneDecimal(c[i]) +
|
|
46
|
+
" is out of range",
|
|
47
|
+
&node.position());
|
|
32
48
|
}
|
|
49
|
+
rgba = c;
|
|
50
|
+
}
|
|
51
|
+
if (const double* a = std::get_if<double>(&alphaArg)) {
|
|
52
|
+
if (rgba) (*rgba)[3] = *a;
|
|
53
|
+
if (*a < 0.0 || *a > 1.0)
|
|
54
|
+
ev.warn("color() expects alpha between 0.0 and 1.0. Value of " + oneDecimal(*a) + " is out of range",
|
|
55
|
+
&node.position());
|
|
33
56
|
}
|
|
34
57
|
|
|
35
|
-
|
|
58
|
+
// No colour: the child context inherits the outer one (childCtx's
|
|
59
|
+
// nullopt), and generateColor passes the children through untouched.
|
|
60
|
+
EvalContext childCtx = effCtx.childCtx(nullptr, rgba);
|
|
36
61
|
CSGParams params;
|
|
37
62
|
params["rgba"] = colorToValue(rgba);
|
|
38
63
|
return BuiltinWrapParams{std::move(params), std::move(childCtx)};
|
|
@@ -70,6 +95,8 @@ std::shared_ptr<const std::vector<ColoredBody>> recolorParts(const std::vector<C
|
|
|
70
95
|
std::vector<ColoredBody> generateColor(Evaluator& ev, const CSGParams& params,
|
|
71
96
|
const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode&) {
|
|
72
97
|
const auto rgba = valueToColor(params.at("rgba"));
|
|
98
|
+
// An unreadable colour sets none: the children keep their own.
|
|
99
|
+
if (!rgba) return flattenCsgTree(children);
|
|
73
100
|
std::vector<ColoredBody> result;
|
|
74
101
|
for (ColoredBody b : flattenCsgTree(children)) {
|
|
75
102
|
b.color = rgba;
|
|
@@ -35,6 +35,7 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
|
|
|
35
35
|
const auto& dispatch = generateDispatch();
|
|
36
36
|
for (CSGNode* nodePtr : tree) {
|
|
37
37
|
CSGNode& node = *nodePtr;
|
|
38
|
+
checkCancel();
|
|
38
39
|
|
|
39
40
|
// ManifoldCache lookup: node.uncacheable (rands() taint, set
|
|
40
41
|
// during resolve -- see csg_resolve.cpp) always forces a miss,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
#include "openscad_cpp_evaluator/css_colors.hpp"
|
|
2
|
+
#include "xkcd_colors.hpp"
|
|
2
3
|
|
|
3
4
|
#include <cctype>
|
|
5
|
+
#include <optional>
|
|
4
6
|
#include <unordered_map>
|
|
5
7
|
|
|
6
8
|
namespace oscadeval {
|
|
7
9
|
|
|
8
10
|
namespace {
|
|
9
11
|
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// Originally generated from the Python reference's _css_colors.py (itself
|
|
13
|
+
// from a live PySide6 install). Now OpenSCAD's own WebColors.h list: every
|
|
14
|
+
// RGB here matches it, `rebeccapurple` (CSS Color Level 4) is added, and
|
|
15
|
+
// `transparent`, which needs an alpha of 0, is handled in parseColor.
|
|
14
16
|
const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
15
17
|
static const std::unordered_map<std::string, std::array<double, 3>> table = {
|
|
16
18
|
{"aliceblue", {0.9411764740943909, 0.9725490212440491, 1.0}},
|
|
@@ -132,6 +134,7 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
|
132
134
|
{"plum", {0.8666666746139526, 0.6274510025978088, 0.8666666746139526}},
|
|
133
135
|
{"powderblue", {0.6901960968971252, 0.8784313797950745, 0.9019607901573181}},
|
|
134
136
|
{"purple", {0.501960813999176, 0.0, 0.501960813999176}},
|
|
137
|
+
{"rebeccapurple", {0.4, 0.2, 0.6}},
|
|
135
138
|
{"red", {1.0, 0.0, 0.0}},
|
|
136
139
|
{"rosybrown", {0.7372549176216125, 0.5607843399047852, 0.5607843399047852}},
|
|
137
140
|
{"royalblue", {0.2549019753932953, 0.4117647111415863, 0.8823529481887817}},
|
|
@@ -153,7 +156,6 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
|
153
156
|
{"teal", {0.0, 0.501960813999176, 0.501960813999176}},
|
|
154
157
|
{"thistle", {0.8470588326454163, 0.7490196228027344, 0.8470588326454163}},
|
|
155
158
|
{"tomato", {1.0, 0.38823530077934265, 0.27843138575553894}},
|
|
156
|
-
{"transparent", {0.0, 0.0, 0.0}},
|
|
157
159
|
{"turquoise", {0.250980406999588, 0.8784313797950745, 0.8156862854957581}},
|
|
158
160
|
{"violet", {0.9333333373069763, 0.5098039507865906, 0.9333333373069763}},
|
|
159
161
|
{"wheat", {0.9607843160629272, 0.8705882430076599, 0.7019608020782471}},
|
|
@@ -171,38 +173,44 @@ std::string toLower(const std::string& s) {
|
|
|
171
173
|
return r;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
// OpenSCAD's parse_hex_color (ColorUtil.cc): "#rgb", "#rgba", "#rrggbb" or
|
|
177
|
+
// "#rrggbbaa", every character after '#' a hex digit, or nothing at all.
|
|
178
|
+
std::optional<std::array<double, 4>> parseHex(const std::string& hex) {
|
|
179
|
+
const bool shortForm = hex.size() == 4 || hex.size() == 5;
|
|
180
|
+
const bool longForm = hex.size() == 7 || hex.size() == 9;
|
|
181
|
+
if ((!shortForm && !longForm) || hex[0] != '#') return std::nullopt;
|
|
182
|
+
for (size_t i = 1; i < hex.size(); ++i)
|
|
183
|
+
if (!std::isxdigit(static_cast<unsigned char>(hex[i]))) return std::nullopt;
|
|
184
|
+
const size_t stride = shortForm ? 1 : 2;
|
|
185
|
+
const double channelMax = shortForm ? 15.0 : 255.0;
|
|
186
|
+
std::array<double, 4> rgba{0.0, 0.0, 0.0, 1.0};
|
|
187
|
+
for (size_t i = 0; i < (hex.size() - 1) / stride; ++i)
|
|
188
|
+
rgba[i] = std::stoi(hex.substr(1 + i * stride, stride), nullptr, 16) / channelMax;
|
|
189
|
+
return rgba;
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
} // namespace
|
|
182
193
|
|
|
183
|
-
std::array<double, 4
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
}
|
|
192
|
-
if (h.size() == 3) {
|
|
193
|
-
const double r = hexDigit(h[0]) / 15.0;
|
|
194
|
-
const double g = hexDigit(h[1]) / 15.0;
|
|
195
|
-
const double b = hexDigit(h[2]) / 15.0;
|
|
196
|
-
return {r, g, b, alpha};
|
|
197
|
-
}
|
|
198
|
-
return {1.0, 1.0, 1.0, alpha};
|
|
194
|
+
std::optional<std::array<double, 4>> parseColor(const std::string& text) {
|
|
195
|
+
// OpenSCAD's parse_color: a name first (case-insensitive; "xkcd:" reaches
|
|
196
|
+
// the xkcd survey table, falling back to the CSS table), then hex.
|
|
197
|
+
const std::string name = toLower(text);
|
|
198
|
+
if (name.rfind("xkcd:", 0) == 0) {
|
|
199
|
+
const auto& xk = xkcdColorTable();
|
|
200
|
+
if (auto it = xk.find(name.substr(5)); it != xk.end())
|
|
201
|
+
return std::array<double, 4>{it->second[0] / 255.0, it->second[1] / 255.0, it->second[2] / 255.0, 1.0};
|
|
199
202
|
}
|
|
203
|
+
// OpenSCAD's own addition to the CSS list: fully transparent black.
|
|
204
|
+
if (name == "transparent") return std::array<double, 4>{0.0, 0.0, 0.0, 0.0};
|
|
205
|
+
if (auto it = colorTable().find(name); it != colorTable().end())
|
|
206
|
+
return std::array<double, 4>{it->second[0], it->second[1], it->second[2], 1.0};
|
|
207
|
+
return parseHex(text);
|
|
208
|
+
}
|
|
200
209
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
return {1.0, 1.0, 1.0, alpha};
|
|
210
|
+
std::array<double, 4> cssColor(const std::string& name, double alpha) {
|
|
211
|
+
auto c = parseColor(name);
|
|
212
|
+
if (!c) return {1.0, 1.0, 1.0, alpha};
|
|
213
|
+
return {(*c)[0], (*c)[1], (*c)[2], alpha};
|
|
206
214
|
}
|
|
207
215
|
|
|
208
216
|
} // namespace oscadeval
|
|
@@ -104,6 +104,7 @@ void Evaluator::checkDebug(const oscad::ASTNode& node, EvalContext& ctx, bool fo
|
|
|
104
104
|
// injecting stops the user never wrote and corrupting lastStmtByDepth_'s
|
|
105
105
|
// duplicate-collapse state below. Rides the existing null-hook
|
|
106
106
|
// short-circuit so it costs nothing on the normal path.
|
|
107
|
+
checkCancel(); // every interpreted statement and loop pass comes through here
|
|
107
108
|
if (measuring_ || !debugHooks_.debugHook) return;
|
|
108
109
|
const oscad::Position& pos = node.position();
|
|
109
110
|
const size_t stmtDepth = callStack_.size();
|
|
@@ -733,6 +733,9 @@ Evaluator::UserCallHandle Evaluator::enterUserCall(const std::string& name, cons
|
|
|
733
733
|
error("Recursion too deep while calling " + std::string(isModule ? "module" : "function") + " '" + name + "'",
|
|
734
734
|
declNode);
|
|
735
735
|
}
|
|
736
|
+
if (isModule && moduleCallDepth_ >= kMaxModuleCallDepth) {
|
|
737
|
+
error("Recursion detected calling module '" + name + "'", declNode);
|
|
738
|
+
}
|
|
736
739
|
UserCallHandle h;
|
|
737
740
|
h.kind = kind;
|
|
738
741
|
h.declNode = &declNode;
|