openscad-cpp-evaluator 0.17.0__tar.gz → 0.22.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.17.0 → openscad_cpp_evaluator-0.22.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/bindings/module.cpp +27 -3
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +21 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/lexer.l +5 -1
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +73 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/eval_context.hpp +15 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/evaluator.hpp +41 -2
- openscad_cpp_evaluator-0.22.0/include/openscad_cpp_evaluator/profile.hpp +81 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/python/openscad_cpp_evaluator/__init__.py +20 -2
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/csg_resolve.cpp +3 -1
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/debug_profile.cpp +116 -3
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/eval_context.cpp +1 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/user_calls.cpp +14 -1
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_cli.cpp +1 -1
- openscad_cpp_evaluator-0.22.0/tests/test_profiling.cpp +409 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tools/cli/cli_lib.cpp +8 -5
- openscad_cpp_evaluator-0.17.0/include/openscad_cpp_evaluator/profile.hpp +0 -43
- openscad_cpp_evaluator-0.17.0/tests/test_profiling.cpp +0 -127
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.17.0 → openscad_cpp_evaluator-0.22.0}/uv.lock +0 -0
|
@@ -246,10 +246,34 @@ nb::object profileResultToPy(const std::optional<oscadeval::ProfileResult>& pr)
|
|
|
246
246
|
if (!pr) return nb::none();
|
|
247
247
|
nb::list sites;
|
|
248
248
|
for (const oscadeval::CallSiteProfile& s : pr->callSites) {
|
|
249
|
-
sites.append(facadeAttr("CallSiteProfile")(s.kind, s.name, s.callerName, s.callOrigin, s.callLine, s.
|
|
250
|
-
s.declLine, s.callCount, s.selfTime, s.cumulativeTime));
|
|
249
|
+
sites.append(facadeAttr("CallSiteProfile")(s.kind, s.name, s.callerName, s.callOrigin, s.callLine, s.callColumn,
|
|
250
|
+
s.declOrigin, s.declLine, s.callCount, s.selfTime, s.cumulativeTime));
|
|
251
251
|
}
|
|
252
|
-
|
|
252
|
+
// The calling-context tree, as plain dicts. Parent/child INDICES, not
|
|
253
|
+
// nested objects: the C++ side is already a flat vector keyed that way,
|
|
254
|
+
// and a self-referential nesting would have to be rebuilt here for no
|
|
255
|
+
// gain -- a consumer walks it by index just as C++ does.
|
|
256
|
+
nb::list paths;
|
|
257
|
+
for (const oscadeval::ProfilePathNode& n : pr->paths) {
|
|
258
|
+
nb::dict d;
|
|
259
|
+
d["parent"] = n.parent;
|
|
260
|
+
nb::list kids;
|
|
261
|
+
for (int c : n.children) kids.append(c);
|
|
262
|
+
d["children"] = kids;
|
|
263
|
+
d["kind"] = n.kind;
|
|
264
|
+
d["name"] = n.name;
|
|
265
|
+
d["call_origin"] = n.callOrigin;
|
|
266
|
+
d["call_line"] = n.callLine;
|
|
267
|
+
d["call_column"] = n.callColumn;
|
|
268
|
+
d["decl_origin"] = n.declOrigin;
|
|
269
|
+
d["decl_line"] = n.declLine;
|
|
270
|
+
d["call_count"] = n.callCount;
|
|
271
|
+
d["self_time"] = n.selfTime;
|
|
272
|
+
d["cumulative_time"] = n.cumulativeTime;
|
|
273
|
+
paths.append(d);
|
|
274
|
+
}
|
|
275
|
+
return facadeAttr("ProfileResult")(sites, pr->resolveTime, pr->generateTime, pr->totalTime, pr->unattributedTime,
|
|
276
|
+
paths);
|
|
253
277
|
}
|
|
254
278
|
|
|
255
279
|
// ctx.dyn / ctx.dynExplicit -> (dict[str, Any], set[str]) -- every currently-
|
|
@@ -49,6 +49,18 @@ public:
|
|
|
49
49
|
LexPos tokenEnd;
|
|
50
50
|
std::string stringBuffer; // accumulates a STRING token's content while in the %x STR lexer state
|
|
51
51
|
|
|
52
|
+
// Where the opening quote of the STRING currently being lexed began.
|
|
53
|
+
//
|
|
54
|
+
// Needed because YY_USER_ACTION resets tokenStart on EVERY rule match,
|
|
55
|
+
// and a string is matched by several rules (opening quote, content
|
|
56
|
+
// runs, escapes, closing quote). currentTokenLoc() at the closing
|
|
57
|
+
// quote therefore describes just that one character, which made every
|
|
58
|
+
// StringLiteral's source span a single `"` -- and dragged the span of
|
|
59
|
+
// anything wrapping it (a PositionalArgument, a vector element) along
|
|
60
|
+
// with it. Recorded when the opening quote is matched and used by
|
|
61
|
+
// stringTokenLoc() below.
|
|
62
|
+
LexPos stringStart;
|
|
63
|
+
|
|
52
64
|
Position toPosition(const OscadLocation& loc) const {
|
|
53
65
|
return Position{origin_, loc.first_line, loc.first_column, loc.first_offset, loc.last_offset};
|
|
54
66
|
}
|
|
@@ -58,6 +70,15 @@ public:
|
|
|
58
70
|
tokenEnd.column, tokenStart.offset, tokenEnd.offset};
|
|
59
71
|
}
|
|
60
72
|
|
|
73
|
+
// As currentTokenLoc(), but spanning from the string's OPENING quote
|
|
74
|
+
// (stringStart) to the current token's end -- i.e. the whole literal
|
|
75
|
+
// including both quotes, which is what a caller slicing the source by
|
|
76
|
+
// this span expects to get back.
|
|
77
|
+
OscadLocation stringTokenLoc() const {
|
|
78
|
+
return OscadLocation{stringStart.line, stringStart.column, tokenEnd.line,
|
|
79
|
+
tokenEnd.column, stringStart.offset, tokenEnd.offset};
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
void reportError(const OscadLocation& loc, const std::string& message);
|
|
62
83
|
};
|
|
63
84
|
|
|
@@ -93,13 +93,17 @@ NUMLIT 0[xX][0-9A-Fa-f]+|[0-9]+([.][0-9]*)?([eE][+-]?[0-9]+)?|[.][0-9]+([eE][+-
|
|
|
93
93
|
|
|
94
94
|
\" {
|
|
95
95
|
driver.stringBuffer.clear();
|
|
96
|
+
// YY_USER_ACTION has just set tokenStart to this opening quote; keep
|
|
97
|
+
// it, because the rules that follow will overwrite it (see
|
|
98
|
+
// ParserDriver::stringStart).
|
|
99
|
+
driver.stringStart = driver.tokenStart;
|
|
96
100
|
BEGIN(STR);
|
|
97
101
|
}
|
|
98
102
|
<STR>\\. { driver.stringBuffer.append(yytext, yyleng); }
|
|
99
103
|
<STR>[^"\\]+ { driver.stringBuffer.append(yytext, yyleng); }
|
|
100
104
|
<STR>\" {
|
|
101
105
|
BEGIN(INITIAL);
|
|
102
|
-
return yy::parser::make_STRING(driver.stringBuffer, driver.
|
|
106
|
+
return yy::parser::make_STRING(driver.stringBuffer, driver.stringTokenLoc());
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
<INCFILE>[ \t\r\n]+ { /* skip whitespace before < */ }
|
|
@@ -363,3 +363,76 @@ TEST(LexicalIdentifiers, IdentifierStr) {
|
|
|
363
363
|
std::vector<std::unique_ptr<ASTNode>> ast;
|
|
364
364
|
EXPECT_EQ(exprSrc("foo", ast)->toString(), "foo");
|
|
365
365
|
}
|
|
366
|
+
|
|
367
|
+
// -- Source spans ---------------------------------------------------------
|
|
368
|
+
|
|
369
|
+
namespace {
|
|
370
|
+
// The source text a node's own position spans -- what a consumer slicing
|
|
371
|
+
// by start/end_offset actually gets back.
|
|
372
|
+
std::string spanned(const std::string& src, const oscad::ASTNode& n) {
|
|
373
|
+
const auto& p = n.position();
|
|
374
|
+
return src.substr(static_cast<size_t>(p.start_offset),
|
|
375
|
+
static_cast<size_t>(p.end_offset - p.start_offset));
|
|
376
|
+
}
|
|
377
|
+
} // namespace
|
|
378
|
+
|
|
379
|
+
// A string is matched by SEVERAL lexer rules (opening quote, content runs,
|
|
380
|
+
// escapes, closing quote), and YY_USER_ACTION resets tokenStart on every
|
|
381
|
+
// one of them -- so building the token's location from currentTokenLoc() at
|
|
382
|
+
// the closing quote described just that one character. Every StringLiteral
|
|
383
|
+
// spanned a bare `"`, and so did anything wrapping it, which silently
|
|
384
|
+
// corrupted a downstream consumer that sliced source by those offsets.
|
|
385
|
+
TEST(SourceSpans, StringLiteralSpansTheWholeLiteral) {
|
|
386
|
+
struct Case { std::string src; std::string want; };
|
|
387
|
+
const Case cases[] = {
|
|
388
|
+
{"a = \"txt\";", "\"txt\""},
|
|
389
|
+
{"a = \"\";", "\"\""}, // empty
|
|
390
|
+
{"a = \"with \\\"quote\\\" in it\";", "\"with \\\"quote\\\" in it\""},
|
|
391
|
+
{"a = \"esc \\n seq\";", "\"esc \\n seq\""},
|
|
392
|
+
{"a = \"comma,inside\";", "\"comma,inside\""},
|
|
393
|
+
};
|
|
394
|
+
for (const Case& c : cases) {
|
|
395
|
+
auto ast = oscad::parseSrc(c.src);
|
|
396
|
+
ASSERT_EQ(ast.size(), 1u) << c.src;
|
|
397
|
+
auto* assign = dynamic_cast<oscad::Assignment*>(ast[0].get());
|
|
398
|
+
ASSERT_NE(assign, nullptr) << c.src;
|
|
399
|
+
EXPECT_EQ(spanned(c.src, *assign->expr), c.want) << c.src;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// The enclosing node's span has to be right too -- that is how the bug
|
|
404
|
+
// actually did damage, by dragging an argument's end_offset into the
|
|
405
|
+
// middle of the string.
|
|
406
|
+
TEST(SourceSpans, NodesWrappingAStringSpanCorrectly) {
|
|
407
|
+
const std::string src = "f(\"x,y\", b);";
|
|
408
|
+
auto ast = oscad::parseSrc(src);
|
|
409
|
+
auto* call = dynamic_cast<oscad::ModularCall*>(ast[0].get());
|
|
410
|
+
ASSERT_NE(call, nullptr);
|
|
411
|
+
ASSERT_EQ(call->arguments.size(), 2u);
|
|
412
|
+
EXPECT_EQ(spanned(src, *call->arguments[0]), "\"x,y\"");
|
|
413
|
+
EXPECT_EQ(spanned(src, *call->arguments[1]), "b");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
TEST(SourceSpans, StringsInAVectorSpanCorrectly) {
|
|
417
|
+
const std::string src = "x = [\"a,b\",\"c\"];";
|
|
418
|
+
auto ast = oscad::parseSrc(src);
|
|
419
|
+
auto* assign = dynamic_cast<oscad::Assignment*>(ast[0].get());
|
|
420
|
+
ASSERT_NE(assign, nullptr);
|
|
421
|
+
auto* vec = dynamic_cast<oscad::ListComprehension*>(assign->expr.get());
|
|
422
|
+
ASSERT_NE(vec, nullptr);
|
|
423
|
+
ASSERT_EQ(vec->elements.size(), 2u);
|
|
424
|
+
EXPECT_EQ(spanned(src, *vec->elements[0]), "\"a,b\"");
|
|
425
|
+
EXPECT_EQ(spanned(src, *vec->elements[1]), "\"c\"");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Multi-line strings must still report the OPENING quote's line/column, not
|
|
429
|
+
// the closing one's.
|
|
430
|
+
TEST(SourceSpans, MultiLineStringReportsItsStartingLine) {
|
|
431
|
+
const std::string src = "a = 1;\nb = \"one\ntwo\";\n";
|
|
432
|
+
auto ast = oscad::parseSrc(src);
|
|
433
|
+
ASSERT_EQ(ast.size(), 2u);
|
|
434
|
+
auto* assign = dynamic_cast<oscad::Assignment*>(ast[1].get());
|
|
435
|
+
ASSERT_NE(assign, nullptr);
|
|
436
|
+
EXPECT_EQ(assign->expr->position().line, 2);
|
|
437
|
+
EXPECT_EQ(spanned(src, *assign->expr), "\"one\ntwo\"");
|
|
438
|
+
}
|
|
@@ -59,6 +59,21 @@ struct EvalContext {
|
|
|
59
59
|
std::shared_ptr<const ChildrenNodeList> childrenNodes;
|
|
60
60
|
const EvalContext* childrenCallerCtx = nullptr;
|
|
61
61
|
|
|
62
|
+
// True while evaluating statements that a children() forwarded, so a
|
|
63
|
+
// module call reached this way profiles as kind "child" rather than
|
|
64
|
+
// "module". `foo() foo();` and `module foo() { foo(); }` both produce a
|
|
65
|
+
// foo->foo edge, but only the second is recursion, and a profile that
|
|
66
|
+
// cannot tell them apart is misleading.
|
|
67
|
+
//
|
|
68
|
+
// Propagates through withScope/childCtx (a forwarded `translate()
|
|
69
|
+
// foo()` is still child-passing) but NOT through callCtx, which resets
|
|
70
|
+
// it by omission -- entering a body ends the forwarding. The one
|
|
71
|
+
// deliberate exception is buildModuleChildCtx, which copies the
|
|
72
|
+
// caller's flag onto the body ctx so enterUserCall can read it there;
|
|
73
|
+
// enterUserCall then clears it, so the call it describes is the only
|
|
74
|
+
// one that sees it.
|
|
75
|
+
bool viaChildren = false;
|
|
76
|
+
|
|
62
77
|
// The one genuinely fresh construction: seeds `dyn` with OpenSCAD's
|
|
63
78
|
// built-in $-variable defaults ($fn=0, $fa=12, $fs=2, $t=0,
|
|
64
79
|
// $parent_modules=0). Every other EvalContext in a run is derived
|
|
@@ -1234,12 +1234,16 @@ private:
|
|
|
1234
1234
|
|
|
1235
1235
|
// -- Profiling (Phase 9) --------------------------------------------
|
|
1236
1236
|
|
|
1237
|
-
// (kind, name, callOrigin, callLine) -- the exact call-site
|
|
1237
|
+
// (kind, name, callOrigin, callLine, callColumn) -- the exact call-site
|
|
1238
|
+
// identity a
|
|
1238
1239
|
// CallSiteProfile aggregates by. std::map (not unordered_map): a plain
|
|
1239
1240
|
// tuple of comparable fields already gets a free operator< from the
|
|
1240
1241
|
// standard library, so this needs no custom hash function for a table
|
|
1241
1242
|
// that's never more than a few thousand entries even on a large script.
|
|
1242
|
-
|
|
1243
|
+
// Column is part of the key, not decoration: `foo() foo();` and
|
|
1244
|
+
// `f(g(x))` put two distinct call sites on one line, and without it
|
|
1245
|
+
// they aggregate into one entry whose times belong to neither.
|
|
1246
|
+
using ProfileSiteKey = std::tuple<std::string, std::string, std::string, int, int>;
|
|
1243
1247
|
|
|
1244
1248
|
// Pushes profiling state for a user module/function call about to
|
|
1245
1249
|
// start -- shared by evalUserModule/evalUserFunction/
|
|
@@ -1252,6 +1256,13 @@ private:
|
|
|
1252
1256
|
ProfileSiteKey key;
|
|
1253
1257
|
bool recursiveReentry;
|
|
1254
1258
|
std::chrono::steady_clock::time_point start;
|
|
1259
|
+
// Node this call occupies in the calling-context tree, and the one
|
|
1260
|
+
// to restore on exit. `pathRecursive` is the per-PATH equivalent of
|
|
1261
|
+
// recursiveReentry: true when this entry folded back onto a node
|
|
1262
|
+
// already on the path, so only the outermost entry adds cumulative
|
|
1263
|
+
// time -- the same rule callSites uses, applied per node.
|
|
1264
|
+
int pathNode = -1;
|
|
1265
|
+
int pathPrev = -1;
|
|
1255
1266
|
};
|
|
1256
1267
|
std::optional<ProfileHandle> profileEnter(const std::string& kind, const std::string& name,
|
|
1257
1268
|
const oscad::Position* callPos, const oscad::Position* declPos);
|
|
@@ -1712,6 +1723,34 @@ private:
|
|
|
1712
1723
|
std::map<ProfileSiteKey, CallSiteProfile> profileSites_;
|
|
1713
1724
|
std::set<ProfileSiteKey> profileActive_; // site keys with a call currently on callStack_
|
|
1714
1725
|
std::vector<double> profileChildTime_; // parallel aux stack to callStack_
|
|
1726
|
+
|
|
1727
|
+
// Calling-context tree (see ProfilePathNode). profilePaths_[0] is the
|
|
1728
|
+
// <toplevel> root, created lazily on the first profiled call;
|
|
1729
|
+
// profileCurrentPath_ is the node the running call belongs to, so a
|
|
1730
|
+
// profileEnter knows which parent to hang its node off.
|
|
1731
|
+
std::vector<ProfilePathNode> profilePaths_;
|
|
1732
|
+
int profileCurrentPath_ = -1;
|
|
1733
|
+
|
|
1734
|
+
// Safety valve. The tree is bounded by distinct ACYCLIC paths (see
|
|
1735
|
+
// ProfilePathNode on recursion folding), which is finite but can still
|
|
1736
|
+
// be large for a deeply-layered library. Past this, no new nodes are
|
|
1737
|
+
// created and further calls fold onto their parent -- the report stays
|
|
1738
|
+
// truthful about totals and simply stops subdividing, rather than the
|
|
1739
|
+
// profiler becoming the thing that runs out of memory.
|
|
1740
|
+
static constexpr size_t kMaxProfilePathNodes = 200000;
|
|
1741
|
+
|
|
1742
|
+
// Finds-or-creates the child of profileCurrentPath_ for this call site
|
|
1743
|
+
// and returns its index. Sets `folded` when the returned node was
|
|
1744
|
+
// already on the current path (recursion, or the node cap) rather than
|
|
1745
|
+
// a fresh or sibling child -- the caller must then skip cumulative
|
|
1746
|
+
// time for this entry, exactly as recursiveReentry does for callSites.
|
|
1747
|
+
int profilePathEnter(const std::string& kind, const std::string& name, const std::string& callOrigin,
|
|
1748
|
+
int callLine, int callColumn, const oscad::Position* declPos, bool& folded);
|
|
1749
|
+
|
|
1750
|
+
// Fills in every node's cumulativeTime as selfTime + the cumulative of
|
|
1751
|
+
// its children, bottom-up. See profileExit for why this is derived
|
|
1752
|
+
// rather than measured.
|
|
1753
|
+
void finalizeProfilePaths();
|
|
1715
1754
|
};
|
|
1716
1755
|
|
|
1717
1756
|
} // namespace oscadeval
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
|
|
6
|
+
namespace oscadeval {
|
|
7
|
+
|
|
8
|
+
// Aggregated profiling data for one *call site* -- a specific source
|
|
9
|
+
// location that calls a specific user module/function, not one
|
|
10
|
+
// declaration. Two different calls to the same function get separate
|
|
11
|
+
// entries; the same call expression re-executed many times (a loop body,
|
|
12
|
+
// recursion) aggregates into one entry with callCount > 1, since the AST
|
|
13
|
+
// node (and thus its position) is identical across those invocations.
|
|
14
|
+
// Mirrors the reference's CallSiteProfile.
|
|
15
|
+
struct CallSiteProfile {
|
|
16
|
+
std::string kind; // "module" | "child" (forwarded via children()) | "function"
|
|
17
|
+
std::string name;
|
|
18
|
+
std::string callerName; // enclosing module/function's own name, or "<toplevel>"
|
|
19
|
+
std::string callOrigin;
|
|
20
|
+
int callLine = 0;
|
|
21
|
+
int callColumn = 0; // distinguishes two calls sharing one line
|
|
22
|
+
std::string declOrigin;
|
|
23
|
+
int declLine = 0;
|
|
24
|
+
int callCount = 0;
|
|
25
|
+
double selfTime = 0.0; // seconds, own code only, never double-counted
|
|
26
|
+
double cumulativeTime = 0.0; // seconds, includes children; recursion-guarded
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// One node of the calling-context tree: a call site reached by ONE
|
|
30
|
+
// specific path from <toplevel>. Where CallSiteProfile aggregates a site
|
|
31
|
+
// over every path that reached it, this keeps them separate -- so
|
|
32
|
+
// `cuboid` called from `bracket` and `cuboid` called from `rail` are two
|
|
33
|
+
// nodes with their own times, and a consumer can show what a particular
|
|
34
|
+
// path actually cost rather than a total across all callers.
|
|
35
|
+
//
|
|
36
|
+
// Flat vector with parent/child indices rather than pointers: it survives
|
|
37
|
+
// the vector reallocating as nodes are appended, and crosses the Python
|
|
38
|
+
// binding as plain data with no ownership question.
|
|
39
|
+
//
|
|
40
|
+
// Recursion is folded rather than unrolled. Re-entering a call site
|
|
41
|
+
// already on the current path reuses that node instead of appending a new
|
|
42
|
+
// child, so `fib` calling itself 400 deep is one node with callCount 400,
|
|
43
|
+
// not a 400-node chain. That bounds the tree by distinct ACYCLIC paths and
|
|
44
|
+
// keeps the recursion-guarded cumulative-time rule (only the outermost
|
|
45
|
+
// entry contributes) meaningful per node.
|
|
46
|
+
struct ProfilePathNode {
|
|
47
|
+
int parent = -1; // index into ProfileResult::paths; -1 for the root
|
|
48
|
+
std::vector<int> children; // indices, in first-call order
|
|
49
|
+
std::string kind; // "module" | "child" | "function"; empty for the root
|
|
50
|
+
std::string name; // callee; "<toplevel>" for the root
|
|
51
|
+
std::string callOrigin;
|
|
52
|
+
int callLine = 0;
|
|
53
|
+
int callColumn = 0; // distinguishes two calls sharing one line
|
|
54
|
+
std::string declOrigin;
|
|
55
|
+
int declLine = 0;
|
|
56
|
+
int callCount = 0;
|
|
57
|
+
double selfTime = 0.0; // seconds, this node's own code on this path
|
|
58
|
+
double cumulativeTime = 0.0; // seconds, this node and everything under it
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Whole-evaluate() profiling summary, built when Evaluator is constructed
|
|
62
|
+
// with profiling=true. unattributedTime covers top-level script code and
|
|
63
|
+
// anything else not inside a user module/function call (native builtins'
|
|
64
|
+
// own resolve work, mostly) -- resolveTime always equals
|
|
65
|
+
// sum(s.selfTime for callSites) + unattributedTime, so a UI can show
|
|
66
|
+
// percentages that honestly add to 100%. Mirrors the reference's
|
|
67
|
+
// ProfileResult.
|
|
68
|
+
struct ProfileResult {
|
|
69
|
+
std::vector<CallSiteProfile> callSites;
|
|
70
|
+
// The calling-context tree; paths[0] is always the <toplevel> root.
|
|
71
|
+
// Empty only if profiling was off. callSites stays exactly as it was --
|
|
72
|
+
// the flat per-site view is still the right answer to "what is
|
|
73
|
+
// expensive overall", and is cheaper to scan than walking this.
|
|
74
|
+
std::vector<ProfilePathNode> paths;
|
|
75
|
+
double resolveTime = 0.0;
|
|
76
|
+
double generateTime = 0.0;
|
|
77
|
+
double totalTime = 0.0;
|
|
78
|
+
double unattributedTime = 0.0;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
} // namespace oscadeval
|
|
@@ -9,7 +9,7 @@ like a manifold3d body (`.is_empty()` / `.to_mesh()`), so the renderer reads
|
|
|
9
9
|
`cb.body.to_mesh().vert_properties/tri_verts/run_original_id/run_index`
|
|
10
10
|
exactly as before -- no cross-module Manifold objects are ever exchanged.
|
|
11
11
|
"""
|
|
12
|
-
from dataclasses import dataclass
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
13
|
from typing import Optional
|
|
14
14
|
|
|
15
15
|
from . import _openscad_cpp_evaluator as _ext
|
|
@@ -142,11 +142,12 @@ class _CSGNode:
|
|
|
142
142
|
class CallSiteProfile:
|
|
143
143
|
"""Aggregated profiling data for one call site. Mirrors the reference's
|
|
144
144
|
CallSiteProfile -- see ProfileResult's own docstring."""
|
|
145
|
-
kind: str # "module" | "function"
|
|
145
|
+
kind: str # "module" | "child" | "function"
|
|
146
146
|
name: str
|
|
147
147
|
caller_name: str
|
|
148
148
|
call_origin: str
|
|
149
149
|
call_line: int
|
|
150
|
+
call_column: int
|
|
150
151
|
decl_origin: str
|
|
151
152
|
decl_line: int
|
|
152
153
|
call_count: int = 0
|
|
@@ -165,6 +166,23 @@ class ProfileResult:
|
|
|
165
166
|
generate_time: float
|
|
166
167
|
total_time: float
|
|
167
168
|
unattributed_time: float
|
|
169
|
+
# Calling-context tree: a flat list of dicts, paths[0] the <toplevel>
|
|
170
|
+
# root, linked by `parent`/`children` INDICES into this same list.
|
|
171
|
+
#
|
|
172
|
+
# Where call_sites aggregates a site over every path that reached it,
|
|
173
|
+
# each node here is one call site on ONE path -- so `cuboid` called
|
|
174
|
+
# from `bracket` and from `rail` are separate nodes with their own
|
|
175
|
+
# times, and a report can say what a particular path cost rather than
|
|
176
|
+
# only what a name cost in total.
|
|
177
|
+
#
|
|
178
|
+
# Keys: parent, children, kind, name, call_origin, call_line,
|
|
179
|
+
# decl_origin, decl_line, call_count, self_time, cumulative_time.
|
|
180
|
+
#
|
|
181
|
+
# Recursion is folded: re-entering a site already on the path reuses
|
|
182
|
+
# that node (call_count rises) instead of unrolling a node per level.
|
|
183
|
+
# Defaults to empty so a ProfileResult built by older code still
|
|
184
|
+
# constructs.
|
|
185
|
+
paths: list = field(default_factory=list)
|
|
168
186
|
|
|
169
187
|
|
|
170
188
|
def _summarize_param(value, max_items: int = 6, max_len: int = 40) -> str:
|
|
@@ -269,8 +269,10 @@ std::vector<ColoredBody> Evaluator::evaluateImpl(const NodeList& nodes, EvalCont
|
|
|
269
269
|
selfSum += site.selfTime;
|
|
270
270
|
sites.push_back(site);
|
|
271
271
|
}
|
|
272
|
+
finalizeProfilePaths();
|
|
272
273
|
profileResult = ProfileResult{
|
|
273
|
-
std::move(sites), resolveTime, generateTime, resolveTime + generateTime,
|
|
274
|
+
std::move(sites), profilePaths_, resolveTime, generateTime, resolveTime + generateTime,
|
|
275
|
+
std::max(0.0, resolveTime - selfSum),
|
|
274
276
|
};
|
|
275
277
|
}
|
|
276
278
|
|
|
@@ -116,12 +116,87 @@ void Evaluator::checkDebug(const oscad::ASTNode& node, EvalContext& ctx, bool fo
|
|
|
116
116
|
if (action.stop) throw EvalError(kDebuggingStoppedMessage);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
int Evaluator::profilePathEnter(const std::string& kind, const std::string& name, const std::string& callOrigin,
|
|
120
|
+
int callLine, int callColumn, const oscad::Position* declPos, bool& folded) {
|
|
121
|
+
folded = false;
|
|
122
|
+
if (profilePaths_.empty()) {
|
|
123
|
+
ProfilePathNode root;
|
|
124
|
+
root.name = "<toplevel>";
|
|
125
|
+
profilePaths_.push_back(std::move(root));
|
|
126
|
+
profileCurrentPath_ = 0;
|
|
127
|
+
}
|
|
128
|
+
const int parent = profileCurrentPath_ < 0 ? 0 : profileCurrentPath_;
|
|
129
|
+
|
|
130
|
+
// Immediate self-recursion folds onto the parent rather than growing a
|
|
131
|
+
// chain per level (see ProfilePathNode).
|
|
132
|
+
//
|
|
133
|
+
// Only the parent, never a deeper ancestor. Folding across intervening
|
|
134
|
+
// nodes credits the whole re-entered subtree to the ancestor, and every
|
|
135
|
+
// node between it and here loses that time -- cumulative is derived
|
|
136
|
+
// bottom-up, so it can only count what is actually below. A BOSL2
|
|
137
|
+
// attachment chain showed restore() at 226ms in the flat view and 2.5ms
|
|
138
|
+
// in the tree for the same call site, because its callees re-entered a
|
|
139
|
+
// multmatrix already open further up and took 223ms with them.
|
|
140
|
+
//
|
|
141
|
+
// A cycle through other call sites therefore gets a real node. That is
|
|
142
|
+
// what makes the tree's numbers agree with the flat view's; the cost is
|
|
143
|
+
// more nodes on mutually-recursive chains, which kMaxProfilePathNodes
|
|
144
|
+
// still bounds.
|
|
145
|
+
if (parent > 0) {
|
|
146
|
+
const ProfilePathNode& n = profilePaths_[static_cast<size_t>(parent)];
|
|
147
|
+
if (n.name == name && n.callOrigin == callOrigin && n.callLine == callLine &&
|
|
148
|
+
n.callColumn == callColumn && n.kind == kind) {
|
|
149
|
+
folded = true; // direct recursion: this site called itself
|
|
150
|
+
return parent;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (int childIdx : profilePaths_[static_cast<size_t>(parent)].children) {
|
|
154
|
+
const ProfilePathNode& n = profilePaths_[static_cast<size_t>(childIdx)];
|
|
155
|
+
if (n.name == name && n.callOrigin == callOrigin && n.callLine == callLine &&
|
|
156
|
+
n.callColumn == callColumn && n.kind == kind) {
|
|
157
|
+
return childIdx;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (profilePaths_.size() >= kMaxProfilePathNodes) {
|
|
161
|
+
folded = true; // cap reached: stop subdividing, keep totals honest
|
|
162
|
+
return parent;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
ProfilePathNode node;
|
|
166
|
+
node.parent = parent;
|
|
167
|
+
node.kind = kind;
|
|
168
|
+
node.name = name;
|
|
169
|
+
node.callOrigin = callOrigin;
|
|
170
|
+
node.callLine = callLine;
|
|
171
|
+
node.callColumn = callColumn;
|
|
172
|
+
node.declOrigin = declPos ? declPos->origin : "";
|
|
173
|
+
node.declLine = declPos ? declPos->line : 0;
|
|
174
|
+
const int idx = static_cast<int>(profilePaths_.size());
|
|
175
|
+
profilePaths_.push_back(std::move(node));
|
|
176
|
+
profilePaths_[static_cast<size_t>(parent)].children.push_back(idx);
|
|
177
|
+
return idx;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
void Evaluator::finalizeProfilePaths() {
|
|
181
|
+
// Children always have a higher index than their parent (a node is
|
|
182
|
+
// appended when first reached, and folding never creates an edge back
|
|
183
|
+
// to an ancestor), so one reverse sweep resolves the whole tree with
|
|
184
|
+
// no recursion and no risk of an unbounded native stack.
|
|
185
|
+
for (size_t i = profilePaths_.size(); i-- > 0;) {
|
|
186
|
+
ProfilePathNode& n = profilePaths_[i];
|
|
187
|
+
double total = n.selfTime;
|
|
188
|
+
for (int c : n.children) total += profilePaths_[static_cast<size_t>(c)].cumulativeTime;
|
|
189
|
+
n.cumulativeTime = total;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
119
193
|
std::optional<Evaluator::ProfileHandle> Evaluator::profileEnter(const std::string& kind, const std::string& name,
|
|
120
194
|
const oscad::Position* callPos, const oscad::Position* declPos) {
|
|
121
195
|
if (!profiling_) return std::nullopt;
|
|
122
196
|
const std::string callOrigin = callPos ? callPos->origin : "";
|
|
123
197
|
const int callLine = callPos ? callPos->line : 0;
|
|
124
|
-
const
|
|
198
|
+
const int callColumn = callPos ? callPos->column : 0;
|
|
199
|
+
const ProfileSiteKey key{kind, name, callOrigin, callLine, callColumn};
|
|
125
200
|
|
|
126
201
|
auto it = profileSites_.find(key);
|
|
127
202
|
if (it == profileSites_.end()) {
|
|
@@ -137,6 +212,7 @@ std::optional<Evaluator::ProfileHandle> Evaluator::profileEnter(const std::strin
|
|
|
137
212
|
site.callerName = callStack_.empty() ? "<toplevel>" : callStack_.back().name;
|
|
138
213
|
site.callOrigin = callOrigin;
|
|
139
214
|
site.callLine = callLine;
|
|
215
|
+
site.callColumn = callColumn;
|
|
140
216
|
site.declOrigin = declPos ? declPos->origin : "";
|
|
141
217
|
site.declLine = declPos ? declPos->line : 0;
|
|
142
218
|
it = profileSites_.emplace(key, std::move(site)).first;
|
|
@@ -146,7 +222,17 @@ std::optional<Evaluator::ProfileHandle> Evaluator::profileEnter(const std::strin
|
|
|
146
222
|
const bool recursiveReentry = profileActive_.count(key) > 0;
|
|
147
223
|
if (!recursiveReentry) profileActive_.insert(key);
|
|
148
224
|
profileChildTime_.push_back(0.0);
|
|
149
|
-
|
|
225
|
+
|
|
226
|
+
const int prevPath = profileCurrentPath_;
|
|
227
|
+
bool folded = false; // only affects node reuse now, not accounting
|
|
228
|
+
const int pathNode = profilePathEnter(kind, name, callOrigin, callLine, callColumn, declPos, folded);
|
|
229
|
+
profilePaths_[static_cast<size_t>(pathNode)].callCount += 1;
|
|
230
|
+
profileCurrentPath_ = pathNode;
|
|
231
|
+
|
|
232
|
+
ProfileHandle handle{key, recursiveReentry, std::chrono::steady_clock::now()};
|
|
233
|
+
handle.pathNode = pathNode;
|
|
234
|
+
handle.pathPrev = prevPath;
|
|
235
|
+
return handle;
|
|
150
236
|
}
|
|
151
237
|
|
|
152
238
|
void Evaluator::profileRecordTailHop(const std::string& kind, const std::string& name, const oscad::Position* callPos,
|
|
@@ -154,7 +240,8 @@ void Evaluator::profileRecordTailHop(const std::string& kind, const std::string&
|
|
|
154
240
|
if (!profiling_) return;
|
|
155
241
|
const std::string callOrigin = callPos ? callPos->origin : "";
|
|
156
242
|
const int callLine = callPos ? callPos->line : 0;
|
|
157
|
-
const
|
|
243
|
+
const int callColumn = callPos ? callPos->column : 0;
|
|
244
|
+
const ProfileSiteKey key{kind, name, callOrigin, callLine, callColumn};
|
|
158
245
|
|
|
159
246
|
auto it = profileSites_.find(key);
|
|
160
247
|
if (it == profileSites_.end()) {
|
|
@@ -174,6 +261,7 @@ void Evaluator::profileRecordTailHop(const std::string& kind, const std::string&
|
|
|
174
261
|
site.callerName = callStack_.empty() ? "<toplevel>" : callStack_.back().name;
|
|
175
262
|
site.callOrigin = callOrigin;
|
|
176
263
|
site.callLine = callLine;
|
|
264
|
+
site.callColumn = callColumn;
|
|
177
265
|
site.declOrigin = declPos ? declPos->origin : "";
|
|
178
266
|
site.declLine = declPos ? declPos->line : 0;
|
|
179
267
|
it = profileSites_.emplace(key, std::move(site)).first;
|
|
@@ -199,6 +287,31 @@ void Evaluator::profileExit(const ProfileHandle& handle) {
|
|
|
199
287
|
site.cumulativeTime += elapsed;
|
|
200
288
|
profileActive_.erase(handle.key);
|
|
201
289
|
}
|
|
290
|
+
|
|
291
|
+
// Same accounting, but attributed to this call's own node in the
|
|
292
|
+
// calling-context tree rather than to the site aggregated over every
|
|
293
|
+
// path that reached it.
|
|
294
|
+
if (handle.pathNode >= 0 && static_cast<size_t>(handle.pathNode) < profilePaths_.size()) {
|
|
295
|
+
// Self time only. Cumulative is DERIVED from the subtree once the
|
|
296
|
+
// run finishes (finalizeProfilePaths), not measured here.
|
|
297
|
+
//
|
|
298
|
+
// Measuring it per entry is wrong at a fold point: when a site
|
|
299
|
+
// recurses, every level lands on the same node, but only the
|
|
300
|
+
// outermost entry may add its elapsed (or nested time double-
|
|
301
|
+
// counts) -- while the calls made from every level still attach as
|
|
302
|
+
// that node's children. The node then reads smaller than the
|
|
303
|
+
// children under it. Found on a real model: a `_translate` entered
|
|
304
|
+
// 7 times via recursion showed 22.85ms with 90.09ms of children.
|
|
305
|
+
//
|
|
306
|
+
// Self time has no such problem: it is disjoint by construction
|
|
307
|
+
// (the child-time stack subtracts nested work), so summing it
|
|
308
|
+
// across every entry is exactly this node's own cost on this path,
|
|
309
|
+
// and cumulative built from it can never contradict the subtree.
|
|
310
|
+
ProfilePathNode& node = profilePaths_[static_cast<size_t>(handle.pathNode)];
|
|
311
|
+
node.selfTime += elapsed - childTime;
|
|
312
|
+
profileCurrentPath_ = handle.pathPrev;
|
|
313
|
+
}
|
|
314
|
+
|
|
202
315
|
if (!profileChildTime_.empty()) profileChildTime_.back() += elapsed;
|
|
203
316
|
}
|
|
204
317
|
|
|
@@ -41,6 +41,7 @@ EvalContext EvalContext::childCtx(const oscad::Scope* newScope, std::optional<st
|
|
|
41
41
|
result.color = newColor.has_value() ? newColor : color;
|
|
42
42
|
result.childrenNodes = newChildrenNodes ? newChildrenNodes : childrenNodes;
|
|
43
43
|
result.childrenCallerCtx = newChildrenCallerCtx ? newChildrenCallerCtx : childrenCallerCtx;
|
|
44
|
+
result.viaChildren = viaChildren;
|
|
44
45
|
return result;
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -337,6 +337,9 @@ EvalContext Evaluator::buildModuleChildCtx(const oscad::ModuleDeclaration& decl,
|
|
|
337
337
|
for (const auto& c : call.children) childrenNodes->push_back(c.get());
|
|
338
338
|
|
|
339
339
|
EvalContext childCtx = callCtxFor(decl, ctx, childScope, childrenNodes, &ctx);
|
|
340
|
+
// callCtx reset this to false; carry the CALLER's value across so
|
|
341
|
+
// enterUserCall can tell a forwarded child from a recursive call.
|
|
342
|
+
childCtx.viaChildren = ctx.viaChildren;
|
|
340
343
|
|
|
341
344
|
// $children counts module-instantiation child *statements* passed in
|
|
342
345
|
// `{}`, not the number of geometries they produce -- e.g. children()
|
|
@@ -712,7 +715,12 @@ Evaluator::UserCallHandle Evaluator::enterUserCall(const std::string& name, cons
|
|
|
712
715
|
++nativeUserCallDepth_;
|
|
713
716
|
h.countedTowardNativeDepth = true;
|
|
714
717
|
}
|
|
715
|
-
|
|
718
|
+
// Consumed, not just read: the body's own statements run in this same
|
|
719
|
+
// ctx, and a plain call among them is not itself a forwarded child.
|
|
720
|
+
const bool viaChildren = childCtx.viaChildren;
|
|
721
|
+
childCtx.viaChildren = false;
|
|
722
|
+
h.prof = profileEnter(isModule ? (viaChildren ? "child" : "module") : "function", name, callPos,
|
|
723
|
+
&declNode.position());
|
|
716
724
|
callStack_.push_back(CallStackFrame{kind, name, callPos, &declNode.position(), &declNode, nullptr, upvalueParent});
|
|
717
725
|
callStack_.back().bodyCtx = &childCtx; // per-frame locals for the debugger
|
|
718
726
|
if (isModule) ++moduleCallDepth_;
|
|
@@ -920,6 +928,11 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
920
928
|
// A children() forwarding chain's own dyn/let_/etc. must alias the
|
|
921
929
|
// *caller's* (not this ctx's) -- see EvalContext::withScope's rationale.
|
|
922
930
|
EvalContext evalCtx = callerCtx->childCtx(nullptr, std::nullopt, callerCtx->childrenNodes, callerCtx->childrenCallerCtx);
|
|
931
|
+
// Everything evaluated from this context is a forwarded child, so a
|
|
932
|
+
// module call reached through it profiles as "child" not "module".
|
|
933
|
+
// Set here rather than at the returns: there are two of them (bare
|
|
934
|
+
// children() and indexed children(i)).
|
|
935
|
+
evalCtx.viaChildren = true;
|
|
923
936
|
// `ctx` here is the post-resolveCallArgs effCtx, deliberately: a
|
|
924
937
|
// `children($fn=12)`-style named-$ override lives only at effCtx's own
|
|
925
938
|
// trail level, and TrailView::items() is ancestry-visible, so reading
|
|
@@ -222,7 +222,7 @@ TEST(CliProfile, CsvFormatWritesHeaderAndCommaSeparatedRows) {
|
|
|
222
222
|
0);
|
|
223
223
|
const std::string text = readFile(report);
|
|
224
224
|
EXPECT_NE(text.find("# total_time,"), std::string::npos);
|
|
225
|
-
EXPECT_NE(text.find("kind,name,caller,call_origin,call_line,call_count,self_time,cumulative_time\n"), std::string::npos);
|
|
225
|
+
EXPECT_NE(text.find("kind,name,caller,call_origin,call_line,call_column,call_count,self_time,cumulative_time\n"), std::string::npos);
|
|
226
226
|
EXPECT_NE(text.find("function,fib,"), std::string::npos);
|
|
227
227
|
std::filesystem::remove(src);
|
|
228
228
|
std::filesystem::remove(out);
|