openscad-cpp-evaluator 0.2.0__tar.gz → 0.4.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.2.0 → openscad_cpp_evaluator-0.4.0}/CLAUDE.md +26 -9
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/bindings/module.cpp +74 -12
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/examples/minimal_debugger.cpp +3 -3
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +22 -16
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/debug_repl.hpp +1 -1
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/evaluator.hpp +47 -7
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/python/openscad_cpp_evaluator/__init__.py +12 -3
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/control.cpp +5 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/csg_generate.cpp +37 -6
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/csg_resolve.cpp +10 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/debug/debug_repl.cpp +13 -7
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/debug_profile.cpp +2 -2
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/expr_eval.cpp +54 -6
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/stmt_eval.cpp +40 -15
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/user_calls.cpp +24 -6
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_cli.cpp +1 -1
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_control_flow.cpp +2 -2
- openscad_cpp_evaluator-0.4.0/tests/test_debug_hooks.cpp +422 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_python_bindings.py +72 -1
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_tail_calls.cpp +22 -10
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/cli_lib.cpp +2 -2
- openscad_cpp_evaluator-0.2.0/tests/test_debug_hooks.cpp +0 -170
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bundled_font_path.hpp.in +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.2.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/main.cpp +0 -0
|
@@ -241,15 +241,32 @@ Roman:style=Bold"`) silently gets Liberation Sans instead under this default pro
|
|
|
241
241
|
path needed in this repo: the fix is a Qt host application supplying its own `FontProvider`, which
|
|
242
242
|
is exactly what the injection seam exists for.
|
|
243
243
|
|
|
244
|
-
**Debugger/profiler, Phase 9 (the last phase)**: `checkDebug()` fires
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
sites
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
`
|
|
252
|
-
|
|
244
|
+
**Debugger/profiler, Phase 9 (the last phase)**: `checkDebug()` fires at **full parity with the
|
|
245
|
+
reference's `_check_debug` call sites** — the statement checkpoint in `evalChildren`'s `runAll`,
|
|
246
|
+
user-function/function-literal body entry, `breakpoint()`'s resolve, *and* the reference's
|
|
247
|
+
sub-statement sites: if/else branch entry (`evalStatement`), for-loop per-variable bindings and
|
|
248
|
+
per-iteration body entry (`evalFor`), `intersection_for` body entry, statement- and
|
|
249
|
+
expression-form `let()` assignments, expression-form `echo()`/`assert()`, ternary
|
|
250
|
+
condition/chosen-branch, every list-comprehension clause including the C-style `for`
|
|
251
|
+
(`evalListElement`), modifier-wrapped children (`evalModifier`), and user function/function-literal
|
|
252
|
+
call sites (`evalFunctionCall`, plus their duplicates in `simplifyTailStep` so a tail chain isn't
|
|
253
|
+
debug-invisible). Each carries the reference's `expr_level` flag, threaded all the way through
|
|
254
|
+
`DebugHookFn` and the nanobind trampoline. `expr_depth` is *not* tracked (hardcoded 0 through the
|
|
255
|
+
Python surface) — no consumer reads it.
|
|
256
|
+
|
|
257
|
+
An earlier revision of this file argued the sub-statement sites were unnecessary because no REPL
|
|
258
|
+
steps at that granularity. That was wrong: BelfrySCAD's debugger UI consumes them, and one case was
|
|
259
|
+
an outright bug — a C-style `for` *inside a list comprehension* got zero debug checks anywhere,
|
|
260
|
+
so a breakpoint set on it never fired. Two consequences of full parity worth knowing:
|
|
261
|
+
`useBytecodeVm()` returns false whenever a debug hook is installed (compiled chunks flatten away the
|
|
262
|
+
AST nodes these checkpoints hang off, so debugging always takes the interpreter path), and
|
|
263
|
+
`evalChildren` deliberately skips its own check for `ModularLet` — the reference's
|
|
264
|
+
`_eval_statement_impl` skips it too, pausing on the let's assignments instead. Parity is verified
|
|
265
|
+
test-by-test in `tests/test_debug_hooks.cpp`'s `DebugHooksParity` suite, whose expected
|
|
266
|
+
`(line, expr_level, forced)` sequences were captured by running the Python reference over the same
|
|
267
|
+
sources, not written down from this port's own output.
|
|
268
|
+
|
|
269
|
+
The port was also verified end to end by running an *identical*
|
|
253
270
|
`--debug` session (same script, same `break`/`run`/`print`/`continue`/`step`/`backtrace`/`set`
|
|
254
271
|
sequence) against both this port's CLI and the real Python reference's own `openscad-evaluator
|
|
255
272
|
--debug` side by side: transcripts matched exactly, **including** an unexpected extra pause neither
|
|
@@ -292,13 +292,42 @@ nb::list callStackToPy(const std::vector<oscadeval::CallStackFrame>& cs) {
|
|
|
292
292
|
return out;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
// Called from within a debug_hook/error_break callback (never after it
|
|
296
|
+
// returns) to best-effort generate a live render of whatever's been
|
|
297
|
+
// resolved so far -- see Evaluator::generatePartialTree()'s own doc
|
|
298
|
+
// comment for why this is safe to call mid-resolve.
|
|
299
|
+
using GeneratePartialFn = std::function<std::vector<oscadeval::ColoredBody>()>;
|
|
300
|
+
|
|
301
|
+
// Wraps a GeneratePartialFn as a Python callable returning a plain list of
|
|
302
|
+
// body-dicts (bodiesToList's own shape) -- the facade's _generate_partial_render
|
|
303
|
+
// converts these to ColoredBody and catches whatever exception a GenerateFn
|
|
304
|
+
// raises, the same try/except shape it already had calling generate_tree()
|
|
305
|
+
// directly. No error handling needed here: a C++ exception crossing into
|
|
306
|
+
// Python via this cpp_function is nanobind's normal std::exception ->
|
|
307
|
+
// RuntimeError mapping, which that Python try/except already catches.
|
|
308
|
+
nb::object generatePartialTrampoline(const GeneratePartialFn& generatePartial) {
|
|
309
|
+
return nb::cpp_function([&generatePartial]() -> nb::list {
|
|
310
|
+
std::vector<oscadeval::ColoredBody> bodies = generatePartial();
|
|
311
|
+
return bodiesToList(bodies);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
295
315
|
// Trampoline: C++ debug hook -> the Python DebugSession hook. Runs with the
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
316
|
+
// (origin, line) targets children()/children(N) might forward control to
|
|
317
|
+
// from the just-checked debug-hook node, for the "step to child" command.
|
|
318
|
+
// See Evaluator::lastChildrenPositions()'s own doc comment: valid only
|
|
319
|
+
// synchronously within the current hook call, same as get_frames.
|
|
320
|
+
using GetChildrenPositionsFn = std::function<const std::optional<std::vector<std::pair<std::string, int>>>&()>;
|
|
321
|
+
|
|
322
|
+
// GIL held (reacquired by the caller). `getFrame`/`callStack`/`generatePartial`/
|
|
323
|
+
// `getChildrenPositions` are valid only for this synchronous call, so their
|
|
324
|
+
// closures are only ever invoked from within the Python hook, before it returns.
|
|
325
|
+
oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, bool forced, bool exprLevel,
|
|
326
|
+
const std::string& origin,
|
|
300
327
|
const std::vector<oscadeval::CallStackFrame>& callStack,
|
|
301
|
-
const oscadeval::DebugFramesFn& getFrame
|
|
328
|
+
const oscadeval::DebugFramesFn& getFrame,
|
|
329
|
+
const GeneratePartialFn& generatePartial,
|
|
330
|
+
const GetChildrenPositionsFn& getChildrenPositions) {
|
|
302
331
|
auto getFramesPy = nb::cpp_function([&callStack, &getFrame]() -> nb::object {
|
|
303
332
|
std::vector<oscadeval::DebugFrame> frames = getFrame();
|
|
304
333
|
nb::list allFrameLocals;
|
|
@@ -313,9 +342,22 @@ oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, boo
|
|
|
313
342
|
}
|
|
314
343
|
return nb::make_tuple(nb::make_tuple(lastLocals, allFrameLocals), callStackToPy(callStack));
|
|
315
344
|
});
|
|
345
|
+
nb::object generatePartialPy = generatePartialTrampoline(generatePartial);
|
|
346
|
+
auto getChildrenPositionsPy = nb::cpp_function([&getChildrenPositions]() -> nb::object {
|
|
347
|
+
const std::optional<std::vector<std::pair<std::string, int>>>& positions = getChildrenPositions();
|
|
348
|
+
if (!positions) return nb::none();
|
|
349
|
+
nb::list out;
|
|
350
|
+
for (const auto& [origin, line] : *positions) out.append(nb::make_tuple(origin, line));
|
|
351
|
+
return out;
|
|
352
|
+
});
|
|
316
353
|
|
|
317
|
-
|
|
318
|
-
|
|
354
|
+
// expr_depth stays hardcoded at 0 -- this port deliberately doesn't
|
|
355
|
+
// track the reference's _expr_depth counter (no consumer reads it);
|
|
356
|
+
// expr_level, which consumers do read, is the real threaded value.
|
|
357
|
+
nb::object ret = hook(line, depth, nb::arg("forced") = forced, nb::arg("expr_level") = exprLevel,
|
|
358
|
+
nb::arg("expr_depth") = 0, nb::arg("origin") = origin, nb::arg("get_frames") = getFramesPy,
|
|
359
|
+
nb::arg("generate_partial") = generatePartialPy,
|
|
360
|
+
nb::arg("get_children_positions") = getChildrenPositionsPy);
|
|
319
361
|
nb::tuple t = nb::cast<nb::tuple>(ret);
|
|
320
362
|
oscadeval::DebugAction action;
|
|
321
363
|
action.stop = (nb::cast<std::string>(t[0]) == "stop");
|
|
@@ -327,11 +369,13 @@ oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, boo
|
|
|
327
369
|
// Trampoline: C++ errorBreak -> the Python DebugSession error hook.
|
|
328
370
|
void callPyErrorBreak(nb::handle errorBreak, int line, const std::string& header, const std::string& origin,
|
|
329
371
|
const std::vector<oscadeval::CallStackFrame>& callStack,
|
|
330
|
-
const oscadeval::DebugFramesFn& getFrame) {
|
|
372
|
+
const oscadeval::DebugFramesFn& getFrame, const GeneratePartialFn& generatePartial) {
|
|
331
373
|
std::vector<oscadeval::DebugFrame> frames = getFrame();
|
|
332
374
|
nb::list allFrameLocals;
|
|
333
375
|
for (const oscadeval::DebugFrame& f : frames) allFrameLocals.append(frameToDict(f));
|
|
334
|
-
|
|
376
|
+
nb::object generatePartialPy = generatePartialTrampoline(generatePartial);
|
|
377
|
+
errorBreak(line, header, allFrameLocals, callStackToPy(callStack), nb::arg("origin") = origin,
|
|
378
|
+
nb::arg("generate_partial") = generatePartialPy);
|
|
335
379
|
}
|
|
336
380
|
|
|
337
381
|
// Trampoline: C++ returnHook -> the Python DebugSession return hook. Only
|
|
@@ -362,17 +406,34 @@ nb::object debugEvaluate(const std::string& path, nb::dict viewportParams, nb::c
|
|
|
362
406
|
nb::gil_scoped_acquire g;
|
|
363
407
|
echoFn(m);
|
|
364
408
|
};
|
|
409
|
+
// Set right after `ev` is constructed below, before evaluate() runs
|
|
410
|
+
// -- every hook fires only from within that call, by which point
|
|
411
|
+
// this is always valid. Needed because `hooks` (captured by the
|
|
412
|
+
// lambdas below) must be fully built and passed into Evaluator's
|
|
413
|
+
// constructor before `ev` exists, so the lambdas can't capture `ev`
|
|
414
|
+
// itself; they capture this pointer's address instead, which DOES
|
|
415
|
+
// already exist (see generatePartial's own doc comment on why
|
|
416
|
+
// GeneratePartialFn needs a live Evaluator& at all).
|
|
417
|
+
oscadeval::Evaluator* evPtr = nullptr;
|
|
418
|
+
GeneratePartialFn generatePartial = [&evPtr]() -> std::vector<oscadeval::ColoredBody> {
|
|
419
|
+
return evPtr->generatePartialTree();
|
|
420
|
+
};
|
|
421
|
+
GetChildrenPositionsFn getChildrenPositions =
|
|
422
|
+
[&evPtr]() -> const std::optional<std::vector<std::pair<std::string, int>>>& {
|
|
423
|
+
return evPtr->lastChildrenPositions();
|
|
424
|
+
};
|
|
365
425
|
oscadeval::DebugHooks hooks;
|
|
366
|
-
hooks.debugHook = [&](int line, int depth, bool forced, const std::string& origin,
|
|
426
|
+
hooks.debugHook = [&](int line, int depth, bool forced, bool exprLevel, const std::string& origin,
|
|
367
427
|
const std::vector<oscadeval::CallStackFrame>& cs,
|
|
368
428
|
const oscadeval::DebugFramesFn& gf) -> oscadeval::DebugAction {
|
|
369
429
|
nb::gil_scoped_acquire g;
|
|
370
|
-
return callPyDebugHook(debugHook, line, depth, forced, origin, cs, gf
|
|
430
|
+
return callPyDebugHook(debugHook, line, depth, forced, exprLevel, origin, cs, gf, generatePartial,
|
|
431
|
+
getChildrenPositions);
|
|
371
432
|
};
|
|
372
433
|
hooks.errorBreak = [&](int line, const std::string& header, const std::string& origin,
|
|
373
434
|
const std::vector<oscadeval::CallStackFrame>& cs, const oscadeval::DebugFramesFn& gf) {
|
|
374
435
|
nb::gil_scoped_acquire g;
|
|
375
|
-
callPyErrorBreak(errorBreak, line, header, origin, cs, gf);
|
|
436
|
+
callPyErrorBreak(errorBreak, line, header, origin, cs, gf, generatePartial);
|
|
376
437
|
};
|
|
377
438
|
if (!returnHook.is_none()) {
|
|
378
439
|
hooks.returnHook = [&](const std::string& name, const oscadeval::Value& result, int depth) {
|
|
@@ -384,6 +445,7 @@ nb::object debugEvaluate(const std::string& path, nb::dict viewportParams, nb::c
|
|
|
384
445
|
std::vector<std::unique_ptr<oscad::ASTNode>> ast = oscad::getASTFromFile(path);
|
|
385
446
|
oscadeval::ResolvedUseScopes used = oscadeval::resolveUseScopes(ast, path, echoCpp);
|
|
386
447
|
oscadeval::Evaluator ev(echoCpp, nullptr, manifoldCache, hooks, false);
|
|
448
|
+
evPtr = &ev;
|
|
387
449
|
oscadeval::EvalContext ctx = oscadeval::EvalContext::makeRoot(used.rootScope.get());
|
|
388
450
|
bodies = oscadeval::toRenderableBodies(ev.evaluate(used.processedNodes, ctx, vp));
|
|
389
451
|
collectIdSpans(ev, idSpans);
|
|
@@ -46,7 +46,7 @@ std::string fmtLocals(const std::unordered_map<std::string, Value>& locals) {
|
|
|
46
46
|
void traceEveryStatement() {
|
|
47
47
|
std::cout << "1. trace every statement:\n";
|
|
48
48
|
DebugHooks hooks;
|
|
49
|
-
hooks.debugHook = [](int line, int depth, bool, const std::string&, const std::vector<CallStackFrame>&,
|
|
49
|
+
hooks.debugHook = [](int line, int depth, bool, bool, const std::string&, const std::vector<CallStackFrame>&,
|
|
50
50
|
const DebugFramesFn& getFrame) {
|
|
51
51
|
std::vector<DebugFrame> frames = getFrame();
|
|
52
52
|
DebugFrame frame = frames.empty() ? DebugFrame{} : frames.front();
|
|
@@ -69,7 +69,7 @@ void stopAtBreakpoint() {
|
|
|
69
69
|
constexpr int kBreakLine = 3; // the `translate(...) sphere(...)` statement
|
|
70
70
|
|
|
71
71
|
DebugHooks hooks;
|
|
72
|
-
hooks.debugHook = [](int line, int, bool, const std::string&, const std::vector<CallStackFrame>&, const DebugFramesFn&) {
|
|
72
|
+
hooks.debugHook = [](int line, int, bool, bool, const std::string&, const std::vector<CallStackFrame>&, const DebugFramesFn&) {
|
|
73
73
|
DebugAction action;
|
|
74
74
|
if (line == kBreakLine) {
|
|
75
75
|
std::cout << " breakpoint hit at line " << line << "\n";
|
|
@@ -97,7 +97,7 @@ void stopAtBreakpoint() {
|
|
|
97
97
|
void overrideVariableViaMods() {
|
|
98
98
|
std::cout << "3. override a variable via mods:\n";
|
|
99
99
|
DebugHooks hooks;
|
|
100
|
-
hooks.debugHook = [](int line, int, bool, const std::string&, const std::vector<CallStackFrame>&, const DebugFramesFn&) {
|
|
100
|
+
hooks.debugHook = [](int line, int, bool, bool, const std::string&, const std::vector<CallStackFrame>&, const DebugFramesFn&) {
|
|
101
101
|
DebugAction action;
|
|
102
102
|
if (line == 2) action.mods["width"] = Value{2.0}; // about to run `cube([width, width, width])`
|
|
103
103
|
return action;
|
|
@@ -86,25 +86,31 @@ inline constexpr const char* kDebuggingStoppedMessage = "Debugging stopped.";
|
|
|
86
86
|
// genuine (non-debugger-triggered) EvalError leaves it at.
|
|
87
87
|
enum class PostRunAction { None, Stopped, Restart, Quit };
|
|
88
88
|
|
|
89
|
-
// Called at
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
89
|
+
// Called at every point the Python reference calls _check_debug: every
|
|
90
|
+
// top-level statement in every block (Evaluator::evalChildren's single
|
|
91
|
+
// statement checkpoint), plus the reference's finer-grained sub-statement
|
|
92
|
+
// sites -- ternary condition and chosen branch, if/else branch entry,
|
|
93
|
+
// for-loop per-variable bindings and per-iteration body entry,
|
|
94
|
+
// statement- and expression-form let() assignments, expression-form
|
|
95
|
+
// echo()/assert(), every list-comprehension clause (if / if-else / let /
|
|
96
|
+
// each / for / C-style-for, plus bare elements), modifier-wrapped
|
|
97
|
+
// children, and user function / function-literal call sites. Also called
|
|
98
|
+
// once right before evaluating a user function/function-literal's body
|
|
99
|
+
// expression, and by breakpoint() (forced=true, unconditionally, matching
|
|
100
|
+
// the reference's own _check_debug(..., forced=True) call).
|
|
101
|
+
//
|
|
102
|
+
// `exprLevel` mirrors the reference's `expr_level` keyword exactly: true
|
|
103
|
+
// for the sub-expression markers a debugger should NOT treat as a
|
|
104
|
+
// steppable/breakpointable statement (a chosen ternary or if branch, a
|
|
105
|
+
// for-loop body entry, a list-comprehension body element, a C-style-for
|
|
106
|
+
// condition re-check). Both this port's own debug_repl.cpp and the
|
|
107
|
+
// reference's _debug_repl.py gate every step/breakpoint decision on
|
|
108
|
+
// `!exprLevel`, while still pausing unconditionally on `forced`.
|
|
109
|
+
//
|
|
104
110
|
// `depth` is the live user-call-stack depth (Evaluator::callStack_.size())
|
|
105
111
|
// at the pause point. Mirrors Evaluator._check_debug/the debug_hook
|
|
106
112
|
// callback contract.
|
|
107
|
-
using DebugHookFn = std::function<DebugAction(int line, int depth, bool forced, const std::string& origin,
|
|
113
|
+
using DebugHookFn = std::function<DebugAction(int line, int depth, bool forced, bool exprLevel, const std::string& origin,
|
|
108
114
|
const std::vector<CallStackFrame>& callStack, const DebugFramesFn& getFrame)>;
|
|
109
115
|
|
|
110
116
|
// Called from Evaluator::error() right before it throws, if set -- gives a
|
|
@@ -128,7 +128,7 @@ public:
|
|
|
128
128
|
bool runPrompt();
|
|
129
129
|
|
|
130
130
|
// Wire these three into Evaluator's DebugHooks (see debug_hooks.hpp).
|
|
131
|
-
DebugAction debugHook(int line, int depth, bool forced, const std::string& origin,
|
|
131
|
+
DebugAction debugHook(int line, int depth, bool forced, bool exprLevel, const std::string& origin,
|
|
132
132
|
const std::vector<CallStackFrame>& callStack, const DebugFramesFn& getFrame);
|
|
133
133
|
void errorBreak(int line, const std::string& header, const std::string& origin, const std::vector<CallStackFrame>& callStack,
|
|
134
134
|
const DebugFramesFn& getFrame);
|
|
@@ -174,6 +174,26 @@ public:
|
|
|
174
174
|
// top-level show_only filter -- see evaluate().
|
|
175
175
|
std::vector<ColoredBody> generateTree(const std::vector<std::unique_ptr<CSGNode>>& tree);
|
|
176
176
|
|
|
177
|
+
// Best-effort generate over whatever's been resolved SO FAR, for a live
|
|
178
|
+
// partial render while genuinely paused inside a debug hook mid-
|
|
179
|
+
// evaluation (resolveTree()/evaluate() haven't returned yet) -- flattens
|
|
180
|
+
// treeStack_ across every nesting level and runs the same bottom-up
|
|
181
|
+
// generate walk generateTree() uses, via generateTreeImpl(), over
|
|
182
|
+
// non-owning pointers into nodes treeStack_ (not this call) still owns.
|
|
183
|
+
// Safe to call mid-resolve: the resolve pass never reads CSGNode::bodies,
|
|
184
|
+
// only ever writes kind/params/children, so populating .bodies early
|
|
185
|
+
// here cannot corrupt or race the resolve that's paused around this
|
|
186
|
+
// call -- and if a ManifoldCache is set, the real generateTree() call at
|
|
187
|
+
// the end of evaluate() gets a cache hit for any subtree this already
|
|
188
|
+
// generated, so a debug session pays no repeated Manifold work session-
|
|
189
|
+
// wide (see manifold_cache.hpp's own doc comment on this exact use
|
|
190
|
+
// case). Only meaningful to call synchronously from within a
|
|
191
|
+
// DebugHookFn/ErrorBreakFn callback; the caller must not retain a
|
|
192
|
+
// reference into anything treeStack_ owns past that callback's return.
|
|
193
|
+
// Mirrors the reference's `ev.generate_tree(partial_nodes)` called from
|
|
194
|
+
// `_generate_partial_render`.
|
|
195
|
+
std::vector<ColoredBody> generatePartialTree();
|
|
196
|
+
|
|
177
197
|
// Provenance tables populated by tagGenerated() during generate --
|
|
178
198
|
// originalID -> the AST node that produced it / that node's own
|
|
179
199
|
// resolved color. Public, read by a caller (CLI, WYSIWYG picking) after
|
|
@@ -303,13 +323,16 @@ public:
|
|
|
303
323
|
// filtering, which lives entirely in the injected hook, not here) --
|
|
304
324
|
// it's simply passed through so the hook itself can distinguish an
|
|
305
325
|
// unconditional breakpoint()/function-entry pause from a normal
|
|
306
|
-
// statement-boundary check.
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
|
|
326
|
+
// statement-boundary check. `exprLevel=true` marks a sub-statement
|
|
327
|
+
// (expression-granularity) checkpoint that a stepping debugger should
|
|
328
|
+
// not treat as a statement boundary -- see debug_hooks.hpp's
|
|
329
|
+
// DebugHookFn doc comment for the full list of call sites and the
|
|
330
|
+
// exprLevel contract. Public: called from evalChildren() (every
|
|
331
|
+
// ordinary statement), evalUserFunction()/evalFunctionLiteral()
|
|
332
|
+
// (function body entry), and builtins/control.cpp's
|
|
333
|
+
// resolveBreakpoint/resolveIntersectionFor (free functions). Mirrors
|
|
334
|
+
// Evaluator._check_debug, including its parameter defaults.
|
|
335
|
+
void checkDebug(const oscad::ASTNode& node, EvalContext& ctx, bool forced = false, bool exprLevel = false);
|
|
313
336
|
|
|
314
337
|
// (origin, line) for each top-level, non-declaration child of the
|
|
315
338
|
// node checkDebug() was just called with -- i.e., if that node is a
|
|
@@ -357,6 +380,12 @@ private:
|
|
|
357
380
|
std::vector<ColoredBody> evaluateImpl(const NodeList& nodes, EvalContext& ctx,
|
|
358
381
|
const std::unordered_map<std::string, Value>& viewportParams);
|
|
359
382
|
|
|
383
|
+
// Shared bottom-up generate walk behind generateTree()/generatePartialTree()
|
|
384
|
+
// -- see generatePartialTree()'s own doc comment and this function's
|
|
385
|
+
// definition (csg_generate.cpp) for why non-owning pointers, not
|
|
386
|
+
// unique_ptr, let both callers share one implementation.
|
|
387
|
+
std::vector<ColoredBody> generateTreeImpl(const std::vector<CSGNode*>& tree);
|
|
388
|
+
|
|
360
389
|
// Evaluates one top-level element of a `[...]` list literal (a plain
|
|
361
390
|
// expression, or one of the 6 list-comprehension clause kinds --
|
|
362
391
|
// for/c-for/let/if/if-else/each), appending whatever it contributes to
|
|
@@ -763,6 +792,17 @@ private:
|
|
|
763
792
|
// strategy this enables).
|
|
764
793
|
static bool bytecodeVmEnabled();
|
|
765
794
|
|
|
795
|
+
// Per-evaluator gate actually consulted before using a compiled chunk.
|
|
796
|
+
// Compiled bytecode has no per-AST-node debug checkpoints (its whole
|
|
797
|
+
// point is to flatten those nodes away), so a function body run on the
|
|
798
|
+
// VM would silently skip every checkDebug() call site the interpreter
|
|
799
|
+
// path makes -- ternary branches, let()/echo()/assert() expression
|
|
800
|
+
// forms, list-comprehension clauses, nested call sites. Debugging
|
|
801
|
+
// therefore always takes the interpreter path, where the port matches
|
|
802
|
+
// the reference's _check_debug placement exactly. Costs nothing when
|
|
803
|
+
// no debugger is attached, which is every non-debug render.
|
|
804
|
+
bool useBytecodeVm() const { return !debugHooks_.debugHook && bytecodeVmEnabled(); }
|
|
805
|
+
|
|
766
806
|
// -- Profiling (Phase 9) --------------------------------------------
|
|
767
807
|
|
|
768
808
|
// (kind, name, callOrigin, callLine) -- the exact call-site identity a
|
|
@@ -17,7 +17,7 @@ from ._openscad_cpp_evaluator import ManifoldCache
|
|
|
17
17
|
|
|
18
18
|
__all__ = [
|
|
19
19
|
"Evaluator", "ColoredBody", "EvalError", "ParseError", "OscObject", "parse", "to_renderable_bodies",
|
|
20
|
-
"ManifoldCache", "CallSiteProfile", "ProfileResult", "format_csg_tree",
|
|
20
|
+
"ManifoldCache", "CallSiteProfile", "ProfileResult", "format_csg_tree", "bodies_from_dicts",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
|
|
@@ -132,7 +132,7 @@ class _CSGNode:
|
|
|
132
132
|
def __init__(self, kind, params, bodies, is_builtin, children):
|
|
133
133
|
self.kind = kind
|
|
134
134
|
self.params = params
|
|
135
|
-
self.bodies =
|
|
135
|
+
self.bodies = bodies_from_dicts(bodies)
|
|
136
136
|
self.is_builtin = is_builtin
|
|
137
137
|
self.children = children
|
|
138
138
|
|
|
@@ -289,6 +289,15 @@ class ColoredBody:
|
|
|
289
289
|
flat_preview: bool = False
|
|
290
290
|
|
|
291
291
|
|
|
292
|
+
def bodies_from_dicts(body_dicts) -> list:
|
|
293
|
+
"""Convert raw body-dicts (the shape both evaluate()/debug_evaluate() and
|
|
294
|
+
a debug hook's `generate_partial()` callable return) to ColoredBody
|
|
295
|
+
instances. Shared by Evaluator.evaluate() and a debug session's own live
|
|
296
|
+
partial-render (see debug_evaluate()'s `generate_partial` hook kwarg,
|
|
297
|
+
module.cpp) so both paths convert identically."""
|
|
298
|
+
return [ColoredBody(_BodyShim(d), d["color"], None, d["flat_preview"]) for d in body_dicts]
|
|
299
|
+
|
|
300
|
+
|
|
292
301
|
class Evaluator:
|
|
293
302
|
"""Drop-in for belfryscad.engine.evaluator.Evaluator, backed by C++.
|
|
294
303
|
|
|
@@ -355,7 +364,7 @@ class Evaluator:
|
|
|
355
364
|
raise
|
|
356
365
|
except Exception as e: # ParseError/EvalError from C++ arrive as RuntimeError
|
|
357
366
|
raise EvalError(str(e)) from e
|
|
358
|
-
bodies =
|
|
367
|
+
bodies = bodies_from_dicts(body_dicts)
|
|
359
368
|
# originalID -> a node with `.position` (start/end offsets) for WYSIWYG
|
|
360
369
|
# picking and gizmo write-back.
|
|
361
370
|
id_to_node = {
|
|
@@ -112,6 +112,11 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
112
112
|
|
|
113
113
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
114
114
|
if (depth == varSeqs.size()) {
|
|
115
|
+
// One body-entry marker per full cartesian-product iteration
|
|
116
|
+
// and nothing per individual variable binding (unlike
|
|
117
|
+
// evalFor) -- mirrors _resolve_intersection_for's single
|
|
118
|
+
// `_check_debug(body_node[0], loop_ctx, expr_level=True)`.
|
|
119
|
+
if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
115
120
|
const size_t before = ev.currentTreeFrameSize();
|
|
116
121
|
ev.evalChildren(bodyNodes, parentCtx);
|
|
117
122
|
const size_t after = ev.currentTreeFrameSize();
|
|
@@ -22,10 +22,18 @@ std::vector<ColoredBody> flattenCsgTree(const std::vector<std::unique_ptr<CSGNod
|
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// Shared bottom-up walk behind generateTree() (owning unique_ptr tree) and
|
|
26
|
+
// generatePartialTree() (a live, still-being-resolved treeStack_ level,
|
|
27
|
+
// which the resolve pass -- not this function -- continues to own): takes
|
|
28
|
+
// non-owning CSGNode* so both callers share one implementation without
|
|
29
|
+
// either transferring ownership. unique_ptr's constness doesn't propagate
|
|
30
|
+
// to the pointee, so mutating node.bodies here is legal even from a const
|
|
31
|
+
// vector<unique_ptr<CSGNode>>& (see csg_node.hpp) -- this overload just
|
|
32
|
+
// makes that non-owning access explicit for the treeStack_ caller too.
|
|
33
|
+
std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>& tree) {
|
|
26
34
|
std::vector<ColoredBody> topLevelBodies;
|
|
27
35
|
const auto& dispatch = generateDispatch();
|
|
28
|
-
for (
|
|
36
|
+
for (CSGNode* nodePtr : tree) {
|
|
29
37
|
CSGNode& node = *nodePtr;
|
|
30
38
|
|
|
31
39
|
// ManifoldCache lookup: node.uncacheable (rands() taint, set
|
|
@@ -43,10 +51,11 @@ std::vector<ColoredBody> Evaluator::generateTree(const std::vector<std::unique_p
|
|
|
43
51
|
} else {
|
|
44
52
|
// Recurse into children first (bottom-up) -- populates each
|
|
45
53
|
// child's own .bodies in place so flattenCsgTree/a GenerateFn
|
|
46
|
-
// can read them back.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
// can read them back.
|
|
55
|
+
std::vector<CSGNode*> childPtrs;
|
|
56
|
+
childPtrs.reserve(node.children.size());
|
|
57
|
+
for (const std::unique_ptr<CSGNode>& c : node.children) childPtrs.push_back(c.get());
|
|
58
|
+
generateTreeImpl(childPtrs);
|
|
50
59
|
|
|
51
60
|
auto it = dispatch.find(node.kind);
|
|
52
61
|
if (node.isBuiltin && it != dispatch.end()) {
|
|
@@ -66,6 +75,28 @@ std::vector<ColoredBody> Evaluator::generateTree(const std::vector<std::unique_p
|
|
|
66
75
|
return topLevelBodies;
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
std::vector<ColoredBody> Evaluator::generateTree(const std::vector<std::unique_ptr<CSGNode>>& tree) {
|
|
79
|
+
std::vector<CSGNode*> ptrs;
|
|
80
|
+
ptrs.reserve(tree.size());
|
|
81
|
+
for (const std::unique_ptr<CSGNode>& n : tree) ptrs.push_back(n.get());
|
|
82
|
+
return generateTreeImpl(ptrs);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
std::vector<ColoredBody> Evaluator::generatePartialTree() {
|
|
86
|
+
// Flatten treeStack_ across every nesting level (mirrors the reference's
|
|
87
|
+
// `[node for level in ev._tree_stack for node in level]`): a CSGNode
|
|
88
|
+
// only lands in its parent's own accumulator once the parent's resolve
|
|
89
|
+
// finishes, so for a script whose whole geometry is one deeply-nested
|
|
90
|
+
// top-level statement, the *top* of the tree stays empty for the entire
|
|
91
|
+
// time spent stepping through its innermost leaves -- flattening every
|
|
92
|
+
// level picks up already-resolved leaves (e.g. a finished cube() sitting
|
|
93
|
+
// in a still-in-progress union()'s accumulator) regardless of how deep.
|
|
94
|
+
std::vector<CSGNode*> flat;
|
|
95
|
+
for (const std::vector<std::unique_ptr<CSGNode>>& level : treeStack_)
|
|
96
|
+
for (const std::unique_ptr<CSGNode>& node : level) flat.push_back(node.get());
|
|
97
|
+
return generateTreeImpl(flat);
|
|
98
|
+
}
|
|
99
|
+
|
|
69
100
|
ColoredBody Evaluator::tagGenerated(manifold::Manifold body, const oscad::ASTNode& node, const Value& colorValue) {
|
|
70
101
|
manifold::MeshGL mesh = body.GetMeshGL();
|
|
71
102
|
std::optional<std::array<float, 4>> color = valueToColor(colorValue);
|
|
@@ -140,6 +140,16 @@ void Evaluator::evalModifier(const oscad::ModuleInstantiation& child, const osca
|
|
|
140
140
|
// always empty (role tagging happens entirely in the matching
|
|
141
141
|
// generate function -- generateHighlight/Background/ShowOnly).
|
|
142
142
|
buildTreeNode(kind, wrapperNode, [&]() {
|
|
143
|
+
// The wrapped child gets its own statement-level stop, in addition
|
|
144
|
+
// to the modifier node's (which evalChildren already fired before
|
|
145
|
+
// dispatching here) -- so `#cube(1);` pauses twice, like the
|
|
146
|
+
// reference. There, _resolve_modifier_child has no _check_debug of
|
|
147
|
+
// its own: it calls _eval_statement(node.child, ctx), and _that_
|
|
148
|
+
// dispatcher independently checks every _TREE_NODE_TYPES node it
|
|
149
|
+
// is handed. This port's evalStatement has no such blanket check
|
|
150
|
+
// (evalChildren owns it), so the equivalent stop is made explicit
|
|
151
|
+
// here.
|
|
152
|
+
checkDebug(child, ctx);
|
|
143
153
|
evalStatement(child, ctx);
|
|
144
154
|
return CSGParams{};
|
|
145
155
|
});
|
|
@@ -425,18 +425,24 @@ bool DebugRepl::runPrompt() {
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
DebugAction DebugRepl::debugHook(int line, int depth, bool forced, const std::string& origin,
|
|
428
|
+
DebugAction DebugRepl::debugHook(int line, int depth, bool forced, bool exprLevel, const std::string& origin,
|
|
429
429
|
const std::vector<CallStackFrame>& callStack, const DebugFramesFn& getFrame) {
|
|
430
430
|
if (quit_) return DebugAction{true, {}};
|
|
431
431
|
|
|
432
|
+
// Every step/breakpoint/first-statement decision below is gated on
|
|
433
|
+
// !exprLevel -- a sub-expression marker (chosen ternary/if branch,
|
|
434
|
+
// loop body entry, list-comprehension body element) is not a statement
|
|
435
|
+
// this REPL steps to or breaks on. Only `forced` (breakpoint()) and an
|
|
436
|
+
// async pause request ignore it. Mirrors _debug_repl.py's debug_hook
|
|
437
|
+
// exactly, clause for clause.
|
|
432
438
|
const std::string resolved = resolveOrigin(origin);
|
|
433
439
|
bool stepHit = false;
|
|
434
440
|
if (stepCmd_ == "over") {
|
|
435
|
-
stepHit = depth <= stepDepth_ && resolved == stepOrigin_ && line != stepLine_;
|
|
441
|
+
stepHit = depth <= stepDepth_ && resolved == stepOrigin_ && line != stepLine_ && !exprLevel;
|
|
436
442
|
} else if (stepCmd_ == "into") {
|
|
437
|
-
stepHit = line != stepLine_ || resolved != stepOrigin_;
|
|
443
|
+
stepHit = (line != stepLine_ || resolved != stepOrigin_) && !exprLevel;
|
|
438
444
|
} else if (stepCmd_ == "out") {
|
|
439
|
-
stepHit = depth < stepDepth_;
|
|
445
|
+
stepHit = depth < stepDepth_ && !exprLevel;
|
|
440
446
|
} else if (stepCmd_ == "to_child") {
|
|
441
447
|
// Pause the first time control reaches one of the paused call's
|
|
442
448
|
// own children (wherever children()/children(N) forwards to
|
|
@@ -444,7 +450,7 @@ DebugAction DebugRepl::debugHook(int line, int depth, bool forced, const std::st
|
|
|
444
450
|
// back to the same "call returned" safety net step-out uses, so
|
|
445
451
|
// this can never hang. Mirrors BelfrySCAD's DebugSession::
|
|
446
452
|
// _make_hook exactly.
|
|
447
|
-
stepHit = stepToChildTargets_.count({resolved, line}) > 0 || depth < stepDepth_;
|
|
453
|
+
stepHit = !exprLevel && (stepToChildTargets_.count({resolved, line}) > 0 || depth < stepDepth_);
|
|
448
454
|
}
|
|
449
455
|
|
|
450
456
|
// Read-and-clear, same as BelfrySCAD's own DebugSession.pause()/
|
|
@@ -454,8 +460,8 @@ DebugAction DebugRepl::debugHook(int line, int depth, bool forced, const std::st
|
|
|
454
460
|
// immediate re-pause; a harmless quirk, not a hang or crash.
|
|
455
461
|
const bool pauseRequested = pauseRequested_.exchange(false, std::memory_order_relaxed);
|
|
456
462
|
|
|
457
|
-
const bool shouldPause = forced || pauseRequested || (breakOnFirst_ && resolved == sourcePath_) ||
|
|
458
|
-
breakpoints_[resolved].count(line) > 0 || stepHit;
|
|
463
|
+
const bool shouldPause = forced || pauseRequested || (breakOnFirst_ && !exprLevel && resolved == sourcePath_) ||
|
|
464
|
+
(breakpoints_[resolved].count(line) > 0 && !exprLevel) || stepHit;
|
|
459
465
|
if (!shouldPause) return DebugAction{};
|
|
460
466
|
|
|
461
467
|
breakOnFirst_ = false;
|
|
@@ -74,14 +74,14 @@ std::vector<DebugFrame> Evaluator::buildDebugFrames(const EvalContext* ctx) cons
|
|
|
74
74
|
return frames;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
void Evaluator::checkDebug(const oscad::ASTNode& node, EvalContext& ctx, bool forced) {
|
|
77
|
+
void Evaluator::checkDebug(const oscad::ASTNode& node, EvalContext& ctx, bool forced, bool exprLevel) {
|
|
78
78
|
if (!debugHooks_.debugHook) return;
|
|
79
79
|
const oscad::Position& pos = node.position();
|
|
80
80
|
const int depth = static_cast<int>(callStack_.size());
|
|
81
81
|
const DebugFramesFn getFrame = [this, &ctx]() { return buildDebugFrames(&ctx); };
|
|
82
82
|
lastChildrenPositions_ = childStatementPositions(node);
|
|
83
83
|
|
|
84
|
-
DebugAction action = debugHooks_.debugHook(pos.line, depth, forced, pos.origin, callStack_, getFrame);
|
|
84
|
+
DebugAction action = debugHooks_.debugHook(pos.line, depth, forced, exprLevel, pos.origin, callStack_, getFrame);
|
|
85
85
|
for (auto& [k, v] : action.mods) ctx.let_->set(k, v);
|
|
86
86
|
if (action.stop) throw EvalError(kDebuggingStoppedMessage);
|
|
87
87
|
}
|