openscad-cpp-evaluator 0.3.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.3.0 → openscad_cpp_evaluator-0.4.0}/CLAUDE.md +26 -9
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/bindings/module.cpp +32 -8
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/examples/minimal_debugger.cpp +3 -3
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +22 -16
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/debug_repl.hpp +1 -1
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/evaluator.hpp +21 -7
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/control.cpp +5 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/csg_resolve.cpp +10 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/debug/debug_repl.cpp +13 -7
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/debug_profile.cpp +2 -2
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/expr_eval.cpp +54 -6
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/stmt_eval.cpp +40 -15
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/user_calls.cpp +24 -6
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_cli.cpp +1 -1
- {openscad_cpp_evaluator-0.3.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.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_python_bindings.py +27 -3
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_tail_calls.cpp +22 -10
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/cli_lib.cpp +2 -2
- openscad_cpp_evaluator-0.3.0/tests/test_debug_hooks.cpp +0 -170
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.3.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.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.3.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.3.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.3.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.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bundled_font_path.hpp.in +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.3.0 → openscad_cpp_evaluator-0.4.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.3.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
|
|
@@ -313,13 +313,21 @@ nb::object generatePartialTrampoline(const GeneratePartialFn& generatePartial) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// Trampoline: C++ debug hook -> the Python DebugSession hook. Runs with the
|
|
316
|
-
//
|
|
317
|
-
//
|
|
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
|
|
318
324
|
// closures are only ever invoked from within the Python hook, before it returns.
|
|
319
|
-
oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, bool forced,
|
|
325
|
+
oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, bool forced, bool exprLevel,
|
|
326
|
+
const std::string& origin,
|
|
320
327
|
const std::vector<oscadeval::CallStackFrame>& callStack,
|
|
321
328
|
const oscadeval::DebugFramesFn& getFrame,
|
|
322
|
-
const GeneratePartialFn& generatePartial
|
|
329
|
+
const GeneratePartialFn& generatePartial,
|
|
330
|
+
const GetChildrenPositionsFn& getChildrenPositions) {
|
|
323
331
|
auto getFramesPy = nb::cpp_function([&callStack, &getFrame]() -> nb::object {
|
|
324
332
|
std::vector<oscadeval::DebugFrame> frames = getFrame();
|
|
325
333
|
nb::list allFrameLocals;
|
|
@@ -335,10 +343,21 @@ oscadeval::DebugAction callPyDebugHook(nb::handle hook, int line, int depth, boo
|
|
|
335
343
|
return nb::make_tuple(nb::make_tuple(lastLocals, allFrameLocals), callStackToPy(callStack));
|
|
336
344
|
});
|
|
337
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
|
+
});
|
|
338
353
|
|
|
339
|
-
|
|
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,
|
|
340
358
|
nb::arg("expr_depth") = 0, nb::arg("origin") = origin, nb::arg("get_frames") = getFramesPy,
|
|
341
|
-
nb::arg("generate_partial") = generatePartialPy
|
|
359
|
+
nb::arg("generate_partial") = generatePartialPy,
|
|
360
|
+
nb::arg("get_children_positions") = getChildrenPositionsPy);
|
|
342
361
|
nb::tuple t = nb::cast<nb::tuple>(ret);
|
|
343
362
|
oscadeval::DebugAction action;
|
|
344
363
|
action.stop = (nb::cast<std::string>(t[0]) == "stop");
|
|
@@ -399,12 +418,17 @@ nb::object debugEvaluate(const std::string& path, nb::dict viewportParams, nb::c
|
|
|
399
418
|
GeneratePartialFn generatePartial = [&evPtr]() -> std::vector<oscadeval::ColoredBody> {
|
|
400
419
|
return evPtr->generatePartialTree();
|
|
401
420
|
};
|
|
421
|
+
GetChildrenPositionsFn getChildrenPositions =
|
|
422
|
+
[&evPtr]() -> const std::optional<std::vector<std::pair<std::string, int>>>& {
|
|
423
|
+
return evPtr->lastChildrenPositions();
|
|
424
|
+
};
|
|
402
425
|
oscadeval::DebugHooks hooks;
|
|
403
|
-
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,
|
|
404
427
|
const std::vector<oscadeval::CallStackFrame>& cs,
|
|
405
428
|
const oscadeval::DebugFramesFn& gf) -> oscadeval::DebugAction {
|
|
406
429
|
nb::gil_scoped_acquire g;
|
|
407
|
-
return callPyDebugHook(debugHook, line, depth, forced, origin, cs, gf, generatePartial
|
|
430
|
+
return callPyDebugHook(debugHook, line, depth, forced, exprLevel, origin, cs, gf, generatePartial,
|
|
431
|
+
getChildrenPositions);
|
|
408
432
|
};
|
|
409
433
|
hooks.errorBreak = [&](int line, const std::string& header, const std::string& origin,
|
|
410
434
|
const std::vector<oscadeval::CallStackFrame>& cs, const oscadeval::DebugFramesFn& gf) {
|
|
@@ -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);
|
|
@@ -323,13 +323,16 @@ public:
|
|
|
323
323
|
// filtering, which lives entirely in the injected hook, not here) --
|
|
324
324
|
// it's simply passed through so the hook itself can distinguish an
|
|
325
325
|
// unconditional breakpoint()/function-entry pause from a normal
|
|
326
|
-
// statement-boundary check.
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
|
|
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);
|
|
333
336
|
|
|
334
337
|
// (origin, line) for each top-level, non-declaration child of the
|
|
335
338
|
// node checkDebug() was just called with -- i.e., if that node is a
|
|
@@ -789,6 +792,17 @@ private:
|
|
|
789
792
|
// strategy this enables).
|
|
790
793
|
static bool bytecodeVmEnabled();
|
|
791
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
|
+
|
|
792
806
|
// -- Profiling (Phase 9) --------------------------------------------
|
|
793
807
|
|
|
794
808
|
// (kind, name, callOrigin, callLine) -- the exact call-site identity a
|
|
@@ -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();
|
|
@@ -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
|
}
|
|
@@ -119,6 +119,11 @@ Value Evaluator::evalIdentifier(const std::string& name, const oscad::Position*
|
|
|
119
119
|
|
|
120
120
|
// -- List comprehensions ----------------------------------------------
|
|
121
121
|
|
|
122
|
+
// Debug checkpoints below mirror the reference's _eval_list_comp AND its
|
|
123
|
+
// near-duplicate twin _eval_list_comp_body (both dispatch over the same
|
|
124
|
+
// ListComp* kinds with identical _check_debug placement; this port folds
|
|
125
|
+
// them into this one function plus evalListCompBody's ListComprehension
|
|
126
|
+
// early-out, so one set of calls covers both).
|
|
122
127
|
void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, std::vector<Value>& out) {
|
|
123
128
|
switch (elem.kind()) {
|
|
124
129
|
case oscad::NodeKind::ListCompFor: {
|
|
@@ -147,6 +152,11 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
147
152
|
for (const Value& val : pairs[depth].values) {
|
|
148
153
|
EvalContext childCtx = parentCtx.letChildCtx();
|
|
149
154
|
childCtx.let_->set(pairs[depth].name, val);
|
|
155
|
+
// Per-binding stop, same shape as evalFor's -- but with
|
|
156
|
+
// NO separate body-entry marker at depth == pairs.size()
|
|
157
|
+
// (_eval_listcomp_for has none; the body's own element
|
|
158
|
+
// check below supplies the expr-level stop instead).
|
|
159
|
+
checkDebug(*n.assignments[depth], childCtx);
|
|
150
160
|
recurse(depth + 1, childCtx);
|
|
151
161
|
}
|
|
152
162
|
};
|
|
@@ -154,47 +164,73 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
154
164
|
return;
|
|
155
165
|
}
|
|
156
166
|
case oscad::NodeKind::ListCompCFor: {
|
|
167
|
+
// Stop order per _eval_listcomp_cfor, exactly:
|
|
168
|
+
// init(s) -> [cond(true) -> body -> incr(s)]* -> cond(false)
|
|
169
|
+
// The condition is checked (expr-level) on EVERY pass including
|
|
170
|
+
// the final false one that ends the loop; body entry uses the
|
|
171
|
+
// whole ListCompCFor node, not the body expression.
|
|
157
172
|
auto& n = static_cast<const oscad::ListCompCFor&>(elem);
|
|
158
173
|
EvalContext loopCtx = ctx.letChildCtx();
|
|
159
|
-
for (const auto& assign : n.inits)
|
|
174
|
+
for (const auto& assign : n.inits) {
|
|
175
|
+
checkDebug(*assign, loopCtx);
|
|
176
|
+
loopCtx.let_->set(assign->name->name, evalExpr(*assign->expr, loopCtx));
|
|
177
|
+
}
|
|
160
178
|
|
|
161
179
|
const bool isNestedLc = (n.body->kind() == oscad::NodeKind::ListComprehension);
|
|
162
180
|
constexpr int kMaxCForIterations = 1'000'000;
|
|
163
181
|
int iterations = 0;
|
|
164
|
-
while (
|
|
182
|
+
while (true) {
|
|
183
|
+
checkDebug(*n.condition, loopCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
184
|
+
if (!truthy(evalExpr(*n.condition, loopCtx))) break;
|
|
165
185
|
++iterations;
|
|
166
186
|
if (iterations > kMaxCForIterations) {
|
|
167
187
|
error("C-style for loop exceeded maximum iteration count", n);
|
|
168
188
|
}
|
|
189
|
+
checkDebug(n, loopCtx);
|
|
169
190
|
if (isNestedLc) {
|
|
170
191
|
out.push_back(evalListLiteral(static_cast<const oscad::ListComprehension&>(*n.body), loopCtx));
|
|
171
192
|
} else {
|
|
172
193
|
appendAll(out, evalListCompBody(*n.body, loopCtx));
|
|
173
194
|
}
|
|
174
|
-
for (const auto& assign : n.incrs)
|
|
195
|
+
for (const auto& assign : n.incrs) {
|
|
196
|
+
checkDebug(*assign, loopCtx);
|
|
197
|
+
loopCtx.let_->set(assign->name->name, evalExpr(*assign->expr, loopCtx));
|
|
198
|
+
}
|
|
175
199
|
}
|
|
176
200
|
return;
|
|
177
201
|
}
|
|
178
202
|
case oscad::NodeKind::ListCompIf: {
|
|
179
203
|
auto& n = static_cast<const oscad::ListCompIf&>(elem);
|
|
180
|
-
|
|
204
|
+
checkDebug(n, ctx);
|
|
205
|
+
if (truthy(evalExpr(*n.condition, ctx))) {
|
|
206
|
+
checkDebug(*n.trueExpr, ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
207
|
+
appendAll(out, evalListCompBody(*n.trueExpr, ctx));
|
|
208
|
+
}
|
|
181
209
|
return;
|
|
182
210
|
}
|
|
183
211
|
case oscad::NodeKind::ListCompIfElse: {
|
|
184
212
|
auto& n = static_cast<const oscad::ListCompIfElse&>(elem);
|
|
213
|
+
checkDebug(n, ctx);
|
|
185
214
|
const oscad::ASTNode& branch = truthy(evalExpr(*n.condition, ctx)) ? *n.trueExpr : *n.falseExpr;
|
|
215
|
+
checkDebug(branch, ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
186
216
|
appendAll(out, evalListCompBody(branch, ctx));
|
|
187
217
|
return;
|
|
188
218
|
}
|
|
189
219
|
case oscad::NodeKind::ListCompLet: {
|
|
190
220
|
auto& n = static_cast<const oscad::ListCompLet&>(elem);
|
|
191
221
|
EvalContext letCtx = ctx.letChildCtx();
|
|
192
|
-
|
|
222
|
+
// Per-assignment stops only -- no expr-level body marker here,
|
|
223
|
+
// unlike the if/if-else/each clauses (matches the reference).
|
|
224
|
+
for (const auto& assign : n.assignments) {
|
|
225
|
+
checkDebug(*assign, letCtx);
|
|
226
|
+
bindLetName(letCtx, assign->name->name, evalExpr(*assign->expr, letCtx));
|
|
227
|
+
}
|
|
193
228
|
appendAll(out, evalListCompBody(*n.body, letCtx));
|
|
194
229
|
return;
|
|
195
230
|
}
|
|
196
231
|
case oscad::NodeKind::ListCompEach: {
|
|
197
232
|
auto& n = static_cast<const oscad::ListCompEach&>(elem);
|
|
233
|
+
checkDebug(n, ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
198
234
|
const oscad::ASTNode& inner = *n.body;
|
|
199
235
|
if (isListCompClauseKind(inner.kind())) {
|
|
200
236
|
for (const Value& item : evalListCompBody(inner, ctx)) appendEachInto(out, item);
|
|
@@ -204,6 +240,7 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
204
240
|
return;
|
|
205
241
|
}
|
|
206
242
|
default:
|
|
243
|
+
checkDebug(elem, ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
207
244
|
out.push_back(evalExpr(static_cast<const oscad::Expression&>(elem), ctx));
|
|
208
245
|
return;
|
|
209
246
|
}
|
|
@@ -265,6 +302,9 @@ Value Evaluator::evalLetExpr(const oscad::LetOp& node, EvalContext& ctx) {
|
|
|
265
302
|
// Unlike the *statement* form (evalLetBlock), which does not --
|
|
266
303
|
// see that method's own doc comment for why this isn't a copy/paste
|
|
267
304
|
// mistake in one direction or the other.
|
|
305
|
+
// Checked against childCtx (not ctx) -- _expr_let does the same,
|
|
306
|
+
// the mirror image of _eval_let_block's `_check_debug(assign, ctx)`.
|
|
307
|
+
checkDebug(*assign, childCtx);
|
|
268
308
|
Value v = evalExpr(*assign->expr, childCtx);
|
|
269
309
|
bindLetName(childCtx, assign->name->name, v);
|
|
270
310
|
}
|
|
@@ -272,6 +312,7 @@ Value Evaluator::evalLetExpr(const oscad::LetOp& node, EvalContext& ctx) {
|
|
|
272
312
|
}
|
|
273
313
|
|
|
274
314
|
Value Evaluator::evalEchoExpr(const oscad::EchoOp& node, EvalContext& ctx) {
|
|
315
|
+
checkDebug(node, ctx); // _expr_echo
|
|
275
316
|
doEcho(node.arguments, ctx);
|
|
276
317
|
return evalExpr(*node.body, ctx);
|
|
277
318
|
}
|
|
@@ -281,6 +322,7 @@ Value Evaluator::evalAssertExpr(const oscad::AssertOp& node, EvalContext& ctx) {
|
|
|
281
322
|
// arguments via getArg()/CallArgs, the expression form indexes raw
|
|
282
323
|
// arguments positionally -- mirrors the reference's _expr_assert
|
|
283
324
|
// exactly (`raw[0].expr`/`raw[1].expr`, not _get_arg).
|
|
325
|
+
checkDebug(node, ctx); // _expr_assert, before the condition is evaluated
|
|
284
326
|
const auto& raw = node.arguments;
|
|
285
327
|
const bool condition = raw.empty() || truthy(evalExpr(*argExpr(*raw[0]), ctx));
|
|
286
328
|
if (!condition) {
|
|
@@ -431,8 +473,14 @@ Value Evaluator::evalExpr(const oscad::Expression& node, EvalContext& ctx) {
|
|
|
431
473
|
}
|
|
432
474
|
|
|
433
475
|
case NodeKind::TernaryOp: {
|
|
476
|
+
// Mirrors _expr_ternary: a statement-level stop on the whole
|
|
477
|
+
// ternary before the condition runs, then an expr-level one on
|
|
478
|
+
// whichever branch was chosen, before evaluating it.
|
|
434
479
|
auto& n = static_cast<const oscad::TernaryOp&>(node);
|
|
435
|
-
|
|
480
|
+
checkDebug(n, ctx);
|
|
481
|
+
const oscad::Expression& branch = truthy(evalExpr(*n.condition, ctx)) ? *n.trueExpr : *n.falseExpr;
|
|
482
|
+
checkDebug(branch, ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
483
|
+
return evalExpr(branch, ctx);
|
|
436
484
|
}
|
|
437
485
|
|
|
438
486
|
case NodeKind::BitwiseOrOp: {
|
|
@@ -95,12 +95,22 @@ void Evaluator::evalFor(const oscad::ModularFor& node, EvalContext& ctx) {
|
|
|
95
95
|
// `let_`.
|
|
96
96
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
97
97
|
if (depth == pairs.size()) {
|
|
98
|
+
// Per-full-iteration "entering the body" marker, separate from
|
|
99
|
+
// (and before) the body's own per-statement checks in
|
|
100
|
+
// evalChildren -- mirrors _eval_for's
|
|
101
|
+
// `_check_debug(node.body[0], parent_ctx, expr_level=True)`.
|
|
102
|
+
if (!bodyNodes.empty()) checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
98
103
|
evalChildren(bodyNodes, parentCtx);
|
|
99
104
|
return;
|
|
100
105
|
}
|
|
101
106
|
for (const Value& val : pairs[depth].values) {
|
|
102
107
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
|
103
108
|
childCtx.let_->set(pairs[depth].name, val);
|
|
109
|
+
// One statement-level stop per (bound-so-far) combination, on
|
|
110
|
+
// the loop-variable assignment itself -- so a breakpoint set
|
|
111
|
+
// directly on an `i=[0:2],`/`j=[0:1]` line fires. Mirrors
|
|
112
|
+
// _eval_for's `_check_debug(assign_node, child)`.
|
|
113
|
+
checkDebug(*node.assignments[depth], childCtx);
|
|
104
114
|
recurse(depth + 1, childCtx);
|
|
105
115
|
}
|
|
106
116
|
};
|
|
@@ -119,6 +129,9 @@ void Evaluator::evalLetBlock(const oscad::ModularLet& node, EvalContext& ctx) {
|
|
|
119
129
|
// _eval_let_block, not an oversight -- it evaluates every RHS against
|
|
120
130
|
// `ctx` in the loop, only ever writing into `child_ctx`.
|
|
121
131
|
for (const auto& assign : node.assignments) {
|
|
132
|
+
// Checked against the ORIGINAL ctx (like the RHS eval below), not
|
|
133
|
+
// childCtx -- mirrors _eval_let_block's `_check_debug(assign, ctx)`.
|
|
134
|
+
checkDebug(*assign, ctx);
|
|
122
135
|
Value v = evalExpr(*assign->expr, ctx);
|
|
123
136
|
const std::string& name = assign->name->name;
|
|
124
137
|
if (!name.empty() && name[0] == '$') {
|
|
@@ -163,18 +176,25 @@ void Evaluator::evalStatement(const oscad::ASTNode& node, EvalContext& ctx) {
|
|
|
163
176
|
case oscad::NodeKind::ModularIntersectionFor:
|
|
164
177
|
evalIntersectionForNode(static_cast<const oscad::ModularIntersectionFor&>(node), ctx);
|
|
165
178
|
return;
|
|
179
|
+
// Both if-forms fire a branch-entry marker after the condition and
|
|
180
|
+
// before the branch's own per-statement checks, on the branch's
|
|
181
|
+
// first statement (or the if node itself for an empty branch) --
|
|
182
|
+
// mirrors _eval_statement_impl's
|
|
183
|
+
// `_check_debug(branch[0] if branch else node, ctx, expr_level=True)`.
|
|
166
184
|
case oscad::NodeKind::ModularIf: {
|
|
167
185
|
auto& n = static_cast<const oscad::ModularIf&>(node);
|
|
168
|
-
if (truthy(evalExpr(*n.condition, ctx)))
|
|
186
|
+
if (truthy(evalExpr(*n.condition, ctx))) {
|
|
187
|
+
checkDebug(n.trueBranch.empty() ? node : *n.trueBranch.front(), ctx, /*forced=*/false,
|
|
188
|
+
/*exprLevel=*/true);
|
|
189
|
+
evalChildren(n.trueBranch, ctx);
|
|
190
|
+
}
|
|
169
191
|
return;
|
|
170
192
|
}
|
|
171
193
|
case oscad::NodeKind::ModularIfElse: {
|
|
172
194
|
auto& n = static_cast<const oscad::ModularIfElse&>(node);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
evalChildren(n.falseBranch, ctx);
|
|
177
|
-
}
|
|
195
|
+
const auto& branch = truthy(evalExpr(*n.condition, ctx)) ? n.trueBranch : n.falseBranch;
|
|
196
|
+
checkDebug(branch.empty() ? node : *branch.front(), ctx, /*forced=*/false, /*exprLevel=*/true);
|
|
197
|
+
evalChildren(branch, ctx);
|
|
178
198
|
return;
|
|
179
199
|
}
|
|
180
200
|
case oscad::NodeKind::ModularFor:
|
|
@@ -220,15 +240,20 @@ void Evaluator::evalChildren(const std::vector<const oscad::ASTNode*>& children,
|
|
|
220
240
|
// always overwrites it before any subsequent read could see a
|
|
221
241
|
// dangling value.
|
|
222
242
|
lastCtx_ = &childCtx;
|
|
223
|
-
//
|
|
224
|
-
// (module/function bodies,
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
243
|
+
// The port's statement-level debug checkpoint: every real
|
|
244
|
+
// statement flows through here (module/function bodies,
|
|
245
|
+
// for-loop bodies, if/else branches, let-block bodies, the
|
|
246
|
+
// top-level script). Declarations are pure no-ops at
|
|
247
|
+
// statement-eval time (already hoisted into scope), so there's
|
|
248
|
+
// nothing useful to pause on. ModularLet is excluded for a
|
|
249
|
+
// different reason: the reference's _eval_statement_impl
|
|
250
|
+
// explicitly skips it too (`t is not ModularLet` in its own
|
|
251
|
+
// guard) because evalLetBlock pauses on each of the let's
|
|
252
|
+
// ASSIGNMENTS instead -- checking here as well would produce
|
|
253
|
+
// one extra stop the reference never fires.
|
|
254
|
+
const oscad::NodeKind k = child->kind();
|
|
255
|
+
if (k != oscad::NodeKind::ModuleDeclaration && k != oscad::NodeKind::FunctionDeclaration &&
|
|
256
|
+
k != oscad::NodeKind::ModularLet) {
|
|
232
257
|
checkDebug(*child, childCtx);
|
|
233
258
|
}
|
|
234
259
|
evalStatement(*child, childCtx);
|