openscad-cpp-evaluator 0.41.0__tar.gz → 0.42.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-0.41.0 → openscad_cpp_evaluator-0.42.0}/CLAUDE.md +4 -1
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +4 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/csg_node.hpp +18 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/evaluator.hpp +29 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/booleans.cpp +7 -3
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/control.cpp +1 -2
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/registry.cpp +1 -1
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/bytecode_vm.cpp +14 -4
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/csg_resolve.cpp +6 -1
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/expr_eval.cpp +8 -6
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/user_calls.cpp +10 -2
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-0.42.0/tests/test_children_separate.cpp +278 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/uv.lock +0 -0
|
@@ -481,7 +481,10 @@ grep for `ponytail:`.
|
|
|
481
481
|
lexically nested inside an already-active call," picking `childCtx()` vs `callCtx()`
|
|
482
482
|
accordingly; read its doc comment before touching it, it's the second-trickiest mechanism in this
|
|
483
483
|
codebase after the CSG tree stack), `evalUserModule`/`evalUserFunction`/`evalFunctionLiteral`,
|
|
484
|
-
and `builtinChildren` (children()/children(N), deferred evaluation
|
|
484
|
+
and `builtinChildren` (children()/children(N), deferred evaluation; `children(separate=true)`
|
|
485
|
+
additionally marks each forwarded node `separateOperand` so the enclosing
|
|
486
|
+
union/difference/intersection treats them as separate operands rather than one grouped one --
|
|
487
|
+
a BelfrySCAD extension, see `Evaluator::appendGroupSizes`). `evalFunctionCall`'s
|
|
485
488
|
precedence order (checked in this exact sequence): `import` (special-cased, its own
|
|
486
489
|
module/expression-context split) → `isBuiltinFunctionName` (function_builtins.hpp — always wins
|
|
487
490
|
if true) → user function lookup → function-literal *value* probe → "unknown function" warning.
|
|
@@ -219,6 +219,10 @@ struct VmFrame {
|
|
|
219
219
|
// mirrors evalModularCall's own `&node` (csg_resolve.cpp). Only
|
|
220
220
|
// meaningful when ownsModuleSplice is true.
|
|
221
221
|
const oscad::ASTNode* moduleSpliceCallNode = nullptr;
|
|
222
|
+
// children(separate=true) on the call this frame is forwarding for.
|
|
223
|
+
// Only meaningful while ownsModuleSplice is true, same as the two
|
|
224
|
+
// fields above; reset in releaseVmFrame for the same pooling reason.
|
|
225
|
+
bool separateChildren = false;
|
|
222
226
|
|
|
223
227
|
// Whether callStack_.back() (at push time) genuinely IS this frame's
|
|
224
228
|
// own logical call, and therefore safe for a tail hop inside this
|
|
@@ -34,6 +34,16 @@ struct CSGNode {
|
|
|
34
34
|
CSGParams params; // resolve step's plain-data output
|
|
35
35
|
bool uncacheable = false; // set by a later phase (ManifoldCache, Phase 8)
|
|
36
36
|
|
|
37
|
+
// Set only by children(separate=true): this node begins its OWN operand
|
|
38
|
+
// group in an enclosing union/difference/intersection/intersection_for,
|
|
39
|
+
// instead of merging into the single group its enclosing statement
|
|
40
|
+
// would otherwise form. See Evaluator::appendGroupSizes.
|
|
41
|
+
//
|
|
42
|
+
// Deliberately absent from cacheKey()'s allowlist (manifold_cache.cpp):
|
|
43
|
+
// it changes the PARENT's hashed "group_sizes" param, never this node's
|
|
44
|
+
// own geometry, so the parent already re-keys and this node must not.
|
|
45
|
+
bool separateOperand = false;
|
|
46
|
+
|
|
37
47
|
// The call site that entered this node's call chain from the top
|
|
38
48
|
// level, captured at RESOLVE time -- non-owning, AST-lifetime-bound
|
|
39
49
|
// like `node`. nullptr for a node resolved at top level.
|
|
@@ -73,4 +83,12 @@ struct CSGNode {
|
|
|
73
83
|
std::optional<std::string> cachedKey;
|
|
74
84
|
};
|
|
75
85
|
|
|
86
|
+
// Marks every node from `from` onward as starting its own operand group --
|
|
87
|
+
// what children(separate=true) does to the geometry it just forwarded.
|
|
88
|
+
// A free function, not a member, so all three splice sites (user_calls.cpp
|
|
89
|
+
// and bytecode_vm.cpp's two) can reach it from this header alone.
|
|
90
|
+
inline void markSeparateOperands(std::vector<std::unique_ptr<CSGNode>>& nodes, size_t from) {
|
|
91
|
+
for (size_t i = from; i < nodes.size(); ++i) nodes[i]->separateOperand = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
76
94
|
} // namespace oscadeval
|
|
@@ -190,6 +190,30 @@ public:
|
|
|
190
190
|
// statement.
|
|
191
191
|
size_t currentTreeFrameSize() const { return treeStack_.back().size(); }
|
|
192
192
|
|
|
193
|
+
// Records the group(s) one child statement contributed, given the frame
|
|
194
|
+
// size captured before it ran. Normally that is exactly one group, of
|
|
195
|
+
// however many nodes the statement pushed -- including a group of size
|
|
196
|
+
// ZERO for a statement that produced no geometry (a disabled `*cube()`),
|
|
197
|
+
// which generateCsg relies on to reset intersection() and to bail
|
|
198
|
+
// difference(). Only children(separate=true) produces more than one:
|
|
199
|
+
// each node it marked starts a fresh group, so its forwarded children
|
|
200
|
+
// reach the enclosing operator as separate operands.
|
|
201
|
+
//
|
|
202
|
+
// Shared by all four group builders -- resolveCsg, resolveIntersectionFor
|
|
203
|
+
// and the VM's Op::CsgGroupEnd (which serves both) -- because
|
|
204
|
+
// "group_sizes" is otherwise built twice, once per engine, and would
|
|
205
|
+
// drift.
|
|
206
|
+
void appendGroupSizes(std::vector<Value>& groupSizes, size_t before) const {
|
|
207
|
+
const std::vector<std::unique_ptr<CSGNode>>& frame = treeStack_.back();
|
|
208
|
+
size_t start = before;
|
|
209
|
+
for (size_t i = before + 1; i < frame.size(); ++i) {
|
|
210
|
+
if (!frame[i]->separateOperand) continue;
|
|
211
|
+
groupSizes.push_back(Value{static_cast<double>(i - start)});
|
|
212
|
+
start = i;
|
|
213
|
+
}
|
|
214
|
+
groupSizes.push_back(Value{static_cast<double>(frame.size() - start)});
|
|
215
|
+
}
|
|
216
|
+
|
|
193
217
|
// Generate pass: walks `tree` bottom-up (children before their own
|
|
194
218
|
// node), calling each node's registered GenerateFn (falling back to
|
|
195
219
|
// concatenating children's bodies for a kind with none registered).
|
|
@@ -342,6 +366,11 @@ public:
|
|
|
342
366
|
struct ChildrenForward {
|
|
343
367
|
EvalContext evalCtx;
|
|
344
368
|
std::vector<const oscad::ASTNode*> nodes;
|
|
369
|
+
// children(separate=true): hand these to the enclosing union/
|
|
370
|
+
// difference/intersection as SEPARATE operands rather than as one
|
|
371
|
+
// grouped operand. Acted on after the nodes are evaluated, by
|
|
372
|
+
// marking the CSGNodes they produced -- see markSeparateOperands.
|
|
373
|
+
bool separate = false;
|
|
345
374
|
};
|
|
346
375
|
std::optional<ChildrenForward> prepareChildrenForward(const CallArgs& args, EvalContext& ctx);
|
|
347
376
|
|
|
@@ -68,7 +68,12 @@ std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBo
|
|
|
68
68
|
// operand (unioned together), and each subsequent statement's bodies are
|
|
69
69
|
// unioned then subtracted -- a flat evaluation would lose this grouping and
|
|
70
70
|
// misbehave when e.g. BOSL2's attachable() returns multiple bodies (parent
|
|
71
|
-
// + attached children) as one operand.
|
|
71
|
+
// + attached children) as one operand.
|
|
72
|
+
//
|
|
73
|
+
// One statement can contribute MORE than one group: children(separate=true)
|
|
74
|
+
// marks the nodes it forwards so each starts its own operand group, which is
|
|
75
|
+
// how `difference() children(separate=true)` subtracts children 1..n from
|
|
76
|
+
// child 0. See Evaluator::appendGroupSizes, which both engines share. Mirrors _resolve_csg/_generate_csg,
|
|
72
77
|
// minus _attach_tri_colors' multi-color-merge provenance (ponytail: a
|
|
73
78
|
// merged body always takes its first contributing child's color, matching
|
|
74
79
|
// this evaluator's own pre-tri_colors baseline behavior -- revisit
|
|
@@ -101,8 +106,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
|
|
|
101
106
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
102
107
|
const size_t before = ev.currentTreeFrameSize();
|
|
103
108
|
ev.evalChildren(std::vector<const oscad::ASTNode*>{geoNode}, effCtx);
|
|
104
|
-
|
|
105
|
-
groupSizes.push_back(Value{static_cast<double>(after - before)});
|
|
109
|
+
ev.appendGroupSizes(groupSizes, before);
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
CSGParams params;
|
|
@@ -119,8 +119,7 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
119
119
|
if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
120
120
|
const size_t before = ev.currentTreeFrameSize();
|
|
121
121
|
ev.evalChildren(bodyNodes, parentCtx);
|
|
122
|
-
|
|
123
|
-
groupSizes.push_back(Value{static_cast<double>(after - before)});
|
|
122
|
+
ev.appendGroupSizes(groupSizes, before);
|
|
124
123
|
return;
|
|
125
124
|
}
|
|
126
125
|
const auto& assign = node.assignments[depth];
|
|
@@ -112,7 +112,7 @@ const std::vector<std::string>* builtinParamNames(const std::string& name) {
|
|
|
112
112
|
{"intersection", {}},
|
|
113
113
|
{"hull", {}},
|
|
114
114
|
{"minkowski", {"convexity"}},
|
|
115
|
-
{"children", {"index"}},
|
|
115
|
+
{"children", {"index", "separate"}},
|
|
116
116
|
{"render", {"convexity"}},
|
|
117
117
|
// "repair" is this port's own addition, not an upstream parameter.
|
|
118
118
|
{"import",
|
|
@@ -360,7 +360,7 @@ void pushBracketedModuleFrame(Evaluator& ev, const CompiledChunk& chunk, const o
|
|
|
360
360
|
// because module chunks never contain tail-call opcodes); don't inherit
|
|
361
361
|
// a pooled function frame's stale true here either.
|
|
362
362
|
void pushChildrenForwardFrame(Evaluator& ev, const CompiledChunk& chunk, EvalContext evalCtx,
|
|
363
|
-
std::uint64_t randsBefore, const oscad::ASTNode& callNode) {
|
|
363
|
+
std::uint64_t randsBefore, const oscad::ASTNode& callNode, bool separate) {
|
|
364
364
|
if (ev.vmCallStack_.size() >= Evaluator::kMaxVmCallStackDepth) {
|
|
365
365
|
ev.error("Recursion too deep while forwarding children()", callNode);
|
|
366
366
|
}
|
|
@@ -381,6 +381,7 @@ void pushChildrenForwardFrame(Evaluator& ev, const CompiledChunk& chunk, EvalCon
|
|
|
381
381
|
frame->ownsModuleSplice = true;
|
|
382
382
|
frame->moduleRandsBefore = randsBefore;
|
|
383
383
|
frame->moduleSpliceCallNode = &callNode;
|
|
384
|
+
frame->separateChildren = separate;
|
|
384
385
|
ev.vmCallStack_.push_back(std::move(frame));
|
|
385
386
|
ev.vmCallBrackets_.emplace_back(std::nullopt);
|
|
386
387
|
}
|
|
@@ -505,6 +506,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
505
506
|
const bool ownsModuleSplice = finished->ownsModuleSplice;
|
|
506
507
|
const std::uint64_t moduleRandsBefore = finished->moduleRandsBefore;
|
|
507
508
|
const oscad::ASTNode* moduleSpliceCallNode = finished->moduleSpliceCallNode;
|
|
509
|
+
const bool separateChildren = finished->separateChildren;
|
|
508
510
|
while (!finished->ctxChain.empty()) finished->ctxChain.pop_back();
|
|
509
511
|
// Module frames never fire returnHook (native evalUserModule
|
|
510
512
|
// never did either -- a module call has no "return value"
|
|
@@ -514,6 +516,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
514
516
|
if (isModule && ownsModuleSplice) {
|
|
515
517
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
516
518
|
ev.treeStack_.pop_back();
|
|
519
|
+
if (separateChildren) markSeparateOperands(children, 0);
|
|
517
520
|
ev.spliceModuleChildren(std::move(children), moduleRandsBefore, *moduleSpliceCallNode);
|
|
518
521
|
}
|
|
519
522
|
if (isFloorFrame) {
|
|
@@ -1023,6 +1026,11 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1023
1026
|
static_cast<const oscad::ModularCall*>(f.chunk->nativeStatements[static_cast<size_t>(ins.a)]);
|
|
1024
1027
|
EvalContext scopedCtx = ctx.withScope(callNode->scope() ? callNode->scope() : ctx.scope);
|
|
1025
1028
|
ev.checkDebug(*callNode, scopedCtx);
|
|
1029
|
+
// Same order as evalModularCall's own (csg_resolve.cpp):
|
|
1030
|
+
// warn, then resolve. Without this a children() typo
|
|
1031
|
+
// warns only under the interpreter, so no test for that
|
|
1032
|
+
// warning could run under both engines.
|
|
1033
|
+
warnUnexpectedBuiltinArgs(ev, *callNode);
|
|
1026
1034
|
const std::uint64_t randsBefore = ev.randsCallCount();
|
|
1027
1035
|
auto [args, effCtx] = resolveCallArgs(ev, callNode->arguments, scopedCtx);
|
|
1028
1036
|
std::optional<Evaluator::ChildrenForward> fwd = ev.prepareChildrenForward(args, effCtx);
|
|
@@ -1039,9 +1047,11 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1039
1047
|
const CompiledChunk* chunk = (ev.useBytecodeVm() && ev.inResolvePass())
|
|
1040
1048
|
? ev.lookupOrCompileChildrenListChunk(fwd->nodes)
|
|
1041
1049
|
: nullptr;
|
|
1050
|
+
// Read before fwd->evalCtx is moved from.
|
|
1051
|
+
const bool separate = fwd->separate;
|
|
1042
1052
|
if (chunk) {
|
|
1043
1053
|
ev.treeStack_.emplace_back();
|
|
1044
|
-
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode);
|
|
1054
|
+
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode, separate);
|
|
1045
1055
|
// f.pc deliberately NOT advanced -- resumes when
|
|
1046
1056
|
// the pushed frame completes; driveVm's completion
|
|
1047
1057
|
// branch runs the splice (isModule &&
|
|
@@ -1065,6 +1075,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1065
1075
|
}
|
|
1066
1076
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
1067
1077
|
ev.treeStack_.pop_back();
|
|
1078
|
+
if (separate) markSeparateOperands(children, 0);
|
|
1068
1079
|
ev.spliceModuleChildren(std::move(children), randsBefore, *callNode);
|
|
1069
1080
|
++f.pc;
|
|
1070
1081
|
}
|
|
@@ -1304,8 +1315,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1304
1315
|
}
|
|
1305
1316
|
case Op::CsgGroupEnd: {
|
|
1306
1317
|
PendingCsgWrap& pending = f.csgWrapStack.back();
|
|
1307
|
-
|
|
1308
|
-
pending.groupSizes.push_back(Value{static_cast<double>(after - pending.groupStartSize)});
|
|
1318
|
+
ev.appendGroupSizes(pending.groupSizes, pending.groupStartSize);
|
|
1309
1319
|
++f.pc;
|
|
1310
1320
|
break;
|
|
1311
1321
|
}
|
|
@@ -158,7 +158,12 @@ void Evaluator::spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> child
|
|
|
158
158
|
// landed on.
|
|
159
159
|
for (auto& c : children) c->uncacheable = true;
|
|
160
160
|
}
|
|
161
|
-
|
|
161
|
+
// children(separate=true) marked these to start their own operand
|
|
162
|
+
// groups, and the group walk only inspects the enclosing frame's top
|
|
163
|
+
// level -- so the wrapper would hide the marks. Splice instead.
|
|
164
|
+
const bool anySeparate =
|
|
165
|
+
std::any_of(children.begin(), children.end(), [](const auto& c) { return c->separateOperand; });
|
|
166
|
+
if (children.size() > 1 && !anySeparate) {
|
|
162
167
|
auto unionNode = std::make_unique<CSGNode>();
|
|
163
168
|
unionNode->kind = "union";
|
|
164
169
|
unionNode->node = &callNode;
|
|
@@ -309,12 +309,14 @@ Value Evaluator::applyRange(const Value& startV, const Value& endV, const Value&
|
|
|
309
309
|
// here, at construction, because that is where the reference reports it:
|
|
310
310
|
// `r = [5:0];` warns even if nothing ever iterates r.
|
|
311
311
|
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
312
|
+
// ponytail: only an IMPLICIT step is checked -- a deliberate divergence
|
|
313
|
+
// from the reference, which warns for [5:1:0] and [0:-1:5] as well.
|
|
314
|
+
// Writing the step out is taken as a statement of intent; the warning is
|
|
315
|
+
// for the author who wrote [5:0] meaning [5:-1:0] and got a silent empty
|
|
316
|
+
// loop. An implicit step is always exactly 1, so the reference's other
|
|
317
|
+
// wording ("begin is smaller than the end, but step is negative") cannot
|
|
318
|
+
// arise here and no longer exists in this port -- if it is ever needed
|
|
319
|
+
// again, this gate has been widened back to explicit steps.
|
|
318
320
|
//
|
|
319
321
|
// The epsilon matches the one the iteration path used before this check
|
|
320
322
|
// moved here, so a range built from float arithmetic that lands a hair
|
|
@@ -179,6 +179,7 @@ void Evaluator::releaseVmFrame(std::unique_ptr<VmFrame> frame) {
|
|
|
179
179
|
frame->ownsModuleSplice = false;
|
|
180
180
|
frame->moduleRandsBefore = 0;
|
|
181
181
|
frame->moduleSpliceCallNode = nullptr;
|
|
182
|
+
frame->separateChildren = false;
|
|
182
183
|
vmFramePool_.push_back(std::move(frame));
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -932,6 +933,11 @@ Value Evaluator::parentModuleName(int idx) const {
|
|
|
932
933
|
|
|
933
934
|
std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(const CallArgs& args, EvalContext& ctx) {
|
|
934
935
|
Value idxArg = getArg(args, 0, "index", Value{});
|
|
936
|
+
// Positional slot 1 is accepted as well as the name: adding "separate"
|
|
937
|
+
// to the builtin's parameter list already suppresses the "Too many
|
|
938
|
+
// unnamed arguments" warning for children(0, true), so reading it
|
|
939
|
+
// named-only would silently ignore an argument the author wrote.
|
|
940
|
+
const bool separate = truthy(getArg(args, 1, "separate", Value{false}));
|
|
935
941
|
if (!ctx.childrenNodes || ctx.childrenNodes->empty()) return std::nullopt;
|
|
936
942
|
const EvalContext* callerCtx = ctx.childrenCallerCtx;
|
|
937
943
|
if (!callerCtx) return std::nullopt;
|
|
@@ -977,7 +983,7 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
977
983
|
}
|
|
978
984
|
|
|
979
985
|
if (std::holds_alternative<std::monostate>(idxArg)) {
|
|
980
|
-
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes};
|
|
986
|
+
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes, separate};
|
|
981
987
|
}
|
|
982
988
|
|
|
983
989
|
// children(N) indexes child *statements*, not output bodies -- a
|
|
@@ -1041,13 +1047,15 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
1041
1047
|
picked.push_back(geoNodes[static_cast<size_t>(idx)]);
|
|
1042
1048
|
}
|
|
1043
1049
|
if (picked.empty()) return std::nullopt;
|
|
1044
|
-
return ChildrenForward{std::move(evalCtx), std::move(picked)};
|
|
1050
|
+
return ChildrenForward{std::move(evalCtx), std::move(picked), separate};
|
|
1045
1051
|
}
|
|
1046
1052
|
|
|
1047
1053
|
void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
1048
1054
|
std::optional<ChildrenForward> fwd = prepareChildrenForward(args, ctx);
|
|
1049
1055
|
if (!fwd) return;
|
|
1056
|
+
const size_t before = currentTreeFrameSize();
|
|
1050
1057
|
evalChildren(fwd->nodes, fwd->evalCtx);
|
|
1058
|
+
if (fwd->separate) markSeparateOperands(treeStack_.back(), before);
|
|
1051
1059
|
}
|
|
1052
1060
|
|
|
1053
1061
|
} // namespace oscadeval
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// children(separate=true) -- hand the forwarded children to the enclosing
|
|
2
|
+
// union/difference/intersection as SEPARATE operands instead of as the one
|
|
3
|
+
// grouped operand a statement normally contributes.
|
|
4
|
+
//
|
|
5
|
+
// Every test runs under BOTH engines. That is the standing rule in this
|
|
6
|
+
// repo, and here it is load-bearing rather than ceremonial: "group_sizes"
|
|
7
|
+
// is built in completely separate code per engine (resolveCsg in
|
|
8
|
+
// booleans.cpp vs Op::CsgGroupEnd in bytecode_vm.cpp), and the splice
|
|
9
|
+
// itself has three call sites across the two.
|
|
10
|
+
|
|
11
|
+
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
12
|
+
|
|
13
|
+
#include "test_helpers.hpp"
|
|
14
|
+
|
|
15
|
+
#include <gtest/gtest.h>
|
|
16
|
+
|
|
17
|
+
using namespace oscadeval;
|
|
18
|
+
using namespace oscadeval::test;
|
|
19
|
+
|
|
20
|
+
namespace {
|
|
21
|
+
|
|
22
|
+
// Same reasoning as test_csg_tree.cpp's own copy: the OSCAD_BYTECODE_VM env
|
|
23
|
+
// var is cached after its first read, so a test that must exercise a
|
|
24
|
+
// specific engine has to force it.
|
|
25
|
+
class ScopedVm {
|
|
26
|
+
public:
|
|
27
|
+
explicit ScopedVm(bool enabled) { Evaluator::setBytecodeVmEnabledForTesting(enabled); }
|
|
28
|
+
~ScopedVm() { Evaluator::setBytecodeVmEnabledForTesting(std::nullopt); }
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
double totalVolume(const std::vector<ColoredBody>& bodies) {
|
|
32
|
+
double v = 0.0;
|
|
33
|
+
for (const ColoredBody& b : bodies) {
|
|
34
|
+
if (b.body) v += b.body->Volume();
|
|
35
|
+
}
|
|
36
|
+
return v;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// One big cube with two small cubes fully INSIDE it, disjoint from each
|
|
40
|
+
// other. Deliberate: the two subtrahends contribute nothing to a union, so
|
|
41
|
+
// the union answer (125000) and each partially-wrong grouping (124000) are
|
|
42
|
+
// all numerically distinct from the right one (123000). Overlapping shapes
|
|
43
|
+
// would have made several wrong answers land on the same number.
|
|
44
|
+
constexpr const char* kThreeChildren =
|
|
45
|
+
"{ cube(50, center=true);"
|
|
46
|
+
" translate([-15,0,0]) cube(10, center=true);"
|
|
47
|
+
" translate([ 15,0,0]) cube(10, center=true); }";
|
|
48
|
+
|
|
49
|
+
constexpr double kCube = 125000.0; // 50^3
|
|
50
|
+
constexpr double kSmall = 1000.0; // 10^3
|
|
51
|
+
|
|
52
|
+
} // namespace
|
|
53
|
+
|
|
54
|
+
// -- The feature ----------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
TEST(ChildrenSeparate, DifferenceSubtractsEachForwardedChild) {
|
|
57
|
+
for (bool vm : {false, true}) {
|
|
58
|
+
ScopedVm guard(vm);
|
|
59
|
+
Evaluated e = evalSrc(std::string("module frame() { difference() children(separate=true); }\n"
|
|
60
|
+
"frame() ") + kThreeChildren);
|
|
61
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube - 2 * kSmall, 1e-6) << "vm=" << vm;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
TEST(ChildrenSeparate, MatchesTheHandWrittenDifference) {
|
|
66
|
+
// The oracle: the same shape spelled out. These must agree exactly --
|
|
67
|
+
// that is the whole claim of the feature.
|
|
68
|
+
for (bool vm : {false, true}) {
|
|
69
|
+
ScopedVm guard(vm);
|
|
70
|
+
Evaluated sep = evalSrc(std::string("module frame() { difference() children(separate=true); }\n"
|
|
71
|
+
"frame() ") + kThreeChildren);
|
|
72
|
+
Evaluated hand = evalSrc(std::string("difference() ") + kThreeChildren);
|
|
73
|
+
EXPECT_NEAR(totalVolume(sep.bodies), totalVolume(hand.bodies), 1e-6) << "vm=" << vm;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
TEST(ChildrenSeparate, WithoutTheFlagNothingChanges) {
|
|
78
|
+
// Pins the default. A regression here means every existing script that
|
|
79
|
+
// forwards children through a difference() silently changed meaning.
|
|
80
|
+
for (bool vm : {false, true}) {
|
|
81
|
+
ScopedVm guard(vm);
|
|
82
|
+
Evaluated e = evalSrc(std::string("module frame() { difference() children(); }\n"
|
|
83
|
+
"frame() ") + kThreeChildren);
|
|
84
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube, 1e-6) << "vm=" << vm;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
TEST(ChildrenSeparate, IntersectionIntersectsEachForwardedChild) {
|
|
89
|
+
// The case with no workaround at all: for difference, A-(B|C) == A-B-C,
|
|
90
|
+
// so a union of the subtrahends happens to be right. For intersection
|
|
91
|
+
// it is not -- A&(B|C) != A&B&C.
|
|
92
|
+
for (bool vm : {false, true}) {
|
|
93
|
+
ScopedVm guard(vm);
|
|
94
|
+
const char* kids = "{ cube([10,10,10]); translate([5,0,0]) cube([10,10,10]); }";
|
|
95
|
+
Evaluated sep = evalSrc(std::string("module m() { intersection() children(separate=true); }\nm() ") + kids);
|
|
96
|
+
Evaluated off = evalSrc(std::string("module m() { intersection() children(); }\nm() ") + kids);
|
|
97
|
+
EXPECT_NEAR(totalVolume(sep.bodies), 500.0, 1e-6) << "vm=" << vm; // the overlap
|
|
98
|
+
EXPECT_NEAR(totalVolume(off.bodies), 1500.0, 1e-6) << "vm=" << vm; // the union
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
TEST(ChildrenSeparate, HonorsAnIndexSelection) {
|
|
103
|
+
// The 4th child would change the volume visibly if the selection leaked.
|
|
104
|
+
for (bool vm : {false, true}) {
|
|
105
|
+
ScopedVm guard(vm);
|
|
106
|
+
Evaluated e = evalSrc("module frame() { difference() children([0:2], separate=true); }\n"
|
|
107
|
+
"frame() { cube(50, center=true);"
|
|
108
|
+
" translate([-15,0,0]) cube(10, center=true);"
|
|
109
|
+
" translate([ 15,0,0]) cube(10, center=true);"
|
|
110
|
+
" translate([ 0,0,0]) cube(20, center=true); }");
|
|
111
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube - 2 * kSmall, 1e-6) << "vm=" << vm;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// -- Tree shape: the mechanism itself -------------------------------------
|
|
116
|
+
|
|
117
|
+
TEST(ChildrenSeparate, SplicesInsteadOfWrappingAndSplitsGroupSizes) {
|
|
118
|
+
for (bool vm : {false, true}) {
|
|
119
|
+
ScopedVm guard(vm);
|
|
120
|
+
Evaluated e = evalSrc(std::string("module frame() { difference() children(separate=true); }\n"
|
|
121
|
+
"frame() ") + kThreeChildren);
|
|
122
|
+
ASSERT_EQ(e.tree.size(), 1u) << "vm=" << vm;
|
|
123
|
+
const CSGNode& diff = *e.tree[0];
|
|
124
|
+
EXPECT_EQ(diff.kind, "difference") << "vm=" << vm;
|
|
125
|
+
// The grouping wrapper would hide the marks from the group walk, so
|
|
126
|
+
// it must not be there: three children, three groups of one.
|
|
127
|
+
ASSERT_EQ(diff.children.size(), 3u) << "vm=" << vm;
|
|
128
|
+
for (const auto& c : diff.children) {
|
|
129
|
+
EXPECT_NE(c->kind, "union") << "vm=" << vm;
|
|
130
|
+
}
|
|
131
|
+
const ListPtr* sizes = std::get_if<ListPtr>(&diff.params.at("group_sizes"));
|
|
132
|
+
ASSERT_NE(sizes, nullptr) << "vm=" << vm;
|
|
133
|
+
ASSERT_EQ((*sizes)->items.size(), 3u) << "vm=" << vm;
|
|
134
|
+
for (const Value& s : (*sizes)->items) EXPECT_EQ(std::get<double>(s), 1.0) << "vm=" << vm;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
TEST(ChildrenSeparate, WithoutTheFlagStillWrapsIntoOneGroup) {
|
|
139
|
+
for (bool vm : {false, true}) {
|
|
140
|
+
ScopedVm guard(vm);
|
|
141
|
+
Evaluated e = evalSrc(std::string("module frame() { difference() children(); }\n"
|
|
142
|
+
"frame() ") + kThreeChildren);
|
|
143
|
+
ASSERT_EQ(e.tree.size(), 1u) << "vm=" << vm;
|
|
144
|
+
const CSGNode& diff = *e.tree[0];
|
|
145
|
+
ASSERT_EQ(diff.children.size(), 1u) << "vm=" << vm;
|
|
146
|
+
EXPECT_EQ(diff.children[0]->kind, "union") << "vm=" << vm;
|
|
147
|
+
EXPECT_FALSE(diff.children[0]->isBuiltin) << "vm=" << vm;
|
|
148
|
+
const ListPtr* sizes = std::get_if<ListPtr>(&diff.params.at("group_sizes"));
|
|
149
|
+
ASSERT_NE(sizes, nullptr) << "vm=" << vm;
|
|
150
|
+
ASSERT_EQ((*sizes)->items.size(), 1u) << "vm=" << vm;
|
|
151
|
+
EXPECT_EQ(std::get<double>((*sizes)->items[0]), 1.0) << "vm=" << vm;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// -- Degradation: it must not leak ----------------------------------------
|
|
156
|
+
|
|
157
|
+
TEST(ChildrenSeparate, UnderATransformDegradesToOneOperand) {
|
|
158
|
+
// The children land in translate()'s own frame, so difference() sees the
|
|
159
|
+
// single translate node. Nothing to separate -- the union is correct.
|
|
160
|
+
for (bool vm : {false, true}) {
|
|
161
|
+
ScopedVm guard(vm);
|
|
162
|
+
Evaluated e = evalSrc(std::string("module frame() { difference() translate([0,0,0]) children(separate=true); }\n"
|
|
163
|
+
"frame() ") + kThreeChildren);
|
|
164
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube, 1e-6) << "vm=" << vm;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
TEST(ChildrenSeparate, DoesNotAffectALaterUnrelatedDifference) {
|
|
169
|
+
// A separated splice under a non-CSG parent must not colour the grouping
|
|
170
|
+
// of a difference() elsewhere in the same evaluation -- including one
|
|
171
|
+
// whose first statement happens to produce the same number of nodes.
|
|
172
|
+
for (bool vm : {false, true}) {
|
|
173
|
+
ScopedVm guard(vm);
|
|
174
|
+
Evaluated e = evalSrc("module m() { translate([200,0,0]) children(separate=true); }\n"
|
|
175
|
+
"m() { cube(1); cube(2); cube(3); }\n"
|
|
176
|
+
"difference() { cube(50, center=true); translate([-15,0,0]) cube(10, center=true); }");
|
|
177
|
+
// 1 + 8 + 27 from the spliced group, plus a normal difference.
|
|
178
|
+
EXPECT_NEAR(totalVolume(e.bodies), 36.0 + kCube - kSmall, 1e-6) << "vm=" << vm;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
TEST(ChildrenSeparate, PropagatesThroughAUserModuleWrapper) {
|
|
183
|
+
// A judgement call, pinned so it cannot drift silently: the mark rides
|
|
184
|
+
// on the nodes, so a module whose whole body is children(separate=true)
|
|
185
|
+
// passes the separateness outward to whatever encloses the call.
|
|
186
|
+
// Retreating to "stop at the module boundary" is any_of -> all_of in
|
|
187
|
+
// spliceModuleChildren.
|
|
188
|
+
for (bool vm : {false, true}) {
|
|
189
|
+
ScopedVm guard(vm);
|
|
190
|
+
Evaluated e = evalSrc(std::string("module pass() { children(separate=true); }\n"
|
|
191
|
+
"difference() pass() ") + kThreeChildren);
|
|
192
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube - 2 * kSmall, 1e-6) << "vm=" << vm;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// -- Degenerate cases -----------------------------------------------------
|
|
197
|
+
|
|
198
|
+
TEST(ChildrenSeparate, OneChildIsASilentNoOp) {
|
|
199
|
+
for (bool vm : {false, true}) {
|
|
200
|
+
ScopedVm guard(vm);
|
|
201
|
+
std::vector<std::string> warnings;
|
|
202
|
+
Evaluated e = evalSrc("module frame() { difference() children(separate=true); }\n"
|
|
203
|
+
"frame() { cube(3); }",
|
|
204
|
+
[&](const std::string& m) { warnings.push_back(m); });
|
|
205
|
+
EXPECT_NEAR(totalVolume(e.bodies), 27.0, 1e-6) << "vm=" << vm;
|
|
206
|
+
EXPECT_TRUE(warnings.empty()) << "vm=" << vm;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
TEST(ChildrenSeparate, NoChildrenIsASilentNoOp) {
|
|
211
|
+
for (bool vm : {false, true}) {
|
|
212
|
+
ScopedVm guard(vm);
|
|
213
|
+
std::vector<std::string> warnings;
|
|
214
|
+
Evaluated e = evalSrc("module frame() { difference() children(separate=true); }\nframe();",
|
|
215
|
+
[&](const std::string& m) { warnings.push_back(m); });
|
|
216
|
+
EXPECT_TRUE(e.bodies.empty()) << "vm=" << vm;
|
|
217
|
+
EXPECT_TRUE(warnings.empty()) << "vm=" << vm;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
TEST(ChildrenSeparate, LeavesUnionAndHullUnchanged) {
|
|
222
|
+
// union() gives the same geometry either way, and hull()/minkowski()
|
|
223
|
+
// read bodies rather than groups -- the wrapper they used to receive was
|
|
224
|
+
// plain concatenation, so they already saw the children separately.
|
|
225
|
+
// This is the executable form of that claim.
|
|
226
|
+
for (bool vm : {false, true}) {
|
|
227
|
+
ScopedVm guard(vm);
|
|
228
|
+
for (const char* op : {"union", "hull"}) {
|
|
229
|
+
const std::string on = std::string("module m() { ") + op + "() children(separate=true); }\nm() ";
|
|
230
|
+
const std::string off = std::string("module m() { ") + op + "() children(); }\nm() ";
|
|
231
|
+
Evaluated a = evalSrc(on + kThreeChildren);
|
|
232
|
+
Evaluated b = evalSrc(off + kThreeChildren);
|
|
233
|
+
EXPECT_NEAR(totalVolume(a.bodies), totalVolume(b.bodies), 1e-6) << "vm=" << vm << " op=" << op;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// -- The argument itself --------------------------------------------------
|
|
239
|
+
|
|
240
|
+
TEST(ChildrenSeparate, TheArgumentIsAccepted) {
|
|
241
|
+
for (bool vm : {false, true}) {
|
|
242
|
+
ScopedVm guard(vm);
|
|
243
|
+
std::vector<std::string> warnings;
|
|
244
|
+
evalSrc("module m() { children(separate=true); }\nm() { cube(1); cube(2); }",
|
|
245
|
+
[&](const std::string& m) { warnings.push_back(m); });
|
|
246
|
+
EXPECT_TRUE(warnings.empty()) << "vm=" << vm;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
TEST(ChildrenSeparate, AMisspelledArgumentStillWarnsUnderBothEngines) {
|
|
251
|
+
// Op::CallChildren did not call warnUnexpectedBuiltinArgs, so a typo was
|
|
252
|
+
// silent on the compiled path only. That gap is why this test can exist.
|
|
253
|
+
for (bool vm : {false, true}) {
|
|
254
|
+
ScopedVm guard(vm);
|
|
255
|
+
std::vector<std::string> warnings;
|
|
256
|
+
evalSrc("module m() { children(seperate=true); }\nm() { cube(1); cube(2); }",
|
|
257
|
+
[&](const std::string& m) { warnings.push_back(m); });
|
|
258
|
+
bool found = false;
|
|
259
|
+
for (const std::string& w : warnings) {
|
|
260
|
+
if (w.find("seperate") != std::string::npos) found = true;
|
|
261
|
+
}
|
|
262
|
+
EXPECT_TRUE(found) << "vm=" << vm << ", warnings=" << warnings.size();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
TEST(ChildrenSeparate, AcceptsThePositionalSecondArgument) {
|
|
267
|
+
// Adding "separate" to the builtin's parameter list already silences the
|
|
268
|
+
// "Too many unnamed arguments" warning for this shape, so it must be
|
|
269
|
+
// read rather than silently ignored.
|
|
270
|
+
for (bool vm : {false, true}) {
|
|
271
|
+
ScopedVm guard(vm);
|
|
272
|
+
Evaluated e = evalSrc("module frame() { difference() children([0:2], true); }\n"
|
|
273
|
+
"frame() { cube(50, center=true);"
|
|
274
|
+
" translate([-15,0,0]) cube(10, center=true);"
|
|
275
|
+
" translate([ 15,0,0]) cube(10, center=true); }");
|
|
276
|
+
EXPECT_NEAR(totalVolume(e.bodies), kCube - 2 * kSmall, 1e-6) << "vm=" << vm;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
File without changes
|
{openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/.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
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.41.0 → openscad_cpp_evaluator-0.42.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|