openscad-cpp-evaluator 0.55.0__tar.gz → 0.55.2__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-0.55.0 → openscad_cpp_evaluator-0.55.2}/CLAUDE.md +11 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/bindings/ast_to_py.cpp +8 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/bindings/module.cpp +8 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/csg_node.hpp +15 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/evaluator.hpp +2 -1
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/python/openscad_cpp_evaluator/__init__.py +20 -1
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/csg_generate.cpp +36 -7
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/export.cpp +13 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/manifold_cache.cpp +38 -1
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_booleans.cpp +46 -8
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_manifold_cache.cpp +59 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_python_bindings.py +37 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/README.md +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/uv.lock +0 -0
|
@@ -699,6 +699,17 @@ grep for `ponytail:`.
|
|
|
699
699
|
permanent cache miss for any subtree that called `rands()` while resolving, since such a
|
|
700
700
|
subtree's resolved params aren't a pure function of its own content anymore (the actual `rands()`
|
|
701
701
|
output also depends on every earlier `rands()` call's position in the whole evaluation's order).
|
|
702
|
+
A second, separate taint — `CSGNode::keyHasClosure`, set by `cacheKey()` itself rather than at
|
|
703
|
+
resolve time — does the same for any subtree holding a **function literal** in its params (the
|
|
704
|
+
`levelset(function (x,y,z) ..., ...)` shape). `canonValue()` can only key a closure by its AST
|
|
705
|
+
node's raw address, which is meaningful for exactly one parse: the next render frees that AST and
|
|
706
|
+
a fresh closure over *different* captured values can be allocated at the very same address, so
|
|
707
|
+
the key silently hits the previous render's geometry — the GUI symptom was an edited script
|
|
708
|
+
rendering its **old** shape until saved a second time. (The address also ignores the captured
|
|
709
|
+
values themselves, so two closures over one literal collide within a single render, which is what
|
|
710
|
+
`tests/test_manifold_cache.cpp` pins down deterministically.) Keying a closure honestly means
|
|
711
|
+
canonicalizing its captured `let_` trail, which is type-erased (`Closure::capturedLet` is a
|
|
712
|
+
`shared_ptr<void>`); until that exists such a subtree simply does not participate in the cache.
|
|
702
713
|
Builtins are registered in `src/builtins/registry.cpp` as `(name string) -> (ResolveFn,
|
|
703
714
|
GenerateFn)` pairs — `dispatch.hpp` has the exact reasoning for `GenerateFn`'s `Evaluator&`
|
|
704
715
|
parameter (provenance-table writes only, no `EvalContext`/dynamic-scope access, so the
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
// losing how the author wrote it (1.500 -> 1.5, 1e3 -> 1000).
|
|
26
26
|
|
|
27
27
|
#include "openscad_cpp_parser/api.hpp"
|
|
28
|
+
#include "openscad_cpp_parser/pretty_print.hpp"
|
|
28
29
|
#include "openscad_cpp_parser/ast/ast_node.hpp"
|
|
29
30
|
#include "openscad_cpp_parser/ast/comments.hpp"
|
|
30
31
|
#include "openscad_cpp_parser/ast/declarations.hpp"
|
|
@@ -323,4 +324,11 @@ nb::list parseAstFromString(const std::string& code, bool includeComments) {
|
|
|
323
324
|
return astToPy(oscad::getASTFromString(code, includeComments));
|
|
324
325
|
}
|
|
325
326
|
|
|
327
|
+
// The parser already has a pretty-printer -- comment-preserving, idempotent
|
|
328
|
+
// and covered by its own tests -- so an editor's "reformat" needs no second
|
|
329
|
+
// implementation guessing at the same grammar from a token stream.
|
|
330
|
+
std::string formatSourceString(const std::string& code, int indentWidth, bool includeComments) {
|
|
331
|
+
return oscad::toOpenscad(oscad::getASTFromString(code, includeComments), indentWidth);
|
|
332
|
+
}
|
|
333
|
+
|
|
326
334
|
} // namespace oscadbind
|
|
@@ -49,6 +49,7 @@ namespace nb = nanobind;
|
|
|
49
49
|
namespace oscadbind {
|
|
50
50
|
nb::list parseAstFromFile(const std::string& path, bool includeComments);
|
|
51
51
|
nb::list parseAstFromString(const std::string& code, bool includeComments);
|
|
52
|
+
std::string formatSourceString(const std::string& code, int indentWidth, bool includeComments);
|
|
52
53
|
} // namespace oscadbind
|
|
53
54
|
|
|
54
55
|
namespace {
|
|
@@ -809,6 +810,13 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
809
810
|
"safe to keep, share across threads, and outlive the parse.");
|
|
810
811
|
m.def("parse_ast_string", &oscadbind::parseAstFromString, nb::arg("code"), nb::arg("include_comments") = false,
|
|
811
812
|
"As parse_ast(), but parses a source string instead of a file.");
|
|
813
|
+
m.def("format_source", &oscadbind::formatSourceString, nb::arg("code"),
|
|
814
|
+
nb::arg("indent") = 4, nb::arg("include_comments") = true,
|
|
815
|
+
"Reformat OpenSCAD source: parse it and print the AST back out. "
|
|
816
|
+
"Wraps over-long argument lists and vectors, puts a modifier's "
|
|
817
|
+
"children on their own indented line, and preserves comments. "
|
|
818
|
+
"Idempotent -- formatting formatted source returns it unchanged. "
|
|
819
|
+
"Raises ParseError if the source does not parse.");
|
|
812
820
|
m.def("debug_evaluate", &debugEvaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("debug_hook"),
|
|
813
821
|
nb::arg("error_break"), nb::arg("echo_fn"), nb::arg("manifold_cache") = nullptr,
|
|
814
822
|
nb::arg("return_hook") = nb::none(), nb::arg("fast_continue_signal") = nullptr,
|
|
@@ -72,6 +72,21 @@ struct CSGNode {
|
|
|
72
72
|
// on first cacheKey() call; every node here is always reached through a
|
|
73
73
|
// non-const CSGNode&, so no `mutable` is needed to write it.
|
|
74
74
|
std::optional<std::string> cachedKey;
|
|
75
|
+
|
|
76
|
+
// Set by the same cacheKey() pass that fills cachedKey: true if this
|
|
77
|
+
// node's own params, or any descendant's, hold a function literal.
|
|
78
|
+
//
|
|
79
|
+
// canonValue() can only key a closure by its AST node's raw address,
|
|
80
|
+
// and that address is meaningful for exactly one parse: the next
|
|
81
|
+
// render frees that AST, and a fresh closure over different captured
|
|
82
|
+
// values can be allocated at the very same address -- so the key
|
|
83
|
+
// silently hits the PREVIOUS render's geometry. (It also ignores the
|
|
84
|
+
// captured values themselves, so two closures over one literal share a
|
|
85
|
+
// key within a single render.) Keying a closure honestly would mean
|
|
86
|
+
// canonicalising its captured `let_` trail, which is type-erased; until
|
|
87
|
+
// that exists, such a subtree just does not participate in the cache.
|
|
88
|
+
// See csg_generate.cpp's lookup.
|
|
89
|
+
bool keyHasClosure = false;
|
|
75
90
|
};
|
|
76
91
|
|
|
77
92
|
|
|
@@ -427,7 +427,8 @@ public:
|
|
|
427
427
|
// before its GenerateFn runs -- see csg_generate.cpp.
|
|
428
428
|
void applyDimensionRules(CSGNode& node);
|
|
429
429
|
// ruleValue is a DimRule; the enum is file-local to csg_generate.cpp.
|
|
430
|
-
void applyDimensionRulesTo(const std::vector<CSGNode*>& children, int ruleValue
|
|
430
|
+
void applyDimensionRulesTo(const std::vector<CSGNode*>& children, int ruleValue,
|
|
431
|
+
bool keepMixed = false);
|
|
431
432
|
|
|
432
433
|
// Apply `!`: replace the whole tree with the first show_only
|
|
433
434
|
// subtree, discarding its ancestors and every sibling. See its
|
|
@@ -18,7 +18,8 @@ from ._openscad_cpp_evaluator import FastContinueSignal, ManifoldCache
|
|
|
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", "
|
|
21
|
+
"FastContinueSignal", "parse_ast", "parse_ast_string", "format_source",
|
|
22
|
+
"check_mesh", "strip_slivers",
|
|
22
23
|
"export_model", "export_extensions",
|
|
23
24
|
]
|
|
24
25
|
|
|
@@ -376,6 +377,24 @@ def parse_ast_string(code: str, include_comments: bool = False) -> list:
|
|
|
376
377
|
raise ParseError(str(e)) from e
|
|
377
378
|
|
|
378
379
|
|
|
380
|
+
def format_source(code: str, indent: int = 4, include_comments: bool = True) -> str:
|
|
381
|
+
"""Reformat OpenSCAD source: parse it and print the AST back out.
|
|
382
|
+
|
|
383
|
+
Wraps over-long argument lists and vector literals, puts a modifier's
|
|
384
|
+
children on their own indented line, and preserves comments. Idempotent
|
|
385
|
+
-- formatting already-formatted source returns it unchanged. Raises
|
|
386
|
+
ParseError on a syntax error.
|
|
387
|
+
|
|
388
|
+
This is the parser's own printer (`oscad::toOpenscad`), so an editor
|
|
389
|
+
reformatting a selection does not need a second implementation guessing
|
|
390
|
+
at the same grammar from a token stream.
|
|
391
|
+
"""
|
|
392
|
+
try:
|
|
393
|
+
return _ext.format_source(code, indent, include_comments)
|
|
394
|
+
except Exception as e:
|
|
395
|
+
raise ParseError(str(e)) from e
|
|
396
|
+
|
|
397
|
+
|
|
379
398
|
class _MeshShim:
|
|
380
399
|
"""Duck-types a manifold3d mesh: the four arrays the renderer reads."""
|
|
381
400
|
__slots__ = ("vert_properties", "tri_verts", "run_original_id", "run_index", "num_prop")
|
|
@@ -44,7 +44,15 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
|
|
|
44
44
|
// re-deriving results that would just be discarded. Mirrors
|
|
45
45
|
// generate_tree()'s own cache check exactly.
|
|
46
46
|
std::optional<std::string> key;
|
|
47
|
-
if (manifoldCache_ && !node.uncacheable)
|
|
47
|
+
if (manifoldCache_ && !node.uncacheable) {
|
|
48
|
+
key = cacheKey(node);
|
|
49
|
+
// A key that serialized a function literal is not a pure
|
|
50
|
+
// function of content -- it embeds a raw AST address that the
|
|
51
|
+
// next parse can hand out again. Dropping the key here forces
|
|
52
|
+
// both the get() below and the put() further down to be
|
|
53
|
+
// skipped. See CSGNode::keyHasClosure.
|
|
54
|
+
if (node.keyHasClosure) key.reset();
|
|
55
|
+
}
|
|
48
56
|
std::optional<std::vector<ColoredBody>> cached = key ? manifoldCache_->get(*key) : std::nullopt;
|
|
49
57
|
if (cached) {
|
|
50
58
|
node.bodies = std::move(*cached);
|
|
@@ -163,9 +171,10 @@ void Evaluator::applyDimensionRules(CSGNode& node) {
|
|
|
163
171
|
applyDimensionRulesTo(kids, static_cast<int>(rule));
|
|
164
172
|
}
|
|
165
173
|
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
void Evaluator::applyDimensionRulesTo(const std::vector<CSGNode*>& children, int ruleValue
|
|
174
|
+
// `keepMixed` warns about a mixed group but drops nothing -- the top level's
|
|
175
|
+
// behaviour, see generateTree.
|
|
176
|
+
void Evaluator::applyDimensionRulesTo(const std::vector<CSGNode*>& children, int ruleValue,
|
|
177
|
+
bool keepMixed) {
|
|
169
178
|
const DimRule rule = static_cast<DimRule>(ruleValue);
|
|
170
179
|
int target = rule == DimRule::Only2D ? 2 : rule == DimRule::Only3D ? 3 : 0;
|
|
171
180
|
bool warnedMixing = false;
|
|
@@ -194,6 +203,16 @@ void Evaluator::applyDimensionRulesTo(const std::vector<CSGNode*>& children, int
|
|
|
194
203
|
warn("Mixing 2D and 3D objects is not supported", pos);
|
|
195
204
|
warnedMixing = true;
|
|
196
205
|
}
|
|
206
|
+
if (keepMixed) {
|
|
207
|
+
// Kept, not dropped: at the top level there is no single
|
|
208
|
+
// result to build, so nothing downstream can be confused by
|
|
209
|
+
// the other dimension, and the reference's own preview shows
|
|
210
|
+
// both. The warning above still stands -- an export cannot
|
|
211
|
+
// represent the mix -- but silently losing the 2D geometry
|
|
212
|
+
// from the picture is worse than showing it.
|
|
213
|
+
kept.push_back(std::move(b));
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
197
216
|
warn(std::string("Ignoring ") + (dim == 3 ? "3D" : "2D") + " child object for " +
|
|
198
217
|
(target == 3 ? "3D" : "2D") + " operation",
|
|
199
218
|
pos);
|
|
@@ -208,9 +227,19 @@ std::vector<ColoredBody> Evaluator::generateTree(const std::vector<std::unique_p
|
|
|
208
227
|
ptrs.reserve(tree.size());
|
|
209
228
|
for (const std::unique_ptr<CSGNode>& n : tree) ptrs.push_back(n.get());
|
|
210
229
|
std::vector<ColoredBody> bodies = generateTreeImpl(ptrs);
|
|
211
|
-
// The top level is an implicit union
|
|
212
|
-
// every other group node gets
|
|
213
|
-
|
|
230
|
+
// The top level is an implicit union, so it gets the same Group warning
|
|
231
|
+
// every other group node gets -- but it KEEPS both dimensions.
|
|
232
|
+
//
|
|
233
|
+
// A real group has to pick one: generateCsg builds a single result and
|
|
234
|
+
// switches on whether it holds a body or a section, so a group that
|
|
235
|
+
// changed dimension part-way used to take the process down. The top
|
|
236
|
+
// level builds no such result; it just hands back a list. Dropping there
|
|
237
|
+
// only lost geometry, and it lost it from the picture: the reference's
|
|
238
|
+
// preview draws top-level 2D and 3D side by side (a 2D shape as a thin
|
|
239
|
+
// slab), which is exactly what BOSL2's debug_bezier() of a 2D bezier
|
|
240
|
+
// relies on -- every curve and control arrow it draws is 2D, so beside
|
|
241
|
+
// a 3D sphere the whole debug overlay vanished.
|
|
242
|
+
applyDimensionRulesTo(ptrs, static_cast<int>(DimRule::Group), /*keepMixed=*/true);
|
|
214
243
|
bodies.clear();
|
|
215
244
|
for (CSGNode* n : ptrs) {
|
|
216
245
|
for (const ColoredBody& b : n->bodies) bodies.push_back(b);
|
|
@@ -429,10 +429,23 @@ std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& b
|
|
|
429
429
|
std::vector<Solid> solids;
|
|
430
430
|
std::vector<ExportObject> loose;
|
|
431
431
|
|
|
432
|
+
// A `flatPreview` body is a top-level 2D shape thin-extruded so it can be
|
|
433
|
+
// SEEN (toRenderableBodies). The top level keeps 2D and 3D side by side
|
|
434
|
+
// for exactly that reason -- but a mesh export of a mixed script must
|
|
435
|
+
// not smuggle a 1e-3-tall slab in beside the real solids, which is what
|
|
436
|
+
// the reference drops there too. A 2D-ONLY script still exports its
|
|
437
|
+
// slab, unchanged: that is the only geometry there is, and dropping it
|
|
438
|
+
// would leave nothing to write.
|
|
439
|
+
bool hasRealSolid = false;
|
|
440
|
+
for (const ColoredBody& cb : bodies) {
|
|
441
|
+
if (!cb.flatPreview && isExportable(cb)) { hasRealSolid = true; break; }
|
|
442
|
+
}
|
|
443
|
+
|
|
432
444
|
int index = 0;
|
|
433
445
|
for (const ColoredBody& cb : bodies) {
|
|
434
446
|
++index;
|
|
435
447
|
if (!isExportable(cb)) continue;
|
|
448
|
+
if (cb.flatPreview && hasRealSolid) continue;
|
|
436
449
|
if (cb.isDisplayOnly()) {
|
|
437
450
|
// Manifold rejected this one -- an open shell is not a solid --
|
|
438
451
|
// so it can join no boolean. Its triangles are real geometry the
|
|
@@ -93,6 +93,32 @@ std::string canonValue(const Value& v) {
|
|
|
93
93
|
v);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
// True if `v` is a function literal, or a list/object holding one at any
|
|
97
|
+
// depth. Drives CSGNode::keyHasClosure -- see its doc comment for why a
|
|
98
|
+
// closure cannot be keyed.
|
|
99
|
+
bool valueHasClosure(const Value& v) {
|
|
100
|
+
return std::visit(
|
|
101
|
+
[](const auto& val) -> bool {
|
|
102
|
+
using T = std::decay_t<decltype(val)>;
|
|
103
|
+
if constexpr (std::is_same_v<T, ClosurePtr>) {
|
|
104
|
+
return true;
|
|
105
|
+
} else if constexpr (std::is_same_v<T, ListPtr>) {
|
|
106
|
+
if (!val) return false;
|
|
107
|
+
for (const Value& item : val->items)
|
|
108
|
+
if (valueHasClosure(item)) return true;
|
|
109
|
+
return false;
|
|
110
|
+
} else if constexpr (std::is_same_v<T, ObjectPtr>) {
|
|
111
|
+
if (!val) return false;
|
|
112
|
+
for (const auto& [k, vv] : val->items)
|
|
113
|
+
if (valueHasClosure(vv)) return true;
|
|
114
|
+
return false;
|
|
115
|
+
} else {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
v);
|
|
120
|
+
}
|
|
121
|
+
|
|
96
122
|
std::string canonParams(const CSGParams& params) {
|
|
97
123
|
std::vector<std::pair<std::string, std::string>> entries;
|
|
98
124
|
entries.reserve(params.size());
|
|
@@ -120,13 +146,24 @@ std::string canonParams(const CSGParams& params) {
|
|
|
120
146
|
std::string cacheKey(CSGNode& node) {
|
|
121
147
|
if (node.cachedKey) return *node.cachedKey;
|
|
122
148
|
|
|
149
|
+
bool hasClosure = false;
|
|
150
|
+
for (const auto& [k, v] : node.params) {
|
|
151
|
+
if (valueHasClosure(v)) { hasClosure = true; break; }
|
|
152
|
+
}
|
|
153
|
+
|
|
123
154
|
std::string out = "N(";
|
|
124
155
|
appendLenPrefixed(out, node.kind);
|
|
125
156
|
out += node.isBuiltin ? "1" : "0";
|
|
126
157
|
appendLenPrefixed(out, canonParams(node.params));
|
|
127
158
|
out += std::to_string(node.children.size()) + "[";
|
|
128
|
-
for (const auto& c : node.children)
|
|
159
|
+
for (const auto& c : node.children) {
|
|
160
|
+
appendLenPrefixed(out, cacheKey(*c));
|
|
161
|
+
// A closure anywhere below poisons this key too: it is built from
|
|
162
|
+
// the children's keys.
|
|
163
|
+
hasClosure = hasClosure || c->keyHasClosure;
|
|
164
|
+
}
|
|
129
165
|
out += "])";
|
|
166
|
+
node.keyHasClosure = hasClosure;
|
|
130
167
|
node.cachedKey = out;
|
|
131
168
|
return *node.cachedKey;
|
|
132
169
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
2
|
+
#include "openscad_cpp_evaluator/colored_body.hpp"
|
|
3
|
+
#include "openscad_cpp_evaluator/export.hpp"
|
|
2
4
|
|
|
3
5
|
#include "test_helpers.hpp"
|
|
4
6
|
|
|
@@ -576,8 +578,11 @@ TEST(MixedDimensions, TransformsAndControlFlowAreGroupsToo) {
|
|
|
576
578
|
EXPECT_EQ(dimWarnings("translate([0,0,0]) { square(4); cube(1); }"), expected);
|
|
577
579
|
EXPECT_EQ(dimWarnings("scale(2) { square(4); cube(1); }"), expected);
|
|
578
580
|
EXPECT_EQ(dimWarnings("color(\"red\") { square(4); cube(1); }"), expected);
|
|
579
|
-
|
|
580
|
-
|
|
581
|
+
// for/if are transparent -- their children land at the top level, so
|
|
582
|
+
// they get the top level's keep-both treatment rather than a group's.
|
|
583
|
+
const std::vector<std::string> topLevel{"WARNING: Mixing 2D and 3D objects is not supported"};
|
|
584
|
+
EXPECT_EQ(dimWarnings("for (i = [0:0]) { square(4); cube(1); }"), topLevel);
|
|
585
|
+
EXPECT_EQ(dimWarnings("if (true) { square(4); cube(1); }"), topLevel);
|
|
581
586
|
EXPECT_EQ(dimWarnings("hull() { square(4); cube(1); }"), expected);
|
|
582
587
|
}
|
|
583
588
|
|
|
@@ -603,14 +608,47 @@ TEST(MixedDimensions, RoofWarnsForNeither) {
|
|
|
603
608
|
EXPECT_TRUE(dimWarnings("roof() { square(4); cube(1); }").empty());
|
|
604
609
|
}
|
|
605
610
|
|
|
606
|
-
TEST(MixedDimensions,
|
|
607
|
-
// The top level
|
|
611
|
+
TEST(MixedDimensions, TopLevelWarnsButKeepsBothDimensions) {
|
|
612
|
+
// The top level warns like any other group, but drops NOTHING. A real
|
|
613
|
+
// group has to pick one dimension because generateCsg builds a single
|
|
614
|
+
// result from it; the top level just hands back a list, and the
|
|
615
|
+
// reference's own preview draws 2D and 3D side by side. Dropping here
|
|
616
|
+
// silently lost the whole of a BOSL2 debug overlay (debug_bezier() of a
|
|
617
|
+
// 2D bezier is entirely 2D) whenever a 3D shape shared the script.
|
|
608
618
|
EXPECT_EQ(dimWarnings("square(4); cube(1);"),
|
|
609
|
-
(std::vector<std::string>{"WARNING:
|
|
610
|
-
"WARNING: Mixing 2D and 3D objects is not supported"}));
|
|
619
|
+
(std::vector<std::string>{"WARNING: Mixing 2D and 3D objects is not supported"}));
|
|
611
620
|
Evaluated e = evalSrc("square(4); cube(1);");
|
|
612
|
-
ASSERT_EQ(e.bodies.size(),
|
|
613
|
-
EXPECT_TRUE(e.bodies[0].section.has_value());
|
|
621
|
+
ASSERT_EQ(e.bodies.size(), 2u);
|
|
622
|
+
EXPECT_TRUE(e.bodies[0].section.has_value()) << "the 2D shape survived";
|
|
623
|
+
EXPECT_TRUE(e.bodies[1].body.has_value()) << "and so did the 3D one";
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
TEST(MixedDimensions, ExportDropsTheFlatSlabWhenRealSolidsArePresent) {
|
|
627
|
+
// The top level keeps a 2D shape so it can be SEEN, thin-extruded by
|
|
628
|
+
// toRenderableBodies. A mesh export must not smuggle that 1e-3-tall slab
|
|
629
|
+
// in beside the real solids -- the reference drops it there too.
|
|
630
|
+
Evaluated e = evalSrc("square(4); cube(1);");
|
|
631
|
+
const std::vector<ColoredBody> renderable = toRenderableBodies(e.bodies);
|
|
632
|
+
ASSERT_EQ(renderable.size(), 2u) << "both are still drawn";
|
|
633
|
+
|
|
634
|
+
const std::vector<ExportObject> objects = splitBodiesForExport(renderable, nullptr);
|
|
635
|
+
ASSERT_EQ(objects.size(), 1u) << "but only the cube is exported";
|
|
636
|
+
// The cube is a unit tall; the dropped slab would have been 1e-3.
|
|
637
|
+
float zmin = 1e9f, zmax = -1e9f;
|
|
638
|
+
for (size_t i = 2; i < objects[0].verts.size(); i += 3) {
|
|
639
|
+
zmin = std::min(zmin, objects[0].verts[i]);
|
|
640
|
+
zmax = std::max(zmax, objects[0].verts[i]);
|
|
641
|
+
}
|
|
642
|
+
EXPECT_NEAR(zmax - zmin, 1.0f, 1e-5f);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
TEST(MixedDimensions, ExportKeepsTheFlatSlabWhenItIsTheOnlyGeometry) {
|
|
646
|
+
// A 2D-only script has nothing else to write, so its slab still exports
|
|
647
|
+
// -- unchanged behaviour, and the only reason the filter is conditional.
|
|
648
|
+
Evaluated e = evalSrc("square(4);");
|
|
649
|
+
const std::vector<ExportObject> objects =
|
|
650
|
+
splitBodiesForExport(toRenderableBodies(e.bodies), nullptr);
|
|
651
|
+
EXPECT_EQ(objects.size(), 1u);
|
|
614
652
|
}
|
|
615
653
|
|
|
616
654
|
TEST(MixedDimensions, UniformChildrenAreUntouched) {
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_manifold_cache.cpp
RENAMED
|
@@ -121,6 +121,65 @@ TEST(ManifoldCacheUncacheable, RandsBeforeGeometryInModuleBodyTaintsSplicedSibli
|
|
|
121
121
|
EXPECT_TRUE(e.tree[0]->uncacheable);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// -- closure taint ---------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
TEST(ManifoldCacheClosure, PlainNodeHasNoClosureTaint) {
|
|
127
|
+
Evaluated e = evalSrc("cube(5);");
|
|
128
|
+
ASSERT_EQ(e.tree.size(), 1u);
|
|
129
|
+
cacheKey(*e.tree[0]);
|
|
130
|
+
EXPECT_FALSE(e.tree[0]->keyHasClosure);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
TEST(ManifoldCacheClosure, FunctionLiteralParamTaintsTheNode) {
|
|
134
|
+
Evaluated e = evalSrc(
|
|
135
|
+
"levelset(function (x,y,z) x*x+y*y+z*z-100,"
|
|
136
|
+
" bounds=[[-15,-15,-15],[15,15,15]], edge=5);");
|
|
137
|
+
ASSERT_EQ(e.tree.size(), 1u);
|
|
138
|
+
cacheKey(*e.tree[0]);
|
|
139
|
+
EXPECT_TRUE(e.tree[0]->keyHasClosure);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
TEST(ManifoldCacheClosure, TaintPropagatesUpThroughATransform) {
|
|
143
|
+
// The parent's key is built from the child's, so a closure below is
|
|
144
|
+
// just as unusable there.
|
|
145
|
+
Evaluated e = evalSrc(
|
|
146
|
+
"translate([1,0,0]) levelset(function (x,y,z) x*x+y*y+z*z-100,"
|
|
147
|
+
" bounds=[[-15,-15,-15],[15,15,15]], edge=5);");
|
|
148
|
+
ASSERT_EQ(e.tree.size(), 1u);
|
|
149
|
+
EXPECT_EQ(e.tree[0]->kind, "translate");
|
|
150
|
+
cacheKey(*e.tree[0]);
|
|
151
|
+
EXPECT_TRUE(e.tree[0]->keyHasClosure);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// The bug this taint exists for, at full size: both closures come from the
|
|
155
|
+
// SAME function literal (so canonValue's "F<pointer>" is byte-identical)
|
|
156
|
+
// but capture different `r`. Every other cache-key input matches too, so
|
|
157
|
+
// before the taint the second levelset() was served the first one's
|
|
158
|
+
// geometry and both spheres came out radius 10.
|
|
159
|
+
//
|
|
160
|
+
// Deterministic on purpose: one evaluation, one AST, so the two closures
|
|
161
|
+
// genuinely share a node address rather than relying on the allocator
|
|
162
|
+
// handing back a freed one.
|
|
163
|
+
TEST(ManifoldCacheClosure, TwoClosuresOverOneLiteralAreNotServedEachOthersGeometry) {
|
|
164
|
+
auto cache = std::make_shared<ManifoldCache>();
|
|
165
|
+
Evaluated e = evalSrcWithCache(
|
|
166
|
+
"function mk(r) = function (x,y,z) x*x+y*y+z*z-r*r;\n"
|
|
167
|
+
"levelset(mk(10), bounds=[[-15,-15,-15],[15,15,15]], edge=2);\n"
|
|
168
|
+
"translate([40,0,0])\n"
|
|
169
|
+
" levelset(mk(5), bounds=[[-15,-15,-15],[15,15,15]], edge=2);\n",
|
|
170
|
+
cache);
|
|
171
|
+
|
|
172
|
+
ASSERT_EQ(e.bodies.size(), 2u);
|
|
173
|
+
ASSERT_TRUE(e.bodies[0].body.has_value());
|
|
174
|
+
ASSERT_TRUE(e.bodies[1].body.has_value());
|
|
175
|
+
const double volBig = e.bodies[0].body->Volume();
|
|
176
|
+
const double volSmall = e.bodies[1].body->Volume();
|
|
177
|
+
// Coarse sampling, so compare the two against each other rather than
|
|
178
|
+
// against 4/3*pi*r^3: r=10 vs r=5 is an 8x volume ratio.
|
|
179
|
+
EXPECT_GT(volBig, 2.0 * volSmall)
|
|
180
|
+
<< "the second closure was served the first one's cached geometry";
|
|
181
|
+
}
|
|
182
|
+
|
|
124
183
|
// -- cache reuse -----------------------------------------------------------
|
|
125
184
|
|
|
126
185
|
TEST(ManifoldCache, CacheHitSkipsRegeneratingTheSubtree) {
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/tests/test_python_bindings.py
RENAMED
|
@@ -351,6 +351,43 @@ def test_parse_ast_raises_parse_error_on_bad_syntax():
|
|
|
351
351
|
raise AssertionError("expected ParseError")
|
|
352
352
|
|
|
353
353
|
|
|
354
|
+
def test_format_source_round_trips_and_is_idempotent():
|
|
355
|
+
from openscad_cpp_evaluator import format_source
|
|
356
|
+
|
|
357
|
+
out = format_source("module thing(a=1,b=[1,2,3]){translate([0,0,1])cube([a,a,a]);}\n")
|
|
358
|
+
assert "module thing(a=1, b=[1, 2, 3])" in out, out
|
|
359
|
+
# A modifier's children go on their own indented line.
|
|
360
|
+
assert "translate([0, 0, 1])\n cube([a, a, a]);" in out, out
|
|
361
|
+
# Formatting formatted source changes nothing: the printer is the
|
|
362
|
+
# parser's own, so its output parses back to the same tree.
|
|
363
|
+
assert format_source(out) == out
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def test_format_source_keeps_comments():
|
|
367
|
+
from openscad_cpp_evaluator import format_source
|
|
368
|
+
|
|
369
|
+
out = format_source("// keep me\ncube(1);\n")
|
|
370
|
+
assert "// keep me" in out, out
|
|
371
|
+
# ...and can be told not to.
|
|
372
|
+
assert "// keep me" not in format_source("// keep me\ncube(1);\n", include_comments=False)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def test_format_source_honours_the_indent_width():
|
|
376
|
+
from openscad_cpp_evaluator import format_source
|
|
377
|
+
|
|
378
|
+
two = format_source("module m(){cube(1);}\n", indent=2)
|
|
379
|
+
assert "\n cube(1);" in two, two
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def test_format_source_raises_parse_error_on_bad_input():
|
|
383
|
+
from openscad_cpp_evaluator import ParseError, format_source
|
|
384
|
+
try:
|
|
385
|
+
format_source("module {{{")
|
|
386
|
+
except ParseError:
|
|
387
|
+
return
|
|
388
|
+
raise AssertionError("expected ParseError")
|
|
389
|
+
|
|
390
|
+
|
|
354
391
|
def main():
|
|
355
392
|
tests = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
|
|
356
393
|
failures = []
|
|
File without changes
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/.github/workflows/wheels.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.55.0 → openscad_cpp_evaluator-0.55.2}/examples/minimal_debugger.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|