openscad-cpp-evaluator 0.42.1__tar.gz → 0.43.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.43.0}/CLAUDE.md +13 -7
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/bytecode.hpp +15 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -4
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -16
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/evaluator.hpp +46 -33
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/booleans.cpp +8 -7
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/control.cpp +5 -4
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/bytecode_compiler.cpp +7 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/bytecode_vm.cpp +26 -16
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/csg_resolve.cpp +5 -21
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/user_calls.cpp +94 -9
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_children_separate.cpp +119 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.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.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.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.43.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.43.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.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.42.1 → openscad_cpp_evaluator-0.43.0}/uv.lock +0 -0
|
@@ -481,13 +481,19 @@ 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
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
children
|
|
484
|
+
and `builtinChildren` (children()/children(N), deferred evaluation).
|
|
485
|
+
**`children(..., separate=true)`** is a BelfrySCAD extension handled *before* any of that, by
|
|
486
|
+
`expandChildStatements`: a block is read with each separating forward replaced by one synthetic
|
|
487
|
+
`children(k)` statement per child it selects (`makeChildrenIndexCall`, owned by
|
|
488
|
+
`syntheticNodes_` and cleared with `idToNode` at `resolveTreeImpl` entry). Everything the
|
|
489
|
+
feature does follows from their being real statements -- `$children` counts them,
|
|
490
|
+
`children(i)` indexes them, and `union`/`difference`/`intersection` give each its own operand
|
|
491
|
+
group -- with no flag on `CSGNode` and nothing to leak. Called from `buildModuleChildCtx`,
|
|
492
|
+
`resolveCsg`, `resolveIntersectionFor`, and the VM's `Op::CsgGroupChildren`, which exists
|
|
493
|
+
because the compiler fixes group boundaries long before `$children` (and so the expansion size)
|
|
494
|
+
is knowable; it shares `expandSeparatingChildren` with the interpreter so the engines cannot
|
|
495
|
+
drift. Synthetic calls carry the author's own `Position` and no scope, so they resolve in the
|
|
496
|
+
evaluating context (`evalChildren`'s `runAll`). `evalFunctionCall`'s
|
|
491
497
|
precedence order (checked in this exact sequence): `import` (special-cased, its own
|
|
492
498
|
module/expression-context split) → `isBuiltinFunctionName` (function_builtins.hpp — always wins
|
|
493
499
|
if true) → user function lookup → function-literal *value* probe → "unknown function" warning.
|
|
@@ -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,49 @@ 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
|
+
// Syntactic gate: is this statement a `children(..., separate=true)`?
|
|
376
|
+
// Cheap and side-effect-free, so the bytecode compiler can ask it at
|
|
377
|
+
// COMPILE time to decide which opcode to emit, long before the flag's
|
|
378
|
+
// value (or the child count it selects) is knowable.
|
|
379
|
+
static bool isSeparatingChildrenCall(const oscad::ASTNode& stmt);
|
|
380
|
+
|
|
381
|
+
// The runtime half: the statements `call` expands to. nullopt means the
|
|
382
|
+
// `separate` flag resolved falsey after all, and the caller should run
|
|
383
|
+
// the original statement unchanged. Shared by expandChildStatements
|
|
384
|
+
// (interpreter) and Op::CsgGroupChildren (VM) so the engines cannot
|
|
385
|
+
// drift on what expansion means.
|
|
386
|
+
std::optional<std::vector<const oscad::ASTNode*>> expandSeparatingChildren(const oscad::ModularCall& call,
|
|
387
|
+
EvalContext& ctx);
|
|
388
|
+
|
|
377
389
|
// "WARNING: {message}{locSuffix(position)}" via echoFn_, no-op if unset.
|
|
378
390
|
// Public: builtins/import.cpp's not-manifold warning is emitted from a
|
|
379
391
|
// free function, same reasoning as tagGenerated()/builtinChildren().
|
|
@@ -999,13 +1011,8 @@ public:
|
|
|
999
1011
|
// (evalModularCall's OWN "is this splice or wrap-as-a-tagged-node"
|
|
1000
1012
|
// branch already decided `splice` before ever reaching a user module,
|
|
1001
1013
|
// 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
1014
|
void spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> children, std::uint64_t randsBefore,
|
|
1008
|
-
const oscad::ASTNode& callNode
|
|
1015
|
+
const oscad::ASTNode& callNode);
|
|
1009
1016
|
private:
|
|
1010
1017
|
Value evalUserFunction(const std::string& name, const oscad::FunctionDeclaration& decl,
|
|
1011
1018
|
const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx,
|
|
@@ -1661,6 +1668,12 @@ public:
|
|
|
1661
1668
|
// is on top *at that moment* -- the frame this node's own build call
|
|
1662
1669
|
// pushed just before resolving. See csg_resolve.cpp for the full
|
|
1663
1670
|
// push/call/pop sequence.
|
|
1671
|
+
// Synthetic `children(k)` calls built by expandChildStatements. Owned
|
|
1672
|
+
// here because CSGNode::node and idToNode hold non-owning pointers into
|
|
1673
|
+
// them, so they must outlive the pass; cleared with those maps at
|
|
1674
|
+
// resolveTreeImpl entry.
|
|
1675
|
+
std::vector<std::unique_ptr<oscad::ASTNode>> syntheticNodes_;
|
|
1676
|
+
|
|
1664
1677
|
std::vector<std::vector<std::unique_ptr<CSGNode>>> treeStack_;
|
|
1665
1678
|
|
|
1666
1679
|
private:
|
|
@@ -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];
|
|
@@ -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"
|
|
@@ -1292,6 +1293,12 @@ public:
|
|
|
1292
1293
|
}
|
|
1293
1294
|
compileStatementList(assignNodes, out);
|
|
1294
1295
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
1296
|
+
// A separating children() forward contributes a runtime-decided
|
|
1297
|
+
// NUMBER of groups, so it cannot be bracketed at compile time.
|
|
1298
|
+
if (Evaluator::isSeparatingChildrenCall(*geoNode)) {
|
|
1299
|
+
out.push_back({Op::CsgGroupChildren, internNativeStatement(geoNode), 0, &geoNode->position()});
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1295
1302
|
out.push_back({Op::CsgGroupStart, 0, 0, nullptr});
|
|
1296
1303
|
compileStatementList(std::vector<const oscad::ASTNode*>{geoNode}, out);
|
|
1297
1304
|
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
|
}
|
|
@@ -126,10 +126,9 @@ void Evaluator::evalModularCall(const oscad::ModularCall& node, EvalContext& ctx
|
|
|
126
126
|
// under a synthetic (display-only, is_builtin=false) "union" node so
|
|
127
127
|
// the tree still reads as one shape at this call site. Mirrors
|
|
128
128
|
// _eval_statement's splice branch exactly.
|
|
129
|
-
const bool
|
|
130
|
-
const bool splice = isChildrenCall || !isBuiltin;
|
|
129
|
+
const bool splice = (name == "children" && isBuiltin) || !isBuiltin;
|
|
131
130
|
if (splice) {
|
|
132
|
-
spliceModuleChildren(std::move(children), randsBefore, node
|
|
131
|
+
spliceModuleChildren(std::move(children), randsBefore, node);
|
|
133
132
|
return;
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -148,7 +147,7 @@ void Evaluator::evalModularCall(const oscad::ModularCall& node, EvalContext& ctx
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
void Evaluator::spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> children, std::uint64_t randsBefore,
|
|
151
|
-
const oscad::ASTNode& callNode
|
|
150
|
+
const oscad::ASTNode& callNode) {
|
|
152
151
|
if (randsCallCount_ != randsBefore) {
|
|
153
152
|
// rands() fired directly during *this* call's own resolve (e.g. an
|
|
154
153
|
// assignment before any geometry statement in a user module's
|
|
@@ -159,23 +158,7 @@ void Evaluator::spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> child
|
|
|
159
158
|
// landed on.
|
|
160
159
|
for (auto& c : children) c->uncacheable = true;
|
|
161
160
|
}
|
|
162
|
-
|
|
163
|
-
// groups, and the group walk only inspects the enclosing frame's top
|
|
164
|
-
// level -- so the wrapper would hide the marks. Splice instead.
|
|
165
|
-
//
|
|
166
|
-
// Only for the children() call's own splice. A USER MODULE wrapping
|
|
167
|
-
// such a call wraps as usual, which hides the marks and is exactly what
|
|
168
|
-
// makes separateness stop at the module boundary:
|
|
169
|
-
//
|
|
170
|
-
// module pass() { children(separate=true); }
|
|
171
|
-
// difference() pass() { a; b; } // a | b, not a - b
|
|
172
|
-
//
|
|
173
|
-
// pass() is its own shape; that it happens to forward its children
|
|
174
|
-
// separately is its business, not its caller's.
|
|
175
|
-
const bool anySeparate =
|
|
176
|
-
honorSeparateMarks &&
|
|
177
|
-
std::any_of(children.begin(), children.end(), [](const auto& c) { return c->separateOperand; });
|
|
178
|
-
if (children.size() > 1 && !anySeparate) {
|
|
161
|
+
if (children.size() > 1) {
|
|
179
162
|
auto unionNode = std::make_unique<CSGNode>();
|
|
180
163
|
unionNode->kind = "union";
|
|
181
164
|
unionNode->node = &callNode;
|
|
@@ -224,6 +207,7 @@ template <typename NodeList>
|
|
|
224
207
|
std::vector<std::unique_ptr<CSGNode>> Evaluator::resolveTreeImpl(const NodeList& nodes, EvalContext& ctx) {
|
|
225
208
|
idToNode.clear();
|
|
226
209
|
idToColor.clear();
|
|
210
|
+
syntheticNodes_.clear();
|
|
227
211
|
cacheProducer_.clear(); // holds AST pointers, same lifetime as idToNode's
|
|
228
212
|
treeStack_.clear();
|
|
229
213
|
treeStack_.emplace_back();
|
|
@@ -179,7 +179,6 @@ 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;
|
|
183
182
|
vmFramePool_.push_back(std::move(frame));
|
|
184
183
|
}
|
|
185
184
|
|
|
@@ -340,9 +339,10 @@ EvalContext Evaluator::buildModuleChildCtx(const oscad::ModuleDeclaration& decl,
|
|
|
340
339
|
EvalContext& ctx, BoundArgs bound) {
|
|
341
340
|
const oscad::Scope* childScope = decl.scope() ? decl.scope() : ctx.scope;
|
|
342
341
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
342
|
+
// Expanded, so a children(..., separate=true) in this block becomes one
|
|
343
|
+
// real statement per child it selects -- which is what makes $children
|
|
344
|
+
// below count them and children(i) index them.
|
|
345
|
+
auto childrenNodes = std::make_shared<ChildrenNodeList>(expandChildStatements(call.children, ctx));
|
|
346
346
|
|
|
347
347
|
EvalContext childCtx = callCtxFor(decl, ctx, childScope, childrenNodes, &ctx);
|
|
348
348
|
// callCtx reset this to false; carry the CALLER's value across so
|
|
@@ -353,7 +353,7 @@ EvalContext Evaluator::buildModuleChildCtx(const oscad::ModuleDeclaration& decl,
|
|
|
353
353
|
// `{}`, not the number of geometries they produce -- e.g. children()
|
|
354
354
|
// counts as one child even if it forwards zero bodies.
|
|
355
355
|
int childrenCount = 0;
|
|
356
|
-
for (const
|
|
356
|
+
for (const oscad::ASTNode* c : *childrenNodes) {
|
|
357
357
|
if (c->kind() != oscad::NodeKind::Assignment && c->kind() != oscad::NodeKind::ModuleDeclaration &&
|
|
358
358
|
c->kind() != oscad::NodeKind::FunctionDeclaration) {
|
|
359
359
|
++childrenCount;
|
|
@@ -983,7 +983,15 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
983
983
|
}
|
|
984
984
|
|
|
985
985
|
if (std::holds_alternative<std::monostate>(idxArg)) {
|
|
986
|
-
|
|
986
|
+
std::vector<size_t> allIndices;
|
|
987
|
+
size_t geoIdx = 0;
|
|
988
|
+
for (const oscad::ASTNode* c : *ctx.childrenNodes) {
|
|
989
|
+
if (c->kind() != oscad::NodeKind::Assignment && c->kind() != oscad::NodeKind::ModuleDeclaration &&
|
|
990
|
+
c->kind() != oscad::NodeKind::FunctionDeclaration) {
|
|
991
|
+
allIndices.push_back(geoIdx++);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes, separate, std::move(allIndices)};
|
|
987
995
|
}
|
|
988
996
|
|
|
989
997
|
// children(N) indexes child *statements*, not output bodies -- a
|
|
@@ -1025,6 +1033,7 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
1025
1033
|
// does evaluate child 2 three times, and the order shows through in the
|
|
1026
1034
|
// CSG tree even though a union usually hides it.
|
|
1027
1035
|
std::vector<const oscad::ASTNode*> picked;
|
|
1036
|
+
std::vector<size_t> pickedIndices;
|
|
1028
1037
|
picked.reserve(indexValues.size());
|
|
1029
1038
|
for (const Value& v : indexValues) {
|
|
1030
1039
|
if (!std::holds_alternative<double>(v)) {
|
|
@@ -1045,17 +1054,93 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
1045
1054
|
continue;
|
|
1046
1055
|
}
|
|
1047
1056
|
picked.push_back(geoNodes[static_cast<size_t>(idx)]);
|
|
1057
|
+
pickedIndices.push_back(static_cast<size_t>(idx));
|
|
1048
1058
|
}
|
|
1049
1059
|
if (picked.empty()) return std::nullopt;
|
|
1050
|
-
return ChildrenForward{std::move(evalCtx), std::move(picked), separate};
|
|
1060
|
+
return ChildrenForward{std::move(evalCtx), std::move(picked), separate, std::move(pickedIndices)};
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Syntactic only -- whether the flag is actually TRUE still needs the
|
|
1064
|
+
// argument evaluated, but gating on its presence first means an ordinary
|
|
1065
|
+
// children() call never has its arguments resolved twice.
|
|
1066
|
+
bool Evaluator::isSeparatingChildrenCall(const oscad::ASTNode& stmt) {
|
|
1067
|
+
if (stmt.kind() != oscad::NodeKind::ModularCall) return false;
|
|
1068
|
+
const auto& call = static_cast<const oscad::ModularCall&>(stmt);
|
|
1069
|
+
if (!call.name || call.name->name != "children") return false;
|
|
1070
|
+
size_t positional = 0;
|
|
1071
|
+
for (const auto& arg : call.arguments) {
|
|
1072
|
+
if (arg->kind() == oscad::NodeKind::NamedArgument) {
|
|
1073
|
+
if (static_cast<const oscad::NamedArgument&>(*arg).name->name == "separate") return true;
|
|
1074
|
+
} else if (++positional == 2) {
|
|
1075
|
+
return true; // children(index, separate) positionally
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
std::optional<std::vector<const oscad::ASTNode*>> Evaluator::expandSeparatingChildren(const oscad::ModularCall& call,
|
|
1082
|
+
EvalContext& ctx) {
|
|
1083
|
+
auto [args, effCtx] = resolveCallArgs(*this, call.arguments, ctx);
|
|
1084
|
+
std::optional<ChildrenForward> fwd = prepareChildrenForward(args, effCtx);
|
|
1085
|
+
if (!fwd) return std::vector<const oscad::ASTNode*>{}; // selects nothing -> no statements at all
|
|
1086
|
+
if (!fwd->separate) {
|
|
1087
|
+
// ponytail: `separate` written but falsey -- tell the caller to run
|
|
1088
|
+
// the original statement, which resolves its arguments a second
|
|
1089
|
+
// time. Only observable if an argument expression has side effects
|
|
1090
|
+
// (echo/rands inside `children(0, someFalseFlag)`); building a
|
|
1091
|
+
// faithful single-statement equivalent instead would cost a
|
|
1092
|
+
// synthetic vector-literal node for a shape nobody writes.
|
|
1093
|
+
return std::nullopt;
|
|
1094
|
+
}
|
|
1095
|
+
std::vector<const oscad::ASTNode*> out;
|
|
1096
|
+
out.reserve(fwd->pickedIndices.size());
|
|
1097
|
+
for (size_t idx : fwd->pickedIndices) out.push_back(makeChildrenIndexCall(call, idx));
|
|
1098
|
+
return out;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
const oscad::ASTNode* Evaluator::makeChildrenIndexCall(const oscad::ModularCall& origin, size_t index) {
|
|
1102
|
+
std::vector<std::unique_ptr<oscad::Argument>> args;
|
|
1103
|
+
args.push_back(std::make_unique<oscad::PositionalArgument>(
|
|
1104
|
+
origin.position(), std::make_unique<oscad::NumberLiteral>(origin.position(), static_cast<double>(index))));
|
|
1105
|
+
auto call = std::make_unique<oscad::ModularCall>(
|
|
1106
|
+
origin.position(), std::make_unique<oscad::Identifier>(origin.position(), "children"), std::move(args),
|
|
1107
|
+
std::vector<std::unique_ptr<oscad::ASTNode>>{});
|
|
1108
|
+
// Position copied from the call the author actually wrote, so a warning
|
|
1109
|
+
// or a click-to-source lands on that line rather than nowhere.
|
|
1110
|
+
//
|
|
1111
|
+
// No scope is set: every consumer falls back to the evaluating
|
|
1112
|
+
// context's own scope for a node without one (see evalChildren's runAll
|
|
1113
|
+
// in stmt_eval.cpp), which is exactly where this call should resolve.
|
|
1114
|
+
const oscad::ASTNode* raw = call.get();
|
|
1115
|
+
syntheticNodes_.push_back(std::move(call));
|
|
1116
|
+
return raw;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
std::vector<const oscad::ASTNode*> Evaluator::expandChildStatements(
|
|
1120
|
+
const std::vector<std::unique_ptr<oscad::ASTNode>>& block, EvalContext& ctx) {
|
|
1121
|
+
std::vector<const oscad::ASTNode*> out;
|
|
1122
|
+
out.reserve(block.size());
|
|
1123
|
+
for (const auto& stmtPtr : block) {
|
|
1124
|
+
const oscad::ASTNode* stmt = stmtPtr.get();
|
|
1125
|
+
if (!isSeparatingChildrenCall(*stmt)) {
|
|
1126
|
+
out.push_back(stmt);
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
std::optional<std::vector<const oscad::ASTNode*>> expanded =
|
|
1130
|
+
expandSeparatingChildren(static_cast<const oscad::ModularCall&>(*stmt), ctx);
|
|
1131
|
+
if (!expanded) {
|
|
1132
|
+
out.push_back(stmt);
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
for (const oscad::ASTNode* n : *expanded) out.push_back(n);
|
|
1136
|
+
}
|
|
1137
|
+
return out;
|
|
1051
1138
|
}
|
|
1052
1139
|
|
|
1053
1140
|
void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
1054
1141
|
std::optional<ChildrenForward> fwd = prepareChildrenForward(args, ctx);
|
|
1055
1142
|
if (!fwd) return;
|
|
1056
|
-
const size_t before = currentTreeFrameSize();
|
|
1057
1143
|
evalChildren(fwd->nodes, fwd->evalCtx);
|
|
1058
|
-
if (fwd->separate) markSeparateOperands(treeStack_.back(), before);
|
|
1059
1144
|
}
|
|
1060
1145
|
|
|
1061
1146
|
} // namespace oscadeval
|