openscad-cpp-evaluator 1.18.0__tar.gz → 1.19.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-1.18.0 → openscad_cpp_evaluator-1.19.0}/CLAUDE.md +33 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/bindings/module.cpp +56 -4
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/bytecode.hpp +6 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +5 -5
- openscad_cpp_evaluator-1.19.0/include/openscad_cpp_evaluator/coverage.hpp +116 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/evaluator.hpp +20 -1
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/python/openscad_cpp_evaluator/__init__.py +13 -3
- openscad_cpp_evaluator-1.19.0/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/CMakeLists.txt +1 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/bytecode_compiler.cpp +35 -16
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/bytecode_vm.cpp +4 -0
- openscad_cpp_evaluator-1.19.0/src/coverage.cpp +397 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/csg_resolve.cpp +11 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/expr_eval.cpp +7 -2
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/stmt_eval.cpp +9 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/user_calls.cpp +7 -5
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-1.19.0/tests/test_coverage.cpp +234 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_python_bindings.py +33 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.18.0 → openscad_cpp_evaluator-1.19.0}/uv.lock +0 -0
|
@@ -1480,6 +1480,39 @@ than the current pause point). Ported identically (same qualifier syntax, same e
|
|
|
1480
1480
|
- `tools/cli/main.cpp` — a 3-line wrapper: builds `args` from `argv`, calls `runCli(args)` with the
|
|
1481
1481
|
real `std::cin`/`std::cout`/`std::cerr`, returns its exit code.
|
|
1482
1482
|
|
|
1483
|
+
## Coverage
|
|
1484
|
+
|
|
1485
|
+
`Evaluator(coverage=true)` records which parts of a run's source actually executed and
|
|
1486
|
+
fills `coverageResult`: `spans` (one per coverable node), `files` (one `CoverageFileSummary`
|
|
1487
|
+
per origin, sorted: statements/branches/bodies/spans, each with a hit count and a percent;
|
|
1488
|
+
`branches` counts Branch spans plus arm Statements, `percent` is over every span) and `total`
|
|
1489
|
+
(the same over every file). `summarizeCoverage()` is public so an aggregated span list can be
|
|
1490
|
+
re-summarised. Bindings: `Evaluator(coverage=True)` → `ev.coverage_result`, a dict
|
|
1491
|
+
`{spans, files, total}` of plain dicts. The vocabulary is fixed in one place,
|
|
1492
|
+
`coverage.hpp`/`coverage.cpp`, and used by both the recorder and the universe walk, so
|
|
1493
|
+
"covered" and "uncovered" never disagree about what counts:
|
|
1494
|
+
|
|
1495
|
+
- **statement** — every node in a statement list (top level, module/if/for/let bodies,
|
|
1496
|
+
`render()` children). A modifier (`%`/`#`/`!`/`*`) is the statement; the call it wraps is
|
|
1497
|
+
not one of its own. The first statement of an if/else arm carries `arm=true`.
|
|
1498
|
+
- **branch** — a ternary arm, a comprehension if/else arm, the right operand of `&&`/`||`.
|
|
1499
|
+
- **body** — a function, module or function-literal declaration: was it ever entered?
|
|
1500
|
+
|
|
1501
|
+
Hits are recorded at deliberate points, once per execution: `evalChildren`'s statement loop
|
|
1502
|
+
and `Op::Cover` (emitted per statement by `compileOneStatement`/`tryCompileAssignmentBlock`
|
|
1503
|
+
and at every arm, only when the Evaluator was built with coverage — chunks are per-Evaluator)
|
|
1504
|
+
on the two paths; `enterUserCall` for bodies; the arm sites in `evalExpr`, the tail
|
|
1505
|
+
trampoline (`simplifyTailStep`, which bypasses `evalExpr`'s own TernaryOp case) and the
|
|
1506
|
+
comprehension if/else cases. **Not** from `checkDebug`: the debugger checkpoints an if-arm's
|
|
1507
|
+
first statement twice and the `if` itself never, so piggybacking on it gave counts that
|
|
1508
|
+
differed between the VM and the interpreter. `Coverage.VmAndInterpreterAgree` compares the
|
|
1509
|
+
covered set under both and is the test that keeps them honest. The VM stays on under
|
|
1510
|
+
coverage (unlike a debug hook). The hit table is indexed by the node's `(treeId, slot)`
|
|
1511
|
+
numbering, so a hit is an array increment. Used-file globals are in the universe via
|
|
1512
|
+
`usedFileGlobals_`; everything else comes from the processed node list with each node's own
|
|
1513
|
+
`origin`, so includes and `use`d files report under their own paths. Let-bindings and plain
|
|
1514
|
+
comprehension elements are not in the vocabulary; hits on them are simply not reported.
|
|
1515
|
+
|
|
1483
1516
|
## `render()` in expression position
|
|
1484
1517
|
|
|
1485
1518
|
`render()` has two jobs, decided by where it is written:
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
#include "openscad_cpp_evaluator/freetype_font_provider.hpp"
|
|
27
27
|
#include "openscad_cpp_evaluator/mesh_check.hpp"
|
|
28
28
|
#include "openscad_cpp_evaluator/manifold_cache.hpp"
|
|
29
|
+
#include "openscad_cpp_evaluator/coverage.hpp"
|
|
29
30
|
#include "openscad_cpp_evaluator/profile.hpp"
|
|
30
31
|
#include "openscad_cpp_evaluator/value.hpp"
|
|
31
32
|
|
|
@@ -432,9 +433,51 @@ nb::list exportModelPy(const std::string& path, const Geometry& geom, const std:
|
|
|
432
433
|
return out;
|
|
433
434
|
}
|
|
434
435
|
|
|
436
|
+
nb::dict coverageSummaryToPy(const oscadeval::CoverageFileSummary& f) {
|
|
437
|
+
nb::dict d;
|
|
438
|
+
d["origin"] = f.origin;
|
|
439
|
+
d["statements"] = f.statements;
|
|
440
|
+
d["statements_hit"] = f.statements_hit;
|
|
441
|
+
d["branches"] = f.branches;
|
|
442
|
+
d["branches_hit"] = f.branches_hit;
|
|
443
|
+
d["bodies"] = f.bodies;
|
|
444
|
+
d["bodies_hit"] = f.bodies_hit;
|
|
445
|
+
d["spans"] = f.spans;
|
|
446
|
+
d["spans_hit"] = f.spans_hit;
|
|
447
|
+
d["percent"] = f.percent();
|
|
448
|
+
d["statement_percent"] = f.statement_percent();
|
|
449
|
+
d["branch_percent"] = f.branch_percent();
|
|
450
|
+
d["body_percent"] = f.body_percent();
|
|
451
|
+
return d;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
nb::object coverageResultToPy(const std::optional<oscadeval::CoverageResult>& cr) {
|
|
455
|
+
if (!cr) return nb::none();
|
|
456
|
+
nb::list files;
|
|
457
|
+
for (const oscadeval::CoverageFileSummary& f : cr->files) files.append(coverageSummaryToPy(f));
|
|
458
|
+
nb::list out;
|
|
459
|
+
for (const oscadeval::CoverageSpan& s : cr->spans) {
|
|
460
|
+
nb::dict d;
|
|
461
|
+
d["origin"] = s.origin;
|
|
462
|
+
d["line"] = s.line;
|
|
463
|
+
d["column"] = s.column;
|
|
464
|
+
d["start"] = s.start_offset;
|
|
465
|
+
d["end"] = s.end_offset;
|
|
466
|
+
d["kind"] = oscadeval::coverageKindName(s.kind);
|
|
467
|
+
d["arm"] = s.arm;
|
|
468
|
+
d["hits"] = s.hits;
|
|
469
|
+
out.append(d);
|
|
470
|
+
}
|
|
471
|
+
nb::dict result;
|
|
472
|
+
result["spans"] = out;
|
|
473
|
+
result["files"] = files;
|
|
474
|
+
result["total"] = coverageSummaryToPy(cr->total);
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
|
|
435
478
|
nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
436
479
|
std::shared_ptr<oscadeval::ManifoldCache> manifoldCache, bool profile,
|
|
437
|
-
bool generate, bool strictCommas) {
|
|
480
|
+
bool generate, bool strictCommas, bool coverage) {
|
|
438
481
|
std::unordered_map<std::string, oscadeval::Value> vp = toViewportParams(viewportParams);
|
|
439
482
|
|
|
440
483
|
std::vector<oscadeval::ColoredBody> bodies;
|
|
@@ -442,6 +485,7 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
442
485
|
std::vector<IdSpan> idSpans;
|
|
443
486
|
std::vector<std::unique_ptr<oscadeval::CSGNode>> csgTree;
|
|
444
487
|
std::optional<oscadeval::ProfileResult> profileResult;
|
|
488
|
+
std::optional<oscadeval::CoverageResult> coverageResult;
|
|
445
489
|
nb::dict dyn;
|
|
446
490
|
nb::object dynExplicit;
|
|
447
491
|
{
|
|
@@ -456,7 +500,7 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
456
500
|
if (strictCommas) strict.emplace();
|
|
457
501
|
oscad::ParsedProgram program = oscad::getProgramFromFile(path);
|
|
458
502
|
oscadeval::ResolvedUseScopes used = oscadeval::resolveUseScopes(program.nodes, path, logFn);
|
|
459
|
-
oscadeval::Evaluator ev(logFn, nullptr, manifoldCache, oscadeval::DebugHooks{}, profile);
|
|
503
|
+
oscadeval::Evaluator ev(logFn, nullptr, manifoldCache, oscadeval::DebugHooks{}, profile, coverage);
|
|
460
504
|
ev.setUsedFileGlobals(used.usedFileGlobals);
|
|
461
505
|
oscadeval::EvalContext ctx = oscadeval::EvalContext::makeRoot(used.rootScope.get());
|
|
462
506
|
bodies = oscadeval::toRenderableBodies(ev.evaluate(used.processedNodes, ctx, vp, generate));
|
|
@@ -466,6 +510,7 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
466
510
|
// which a resolve-only caller has no use for.
|
|
467
511
|
if (generate) csgTree = std::move(ev.csgTree);
|
|
468
512
|
profileResult = std::move(ev.profileResult);
|
|
513
|
+
coverageResult = std::move(ev.coverageResult);
|
|
469
514
|
{
|
|
470
515
|
nb::gil_scoped_acquire g; // building Python objects needs the GIL back
|
|
471
516
|
std::tie(dyn, dynExplicit) = dynStateToPy(ctx);
|
|
@@ -495,7 +540,7 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
495
540
|
auto geom = std::make_shared<Geometry>();
|
|
496
541
|
geom->bodies = std::move(bodies);
|
|
497
542
|
return nb::make_tuple(bodiesToList(geom->bodies), echoList, idSpansToDict(idSpans), csgTreeToPy(csgTree),
|
|
498
|
-
profileResultToPy(profileResult), dyn, dynExplicit, geom);
|
|
543
|
+
profileResultToPy(profileResult), dyn, dynExplicit, geom, coverageResultToPy(coverageResult));
|
|
499
544
|
}
|
|
500
545
|
|
|
501
546
|
// ------------------------------------------------------------------------
|
|
@@ -910,7 +955,14 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
910
955
|
|
|
911
956
|
m.def("evaluate", &evaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("manifold_cache") = nullptr,
|
|
912
957
|
nb::arg("profile") = false, nb::arg("generate") = true, nb::arg("strict_commas") = false,
|
|
913
|
-
"
|
|
958
|
+
nb::arg("coverage") = false,
|
|
959
|
+
"Evaluate a .scad file; return (bodies, echoes, id_to_node, csg_tree, profile_result, dyn, dyn_explicit, "
|
|
960
|
+
"geometry, coverage_result).\n"
|
|
961
|
+
"coverage=True records which statements, branch arms and bodies ran: coverage_result is a dict "
|
|
962
|
+
"{spans, files, total}: spans is a list of dicts (origin, line, column, start, end, kind, arm, hits), "
|
|
963
|
+
"one per coverable node of every file the run touched; files is one summary per origin, sorted "
|
|
964
|
+
"(statements/statements_hit, branches/branches_hit, bodies/bodies_hit, spans/spans_hit and the four "
|
|
965
|
+
"percent fields); total is the same over every file. None when off.\n"
|
|
914
966
|
"generate=False stops after the resolve pass: the script runs and reports everything "
|
|
915
967
|
"it normally would, but no Manifold geometry is built, and neither bodies nor csg_tree "
|
|
916
968
|
"are populated.\n\n"
|
|
@@ -728,6 +728,12 @@ enum class Op {
|
|
|
728
728
|
// on failure, otherwise runs any chained node.children natively (rare;
|
|
729
729
|
// not worth its own compiled path -- see AssertSite's own doc comment).
|
|
730
730
|
AssertStatement,
|
|
731
|
+
// a = nativeStatements index of the AST node whose arm this is. Emitted
|
|
732
|
+
// only when the Evaluator was built with coverage on (compile-time
|
|
733
|
+
// flag, and chunks are per-Evaluator): Evaluator::coverHit(node), nothing
|
|
734
|
+
// else. Marks the arms the debugger never checkpoints in compiled code
|
|
735
|
+
// -- ternary arms, comprehension if/else arms, `&&`/`||` right operands.
|
|
736
|
+
Cover,
|
|
731
737
|
};
|
|
732
738
|
|
|
733
739
|
struct Instruction {
|
|
@@ -21,7 +21,7 @@ namespace oscadeval {
|
|
|
21
21
|
// whole function, unconditionally correct since nothing about this
|
|
22
22
|
// function's behavior changes based on whether it happened to compile.
|
|
23
23
|
std::optional<CompiledChunk> tryCompileFunction(const oscad::FunctionDeclaration& decl,
|
|
24
|
-
const oscad::ScopeTable* scopeTable);
|
|
24
|
+
const oscad::ScopeTable* scopeTable, bool coverage = false);
|
|
25
25
|
|
|
26
26
|
// Compiles a bare STATEMENT-context expression -- an assignment's RHS, an
|
|
27
27
|
// if/for condition, a module-call or echo()/assert() argument -- rather
|
|
@@ -50,7 +50,7 @@ std::optional<CompiledChunk> tryCompileFunction(const oscad::FunctionDeclaration
|
|
|
50
50
|
// any callee inside it statically, the same way a function body's call
|
|
51
51
|
// sites are.
|
|
52
52
|
std::optional<CompiledChunk> tryCompileStatementExpr(const oscad::Expression& expr, const oscad::Scope* scope,
|
|
53
|
-
const oscad::ScopeTable* scopeTable);
|
|
53
|
+
const oscad::ScopeTable* scopeTable, bool coverage = false);
|
|
54
54
|
|
|
55
55
|
// Compiles a run of SIBLING assignment statements sharing one scope --
|
|
56
56
|
// exactly Evaluator::evalChildren's own `assignments` sub-list (stmt_eval.
|
|
@@ -85,7 +85,7 @@ std::optional<CompiledChunk> tryCompileStatementExpr(const oscad::Expression& ex
|
|
|
85
85
|
// instead of just for that one assignment's own RHS.
|
|
86
86
|
std::optional<CompiledChunk> tryCompileAssignmentBlock(const std::vector<const oscad::Assignment*>& assigns,
|
|
87
87
|
const oscad::ScopeTable* scopeTable,
|
|
88
|
-
const oscad::Scope* scope);
|
|
88
|
+
const oscad::Scope* scope, bool coverage = false);
|
|
89
89
|
|
|
90
90
|
// Attempts to compile `decl`'s parameter defaults + STATEMENT-list body
|
|
91
91
|
// (decl.children) to bytecode (Stage 2) -- the module-side analog of
|
|
@@ -101,7 +101,7 @@ std::optional<CompiledChunk> tryCompileAssignmentBlock(const std::vector<const o
|
|
|
101
101
|
// EXPRESSION (inside an if-condition/for-range/argument) can still bail
|
|
102
102
|
// (via tryCompileStatementExpr's own NotCompilable, propagated up).
|
|
103
103
|
std::optional<CompiledChunk> tryCompileModuleBody(const oscad::ModuleDeclaration& decl,
|
|
104
|
-
const oscad::ScopeTable* scopeTable);
|
|
104
|
+
const oscad::ScopeTable* scopeTable, bool coverage = false);
|
|
105
105
|
|
|
106
106
|
// Same compilation (assignment/if/for/resolved-module-call get real
|
|
107
107
|
// bytecode, everything else a native passthrough), but for an ARBITRARY
|
|
@@ -126,6 +126,6 @@ std::optional<CompiledChunk> tryCompileModuleBody(const oscad::ModuleDeclaration
|
|
|
126
126
|
// scope()`, mirroring tryRunCompiledAssignmentBlock's own convention.
|
|
127
127
|
std::optional<CompiledChunk> tryCompileChildrenList(const std::vector<const oscad::ASTNode*>& children,
|
|
128
128
|
const oscad::ScopeTable* scopeTable,
|
|
129
|
-
const oscad::Scope* scope);
|
|
129
|
+
const oscad::Scope* scope, bool coverage = false);
|
|
130
130
|
|
|
131
131
|
} // namespace oscadeval
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Coverage: which parts of a script (and of the libraries it pulls in) ran.
|
|
4
|
+
//
|
|
5
|
+
// The unit of coverage is the checkpoint set the debugger already uses --
|
|
6
|
+
// Evaluator::checkDebug fires for every statement, every function/module
|
|
7
|
+
// body entered, every if/else arm's first statement, every ternary arm and
|
|
8
|
+
// list-comprehension if/else arm -- plus two arms the debugger never needed
|
|
9
|
+
// to stop at, the right operands of `&&`/`||`. Recording a hit is an array
|
|
10
|
+
// increment indexed by the node's (treeId, slot), the dense per-parse
|
|
11
|
+
// numbering ScopeTable relies on, so the bytecode VM stays on and a hit
|
|
12
|
+
// costs no hashing and no string.
|
|
13
|
+
//
|
|
14
|
+
// What COULD have run -- the universe the report counts against -- comes
|
|
15
|
+
// from a walk over the same trees (collectCoverable) using one predicate
|
|
16
|
+
// for both sides, so "covered" and "uncovered" are one vocabulary. A hit
|
|
17
|
+
// on a node outside that vocabulary (a let-binding, a plain comprehension
|
|
18
|
+
// element) is simply not reported.
|
|
19
|
+
|
|
20
|
+
#include "openscad_cpp_parser/ast/ast_node.hpp"
|
|
21
|
+
|
|
22
|
+
#include <cstdint>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <vector>
|
|
25
|
+
|
|
26
|
+
namespace oscadeval {
|
|
27
|
+
|
|
28
|
+
enum class CoverageKind {
|
|
29
|
+
Statement, // a statement in a module body, an if/for/let body, or at top level
|
|
30
|
+
Branch, // a ternary arm, a comprehension if/else arm, a `&&`/`||` right operand
|
|
31
|
+
Body, // a function, module or function-literal body: was it ever entered?
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const char* coverageKindName(CoverageKind kind);
|
|
35
|
+
|
|
36
|
+
struct CoverageSpan {
|
|
37
|
+
std::string origin;
|
|
38
|
+
int line = 0;
|
|
39
|
+
int column = 0;
|
|
40
|
+
int start_offset = 0;
|
|
41
|
+
int end_offset = 0;
|
|
42
|
+
CoverageKind kind = CoverageKind::Statement;
|
|
43
|
+
// A Statement that is the first of an if/else arm. Branch coverage counts
|
|
44
|
+
// these alongside the Branch kind; they stay Statements so a statement
|
|
45
|
+
// count is still a statement count.
|
|
46
|
+
bool arm = false;
|
|
47
|
+
std::uint32_t hits = 0;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Per-file totals. "branches" counts Branch spans plus arm Statements (an
|
|
51
|
+
// if/else arm is a branch too); those arm statements are ALSO in
|
|
52
|
+
// "statements", since a statement count should be a statement count.
|
|
53
|
+
// "percent" is over every span in the file, whatever its kind.
|
|
54
|
+
struct CoverageFileSummary {
|
|
55
|
+
std::string origin;
|
|
56
|
+
std::uint32_t statements = 0, statements_hit = 0;
|
|
57
|
+
std::uint32_t branches = 0, branches_hit = 0;
|
|
58
|
+
std::uint32_t bodies = 0, bodies_hit = 0;
|
|
59
|
+
std::uint32_t spans = 0, spans_hit = 0;
|
|
60
|
+
double percent() const { return spans ? 100.0 * spans_hit / spans : 100.0; }
|
|
61
|
+
double statement_percent() const { return statements ? 100.0 * statements_hit / statements : 100.0; }
|
|
62
|
+
double branch_percent() const { return branches ? 100.0 * branches_hit / branches : 100.0; }
|
|
63
|
+
double body_percent() const { return bodies ? 100.0 * bodies_hit / bodies : 100.0; }
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
struct CoverageResult {
|
|
67
|
+
std::vector<CoverageSpan> spans; // one per coverable node, source order per tree
|
|
68
|
+
std::vector<CoverageFileSummary> files; // one per origin, sorted by origin
|
|
69
|
+
CoverageFileSummary total; // every file together (origin empty)
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// The per-file and total summaries for `spans`; buildCoverageResult calls
|
|
73
|
+
// this, and a merged/aggregated span list (BelfrySCAD's --test --coverage)
|
|
74
|
+
// can call it again.
|
|
75
|
+
void summarizeCoverage(CoverageResult& result);
|
|
76
|
+
|
|
77
|
+
class CoverageRecorder {
|
|
78
|
+
public:
|
|
79
|
+
void clear() { hits_.clear(); }
|
|
80
|
+
void hit(const oscad::ASTNode& node) {
|
|
81
|
+
const std::uint32_t tree = node.treeId(), slot = node.slot();
|
|
82
|
+
if (tree >= hits_.size()) hits_.resize(tree + 1);
|
|
83
|
+
std::vector<std::uint32_t>& slots = hits_[tree];
|
|
84
|
+
if (slot >= slots.size()) slots.resize(slot + 1, 0);
|
|
85
|
+
++slots[slot];
|
|
86
|
+
}
|
|
87
|
+
std::uint32_t hitsFor(const oscad::ASTNode& node) const {
|
|
88
|
+
const std::uint32_t tree = node.treeId(), slot = node.slot();
|
|
89
|
+
if (tree >= hits_.size()) return 0;
|
|
90
|
+
const std::vector<std::uint32_t>& slots = hits_[tree];
|
|
91
|
+
return slot < slots.size() ? slots[slot] : 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private:
|
|
95
|
+
std::vector<std::vector<std::uint32_t>> hits_;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
struct Coverable {
|
|
99
|
+
const oscad::ASTNode* node = nullptr;
|
|
100
|
+
CoverageKind kind = CoverageKind::Statement;
|
|
101
|
+
bool arm = false;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Every coverable node under `roots` (a top-level statement list: the main
|
|
105
|
+
// file with its includes spliced in and any use-injected declarations) plus
|
|
106
|
+
// `extraStatements` (a used file's own top-level assignments, which `use`
|
|
107
|
+
// never splices anywhere -- see Evaluator::setUsedFileGlobals). Source
|
|
108
|
+
// order within each tree; a node reachable twice is listed once.
|
|
109
|
+
std::vector<Coverable> collectCoverable(const std::vector<const oscad::ASTNode*>& roots,
|
|
110
|
+
const std::vector<const oscad::ASTNode*>& extraStatements);
|
|
111
|
+
|
|
112
|
+
CoverageResult buildCoverageResult(const std::vector<const oscad::ASTNode*>& roots,
|
|
113
|
+
const std::vector<const oscad::ASTNode*>& extraStatements,
|
|
114
|
+
const CoverageRecorder& recorder);
|
|
115
|
+
|
|
116
|
+
} // namespace oscadeval
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include "openscad_cpp_evaluator/debug_hooks.hpp"
|
|
9
9
|
#include "openscad_cpp_evaluator/eval_context.hpp"
|
|
10
10
|
#include "openscad_cpp_evaluator/eval_use.hpp"
|
|
11
|
+
#include "openscad_cpp_evaluator/coverage.hpp"
|
|
11
12
|
#include "openscad_cpp_evaluator/eval_error.hpp"
|
|
12
13
|
#include "openscad_cpp_evaluator/font_provider.hpp"
|
|
13
14
|
#include "openscad_cpp_evaluator/manifold_cache.hpp"
|
|
@@ -84,7 +85,7 @@ public:
|
|
|
84
85
|
// work at all.
|
|
85
86
|
explicit Evaluator(EchoFn echoFn = {}, std::shared_ptr<FontProvider> fontProvider = nullptr,
|
|
86
87
|
std::shared_ptr<ManifoldCache> manifoldCache = nullptr, DebugHooks debugHooks = {},
|
|
87
|
-
bool profiling = false);
|
|
88
|
+
bool profiling = false, bool coverage = false);
|
|
88
89
|
|
|
89
90
|
// Text/font builtins' shared access to the resolved FontProvider
|
|
90
91
|
// (lazily constructing the built-in default on first call if none was
|
|
@@ -659,6 +660,22 @@ public:
|
|
|
659
660
|
// resolve+generate bracket evaluate() itself runs). Mirrors the
|
|
660
661
|
// reference's Evaluator.profile_result.
|
|
661
662
|
std::optional<ProfileResult> profileResult;
|
|
663
|
+
// Filled by evaluate() when constructed with coverage=true: one span per
|
|
664
|
+
// coverable node of every tree the run touched, with its hit count.
|
|
665
|
+
// See coverage.hpp for the vocabulary.
|
|
666
|
+
std::optional<CoverageResult> coverageResult;
|
|
667
|
+
|
|
668
|
+
bool coverageEnabled() const { return coverage_; }
|
|
669
|
+
// Called once per statement execution (evalChildren on the interpreter
|
|
670
|
+
// side, Op::Cover on the compiled side), once per body entry
|
|
671
|
+
// (enterUserCall), and once per branch arm taken (ternary, comprehension
|
|
672
|
+
// if/else, `&&`/`||` right operand). Deliberately NOT from checkDebug:
|
|
673
|
+
// the debugger's checkpoints double up on an if-arm's first statement
|
|
674
|
+
// and never land on the `if` itself. Free when coverage is off: one
|
|
675
|
+
// predictable branch.
|
|
676
|
+
void coverHit(const oscad::ASTNode& node) {
|
|
677
|
+
if (coverage_) coverageRecorder_.hit(node);
|
|
678
|
+
}
|
|
662
679
|
|
|
663
680
|
// The resolved (and, after evaluate() runs, generated) CSG tree from the
|
|
664
681
|
// most recent evaluate() call -- moved here from evaluateImpl's local
|
|
@@ -1984,6 +2001,8 @@ private:
|
|
|
1984
2001
|
// -- Profiling (Phase 9) ----------------------------------------------
|
|
1985
2002
|
|
|
1986
2003
|
bool profiling_ = false;
|
|
2004
|
+
bool coverage_ = false;
|
|
2005
|
+
CoverageRecorder coverageRecorder_;
|
|
1987
2006
|
std::map<ProfileSiteKey, CallSiteProfile> profileSites_;
|
|
1988
2007
|
std::set<ProfileSiteKey> profileActive_; // site keys with a call currently on callStack_
|
|
1989
2008
|
std::vector<double> profileChildTime_; // parallel aux stack to callStack_
|
|
@@ -532,7 +532,7 @@ class Evaluator:
|
|
|
532
532
|
"""
|
|
533
533
|
|
|
534
534
|
def __init__(self, echo_fn=None, debug_hook=None, error_break_fn=None, return_hook=None,
|
|
535
|
-
manifold_cache=None, profile=False, fast_continue_signal=None):
|
|
535
|
+
manifold_cache=None, profile=False, fast_continue_signal=None, coverage=False):
|
|
536
536
|
self._echo_fn = echo_fn
|
|
537
537
|
self._debug_hook = debug_hook
|
|
538
538
|
self._error_break_fn = error_break_fn
|
|
@@ -540,8 +540,17 @@ class Evaluator:
|
|
|
540
540
|
self._manifold_cache = manifold_cache
|
|
541
541
|
self._profile = profile
|
|
542
542
|
self._fast_continue_signal = fast_continue_signal
|
|
543
|
+
self._coverage = coverage
|
|
543
544
|
self.csg_tree = []
|
|
544
545
|
self.profile_result = None
|
|
546
|
+
# coverage=True: after evaluate(), {"spans": [...], "files": [...],
|
|
547
|
+
# "total": {...}}. spans: one dict (origin, line, column, start, end,
|
|
548
|
+
# kind, arm, hits) per coverable node -- statement, branch arm, or
|
|
549
|
+
# function/module body -- of every file the run touched. files: one
|
|
550
|
+
# summary per origin, sorted, with counts and percentages per kind
|
|
551
|
+
# and overall; total: the same over every file. None when off. See
|
|
552
|
+
# coverage.hpp.
|
|
553
|
+
self.coverage_result = None
|
|
545
554
|
self.dyn = {}
|
|
546
555
|
self.dyn_explicit = set()
|
|
547
556
|
|
|
@@ -583,9 +592,9 @@ class Evaluator:
|
|
|
583
592
|
self.geometry = None
|
|
584
593
|
else:
|
|
585
594
|
(body_dicts, echoes, id_spans, csg_tree, profile_result, dyn,
|
|
586
|
-
dyn_explicit, geometry) = _ext.evaluate(
|
|
595
|
+
dyn_explicit, geometry, coverage_result) = _ext.evaluate(
|
|
587
596
|
source_path, vp, self._manifold_cache, self._profile, generate,
|
|
588
|
-
strict_commas)
|
|
597
|
+
strict_commas, self._coverage)
|
|
589
598
|
# The evaluated bodies, still on the C++ side. Stashed like
|
|
590
599
|
# csg_tree/profile_result rather than returned, so
|
|
591
600
|
# evaluate()'s own 2-tuple result is unchanged -- callers
|
|
@@ -598,6 +607,7 @@ class Evaluator:
|
|
|
598
607
|
self._echo_fn(line)
|
|
599
608
|
self.csg_tree = csg_tree
|
|
600
609
|
self.profile_result = profile_result
|
|
610
|
+
self.coverage_result = coverage_result
|
|
601
611
|
self.dyn = dyn
|
|
602
612
|
self.dyn_explicit = dyn_explicit
|
|
603
613
|
except EvalError:
|
|
Binary file
|
|
@@ -271,7 +271,7 @@ class Compiler;
|
|
|
271
271
|
bool compileFunctionLike(CompiledChunk& chunk, const oscad::Scope* staticScope, const oscad::ASTNode* selfDecl,
|
|
272
272
|
const oscad::ScopeTable* scopeTable, std::vector<EnclosingLevel> enclosing,
|
|
273
273
|
const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params,
|
|
274
|
-
const oscad::Expression& bodyExpr);
|
|
274
|
+
const oscad::Expression& bodyExpr, bool coverage = false);
|
|
275
275
|
|
|
276
276
|
class Compiler {
|
|
277
277
|
public:
|
|
@@ -291,9 +291,9 @@ public:
|
|
|
291
291
|
// when compiling a FunctionLiteral nested inside another compile --
|
|
292
292
|
// see the FunctionLiteral case in compileExpr).
|
|
293
293
|
Compiler(CompiledChunk& chunk, const oscad::Scope* scope, const oscad::ASTNode* selfDecl,
|
|
294
|
-
const oscad::ScopeTable* scopeTable, std::vector<EnclosingLevel> enclosing)
|
|
294
|
+
const oscad::ScopeTable* scopeTable, std::vector<EnclosingLevel> enclosing, bool coverage = false)
|
|
295
295
|
: chunk_(chunk), scope_(scope), selfDecl_(selfDecl), scopeTable_(scopeTable),
|
|
296
|
-
enclosing_(std::move(enclosing)) {}
|
|
296
|
+
enclosing_(std::move(enclosing)), coverage_(coverage) {}
|
|
297
297
|
|
|
298
298
|
// A node's own lexical scope, or null. Replaces ASTNode::scope(),
|
|
299
299
|
// which is gone: one parsed tree is shared between evaluations, so a
|
|
@@ -470,7 +470,7 @@ public:
|
|
|
470
470
|
childEnclosing.push_back({selfDecl_, &scope});
|
|
471
471
|
CompiledChunk literalChunk;
|
|
472
472
|
if (!compileFunctionLike(literalChunk, scopeOf(n), &n, scopeTable_, std::move(childEnclosing), n.parameters,
|
|
473
|
-
*n.body)) {
|
|
473
|
+
*n.body, coverage_)) {
|
|
474
474
|
throw NotCompilable{};
|
|
475
475
|
}
|
|
476
476
|
// Effective capture set: `n`'s own direct free-variable
|
|
@@ -555,10 +555,12 @@ public:
|
|
|
555
555
|
compileExpr(*n.condition, out, scope); // condition is never tail
|
|
556
556
|
size_t jumpToFalse = out.size();
|
|
557
557
|
out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
|
|
558
|
+
cover(out, n.trueExpr.get());
|
|
558
559
|
compileExpr(*n.trueExpr, out, scope, tail); // both branches inherit
|
|
559
560
|
size_t jumpToEnd = out.size();
|
|
560
561
|
out.push_back({Op::Jump, 0, 0, nullptr});
|
|
561
562
|
out[jumpToFalse].a = static_cast<int>(out.size());
|
|
563
|
+
cover(out, n.falseExpr.get());
|
|
562
564
|
compileExpr(*n.falseExpr, out, scope, tail);
|
|
563
565
|
out[jumpToEnd].a = static_cast<int>(out.size());
|
|
564
566
|
return;
|
|
@@ -568,6 +570,7 @@ public:
|
|
|
568
570
|
compileExpr(*n.left, out, scope);
|
|
569
571
|
size_t j1 = out.size();
|
|
570
572
|
out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
|
|
573
|
+
cover(out, n.right.get());
|
|
571
574
|
compileExpr(*n.right, out, scope);
|
|
572
575
|
size_t j2 = out.size();
|
|
573
576
|
out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
|
|
@@ -586,6 +589,7 @@ public:
|
|
|
586
589
|
compileExpr(*n.left, out, scope);
|
|
587
590
|
size_t j1 = out.size();
|
|
588
591
|
out.push_back({Op::JumpIfTrue, 0, 0, nullptr});
|
|
592
|
+
cover(out, n.right.get());
|
|
589
593
|
compileExpr(*n.right, out, scope);
|
|
590
594
|
size_t j2 = out.size();
|
|
591
595
|
out.push_back({Op::JumpIfTrue, 0, 0, nullptr});
|
|
@@ -1172,6 +1176,7 @@ public:
|
|
|
1172
1176
|
compileExpr(*n.condition, out, scope);
|
|
1173
1177
|
size_t j = out.size();
|
|
1174
1178
|
out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
|
|
1179
|
+
cover(out, n.trueExpr.get());
|
|
1175
1180
|
compileListCompBody(*n.trueExpr, out, scope);
|
|
1176
1181
|
out[j].a = static_cast<int>(out.size());
|
|
1177
1182
|
return;
|
|
@@ -1181,10 +1186,12 @@ public:
|
|
|
1181
1186
|
compileExpr(*n.condition, out, scope);
|
|
1182
1187
|
size_t j = out.size();
|
|
1183
1188
|
out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
|
|
1189
|
+
cover(out, n.trueExpr.get());
|
|
1184
1190
|
compileListCompBody(*n.trueExpr, out, scope);
|
|
1185
1191
|
size_t jend = out.size();
|
|
1186
1192
|
out.push_back({Op::Jump, 0, 0, nullptr});
|
|
1187
1193
|
out[j].a = static_cast<int>(out.size());
|
|
1194
|
+
cover(out, n.falseExpr.get());
|
|
1188
1195
|
compileListCompBody(*n.falseExpr, out, scope);
|
|
1189
1196
|
out[jend].a = static_cast<int>(out.size());
|
|
1190
1197
|
return;
|
|
@@ -1511,6 +1518,11 @@ public:
|
|
|
1511
1518
|
void compileOneStatement(const oscad::ASTNode& stmt, std::vector<Instruction>& out) {
|
|
1512
1519
|
using oscad::NodeKind;
|
|
1513
1520
|
trackSpan(stmt);
|
|
1521
|
+
// One coverage hit per statement execution, whichever way it is
|
|
1522
|
+
// compiled below (inline or Op::NativeStatement -- the native path
|
|
1523
|
+
// calls evalStatement directly, not evalChildren, so it does not
|
|
1524
|
+
// count itself). Mirrors evalChildren's own coverHit.
|
|
1525
|
+
if (stmt.kind() != NodeKind::ModuleDeclaration && stmt.kind() != NodeKind::FunctionDeclaration) cover(out, &stmt);
|
|
1514
1526
|
// A statement's own .scope() can differ from this whole chunk's
|
|
1515
1527
|
// fixed scope_ member (e.g. a `use` statement earlier in the SAME
|
|
1516
1528
|
// script/module body changes what later statements can see) --
|
|
@@ -1916,14 +1928,20 @@ private:
|
|
|
1916
1928
|
std::vector<EnclosingLevel> enclosing_;
|
|
1917
1929
|
int nextSlot_ = 0;
|
|
1918
1930
|
int nextIterList_ = 0;
|
|
1931
|
+
bool coverage_ = false; // emit Op::Cover for every statement and every arm
|
|
1932
|
+
|
|
1933
|
+
public:
|
|
1934
|
+
void cover(std::vector<Instruction>& out, const oscad::ASTNode* arm) {
|
|
1935
|
+
if (coverage_) out.push_back({Op::Cover, internNativeStatement(arm), 0, nullptr});
|
|
1936
|
+
}
|
|
1919
1937
|
};
|
|
1920
1938
|
|
|
1921
1939
|
bool compileFunctionLike(CompiledChunk& chunk, const oscad::Scope* staticScope, const oscad::ASTNode* selfDecl,
|
|
1922
1940
|
const oscad::ScopeTable* scopeTable, std::vector<EnclosingLevel> enclosing,
|
|
1923
1941
|
const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params,
|
|
1924
|
-
const oscad::Expression& bodyExpr) {
|
|
1942
|
+
const oscad::Expression& bodyExpr, bool coverage) {
|
|
1925
1943
|
chunk.selfDecl = selfDecl;
|
|
1926
|
-
Compiler compiler(chunk, staticScope, selfDecl, scopeTable, std::move(enclosing));
|
|
1944
|
+
Compiler compiler(chunk, staticScope, selfDecl, scopeTable, std::move(enclosing), coverage);
|
|
1927
1945
|
CompileScope bodyScope;
|
|
1928
1946
|
bodyScope.push();
|
|
1929
1947
|
for (const auto& p : params) {
|
|
@@ -1960,19 +1978,19 @@ bool compileFunctionLike(CompiledChunk& chunk, const oscad::Scope* staticScope,
|
|
|
1960
1978
|
} // namespace
|
|
1961
1979
|
|
|
1962
1980
|
std::optional<CompiledChunk> tryCompileFunction(const oscad::FunctionDeclaration& decl,
|
|
1963
|
-
const oscad::ScopeTable* scopeTable) {
|
|
1981
|
+
const oscad::ScopeTable* scopeTable, bool coverage) {
|
|
1964
1982
|
CompiledChunk chunk;
|
|
1965
1983
|
if (!compileFunctionLike(chunk, scopeTable ? scopeTable->get(decl) : nullptr, &decl, scopeTable, {},
|
|
1966
|
-
decl.parameters, *decl.expr))
|
|
1984
|
+
decl.parameters, *decl.expr, coverage))
|
|
1967
1985
|
return std::nullopt;
|
|
1968
1986
|
return chunk;
|
|
1969
1987
|
}
|
|
1970
1988
|
|
|
1971
1989
|
std::optional<CompiledChunk> tryCompileStatementExpr(const oscad::Expression& expr, const oscad::Scope* scope,
|
|
1972
|
-
const oscad::ScopeTable* scopeTable) {
|
|
1990
|
+
const oscad::ScopeTable* scopeTable, bool coverage) {
|
|
1973
1991
|
static const std::vector<std::unique_ptr<oscad::ParameterDeclaration>> kNoParams;
|
|
1974
1992
|
CompiledChunk chunk;
|
|
1975
|
-
if (!compileFunctionLike(chunk, scope, nullptr, scopeTable, {}, kNoParams, expr)) return std::nullopt;
|
|
1993
|
+
if (!compileFunctionLike(chunk, scope, nullptr, scopeTable, {}, kNoParams, expr, coverage)) return std::nullopt;
|
|
1976
1994
|
// See this function's own doc comment (bytecode_compiler.hpp) for why a
|
|
1977
1995
|
// captures-having nested closure can't be supported by this bare
|
|
1978
1996
|
// wrapper -- selfDecl is nullptr and enclosing is empty above, so its
|
|
@@ -1986,7 +2004,7 @@ std::optional<CompiledChunk> tryCompileStatementExpr(const oscad::Expression& ex
|
|
|
1986
2004
|
|
|
1987
2005
|
std::optional<CompiledChunk> tryCompileAssignmentBlock(const std::vector<const oscad::Assignment*>& assigns,
|
|
1988
2006
|
const oscad::ScopeTable* scopeTable,
|
|
1989
|
-
const oscad::Scope* scope) {
|
|
2007
|
+
const oscad::Scope* scope, bool coverage) {
|
|
1990
2008
|
// Reassignment-warning fidelity (see this function's own doc comment,
|
|
1991
2009
|
// bytecode_compiler.hpp) -- cheap, one-time scan before touching the
|
|
1992
2010
|
// compiler at all.
|
|
@@ -2002,11 +2020,12 @@ std::optional<CompiledChunk> tryCompileAssignmentBlock(const std::vector<const o
|
|
|
2002
2020
|
}
|
|
2003
2021
|
|
|
2004
2022
|
CompiledChunk chunk;
|
|
2005
|
-
Compiler compiler(chunk, scope, nullptr, scopeTable, {});
|
|
2023
|
+
Compiler compiler(chunk, scope, nullptr, scopeTable, {}, coverage);
|
|
2006
2024
|
CompileScope compileScope;
|
|
2007
2025
|
compileScope.push();
|
|
2008
2026
|
try {
|
|
2009
2027
|
for (const oscad::Assignment* a : assigns) {
|
|
2028
|
+
compiler.cover(chunk.bodyCode, a); // one statement, one hit, same as evalChildren
|
|
2010
2029
|
compiler.compileExpr(*a->expr, chunk.bodyCode, compileScope); // RHS is never tail
|
|
2011
2030
|
const std::string& name = a->name->name;
|
|
2012
2031
|
if (!name.empty() && name[0] == '$') {
|
|
@@ -2041,7 +2060,7 @@ std::optional<CompiledChunk> tryCompileAssignmentBlock(const std::vector<const o
|
|
|
2041
2060
|
}
|
|
2042
2061
|
|
|
2043
2062
|
std::optional<CompiledChunk> tryCompileModuleBody(const oscad::ModuleDeclaration& decl,
|
|
2044
|
-
const oscad::ScopeTable* scopeTable) {
|
|
2063
|
+
const oscad::ScopeTable* scopeTable, bool coverage) {
|
|
2045
2064
|
CompiledChunk chunk;
|
|
2046
2065
|
chunk.isModule = true;
|
|
2047
2066
|
chunk.selfDecl = &decl;
|
|
@@ -2055,7 +2074,7 @@ std::optional<CompiledChunk> tryCompileModuleBody(const oscad::ModuleDeclaration
|
|
|
2055
2074
|
// compile path, just scoped to that one statement's own sub-
|
|
2056
2075
|
// expression -- see this file's own module-chunk doc comment
|
|
2057
2076
|
// (bytecode.hpp) for the full reasoning.
|
|
2058
|
-
Compiler compiler(chunk, scopeTable ? scopeTable->get(decl) : nullptr, nullptr, scopeTable, {});
|
|
2077
|
+
Compiler compiler(chunk, scopeTable ? scopeTable->get(decl) : nullptr, nullptr, scopeTable, {}, coverage);
|
|
2059
2078
|
try {
|
|
2060
2079
|
compiler.compileStatementList(decl.children, chunk.bodyCode);
|
|
2061
2080
|
} catch (const NotCompilable&) {
|
|
@@ -2068,7 +2087,7 @@ std::optional<CompiledChunk> tryCompileModuleBody(const oscad::ModuleDeclaration
|
|
|
2068
2087
|
|
|
2069
2088
|
std::optional<CompiledChunk> tryCompileChildrenList(const std::vector<const oscad::ASTNode*>& children,
|
|
2070
2089
|
const oscad::ScopeTable* scopeTable,
|
|
2071
|
-
const oscad::Scope* scope) {
|
|
2090
|
+
const oscad::Scope* scope, bool coverage) {
|
|
2072
2091
|
CompiledChunk chunk;
|
|
2073
2092
|
// Same completion semantics as a module chunk (no return value, its
|
|
2074
2093
|
// whole effect is the side effect of what lands in treeStack_) --
|
|
@@ -2079,7 +2098,7 @@ std::optional<CompiledChunk> tryCompileChildrenList(const std::vector<const osca
|
|
|
2079
2098
|
// ever resolved against it either way; module bodies don't create
|
|
2080
2099
|
// escaping closures).
|
|
2081
2100
|
chunk.isModule = true;
|
|
2082
|
-
Compiler compiler(chunk, scope, nullptr, scopeTable, {});
|
|
2101
|
+
Compiler compiler(chunk, scope, nullptr, scopeTable, {}, coverage);
|
|
2083
2102
|
try {
|
|
2084
2103
|
compiler.compileStatementList(children, chunk.bodyCode);
|
|
2085
2104
|
} catch (const NotCompilable&) {
|