openscad-cpp-evaluator 0.13.7__tar.gz → 0.13.9__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.13.7 → openscad_cpp_evaluator-0.13.9}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/bytecode.hpp +20 -9
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/control.cpp +16 -13
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/bytecode_compiler.cpp +110 -102
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/expr_eval.cpp +18 -17
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/stmt_eval.cpp +25 -18
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/user_calls.cpp +21 -1
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_control_flow.cpp +99 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/README.md +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.13.7 → openscad_cpp_evaluator-0.13.9}/tools/cli/main.cpp +0 -0
|
@@ -104,18 +104,29 @@ enum class Op {
|
|
|
104
104
|
// themselves lists).
|
|
105
105
|
AccumMergeEach,
|
|
106
106
|
|
|
107
|
-
// ListCompFor's per-assignment iteration
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
107
|
+
// ListCompFor's per-assignment iteration. `a` = an iterList id (see
|
|
108
|
+
// CompiledChunk::numIterLists), unique per assignment across the whole
|
|
109
|
+
// chunk. Each dimension's own IterMaterialize is emitted INSIDE the
|
|
110
|
+
// enclosing dimension's own loop body (compileListElement's own
|
|
111
|
+
// emitDim recursion), so it re-executes once per outer-dimension
|
|
112
|
+
// binding -- required for a later dimension's own RHS to see an
|
|
113
|
+
// earlier one's current value (e.g. `[for (p=[1:N], pt=f(p)) pt]`),
|
|
114
|
+
// matching evalFor's own doc comment (stmt_eval.cpp) and real
|
|
115
|
+
// OpenSCAD.app's verified behavior.
|
|
114
116
|
IterMaterialize, // pops one Value (the assignment's RHS), expandIterable()s it into iterLists[a], resets its index
|
|
115
|
-
|
|
117
|
+
// Resets iterLists[a]'s index to 0 WITHOUT re-materializing. UNREACHABLE
|
|
118
|
+
// as of the materialize-inside-the-nesting fix above: re-materializing
|
|
119
|
+
// on every dimension re-entry already resets the index as a side
|
|
120
|
+
// effect (see IterMaterialize's own doc comment), so there's no longer
|
|
121
|
+
// a "reset without re-materializing" case left to reach for either
|
|
122
|
+
// ListCompFor (compileListElement) or ModularFor (compileForLoop).
|
|
123
|
+
// Left defined rather than removed in the same change -- a distinct,
|
|
124
|
+
// lower-risk cleanup (same convention as LoadUpvalue's own doc
|
|
125
|
+
// comment, above).
|
|
126
|
+
IterReset,
|
|
116
127
|
IterNext, // a = loop-variable slot, b = iterList id, c = jump target for exhaustion: if iterLists[b] has a
|
|
117
128
|
// next value (at its current index), write it to slots[a], advance the index, fall through;
|
|
118
|
-
// else jump to c (index is left as-is; the next
|
|
129
|
+
// else jump to c (index is left as-is; the next IterMaterialize for this id will restart it)
|
|
119
130
|
|
|
120
131
|
// ListCompCFor's runaway-loop guard, mirroring evalListElement's own
|
|
121
132
|
// 1,000,000-iteration safety limit exactly (see its own doc comment
|
|
@@ -97,24 +97,21 @@ 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
|
-
std::vector<std::pair<std::string, IterableValues>> varSeqs;
|
|
101
|
-
varSeqs.reserve(node.assignments.size());
|
|
102
|
-
for (const auto& assign : node.assignments) {
|
|
103
|
-
Value values = ev.evalExpr(*assign->expr, ctx);
|
|
104
|
-
const oscad::Position* pos = &assign->position();
|
|
105
|
-
varSeqs.emplace_back(assign->name->name, expandIterable(values, [&](size_t count) {
|
|
106
|
-
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
107
|
-
}));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
100
|
std::vector<const oscad::ASTNode*> bodyNodes;
|
|
111
101
|
bodyNodes.reserve(node.body.size());
|
|
112
102
|
for (const auto& b : node.body) bodyNodes.push_back(b.get());
|
|
113
103
|
|
|
114
104
|
std::vector<Value> groupSizes;
|
|
115
105
|
|
|
106
|
+
// Each dimension's own RHS is evaluated against `parentCtx` (not
|
|
107
|
+
// upfront against the original `ctx`), re-evaluated on every entry
|
|
108
|
+
// into this recursion level -- see evalFor's own doc comment
|
|
109
|
+
// (stmt_eval.cpp) for the full "verified against real OpenSCAD.app"
|
|
110
|
+
// rationale; this is the identical bug in intersection_for's own
|
|
111
|
+
// cartesian loop (e.g. `intersection_for (i=[0:2], j=[0:i]) ...`
|
|
112
|
+
// needs `i` visible in `j`'s own range expression).
|
|
116
113
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
117
|
-
if (depth ==
|
|
114
|
+
if (depth == node.assignments.size()) {
|
|
118
115
|
// One body-entry marker per full cartesian-product iteration
|
|
119
116
|
// and nothing per individual variable binding (unlike
|
|
120
117
|
// evalFor) -- mirrors _resolve_intersection_for's single
|
|
@@ -126,9 +123,15 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
126
123
|
groupSizes.push_back(Value{static_cast<double>(after - before)});
|
|
127
124
|
return;
|
|
128
125
|
}
|
|
129
|
-
|
|
126
|
+
const auto& assign = node.assignments[depth];
|
|
127
|
+
Value values = ev.evalExpr(*assign->expr, parentCtx);
|
|
128
|
+
const oscad::Position* pos = &assign->position();
|
|
129
|
+
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
130
|
+
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
131
|
+
});
|
|
132
|
+
for (const Value& val : iter) {
|
|
130
133
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
|
131
|
-
childCtx.let_->set(
|
|
134
|
+
childCtx.let_->set(assign->name->name, val);
|
|
132
135
|
recurse(depth + 1, childCtx);
|
|
133
136
|
}
|
|
134
137
|
};
|
|
@@ -884,22 +884,27 @@ public:
|
|
|
884
884
|
switch (elem.kind()) {
|
|
885
885
|
case NodeKind::ListCompFor: {
|
|
886
886
|
auto& n = static_cast<const oscad::ListCompFor&>(elem);
|
|
887
|
-
// Each assignment's RHS is evaluated exactly once, against
|
|
888
|
-
// the OUTER scope (never seeing an earlier sibling
|
|
889
|
-
// assignment's own loop variable) -- mirrors the
|
|
890
|
-
// interpreter's own upfront `pairs.push_back(...)` loop,
|
|
891
|
-
// and vector_element.hpp's own doc comment on this
|
|
892
|
-
// asymmetry with ListCompCFor.
|
|
893
|
-
std::vector<int> iterIds;
|
|
894
|
-
iterIds.reserve(n.assignments.size());
|
|
895
|
-
for (const auto& assign : n.assignments) {
|
|
896
|
-
compileExpr(*assign->expr, out, scope);
|
|
897
|
-
int id = nextIterList_++;
|
|
898
|
-
iterIds.push_back(id);
|
|
899
|
-
out.push_back({Op::IterMaterialize, id, 0, &assign->position()});
|
|
900
|
-
}
|
|
901
887
|
scope.push();
|
|
902
888
|
const bool isNestedLc = (n.body->kind() == NodeKind::ListComprehension);
|
|
889
|
+
// Each dimension's own RHS is compiled+materialized INSIDE
|
|
890
|
+
// the enclosing dimension's own loop body (nested, via the
|
|
891
|
+
// recursive call below), so it naturally re-executes once
|
|
892
|
+
// per outer binding, resolved against `scope` with every
|
|
893
|
+
// OUTER dimension's own slot already declared -- see
|
|
894
|
+
// compileForLoop's own doc comment (this file) / evalFor's
|
|
895
|
+
// (stmt_eval.cpp) for the full "verified against real
|
|
896
|
+
// OpenSCAD.app" rationale. This used to evaluate every
|
|
897
|
+
// dimension's RHS exactly once, upfront, against the outer
|
|
898
|
+
// scope -- justified at the time by appeal to
|
|
899
|
+
// vector_element.hpp's own buildScope() "asymmetric with
|
|
900
|
+
// ListCompCFor" comment, but that comment describes STATIC
|
|
901
|
+
// scope-TREE construction for name resolution (module/
|
|
902
|
+
// function lookups), not RUNTIME value-binding order
|
|
903
|
+
// (always the dynamic ctx.let_ chain regardless of the
|
|
904
|
+
// Scope tree) -- it doesn't justify this, and real
|
|
905
|
+
// OpenSCAD.app confirms a later dimension's range CAN
|
|
906
|
+
// depend on an earlier one's current value (e.g. `[for
|
|
907
|
+
// (p=[1:N], pt=f(p)) pt]`).
|
|
903
908
|
std::function<void(size_t)> emitDim = [&](size_t depth) {
|
|
904
909
|
if (depth == n.assignments.size()) {
|
|
905
910
|
if (isNestedLc) {
|
|
@@ -910,17 +915,16 @@ public:
|
|
|
910
915
|
}
|
|
911
916
|
return;
|
|
912
917
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
int loopVarSlot = declareLocal(scope, n.assignments[depth]->name->name);
|
|
918
|
+
const auto& assign = n.assignments[depth];
|
|
919
|
+
compileExpr(*assign->expr, out, scope);
|
|
920
|
+
const int iterId = nextIterList_++;
|
|
921
|
+
out.push_back({Op::IterMaterialize, iterId, 0, &assign->position()});
|
|
922
|
+
int loopVarSlot = declareLocal(scope, assign->name->name);
|
|
919
923
|
size_t loopStart = out.size();
|
|
920
924
|
Instruction iterNext;
|
|
921
925
|
iterNext.op = Op::IterNext;
|
|
922
926
|
iterNext.a = loopVarSlot;
|
|
923
|
-
iterNext.b =
|
|
927
|
+
iterNext.b = iterId;
|
|
924
928
|
size_t iterNextIdx = out.size();
|
|
925
929
|
out.push_back(iterNext);
|
|
926
930
|
emitDim(depth + 1);
|
|
@@ -1250,23 +1254,27 @@ public:
|
|
|
1250
1254
|
// a cartesian-product loop over `node.assignments`, and at the
|
|
1251
1255
|
// innermost base case, ONE currentTreeFrameSize()-delta group per full
|
|
1252
1256
|
// iteration. Reuses compileForLoop's own cartesian-loop scaffold
|
|
1253
|
-
// verbatim (Op::NativeIterMaterialize/ForIterNext/ForIterEnd
|
|
1254
|
-
//
|
|
1255
|
-
//
|
|
1256
|
-
//
|
|
1257
|
-
//
|
|
1258
|
-
//
|
|
1259
|
-
// childrenNodes
|
|
1260
|
-
//
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
//
|
|
1264
|
-
//
|
|
1265
|
-
//
|
|
1266
|
-
//
|
|
1267
|
-
//
|
|
1268
|
-
//
|
|
1269
|
-
//
|
|
1257
|
+
// verbatim (Op::NativeIterMaterialize/ForIterNext/ForIterEnd, each
|
|
1258
|
+
// dimension nested INSIDE the enclosing one's own loop body -- see
|
|
1259
|
+
// compileForLoop's own doc comment for why this shape, not a flat
|
|
1260
|
+
// materialize-everything-upfront pass, is required for a later
|
|
1261
|
+
// dimension's range to see an earlier one's binding) -- Op::
|
|
1262
|
+
// ForIterNext's own ctx construction, `ctx.childCtx(nullptr,
|
|
1263
|
+
// std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx)`, is exactly
|
|
1264
|
+
// what resolveIntersectionFor's own recurse lambda does too
|
|
1265
|
+
// (`parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes,
|
|
1266
|
+
// ctx.childrenCallerCtx)`), since childrenNodes/childrenCallerCtx
|
|
1267
|
+
// propagate unchanged through every nested childCtx either way --
|
|
1268
|
+
// just with Op::CsgGroupStart/CsgGroupEnd wrapped around the body
|
|
1269
|
+
// instead of a bare compileStatementList. The leading checkDebug is
|
|
1270
|
+
// only emitted when node.body isn't empty, mirroring
|
|
1271
|
+
// resolveIntersectionFor's own `if (!bodyNodes.empty())` guard
|
|
1272
|
+
// exactly (unlike compileForLoop's own ModularFor sibling, which
|
|
1273
|
+
// always emits one even for an empty body, against the FOR node
|
|
1274
|
+
// itself as a fallback marker -- intersection_for has no such native
|
|
1275
|
+
// fallback, so neither does this) -- but CsgGroupStart/CsgGroupEnd
|
|
1276
|
+
// themselves are UNCONDITIONAL, since native measures a (possibly
|
|
1277
|
+
// zero-size) group regardless of body emptiness.
|
|
1270
1278
|
void compileIntersectionForLoop(const oscad::ModularIntersectionFor& n, std::vector<Instruction>& out) {
|
|
1271
1279
|
out.push_back({Op::CheckDebugStatement, internNativeStatement(&n), 0, nullptr});
|
|
1272
1280
|
CompiledChunk::CsgWrapSite site;
|
|
@@ -1279,35 +1287,32 @@ public:
|
|
|
1279
1287
|
out.push_back({Op::PushCsgWrap, idx, 0, &n.position()});
|
|
1280
1288
|
|
|
1281
1289
|
const size_t numDims = n.assignments.size();
|
|
1282
|
-
std::
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1290
|
+
std::function<void(size_t)> emitDim = [&](size_t d) {
|
|
1291
|
+
if (d == numDims) {
|
|
1292
|
+
if (!n.body.empty()) {
|
|
1293
|
+
out.push_back({Op::NativeCheckDebugExprLevel, internNativeStatement(n.body.front().get()), 0, nullptr});
|
|
1294
|
+
}
|
|
1295
|
+
out.push_back({Op::CsgGroupStart, 0, 0, nullptr});
|
|
1296
|
+
compileStatementList(n.body, out);
|
|
1297
|
+
out.push_back({Op::CsgGroupEnd, 0, 0, nullptr});
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
const int iterListId = nextIterList_++;
|
|
1301
|
+
out.push_back({Op::NativeIterMaterialize, internNativeExpr(n.assignments[d]->expr.get()), iterListId,
|
|
1286
1302
|
&n.assignments[d]->position()});
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
std::vector<size_t> forIterNextIdx(numDims);
|
|
1290
|
-
for (size_t d = 0; d < numDims; ++d) {
|
|
1291
|
-
if (d > 0) out.push_back({Op::IterReset, iterListIds[d], 0, nullptr});
|
|
1292
|
-
topIdx[d] = out.size();
|
|
1293
|
-
forIterNextIdx[d] = out.size();
|
|
1303
|
+
const size_t topIdx = out.size();
|
|
1304
|
+
const size_t forIterNextIdx = out.size();
|
|
1294
1305
|
Instruction ins;
|
|
1295
1306
|
ins.op = Op::ForIterNext;
|
|
1296
1307
|
ins.a = internName(n.assignments[d]->name->name);
|
|
1297
|
-
ins.b =
|
|
1308
|
+
ins.b = iterListId;
|
|
1298
1309
|
ins.node = n.assignments[d].get();
|
|
1299
1310
|
out.push_back(ins);
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
out.
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
compileStatementList(n.body, out);
|
|
1306
|
-
out.push_back({Op::CsgGroupEnd, 0, 0, nullptr});
|
|
1307
|
-
for (size_t i = numDims; i-- > 0;) {
|
|
1308
|
-
out.push_back({Op::ForIterEnd, static_cast<int>(topIdx[i]), 0, nullptr});
|
|
1309
|
-
out[forIterNextIdx[i]].c = static_cast<int>(out.size());
|
|
1310
|
-
}
|
|
1311
|
+
emitDim(d + 1);
|
|
1312
|
+
out.push_back({Op::ForIterEnd, static_cast<int>(topIdx), 0, nullptr});
|
|
1313
|
+
out[forIterNextIdx].c = static_cast<int>(out.size());
|
|
1314
|
+
};
|
|
1315
|
+
emitDim(0);
|
|
1311
1316
|
out.push_back({Op::PopCsgWrap, idx, 0, &n.position()});
|
|
1312
1317
|
}
|
|
1313
1318
|
|
|
@@ -1643,54 +1648,57 @@ public:
|
|
|
1643
1648
|
// based code at COMPILE time (bounded by the source's own for-clause
|
|
1644
1649
|
// count, always small -- never runtime-driven) rather than the
|
|
1645
1650
|
// interpreter's own runtime recursion (evalFor's `recurse(depth+1,
|
|
1646
|
-
// ...)`, stmt_eval.cpp)
|
|
1647
|
-
//
|
|
1648
|
-
//
|
|
1649
|
-
//
|
|
1650
|
-
//
|
|
1651
|
-
//
|
|
1651
|
+
// ...)`, stmt_eval.cpp) -- but structurally mirroring that SAME
|
|
1652
|
+
// recursion shape at compile time (emitDim, below), not a flat
|
|
1653
|
+
// "materialize every dimension, then loop every dimension" two-pass
|
|
1654
|
+
// shape (what used to be here): dimension d's own Op::
|
|
1655
|
+
// NativeIterMaterialize is emitted INSIDE dimension d-1's own loop
|
|
1656
|
+
// body (nested, via the recursive call), so it naturally re-executes
|
|
1657
|
+
// once per (d-1)-and-outer binding, evaluated against whatever ctx is
|
|
1658
|
+
// current at that point in the instruction stream -- i.e. with every
|
|
1659
|
+
// OUTER dimension's own loop variable already bound. Required for real
|
|
1660
|
+
// OpenSCAD's own documented/verified behavior: a later `for` clause's
|
|
1661
|
+
// range CAN depend on an earlier one (`for (i=[0:2], j=[0:i])` is a
|
|
1662
|
+
// standard triangular-loop idiom) -- the old flat-materialize-upfront
|
|
1663
|
+
// shape evaluated every dimension's RHS before ANY variable was bound,
|
|
1664
|
+
// so a later dimension's own reference to an earlier one always failed
|
|
1665
|
+
// with "unknown variable" (confirmed wrong against real OpenSCAD.app
|
|
1666
|
+
// directly, not just an internal inconsistency; see evalFor's own doc
|
|
1667
|
+
// comment, stmt_eval.cpp, for the fuller story -- same bug, same fix
|
|
1668
|
+
// shape, on the interpreter side).
|
|
1669
|
+
//
|
|
1670
|
+
// No Op::IterReset needed any more: since Materialize now runs exactly
|
|
1671
|
+
// once per entry into this dimension's own block (not once total),
|
|
1672
|
+
// its own index-reset (see that op's own doc comment) already covers
|
|
1673
|
+
// "restart this dimension for the next outer binding" -- the OLD
|
|
1674
|
+
// separate reset-without-rematerializing step existed purely to avoid
|
|
1675
|
+
// an unnecessary re-evaluation under the old (buggy) "materialize
|
|
1676
|
+
// once ever" shape, which no longer exists.
|
|
1652
1677
|
void compileForLoop(const oscad::ModularFor& n, std::vector<Instruction>& out) {
|
|
1653
1678
|
const size_t numDims = n.assignments.size();
|
|
1654
|
-
std::
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
// only resets it once, up front, before ANY iteration runs; by
|
|
1667
|
-
// the second (and every later) outer-dimension value, this
|
|
1668
|
-
// dimension's own index is still sitting at "exhausted" from
|
|
1669
|
-
// the PREVIOUS pass, and would immediately look exhausted
|
|
1670
|
-
// again without this. Placed strictly BEFORE this dimension's
|
|
1671
|
-
// own ForIterNext/topIdx (not at it) so this dimension's OWN
|
|
1672
|
-
// "try the next value" jump (its own ForIterEnd, below) lands
|
|
1673
|
-
// AT ForIterNext directly and skips the reset -- only the
|
|
1674
|
-
// fall-through from the enclosing dimension's bind passes
|
|
1675
|
-
// through it. Harmless (a no-op) the very first time, since
|
|
1676
|
-
// the index is already 0 from NativeIterMaterialize then.
|
|
1677
|
-
if (d > 0) out.push_back({Op::IterReset, iterListIds[d], 0, nullptr});
|
|
1678
|
-
topIdx[d] = out.size();
|
|
1679
|
-
forIterNextIdx[d] = out.size();
|
|
1679
|
+
std::function<void(size_t)> emitDim = [&](size_t d) {
|
|
1680
|
+
if (d == numDims) {
|
|
1681
|
+
const oscad::ASTNode* marker = n.body.empty() ? static_cast<const oscad::ASTNode*>(&n) : n.body.front().get();
|
|
1682
|
+
out.push_back({Op::NativeCheckDebugExprLevel, internNativeStatement(marker), 0, nullptr});
|
|
1683
|
+
compileStatementList(n.body, out);
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
const int iterListId = nextIterList_++;
|
|
1687
|
+
out.push_back({Op::NativeIterMaterialize, internNativeExpr(n.assignments[d]->expr.get()), iterListId,
|
|
1688
|
+
&n.assignments[d]->position()});
|
|
1689
|
+
const size_t topIdx = out.size();
|
|
1690
|
+
const size_t forIterNextIdx = out.size();
|
|
1680
1691
|
Instruction ins;
|
|
1681
1692
|
ins.op = Op::ForIterNext;
|
|
1682
1693
|
ins.a = internName(n.assignments[d]->name->name);
|
|
1683
|
-
ins.b =
|
|
1694
|
+
ins.b = iterListId;
|
|
1684
1695
|
ins.node = n.assignments[d].get();
|
|
1685
1696
|
out.push_back(ins); // ins.c (exhaustion target) patched below
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
out.push_back({Op::ForIterEnd, static_cast<int>(topIdx[i]), 0, nullptr});
|
|
1692
|
-
out[forIterNextIdx[i]].c = static_cast<int>(out.size());
|
|
1693
|
-
}
|
|
1697
|
+
emitDim(d + 1);
|
|
1698
|
+
out.push_back({Op::ForIterEnd, static_cast<int>(topIdx), 0, nullptr});
|
|
1699
|
+
out[forIterNextIdx].c = static_cast<int>(out.size());
|
|
1700
|
+
};
|
|
1701
|
+
emitDim(0);
|
|
1694
1702
|
}
|
|
1695
1703
|
|
|
1696
1704
|
private:
|
|
@@ -144,23 +144,18 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
144
144
|
switch (elem.kind()) {
|
|
145
145
|
case oscad::NodeKind::ListCompFor: {
|
|
146
146
|
auto& n = static_cast<const oscad::ListCompFor&>(elem);
|
|
147
|
-
struct Pair {
|
|
148
|
-
std::string name;
|
|
149
|
-
IterableValues values;
|
|
150
|
-
};
|
|
151
|
-
std::vector<Pair> pairs;
|
|
152
|
-
pairs.reserve(n.assignments.size());
|
|
153
|
-
for (const auto& assign : n.assignments) {
|
|
154
|
-
Value values = evalExpr(*assign->expr, ctx);
|
|
155
|
-
const oscad::Position* pos = &assign->position();
|
|
156
|
-
pairs.push_back(Pair{assign->name->name, expandIterable(values, [&](size_t count) {
|
|
157
|
-
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
158
|
-
})});
|
|
159
|
-
}
|
|
160
147
|
const bool isNestedLc = (n.body->kind() == oscad::NodeKind::ListComprehension);
|
|
161
148
|
|
|
149
|
+
// Each dimension's own RHS is evaluated against `parentCtx`
|
|
150
|
+
// (not upfront against the original `ctx`), re-evaluated on
|
|
151
|
+
// every entry into this recursion level -- see evalFor's own
|
|
152
|
+
// doc comment (stmt_eval.cpp) for the full "verified against
|
|
153
|
+
// real OpenSCAD.app" rationale; this is the identical bug in
|
|
154
|
+
// the list-comprehension sibling of that same construct (e.g.
|
|
155
|
+
// `[for (p=[1:N], pt=f(p)) pt]` needs `p` visible in `pt`'s own
|
|
156
|
+
// range expression).
|
|
162
157
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
163
|
-
if (depth ==
|
|
158
|
+
if (depth == n.assignments.size()) {
|
|
164
159
|
if (isNestedLc) {
|
|
165
160
|
out.push_back(evalListLiteral(static_cast<const oscad::ListComprehension&>(*n.body), parentCtx));
|
|
166
161
|
} else {
|
|
@@ -168,14 +163,20 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
168
163
|
}
|
|
169
164
|
return;
|
|
170
165
|
}
|
|
171
|
-
|
|
166
|
+
const auto& assign = n.assignments[depth];
|
|
167
|
+
Value values = evalExpr(*assign->expr, parentCtx);
|
|
168
|
+
const oscad::Position* pos = &assign->position();
|
|
169
|
+
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
170
|
+
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
171
|
+
});
|
|
172
|
+
for (const Value& val : iter) {
|
|
172
173
|
EvalContext childCtx = parentCtx.letChildCtx();
|
|
173
|
-
childCtx.let_->set(
|
|
174
|
+
childCtx.let_->set(assign->name->name, val);
|
|
174
175
|
// Per-binding stop, same shape as evalFor's -- but with
|
|
175
176
|
// NO separate body-entry marker at depth == pairs.size()
|
|
176
177
|
// (_eval_listcomp_for has none; the body's own element
|
|
177
178
|
// check below supplies the expr-level stop instead).
|
|
178
|
-
checkDebug(*
|
|
179
|
+
checkDebug(*assign, childCtx);
|
|
179
180
|
recurse(depth + 1, childCtx);
|
|
180
181
|
}
|
|
181
182
|
};
|
|
@@ -71,20 +71,6 @@ void Evaluator::evalAssertStatement(const oscad::ModularAssert& node, EvalContex
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
void Evaluator::evalFor(const oscad::ModularFor& node, EvalContext& ctx) {
|
|
74
|
-
struct AssignPair {
|
|
75
|
-
std::string name;
|
|
76
|
-
IterableValues values;
|
|
77
|
-
};
|
|
78
|
-
std::vector<AssignPair> pairs;
|
|
79
|
-
pairs.reserve(node.assignments.size());
|
|
80
|
-
for (const auto& assign : node.assignments) {
|
|
81
|
-
Value values = evalExprMaybeCompiled(*assign->expr, ctx);
|
|
82
|
-
const oscad::Position* pos = &assign->position();
|
|
83
|
-
pairs.push_back(AssignPair{assign->name->name, expandIterable(values, [&](size_t count) {
|
|
84
|
-
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
85
|
-
})});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
74
|
std::vector<const oscad::ASTNode*> bodyNodes;
|
|
89
75
|
bodyNodes.reserve(node.body.size());
|
|
90
76
|
for (const auto& b : node.body) bodyNodes.push_back(b.get());
|
|
@@ -96,8 +82,23 @@ void Evaluator::evalFor(const oscad::ModularFor& node, EvalContext& ctx) {
|
|
|
96
82
|
// _eval_for's `_nested` closure exactly) and binds just that one
|
|
97
83
|
// variable, so inner levels/the body see all outer bindings already in
|
|
98
84
|
// `let_`.
|
|
85
|
+
//
|
|
86
|
+
// Each dimension's own RHS is evaluated HERE, against `parentCtx` (not
|
|
87
|
+
// upfront against the original `ctx`), and re-evaluated on every entry
|
|
88
|
+
// into this recursion level -- i.e. once per combination of whatever
|
|
89
|
+
// dimensions 0..depth-1 are currently bound to. This is required for
|
|
90
|
+
// real OpenSCAD's own documented/verified behavior: a later `for`
|
|
91
|
+
// clause's range CAN depend on an earlier one (`for (i=[0:2], j=[0:i])`
|
|
92
|
+
// is a standard triangular-loop idiom; `pt = f(p)` inside `for (p=...,
|
|
93
|
+
// pt=f(p))` needs the same). Evaluating all dimensions upfront in one
|
|
94
|
+
// flat pass (the previous shape here) evaluated every RHS against the
|
|
95
|
+
// ORIGINAL ctx before ANY variable was bound, so a later dimension's
|
|
96
|
+
// own reference to an earlier one always failed with "unknown
|
|
97
|
+
// variable" -- confirmed wrong against real OpenSCAD.app directly
|
|
98
|
+
// (verified both `for(i=[0:2],j=[0:i])` and a dependent list-comp
|
|
99
|
+
// case), not just an internal inconsistency.
|
|
99
100
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
100
|
-
if (depth ==
|
|
101
|
+
if (depth == node.assignments.size()) {
|
|
101
102
|
// Per-full-iteration "entering the body" marker, separate from
|
|
102
103
|
// (and before) the body's own per-statement checks in
|
|
103
104
|
// evalChildren -- mirrors _eval_for's
|
|
@@ -106,14 +107,20 @@ void Evaluator::evalFor(const oscad::ModularFor& node, EvalContext& ctx) {
|
|
|
106
107
|
evalChildren(bodyNodes, parentCtx);
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
const auto& assign = node.assignments[depth];
|
|
111
|
+
Value values = evalExprMaybeCompiled(*assign->expr, parentCtx);
|
|
112
|
+
const oscad::Position* pos = &assign->position();
|
|
113
|
+
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
114
|
+
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
115
|
+
});
|
|
116
|
+
for (const Value& val : iter) {
|
|
110
117
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
|
111
|
-
childCtx.let_->set(
|
|
118
|
+
childCtx.let_->set(assign->name->name, val);
|
|
112
119
|
// One statement-level stop per (bound-so-far) combination, on
|
|
113
120
|
// the loop-variable assignment itself -- so a breakpoint set
|
|
114
121
|
// directly on an `i=[0:2],`/`j=[0:1]` line fires. Mirrors
|
|
115
122
|
// _eval_for's `_check_debug(assign_node, child)`.
|
|
116
|
-
checkDebug(*
|
|
123
|
+
checkDebug(*assign, childCtx);
|
|
117
124
|
recurse(depth + 1, childCtx);
|
|
118
125
|
}
|
|
119
126
|
};
|
|
@@ -925,8 +925,28 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
925
925
|
// trail level, and TrailView::items() is ancestry-visible, so reading
|
|
926
926
|
// from effCtx forwards both the call's own overrides AND everything
|
|
927
927
|
// the wrapper module's body set (`$fn = 100; children();`).
|
|
928
|
+
//
|
|
929
|
+
// EXCLUDING "$children"/"$parent_modules" is required, not incidental:
|
|
930
|
+
// both are set on `ctx` by buildModuleChildCtx for the WRAPPER module's
|
|
931
|
+
// own invocation (e.g. a `left(x) { ... }` positioning helper's own
|
|
932
|
+
// child count/nesting depth), completely unrelated to the forwarded
|
|
933
|
+
// TARGET's real values -- which `evalCtx` already correctly inherited
|
|
934
|
+
// above, from `callerCtx` (the actual forwarding target), a few lines
|
|
935
|
+
// up. Before this exclusion, a bare `children()` forwarded through ANY
|
|
936
|
+
// intermediate wrapper module silently replaced the target's own real
|
|
937
|
+
// `$children` with the wrapper's own (e.g. `left(x) { if ($children >
|
|
938
|
+
// N) children(N); }`, an extremely common BOSL/BOSL2-style guarded-
|
|
939
|
+
// forwarding idiom, would read the WRAPPER's own 1-child count instead
|
|
940
|
+
// of the real caller's, corrupting every such conditional -- silently
|
|
941
|
+
// dropping geometry with no warning of any kind, since the guard just
|
|
942
|
+
// evaluates false instead of erroring. Found via a real user script
|
|
943
|
+
// (snappy-reprap's x_axis_assembly_1, GDMUtils.scad's left()/right()/
|
|
944
|
+
// up() positioning helpers) that render a large fraction of the model
|
|
945
|
+
// through exactly this pattern -- confirmed present since at least
|
|
946
|
+
// v0.13.4 (this port's very first PyPI release), unrelated to any
|
|
947
|
+
// 2026-08-01 VM work.
|
|
928
948
|
for (const auto& [k, v] : ctx.dyn->items()) {
|
|
929
|
-
if (!k.empty() && k[0] == '$') evalCtx.dyn->set(k, v);
|
|
949
|
+
if (!k.empty() && k[0] == '$' && k != "$children" && k != "$parent_modules") evalCtx.dyn->set(k, v);
|
|
930
950
|
}
|
|
931
951
|
for (const auto& [k, v] : ctx.let_->items()) {
|
|
932
952
|
if (!k.empty() && k[0] == '$') evalCtx.let_->set(k, v);
|