openscad-cpp-evaluator 0.42.1__tar.gz → 0.44.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.42.1 → openscad_cpp_evaluator-0.44.0}/CLAUDE.md +28 -7
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/CMakeLists.txt +13 -1
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/bytecode.hpp +15 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -4
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -16
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/evaluator.hpp +53 -33
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/CMakeLists.txt +8 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/booleans.cpp +8 -7
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/control.cpp +5 -4
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/function_builtins.cpp +43 -2
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/bytecode_compiler.cpp +25 -9
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/bytecode_vm.cpp +26 -16
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/csg_resolve.cpp +5 -21
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/eval_context.cpp +28 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/expr_eval.cpp +10 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/user_calls.cpp +104 -9
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/CMakeLists.txt +1 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_bytecode_compiler.cpp +7 -7
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_children_separate.cpp +119 -0
- openscad_cpp_evaluator-0.44.0/tests/test_feature_detection.cpp +161 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_use.cpp +6 -3
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/uv.lock +0 -0
|
@@ -441,6 +441,21 @@ handling in arithmetic, the closure-detection rule for `call_ctx` vs `child_ctx`
|
|
|
441
441
|
verbatim port, not an independent design. Deliberate divergences are called out in code comments —
|
|
442
442
|
grep for `ponytail:`.
|
|
443
443
|
|
|
444
|
+
- **Feature detection** — `$_SUPPORTED_FEATURE` (just `true`; names the CAPABILITY rather than the
|
|
445
|
+
vendor, so any evaluator adding `supported_feature()` is meant to set it, and checking it first
|
|
446
|
+
solves the bootstrapping problem of calling a function you don't know exists. Written
|
|
447
|
+
`!is_undef($_SUPPORTED_FEATURE) && supported_feature(...)` the guard is **silent** in OpenSCAD --
|
|
448
|
+
`is_undef()` is the one way to read an unknown variable there without a warning, and `&&`
|
|
449
|
+
short-circuits past the unknown call; verified against the reference), `$_BELFRYSCAD` (seeded in `EvalContext::makeRoot`, `src/eval_context.cpp`, as
|
|
450
|
+
`[major, minor, patch]` from `OSCAD_EVAL_VERSION_*` compile definitions that the top-level
|
|
451
|
+
`CMakeLists.txt` parses out of `pyproject.toml`, so wheel and local builds cannot disagree and a
|
|
452
|
+
bump needs one edit) and `supported_feature("name")` (`featureLevels()` in
|
|
453
|
+
`src/builtins/function_builtins.cpp`, returning a LEVEL so a feature whose semantics change can
|
|
454
|
+
be told from its earlier self; 0 for unknown names and non-string arguments, deliberately
|
|
455
|
+
silent so probing for a future feature is safe). Both exist because OpenSCAD **silently ignores**
|
|
456
|
+
unknown arguments -- `children(separate=true)` renders the wrong shape there with no warning --
|
|
457
|
+
and both read as `undef` in OpenSCAD, so a guard written against them works in both.
|
|
458
|
+
|
|
444
459
|
- `include/openscad_cpp_evaluator/value.hpp`, `src/value.cpp` — the `Value` variant (OpenSCAD's
|
|
445
460
|
dynamic value type) and its free-function arithmetic/comparison helpers. See the plan's §1 for
|
|
446
461
|
the type-mapping table and why there's no numpy-equivalent library.
|
|
@@ -481,13 +496,19 @@ grep for `ponytail:`.
|
|
|
481
496
|
lexically nested inside an already-active call," picking `childCtx()` vs `callCtx()`
|
|
482
497
|
accordingly; read its doc comment before touching it, it's the second-trickiest mechanism in this
|
|
483
498
|
codebase after the CSG tree stack), `evalUserModule`/`evalUserFunction`/`evalFunctionLiteral`,
|
|
484
|
-
and `builtinChildren` (children()/children(N), deferred evaluation
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
children
|
|
499
|
+
and `builtinChildren` (children()/children(N), deferred evaluation).
|
|
500
|
+
**`children(..., separate=true)`** is a BelfrySCAD extension handled *before* any of that, by
|
|
501
|
+
`expandChildStatements`: a block is read with each separating forward replaced by one synthetic
|
|
502
|
+
`children(k)` statement per child it selects (`makeChildrenIndexCall`, owned by
|
|
503
|
+
`syntheticNodes_` and cleared with `idToNode` at `resolveTreeImpl` entry). Everything the
|
|
504
|
+
feature does follows from their being real statements -- `$children` counts them,
|
|
505
|
+
`children(i)` indexes them, and `union`/`difference`/`intersection` give each its own operand
|
|
506
|
+
group -- with no flag on `CSGNode` and nothing to leak. Called from `buildModuleChildCtx`,
|
|
507
|
+
`resolveCsg`, `resolveIntersectionFor`, and the VM's `Op::CsgGroupChildren`, which exists
|
|
508
|
+
because the compiler fixes group boundaries long before `$children` (and so the expansion size)
|
|
509
|
+
is knowable; it shares `expandSeparatingChildren` with the interpreter so the engines cannot
|
|
510
|
+
drift. Synthetic calls carry the author's own `Position` and no scope, so they resolve in the
|
|
511
|
+
evaluating context (`evalChildren`'s `runAll`). `evalFunctionCall`'s
|
|
491
512
|
precedence order (checked in this exact sequence): `import` (special-cased, its own
|
|
492
513
|
module/expression-context split) → `isBuiltinFunctionName` (function_builtins.hpp — always wins
|
|
493
514
|
if true) → user function lookup → function-literal *value* probe → "unknown function" warning.
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.24)
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
# Read the version straight out of pyproject.toml rather than repeating it
|
|
4
|
+
# here. It reaches C++ as OSCAD_EVAL_VERSION_{MAJOR,MINOR,PATCH} (see
|
|
5
|
+
# src/CMakeLists.txt), which is what seeds $_BELFRYSCAD -- so a released
|
|
6
|
+
# wheel and a local `cmake --build` always report the same numbers, and a
|
|
7
|
+
# version bump needs one edit, not three.
|
|
8
|
+
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml" _oscad_pyproject)
|
|
9
|
+
if(NOT _oscad_pyproject MATCHES "\nversion = \"([0-9]+)\.([0-9]+)\.([0-9]+)\"")
|
|
10
|
+
message(FATAL_ERROR "could not read version = \"X.Y.Z\" from pyproject.toml")
|
|
11
|
+
endif()
|
|
12
|
+
set(OSCAD_EVAL_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
|
|
13
|
+
|
|
14
|
+
project(openscad_cpp_evaluator VERSION ${OSCAD_EVAL_VERSION} LANGUAGES CXX)
|
|
3
15
|
|
|
4
16
|
# On Apple Silicon, warn (don't fail -- a universal or intentionally-x86_64
|
|
5
17
|
# build is legitimate) if the effective target architecture is x86_64 while
|
|
@@ -426,6 +426,21 @@ enum class Op {
|
|
|
426
426
|
// own `groupSizes.push_back(Value{...})` loop.
|
|
427
427
|
CsgGroupEnd,
|
|
428
428
|
|
|
429
|
+
// One `children(..., separate=true)` statement inside a CSG bracket.
|
|
430
|
+
// `a` interns the ModularCall in nativeStatements.
|
|
431
|
+
//
|
|
432
|
+
// A statement of its own, rather than a CsgGroupStart/End pair around
|
|
433
|
+
// compiled code, because how many groups it contributes is only known
|
|
434
|
+
// at RUNTIME -- `children([2:$children-1], separate=true)` reads
|
|
435
|
+
// $children, and the compiler emits its group boundaries long before
|
|
436
|
+
// any of that exists. So this op expands the call (the same
|
|
437
|
+
// Evaluator::expandSeparatingChildren the interpreter uses, so the two
|
|
438
|
+
// engines cannot drift) and records one group per expanded statement.
|
|
439
|
+
//
|
|
440
|
+
// Not an interpreter bail: the forwarded statements go through
|
|
441
|
+
// evalChildren, which self-gates and retries its own compiled chunks.
|
|
442
|
+
CsgGroupChildren,
|
|
443
|
+
|
|
429
444
|
// Closes the matching Op::PushCsgWrap bracket: pops
|
|
430
445
|
// VmFrame::csgWrapStack's own top entry FIRST (before anything that can
|
|
431
446
|
// itself throw, e.g. setTreeDepthOrThrow below -- same "exception-
|
|
@@ -219,10 +219,6 @@ 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;
|
|
226
222
|
|
|
227
223
|
// Whether callStack_.back() (at push time) genuinely IS this frame's
|
|
228
224
|
// own logical call, and therefore safe for a tail hop inside this
|
|
@@ -34,15 +34,6 @@ 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
38
|
// The call site that entered this node's call chain from the top
|
|
48
39
|
// level, captured at RESOLVE time -- non-owning, AST-lifetime-bound
|
|
@@ -83,12 +74,5 @@ struct CSGNode {
|
|
|
83
74
|
std::optional<std::string> cachedKey;
|
|
84
75
|
};
|
|
85
76
|
|
|
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
77
|
|
|
94
78
|
} // namespace oscadeval
|
|
@@ -190,29 +190,6 @@ 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
194
|
// Generate pass: walks `tree` bottom-up (children before their own
|
|
218
195
|
// node), calling each node's registered GenerateFn (falling back to
|
|
@@ -366,14 +343,56 @@ public:
|
|
|
366
343
|
struct ChildrenForward {
|
|
367
344
|
EvalContext evalCtx;
|
|
368
345
|
std::vector<const oscad::ASTNode*> nodes;
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
346
|
+
// The `separate` flag as written at the call. Read by
|
|
347
|
+
// expandSeparatingChildren, which turns the forward into one
|
|
348
|
+
// statement per child; builtinChildren itself ignores it, since by
|
|
349
|
+
// the time a forward runs the expansion has already happened.
|
|
373
350
|
bool separate = false;
|
|
351
|
+
// Which of the caller's geometry statements `nodes` came from, in
|
|
352
|
+
// the same order. Needed by expandChildStatements, which turns each
|
|
353
|
+
// one back into its own `children(k)` statement.
|
|
354
|
+
std::vector<size_t> pickedIndices;
|
|
374
355
|
};
|
|
375
356
|
std::optional<ChildrenForward> prepareChildrenForward(const CallArgs& args, EvalContext& ctx);
|
|
376
357
|
|
|
358
|
+
// A child-statement block with every `children(..., separate=true)`
|
|
359
|
+
// replaced by one synthetic `children(k)` statement per child it
|
|
360
|
+
// selects. That is the whole of what separate=true does: the forwarded
|
|
361
|
+
// children become real, countable statements at this call site, so
|
|
362
|
+
// $children sees them, children(i) indexes them, and a boolean operator
|
|
363
|
+
// gives each its own operand group -- all for free, because they ARE
|
|
364
|
+
// statements rather than nodes wearing a flag.
|
|
365
|
+
//
|
|
366
|
+
// Called wherever a block is consumed: a module call's children
|
|
367
|
+
// (buildModuleChildCtx), and union/difference/intersection/
|
|
368
|
+
// intersection_for's own child list.
|
|
369
|
+
std::vector<const oscad::ASTNode*> expandChildStatements(
|
|
370
|
+
const std::vector<std::unique_ptr<oscad::ASTNode>>& block, EvalContext& ctx);
|
|
371
|
+
|
|
372
|
+
// One synthetic `children(index)` statement, owned by syntheticNodes_.
|
|
373
|
+
const oscad::ASTNode* makeChildrenIndexCall(const oscad::ModularCall& origin, size_t index);
|
|
374
|
+
|
|
375
|
+
// The sole argument of `is_undef(x)` when x is a bare identifier, else
|
|
376
|
+
// nullptr. That call is a PROBE -- asking whether a name is defined must
|
|
377
|
+
// not itself complain that it isn't -- so the name is read with
|
|
378
|
+
// warnIfUndef=false. Static and syntactic so the bytecode compiler can
|
|
379
|
+
// ask at compile time and emit LoadFreeNoWarn.
|
|
380
|
+
static const oscad::Identifier* undefProbeTarget(const oscad::PrimaryCall& call);
|
|
381
|
+
|
|
382
|
+
// Syntactic gate: is this statement a `children(..., separate=true)`?
|
|
383
|
+
// Cheap and side-effect-free, so the bytecode compiler can ask it at
|
|
384
|
+
// COMPILE time to decide which opcode to emit, long before the flag's
|
|
385
|
+
// value (or the child count it selects) is knowable.
|
|
386
|
+
static bool isSeparatingChildrenCall(const oscad::ASTNode& stmt);
|
|
387
|
+
|
|
388
|
+
// The runtime half: the statements `call` expands to. nullopt means the
|
|
389
|
+
// `separate` flag resolved falsey after all, and the caller should run
|
|
390
|
+
// the original statement unchanged. Shared by expandChildStatements
|
|
391
|
+
// (interpreter) and Op::CsgGroupChildren (VM) so the engines cannot
|
|
392
|
+
// drift on what expansion means.
|
|
393
|
+
std::optional<std::vector<const oscad::ASTNode*>> expandSeparatingChildren(const oscad::ModularCall& call,
|
|
394
|
+
EvalContext& ctx);
|
|
395
|
+
|
|
377
396
|
// "WARNING: {message}{locSuffix(position)}" via echoFn_, no-op if unset.
|
|
378
397
|
// Public: builtins/import.cpp's not-manifold warning is emitted from a
|
|
379
398
|
// free function, same reasoning as tagGenerated()/builtinChildren().
|
|
@@ -999,13 +1018,8 @@ public:
|
|
|
999
1018
|
// (evalModularCall's OWN "is this splice or wrap-as-a-tagged-node"
|
|
1000
1019
|
// branch already decided `splice` before ever reaching a user module,
|
|
1001
1020
|
// so this helper never needs that decision itself).
|
|
1002
|
-
// `honorSeparateMarks` is true only for a children() call's OWN splice.
|
|
1003
|
-
// A user module's splice passes false, so it wraps its marked children
|
|
1004
|
-
// as usual and the marks stop there -- children(separate=true) applies
|
|
1005
|
-
// to the operator enclosing that call, not to whatever encloses the
|
|
1006
|
-
// module the call happens to sit in.
|
|
1007
1021
|
void spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> children, std::uint64_t randsBefore,
|
|
1008
|
-
const oscad::ASTNode& callNode
|
|
1022
|
+
const oscad::ASTNode& callNode);
|
|
1009
1023
|
private:
|
|
1010
1024
|
Value evalUserFunction(const std::string& name, const oscad::FunctionDeclaration& decl,
|
|
1011
1025
|
const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx,
|
|
@@ -1661,6 +1675,12 @@ public:
|
|
|
1661
1675
|
// is on top *at that moment* -- the frame this node's own build call
|
|
1662
1676
|
// pushed just before resolving. See csg_resolve.cpp for the full
|
|
1663
1677
|
// push/call/pop sequence.
|
|
1678
|
+
// Synthetic `children(k)` calls built by expandChildStatements. Owned
|
|
1679
|
+
// here because CSGNode::node and idToNode hold non-owning pointers into
|
|
1680
|
+
// them, so they must outlive the pass; cleared with those maps at
|
|
1681
|
+
// resolveTreeImpl entry.
|
|
1682
|
+
std::vector<std::unique_ptr<oscad::ASTNode>> syntheticNodes_;
|
|
1683
|
+
|
|
1664
1684
|
std::vector<std::vector<std::unique_ptr<CSGNode>>> treeStack_;
|
|
1665
1685
|
|
|
1666
1686
|
private:
|
|
@@ -46,6 +46,14 @@ add_library(openscad_cpp_evaluator STATIC
|
|
|
46
46
|
builtins/surface.cpp
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
+
# Seeds $_BELFRYSCAD (eval_context.cpp). Parsed from pyproject.toml by the
|
|
50
|
+
# top-level CMakeLists so there is one source of truth for the version.
|
|
51
|
+
target_compile_definitions(openscad_cpp_evaluator PRIVATE
|
|
52
|
+
OSCAD_EVAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}
|
|
53
|
+
OSCAD_EVAL_VERSION_MINOR=${PROJECT_VERSION_MINOR}
|
|
54
|
+
OSCAD_EVAL_VERSION_PATCH=${PROJECT_VERSION_PATCH}
|
|
55
|
+
)
|
|
56
|
+
|
|
49
57
|
target_include_directories(openscad_cpp_evaluator PUBLIC
|
|
50
58
|
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
|
|
51
59
|
)
|
|
@@ -70,10 +70,11 @@ std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBo
|
|
|
70
70
|
// misbehave when e.g. BOSL2's attachable() returns multiple bodies (parent
|
|
71
71
|
// + attached children) as one operand.
|
|
72
72
|
//
|
|
73
|
-
// One statement can
|
|
74
|
-
//
|
|
73
|
+
// One statement can still turn into several: children(separate=true) is
|
|
74
|
+
// expanded into one `children(k)` statement per child it forwards, before
|
|
75
|
+
// this loop ever sees the block (Evaluator::expandChildStatements), which is
|
|
75
76
|
// how `difference() children(separate=true)` subtracts children 1..n from
|
|
76
|
-
// child 0.
|
|
77
|
+
// child 0. Nothing special happens here -- they are simply statements. Mirrors _resolve_csg/_generate_csg,
|
|
77
78
|
// minus _attach_tri_colors' multi-color-merge provenance (ponytail: a
|
|
78
79
|
// merged body always takes its first contributing child's color, matching
|
|
79
80
|
// this evaluator's own pre-tri_colors baseline behavior -- revisit
|
|
@@ -92,11 +93,11 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
|
|
|
92
93
|
|
|
93
94
|
std::vector<const oscad::ASTNode*> assignNodes;
|
|
94
95
|
std::vector<const oscad::ASTNode*> geoNodes;
|
|
95
|
-
for (const
|
|
96
|
+
for (const oscad::ASTNode* c : ev.expandChildStatements(node.children, effCtx)) {
|
|
96
97
|
if (c->kind() == oscad::NodeKind::Assignment) {
|
|
97
|
-
assignNodes.push_back(c
|
|
98
|
+
assignNodes.push_back(c);
|
|
98
99
|
} else if (c->kind() != oscad::NodeKind::ModuleDeclaration && c->kind() != oscad::NodeKind::FunctionDeclaration) {
|
|
99
|
-
geoNodes.push_back(c
|
|
100
|
+
geoNodes.push_back(c);
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
if (!assignNodes.empty()) ev.evalChildren(assignNodes, effCtx);
|
|
@@ -106,7 +107,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
|
|
|
106
107
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
107
108
|
const size_t before = ev.currentTreeFrameSize();
|
|
108
109
|
ev.evalChildren(std::vector<const oscad::ASTNode*>{geoNode}, effCtx);
|
|
109
|
-
ev.
|
|
110
|
+
groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
CSGParams params;
|
|
@@ -97,9 +97,10 @@ ColoredBody combineBodies(const std::vector<ColoredBody>& bodies) {
|
|
|
97
97
|
// children) -- same rationale as booleans.cpp's own group_sizes. Mirrors
|
|
98
98
|
// _resolve_intersection_for/_generate_intersection_for.
|
|
99
99
|
CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersectionFor& node, EvalContext& ctx) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
// Expanded for the same reason resolveCsg expands its own block: a
|
|
101
|
+
// children(..., separate=true) here contributes one statement -- and so
|
|
102
|
+
// one operand group per iteration -- per child it selects.
|
|
103
|
+
const std::vector<const oscad::ASTNode*> bodyNodes = ev.expandChildStatements(node.body, ctx);
|
|
103
104
|
|
|
104
105
|
std::vector<Value> groupSizes;
|
|
105
106
|
|
|
@@ -119,7 +120,7 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
119
120
|
if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
120
121
|
const size_t before = ev.currentTreeFrameSize();
|
|
121
122
|
ev.evalChildren(bodyNodes, parentCtx);
|
|
122
|
-
ev.
|
|
123
|
+
groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
|
|
123
124
|
return;
|
|
124
125
|
}
|
|
125
126
|
const auto& assign = node.assignments[depth];
|
{openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.44.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -449,7 +449,7 @@ bool isBuiltinFunctionName(const std::string& name) {
|
|
|
449
449
|
"acos", "atan", "atan2", "max", "min", "pow", "norm", "cross", "rands", "concat", "len", "str",
|
|
450
450
|
"chr", "ord", "is_undef", "is_num", "is_bool", "is_string", "is_list", "is_function", "is_object",
|
|
451
451
|
"search", "lookup", "has_key", "version", "version_num", "parent_module",
|
|
452
|
-
"object", "textmetrics", "fontmetrics", "dxf_dim", "dxf_cross",
|
|
452
|
+
"object", "textmetrics", "fontmetrics", "dxf_dim", "dxf_cross", "supported_feature",
|
|
453
453
|
};
|
|
454
454
|
return names.count(name) > 0;
|
|
455
455
|
}
|
|
@@ -591,9 +591,37 @@ enum class BuiltinFnId {
|
|
|
591
591
|
TextMetrics, FontMetrics, Abs, Sign, Ceil, Floor, Round, Sqrt, Ln, Log, Exp, Sin, Cos, Tan,
|
|
592
592
|
Asin, Acos, Atan, Atan2, Max, Min, Pow, Norm, Cross, Rands, Concat, Len, Str, Chr, Ord,
|
|
593
593
|
IsUndef, IsNum, IsBool, IsString, IsList, IsFunction, IsObject, Search, Lookup, HasKey,
|
|
594
|
-
Version, VersionNum, ParentModule, DxfDim, DxfCross,
|
|
594
|
+
Version, VersionNum, ParentModule, DxfDim, DxfCross, SupportedFeature,
|
|
595
595
|
};
|
|
596
596
|
|
|
597
|
+
// supported_feature("name") -> the level at which this build implements that
|
|
598
|
+
// feature, or 0 for one it does not implement (and for a name it has never
|
|
599
|
+
// heard of, which is deliberate: probing for a feature from a future release
|
|
600
|
+
// is supposed to be safe).
|
|
601
|
+
//
|
|
602
|
+
// A LEVEL rather than a boolean so a feature whose semantics change later
|
|
603
|
+
// can be told apart from its earlier self. Everything here is 1 today;
|
|
604
|
+
// nothing has changed since this function existed, and a script cannot
|
|
605
|
+
// observe what a build without supported_feature() did anyway.
|
|
606
|
+
//
|
|
607
|
+
// This is the answer to a real hazard: OpenSCAD does not reject arguments or
|
|
608
|
+
// names it doesn't know -- children(separate=true) is silently ignored there
|
|
609
|
+
// -- so a script using an extension runs and quietly renders something else.
|
|
610
|
+
// Guarding on supported_feature() is how a script says so out loud.
|
|
611
|
+
const std::unordered_map<std::string, double>& featureLevels() {
|
|
612
|
+
static const std::unordered_map<std::string, double> levels = {
|
|
613
|
+
{"separate-children", 1.0}, // children(..., separate=true)
|
|
614
|
+
{"minkowski-diff", 1.0}, // minkowski_difference()
|
|
615
|
+
{"sphere-styles", 1.0}, // sphere(style=)
|
|
616
|
+
{"export-name", 1.0}, // $export_name
|
|
617
|
+
{"simplify-op", 1.0}, // simplify()
|
|
618
|
+
{"expr-import", 1.0}, // import() in expression position
|
|
619
|
+
{"object-function", 1.0}, // object(), unconditional here
|
|
620
|
+
{"roof-op", 1.0}, // roof(), method="voronoi" only
|
|
621
|
+
};
|
|
622
|
+
return levels;
|
|
623
|
+
}
|
|
624
|
+
|
|
597
625
|
const std::unordered_map<std::string, BuiltinFnId>& builtinFnIds() {
|
|
598
626
|
static const std::unordered_map<std::string, BuiltinFnId> ids = {
|
|
599
627
|
{"textmetrics", BuiltinFnId::TextMetrics}, {"fontmetrics", BuiltinFnId::FontMetrics},
|
|
@@ -614,6 +642,7 @@ const std::unordered_map<std::string, BuiltinFnId>& builtinFnIds() {
|
|
|
614
642
|
{"version", BuiltinFnId::Version}, {"version_num", BuiltinFnId::VersionNum},
|
|
615
643
|
{"parent_module", BuiltinFnId::ParentModule},
|
|
616
644
|
{"dxf_dim", BuiltinFnId::DxfDim}, {"dxf_cross", BuiltinFnId::DxfCross},
|
|
645
|
+
{"supported_feature", BuiltinFnId::SupportedFeature},
|
|
617
646
|
};
|
|
618
647
|
return ids;
|
|
619
648
|
}
|
|
@@ -694,6 +723,7 @@ const std::unordered_map<int, BuiltinCheck>& builtinChecks() {
|
|
|
694
723
|
// warning, so only the too-many case is an arity error.
|
|
695
724
|
add(BuiltinFnId::ParentModule, {0, 1, "1", {kNum}});
|
|
696
725
|
add(BuiltinFnId::HasKey, {-1, -1, nullptr, {{TObj, "object"}, {TStr, "string"}}});
|
|
726
|
+
add(BuiltinFnId::SupportedFeature, {1, 1, "1", {}});
|
|
697
727
|
for (BuiltinFnId id : {BuiltinFnId::IsUndef, BuiltinFnId::IsNum, BuiltinFnId::IsBool,
|
|
698
728
|
BuiltinFnId::IsString, BuiltinFnId::IsList, BuiltinFnId::IsFunction,
|
|
699
729
|
BuiltinFnId::IsObject}) {
|
|
@@ -1008,6 +1038,17 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
|
|
|
1008
1038
|
// The OpenSCAD release we track. version_num() is that same
|
|
1009
1039
|
// year/month/day folded as y * 10000 + m * 100 + d, exactly like the
|
|
1010
1040
|
// reference's own builtin_version_num (builtin_functions.cc).
|
|
1041
|
+
case BuiltinFnId::SupportedFeature: {
|
|
1042
|
+
const Value name = getArg(args, 0, "feature", Value{});
|
|
1043
|
+
const std::string* s = std::get_if<std::string>(&name);
|
|
1044
|
+
// A non-string is 0 rather than an error, same as an unknown
|
|
1045
|
+
// name: the whole point of this function is that asking is
|
|
1046
|
+
// always safe.
|
|
1047
|
+
if (!s) return Value{0.0};
|
|
1048
|
+
const auto& levels = featureLevels();
|
|
1049
|
+
const auto it = levels.find(*s);
|
|
1050
|
+
return Value{it == levels.end() ? 0.0 : it->second};
|
|
1051
|
+
}
|
|
1011
1052
|
case BuiltinFnId::Version: return numList({2026.0, 1.0, 1.0});
|
|
1012
1053
|
case BuiltinFnId::VersionNum: {
|
|
1013
1054
|
// The optional vector argument the reference also accepts: with
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "openscad_cpp_evaluator/call_args.hpp"
|
|
4
4
|
#include "openscad_cpp_evaluator/dispatch.hpp"
|
|
5
|
+
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
5
6
|
#include "openscad_cpp_evaluator/function_builtins.hpp"
|
|
6
7
|
|
|
7
8
|
#include "builtins/builtins.hpp"
|
|
@@ -619,15 +620,24 @@ public:
|
|
|
619
620
|
}
|
|
620
621
|
}
|
|
621
622
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
623
|
+
// is_undef(name) probes rather than reads -- the same quiet
|
|
624
|
+
// load the interpreter uses (Evaluator::undefProbeTarget),
|
|
625
|
+
// so the two engines agree on which reads warn.
|
|
626
|
+
if (const oscad::Identifier* undefProbe = Evaluator::undefProbeTarget(n)) {
|
|
627
|
+
compileIdentifierLoad(undefProbe->name, undefProbe->position(), out, scope,
|
|
628
|
+
/*warnIfUndef=*/false);
|
|
629
|
+
site.argNames.push_back(std::nullopt);
|
|
630
|
+
} else {
|
|
631
|
+
for (const auto& argPtr : n.arguments) {
|
|
632
|
+
if (argPtr->kind() == NodeKind::NamedArgument) {
|
|
633
|
+
auto& a = static_cast<const oscad::NamedArgument&>(*argPtr);
|
|
634
|
+
compileExpr(*a.expr, out, scope); // an argument is never tail
|
|
635
|
+
site.argNames.push_back(a.name->name);
|
|
636
|
+
} else {
|
|
637
|
+
auto& a = static_cast<const oscad::PositionalArgument&>(*argPtr);
|
|
638
|
+
compileExpr(*a.expr, out, scope);
|
|
639
|
+
site.argNames.push_back(std::nullopt);
|
|
640
|
+
}
|
|
631
641
|
}
|
|
632
642
|
}
|
|
633
643
|
int siteIdx = static_cast<int>(chunk_.callSites.size());
|
|
@@ -1292,6 +1302,12 @@ public:
|
|
|
1292
1302
|
}
|
|
1293
1303
|
compileStatementList(assignNodes, out);
|
|
1294
1304
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
1305
|
+
// A separating children() forward contributes a runtime-decided
|
|
1306
|
+
// NUMBER of groups, so it cannot be bracketed at compile time.
|
|
1307
|
+
if (Evaluator::isSeparatingChildrenCall(*geoNode)) {
|
|
1308
|
+
out.push_back({Op::CsgGroupChildren, internNativeStatement(geoNode), 0, &geoNode->position()});
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1295
1311
|
out.push_back({Op::CsgGroupStart, 0, 0, nullptr});
|
|
1296
1312
|
compileStatementList(std::vector<const oscad::ASTNode*>{geoNode}, out);
|
|
1297
1313
|
out.push_back({Op::CsgGroupEnd, 0, 0, nullptr});
|
|
@@ -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) {
|
|
364
364
|
if (ev.vmCallStack_.size() >= Evaluator::kMaxVmCallStackDepth) {
|
|
365
365
|
ev.error("Recursion too deep while forwarding children()", callNode);
|
|
366
366
|
}
|
|
@@ -381,7 +381,6 @@ 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;
|
|
385
384
|
ev.vmCallStack_.push_back(std::move(frame));
|
|
386
385
|
ev.vmCallBrackets_.emplace_back(std::nullopt);
|
|
387
386
|
}
|
|
@@ -506,7 +505,6 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
506
505
|
const bool ownsModuleSplice = finished->ownsModuleSplice;
|
|
507
506
|
const std::uint64_t moduleRandsBefore = finished->moduleRandsBefore;
|
|
508
507
|
const oscad::ASTNode* moduleSpliceCallNode = finished->moduleSpliceCallNode;
|
|
509
|
-
const bool separateChildren = finished->separateChildren;
|
|
510
508
|
while (!finished->ctxChain.empty()) finished->ctxChain.pop_back();
|
|
511
509
|
// Module frames never fire returnHook (native evalUserModule
|
|
512
510
|
// never did either -- a module call has no "return value"
|
|
@@ -516,12 +514,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
516
514
|
if (isModule && ownsModuleSplice) {
|
|
517
515
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
518
516
|
ev.treeStack_.pop_back();
|
|
519
|
-
|
|
520
|
-
// so it also answers "is this a children() splice?" -- a
|
|
521
|
-
// user module's frame always passes false and wraps.
|
|
522
|
-
if (separateChildren) markSeparateOperands(children, 0);
|
|
523
|
-
ev.spliceModuleChildren(std::move(children), moduleRandsBefore, *moduleSpliceCallNode,
|
|
524
|
-
/*honorSeparateMarks=*/separateChildren);
|
|
517
|
+
ev.spliceModuleChildren(std::move(children), moduleRandsBefore, *moduleSpliceCallNode);
|
|
525
518
|
}
|
|
526
519
|
if (isFloorFrame) {
|
|
527
520
|
finalResult = std::move(result); // unused by a module caller (runCompiledModuleBody ignores it)
|
|
@@ -1051,11 +1044,9 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1051
1044
|
const CompiledChunk* chunk = (ev.useBytecodeVm() && ev.inResolvePass())
|
|
1052
1045
|
? ev.lookupOrCompileChildrenListChunk(fwd->nodes)
|
|
1053
1046
|
: nullptr;
|
|
1054
|
-
// Read before fwd->evalCtx is moved from.
|
|
1055
|
-
const bool separate = fwd->separate;
|
|
1056
1047
|
if (chunk) {
|
|
1057
1048
|
ev.treeStack_.emplace_back();
|
|
1058
|
-
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode
|
|
1049
|
+
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode);
|
|
1059
1050
|
// f.pc deliberately NOT advanced -- resumes when
|
|
1060
1051
|
// the pushed frame completes; driveVm's completion
|
|
1061
1052
|
// branch runs the splice (isModule &&
|
|
@@ -1079,9 +1070,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1079
1070
|
}
|
|
1080
1071
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
1081
1072
|
ev.treeStack_.pop_back();
|
|
1082
|
-
|
|
1083
|
-
ev.spliceModuleChildren(std::move(children), randsBefore, *callNode,
|
|
1084
|
-
/*honorSeparateMarks=*/true);
|
|
1073
|
+
ev.spliceModuleChildren(std::move(children), randsBefore, *callNode);
|
|
1085
1074
|
++f.pc;
|
|
1086
1075
|
}
|
|
1087
1076
|
break;
|
|
@@ -1318,9 +1307,30 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1318
1307
|
++f.pc;
|
|
1319
1308
|
break;
|
|
1320
1309
|
}
|
|
1310
|
+
case Op::CsgGroupChildren: {
|
|
1311
|
+
const auto& call =
|
|
1312
|
+
static_cast<const oscad::ModularCall&>(*f.chunk->nativeStatements[static_cast<size_t>(ins.a)]);
|
|
1313
|
+
PendingCsgWrap& pending = f.csgWrapStack.back();
|
|
1314
|
+
std::optional<std::vector<const oscad::ASTNode*>> expanded =
|
|
1315
|
+
ev.expandSeparatingChildren(call, ctx);
|
|
1316
|
+
// nullopt = `separate` resolved falsey: one group, the
|
|
1317
|
+
// original statement, exactly as CsgGroupStart/End would
|
|
1318
|
+
// have done for it.
|
|
1319
|
+
const std::vector<const oscad::ASTNode*> stmts =
|
|
1320
|
+
expanded ? *expanded : std::vector<const oscad::ASTNode*>{&call};
|
|
1321
|
+
for (const oscad::ASTNode* stmt : stmts) {
|
|
1322
|
+
const size_t before = ev.treeStack_.back().size();
|
|
1323
|
+
ev.evalChildren(std::vector<const oscad::ASTNode*>{stmt}, ctx);
|
|
1324
|
+
pending.groupSizes.push_back(
|
|
1325
|
+
Value{static_cast<double>(ev.treeStack_.back().size() - before)});
|
|
1326
|
+
}
|
|
1327
|
+
++f.pc;
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1321
1330
|
case Op::CsgGroupEnd: {
|
|
1322
1331
|
PendingCsgWrap& pending = f.csgWrapStack.back();
|
|
1323
|
-
ev.
|
|
1332
|
+
const size_t after = ev.treeStack_.back().size();
|
|
1333
|
+
pending.groupSizes.push_back(Value{static_cast<double>(after - pending.groupStartSize)});
|
|
1324
1334
|
++f.pc;
|
|
1325
1335
|
break;
|
|
1326
1336
|
}
|