openscad-cpp-evaluator 0.13.2__tar.gz → 0.13.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/bytecode.hpp +46 -2
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/evaluator.hpp +106 -5
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/scope_trail.hpp +19 -1
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/bytecode_compiler.cpp +19 -6
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/bytecode_vm.cpp +108 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/user_calls.cpp +48 -13
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_bytecode_compiler.cpp +121 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_scope_trail.cpp +30 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/README.md +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.13.2 → openscad_cpp_evaluator-0.13.4}/tools/cli/main.cpp +0 -0
|
@@ -325,8 +325,50 @@ enum class Op {
|
|
|
325
325
|
// same seam, now a counter).
|
|
326
326
|
PopBuiltinWrap,
|
|
327
327
|
|
|
328
|
+
// A `children()` / `children(N)` statement -- the runtime-varying
|
|
329
|
+
// sibling of Op::CallModule/Op::PushBuiltinWrap, closing the LAST
|
|
330
|
+
// dominant native-reentry source (BOSL2's attachable() calls
|
|
331
|
+
// children() at nearly every wrapper level; measured 85 of 93 native
|
|
332
|
+
// reentries in a real script). Unlike PushBuiltinWrap's constructs,
|
|
333
|
+
// the forwarded children aren't known at compile time (they're the
|
|
334
|
+
// CALLER's own call-site statements, carried on ctx.childrenNodes/
|
|
335
|
+
// childrenCallerCtx -- see Evaluator::buildModuleChildCtx), so they
|
|
336
|
+
// can't compile inline; instead the handler resolves the list at
|
|
337
|
+
// RUNTIME, looks up/compiles its chunk (the same
|
|
338
|
+
// childrenListChunkCache_ tryRunCompiledChildren uses, via
|
|
339
|
+
// lookupOrCompileChildrenListChunk -- gated on useBytecodeVm() &&
|
|
340
|
+
// inResolvePass_, the cache is pass-scoped), and pushes it onto
|
|
341
|
+
// vmCallStack_ directly, mirroring Op::CallModule's own zero-native-
|
|
342
|
+
// call push -- but with a THIRD frame shape: splice-owning like a
|
|
343
|
+
// module frame (ownsModuleSplice=true, mirroring evalModularCall's
|
|
344
|
+
// own unconditional splice branch for "children"), yet bracketless
|
|
345
|
+
// like a bare frame (children() never gets a callStack_/profiling
|
|
346
|
+
// entry natively either -- only enterUserCall pushes those, and
|
|
347
|
+
// resolveChildren/builtinChildren never call it). driveVm's existing
|
|
348
|
+
// completion branch and teardownVmCallStackDownTo both already
|
|
349
|
+
// handle that combination (their bracket and splice concerns are
|
|
350
|
+
// independent).
|
|
351
|
+
//
|
|
352
|
+
// Handler ordering is load-bearing: checkDebug fires in-handler
|
|
353
|
+
// against the scope-wrapped ctx (byte-for-byte what Op::
|
|
354
|
+
// NativeStatement does -- NOT via an emitted Op::CheckDebugStatement,
|
|
355
|
+
// whose handler passes the un-wrapped ctx); randsBefore is captured
|
|
356
|
+
// BEFORE argument resolution (rands-in-args taint, same lesson
|
|
357
|
+
// PushBuiltinWrap already encodes); and treeStack_ is pushed LAST,
|
|
358
|
+
// immediately before the frame push / native fallback (an early-out
|
|
359
|
+
// or a throw during arg resolution then has nothing to clean up --
|
|
360
|
+
// the native path's own catch{pop;throw} has no equivalent here, so
|
|
361
|
+
// the reorder IS the exception-safety mechanism). The not-eligible
|
|
362
|
+
// fallback reuses the ALREADY-resolved args (never evalStatement,
|
|
363
|
+
// which would re-resolve them: double rands(), double side effects)
|
|
364
|
+
// by inlining evalModularCall's own children branch around a native
|
|
365
|
+
// evalChildren call. a = index into CompiledChunk::nativeStatements
|
|
366
|
+
// (the ModularCall node -- arguments, error position, splice node;
|
|
367
|
+
// no separate site table needed).
|
|
368
|
+
CallChildren,
|
|
369
|
+
|
|
328
370
|
// A single "native passthrough" statement -- intersection_for,
|
|
329
|
-
//
|
|
371
|
+
// union/difference/intersection and every other builtin
|
|
330
372
|
// module call NOT covered by Op::PushBuiltinWrap (see that op's own
|
|
331
373
|
// doc comment for exactly which builtins ARE covered), the `*`
|
|
332
374
|
// modifier's own no-op case, or a user-module call that didn't
|
|
@@ -344,7 +386,9 @@ enum class Op {
|
|
|
344
386
|
// pattern that made this op's own native reentry a genuine Windows
|
|
345
387
|
// crash risk in practice, not just a missed optimization. See
|
|
346
388
|
// Op::PushBuiltinWrap's own doc comment for the real story and the
|
|
347
|
-
// fix.)
|
|
389
|
+
// fix. children() fell here too, and was the LAST and largest such
|
|
390
|
+
// reentry source once PushBuiltinWrap's own set was covered -- it
|
|
391
|
+
// now has Op::CallChildren, above.)
|
|
348
392
|
// a = index into CompiledChunk::nativeStatements. Runtime just does
|
|
349
393
|
// what Evaluator::evalChildren's own per-statement loop already does
|
|
350
394
|
// for one node: derive childCtx via ctx.withScope(...), checkDebug,
|
|
@@ -271,6 +271,25 @@ public:
|
|
|
271
271
|
// _builtin_children/_eval_children_lazy.
|
|
272
272
|
void builtinChildren(const CallArgs& args, EvalContext& ctx);
|
|
273
273
|
|
|
274
|
+
// The "which nodes, evaluated against what context" half of
|
|
275
|
+
// builtinChildren, shared with Op::CallChildren's runtime handler
|
|
276
|
+
// (bytecode_vm.cpp) so the native and compiled paths cannot drift on
|
|
277
|
+
// any of the subtle parts: the caller-ctx re-derivation, the
|
|
278
|
+
// $-forwarding loop (which must read the post-resolveCallArgs effCtx
|
|
279
|
+
// -- a children($fn=12) named-$ override lives only there), and the
|
|
280
|
+
// children(N) statement-index filtering/bounds-check. nullopt means
|
|
281
|
+
// "nothing to evaluate" (no forwarded children in scope, empty list,
|
|
282
|
+
// or index out of range) -- a silent no-op in every existing caller,
|
|
283
|
+
// exactly matching builtinChildren's own early returns. `ctx` must be
|
|
284
|
+
// the effCtx resolveCallArgs returned, same as builtinChildren's own
|
|
285
|
+
// parameter today. Public for the same free-function reasoning as
|
|
286
|
+
// builtinChildren itself.
|
|
287
|
+
struct ChildrenForward {
|
|
288
|
+
EvalContext evalCtx;
|
|
289
|
+
std::vector<const oscad::ASTNode*> nodes;
|
|
290
|
+
};
|
|
291
|
+
std::optional<ChildrenForward> prepareChildrenForward(const CallArgs& args, EvalContext& ctx);
|
|
292
|
+
|
|
274
293
|
// "WARNING: {message}{locSuffix(position)}" via echoFn_, no-op if unset.
|
|
275
294
|
// Public: builtins/import.cpp's not-manifold warning is emitted from a
|
|
276
295
|
// free function, same reasoning as tagGenerated()/builtinChildren().
|
|
@@ -532,6 +551,17 @@ private:
|
|
|
532
551
|
// into the caller's scope exactly the way the native per-statement
|
|
533
552
|
// loop's own writes already do.
|
|
534
553
|
bool tryRunCompiledChildren(const std::vector<const oscad::ASTNode*>& children, EvalContext& ctx);
|
|
554
|
+
public:
|
|
555
|
+
// The cache-lookup half of tryRunCompiledChildren, shared with
|
|
556
|
+
// Op::CallChildren's runtime handler (bytecode_vm.cpp, a free
|
|
557
|
+
// function -- public for the same no-friend-declaration reasoning as
|
|
558
|
+
// vmCallStack_/treeStack_). Returns the eligible compiled chunk for
|
|
559
|
+
// `children` or nullptr. Caller owns the useBytecodeVm()/
|
|
560
|
+
// inResolvePass_ gate -- the pass gate is load-bearing
|
|
561
|
+
// (childrenListChunkCache_ is pass-scoped, see its own doc comment),
|
|
562
|
+
// not defensive.
|
|
563
|
+
const CompiledChunk* lookupOrCompileChildrenListChunk(const std::vector<const oscad::ASTNode*>& children);
|
|
564
|
+
private:
|
|
535
565
|
void evalModularCall(const oscad::ModularCall& node, EvalContext& ctx);
|
|
536
566
|
void evalFor(const oscad::ModularFor& node, EvalContext& ctx);
|
|
537
567
|
void evalLetBlock(const oscad::ModularLet& node, EvalContext& ctx);
|
|
@@ -951,15 +981,38 @@ private:
|
|
|
951
981
|
// body -- so a resolvable module call anywhere in that list gets
|
|
952
982
|
// Op::CallModule bytecode, and any if/for control flow around it gets
|
|
953
983
|
// real Jump-based bytecode too, instead of falling through to the
|
|
954
|
-
// native per-statement loop.
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
//
|
|
984
|
+
// native per-statement loop.
|
|
985
|
+
//
|
|
986
|
+
// Keyed by (FIRST element, list SIZE) -- NOT the first element alone,
|
|
987
|
+
// the original convention borrowed from assignBlockChunkCache_
|
|
988
|
+
// (where it IS sufficient: a leading-assignment run's first member
|
|
989
|
+
// uniquely determines the run). Here it wasn't: children()'s
|
|
990
|
+
// forwarding produces two DIFFERENT lists sharing a first element --
|
|
991
|
+
// bare `children()` forwards the caller's whole list, `children(0)`
|
|
992
|
+
// a single-element slice of it -- and keying by front alone made
|
|
993
|
+
// whichever form ran first poison the cache for the other (caught
|
|
994
|
+
// for real: `module m() { children(); children(0); }\n
|
|
995
|
+
// m() { cube(); sphere(); }` made children(0) emit BOTH shapes,
|
|
996
|
+
// or bare children() emit only one, depending on statement order).
|
|
997
|
+
// (front, size) fully disambiguates every real producer: fixed AST
|
|
998
|
+
// lists have unique fronts per call site, and the only same-front
|
|
999
|
+
// pair (bare vs indexed forwarding) always differs in size except
|
|
1000
|
+
// when the lists are literally identical anyway. Same nullopt-means-
|
|
958
1001
|
// tried-and-failed convention, same dangling-pointer hazard, same
|
|
959
1002
|
// two-part fix (cleared alongside stmtExprChunkCache_ at the top of
|
|
960
1003
|
// every resolveTreeImpl call, only read/written while inResolvePass_)
|
|
961
1004
|
// as stmtExprChunkCache_ itself.
|
|
962
|
-
|
|
1005
|
+
struct ChildrenListKeyHash {
|
|
1006
|
+
size_t operator()(const std::pair<const oscad::ASTNode*, size_t>& k) const {
|
|
1007
|
+
// Standard hash-combine (boost-style golden-ratio mix) --
|
|
1008
|
+
// either half alone collides by construction here.
|
|
1009
|
+
const size_t h1 = std::hash<const oscad::ASTNode*>{}(k.first);
|
|
1010
|
+
const size_t h2 = std::hash<size_t>{}(k.second);
|
|
1011
|
+
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
std::unordered_map<std::pair<const oscad::ASTNode*, size_t>, std::optional<CompiledChunk>, ChildrenListKeyHash>
|
|
1015
|
+
childrenListChunkCache_;
|
|
963
1016
|
|
|
964
1017
|
// See stmtExprChunkCache_'s own doc comment, immediately above, for why
|
|
965
1018
|
// this exists. Not a reentrancy guard (resolveTreeImpl is never called
|
|
@@ -1115,6 +1168,17 @@ public:
|
|
|
1115
1168
|
return bytecodeVmEnabled() && (!debugHooks_.debugHook || fastContinueBreakpoints_.has_value());
|
|
1116
1169
|
}
|
|
1117
1170
|
|
|
1171
|
+
// Read accessor for inResolvePass_ (private, below) -- Op::CallChildren's
|
|
1172
|
+
// runtime handler (bytecode_vm.cpp, a free function) must gate its
|
|
1173
|
+
// childrenListChunkCache_ access on it, exactly like
|
|
1174
|
+
// tryRunCompiledChildren's own self-gate: the cache is pass-scoped
|
|
1175
|
+
// (cleared per resolveTreeImpl, AST-address-reuse hazard -- see
|
|
1176
|
+
// stmtExprChunkCache_'s own doc comment), and driveVm CAN run outside
|
|
1177
|
+
// the resolve pass (a host calling evalChildren directly reaches
|
|
1178
|
+
// module opcodes via lookupOrCompileModuleChunk, which is NOT
|
|
1179
|
+
// pass-scoped).
|
|
1180
|
+
bool inResolvePass() const { return inResolvePass_; }
|
|
1181
|
+
|
|
1118
1182
|
private:
|
|
1119
1183
|
// The fine-grained half of the check above: even when useBytecodeVm()
|
|
1120
1184
|
// says compiling/using bytecode is on the table at all, a SPECIFIC
|
|
@@ -1218,6 +1282,12 @@ public:
|
|
|
1218
1282
|
// and callStack_.back() is already gone by the time it runs. See
|
|
1219
1283
|
// activeDeclRefcount_'s own doc comment.
|
|
1220
1284
|
const oscad::ASTNode* declNode = nullptr;
|
|
1285
|
+
// True only when THIS call incremented nativeUserCallDepth_ (i.e.
|
|
1286
|
+
// skipDepthGuard was false) -- exitUserCall* needs it to decrement
|
|
1287
|
+
// symmetrically, for the same "callStack_.back() is already gone"
|
|
1288
|
+
// reason as `kind`/`declNode` above. See nativeUserCallDepth_'s
|
|
1289
|
+
// own doc comment for why this can't just be "always decrement".
|
|
1290
|
+
bool countedTowardNativeDepth = false;
|
|
1221
1291
|
};
|
|
1222
1292
|
// `skipDepthGuard`: kMaxUserCallDepth=50 exists purely to keep the
|
|
1223
1293
|
// NATIVE C++ stack from overflowing (see its own doc comment) -- true
|
|
@@ -1427,6 +1497,37 @@ private:
|
|
|
1427
1497
|
// eval_error.hpp).
|
|
1428
1498
|
std::vector<CallStackFrame> callStack_;
|
|
1429
1499
|
|
|
1500
|
+
// Count of callStack_ entries that ACTUALLY cost native C++ stack --
|
|
1501
|
+
// i.e. pushed with skipDepthGuard=false (enterUserCall's own
|
|
1502
|
+
// interpreted-call sites: evalUserFunctionCore, evalUserModule).
|
|
1503
|
+
// Deliberately NOT the same number as callStack_.size(): a compiled-
|
|
1504
|
+
// to-compiled push (pushBracketedCallFrame/pushBracketedModuleFrame,
|
|
1505
|
+
// bytecode_vm.cpp, skipDepthGuard=true) still grows callStack_ (for
|
|
1506
|
+
// TRACE/closure-detection/$parent_modules bookkeeping) but costs ZERO
|
|
1507
|
+
// native stack, serviced by driveVm's own heap-based loop instead.
|
|
1508
|
+
//
|
|
1509
|
+
// Checking callStack_.size() itself against kMaxUserCallDepth (the
|
|
1510
|
+
// ORIGINAL design) conflates these two: a real BOSL2 script's own
|
|
1511
|
+
// AMBIENT callStack_ depth, inflated by many cheap skip=true compiled
|
|
1512
|
+
// module-call pushes sitting on callStack_ already, could push a
|
|
1513
|
+
// LATER genuinely-native-recursive call (e.g. an interpreted-path
|
|
1514
|
+
// function call like BOSL2's own `ident()`) over the threshold even
|
|
1515
|
+
// though the REAL native C++ nesting at that point was nowhere near
|
|
1516
|
+
// it -- caught for real: Anklet.scad's own ambient callStack_ depth
|
|
1517
|
+
// (mostly cheap Op::CallModule pushes) reached the mid-30s, tripping
|
|
1518
|
+
// kMaxUserCallDepth=30 for an `ident()` call that itself was nested
|
|
1519
|
+
// only a couple of GENUINE native frames deep. Exactly the same class
|
|
1520
|
+
// of "fixed-count guard conflates logical depth with native-stack
|
|
1521
|
+
// cost" bug driveVmNativeDepth_ already exists to avoid for the
|
|
1522
|
+
// OTHER guard site (bytecode_vm.cpp) -- this is that same fix,
|
|
1523
|
+
// applied here. Incremented/decremented symmetrically by
|
|
1524
|
+
// enterUserCall/exitUserCallSuccess/exitUserCallException, gated on
|
|
1525
|
+
// UserCallHandle::countedTowardNativeDepth (skipDepthGuard is only
|
|
1526
|
+
// available at enter time; the handle carries the decision forward
|
|
1527
|
+
// to exit time, since callStack_.back() -- and thus skipDepthGuard's
|
|
1528
|
+
// own original context -- is already gone by then).
|
|
1529
|
+
size_t nativeUserCallDepth_ = 0;
|
|
1530
|
+
|
|
1430
1531
|
// Running count of Module-kind frames currently on callStack_ --
|
|
1431
1532
|
// maintained incrementally by enterUserCall/exitUserCall* rather than
|
|
1432
1533
|
// rescanned from callStack_ on every module call (buildModuleChildCtx's
|
|
@@ -368,12 +368,30 @@ public:
|
|
|
368
368
|
dirty_[level].push_back(id);
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
+
// Level-aware, NOT a blind pop_back() -- the exact fix
|
|
372
|
+
// ScopeTrailStorage::popLevel (above) already carries, for the exact
|
|
373
|
+
// out-of-order-pop bug class its own doc comment describes; this
|
|
374
|
+
// indexed twin never got the same fix because nothing violated LIFO
|
|
375
|
+
// view destruction on the dyn trail until Op::CallChildren's
|
|
376
|
+
// forwarding frame (bytecode_vm.cpp): its evalCtx (a dyn level opened
|
|
377
|
+
// AFTER the call's own effCtx level) is moved into a VmFrame and
|
|
378
|
+
// OUTLIVES effCtx, so effCtx's pop runs while evalCtx's later entry
|
|
379
|
+
// is still physically on top of the same name's stack -- the blind
|
|
380
|
+
// pop_back() silently removed the still-live forwarded value instead
|
|
381
|
+
// of the one actually being popped (caught for real: a
|
|
382
|
+
// children($fn=9) named-$ override read back as the root default 0
|
|
383
|
+
// inside the forwarded child).
|
|
371
384
|
void popLevel(int level) {
|
|
372
385
|
auto it = dirty_.find(level);
|
|
373
386
|
if (it != dirty_.end()) {
|
|
374
387
|
for (int id : it->second) {
|
|
375
388
|
auto& stack = stacks_[static_cast<size_t>(id)];
|
|
376
|
-
|
|
389
|
+
for (auto rit = stack.rbegin(); rit != stack.rend(); ++rit) {
|
|
390
|
+
if (rit->level == level) {
|
|
391
|
+
stack.erase(std::next(rit).base());
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
377
395
|
}
|
|
378
396
|
dirty_.erase(it);
|
|
379
397
|
}
|
|
@@ -1420,12 +1420,25 @@ public:
|
|
|
1420
1420
|
emitBuiltinWrap(*wrapKind, call.name->name, call, children, out);
|
|
1421
1421
|
return;
|
|
1422
1422
|
}
|
|
1423
|
-
//
|
|
1424
|
-
//
|
|
1425
|
-
//
|
|
1426
|
-
//
|
|
1427
|
-
//
|
|
1428
|
-
//
|
|
1423
|
+
// children() -- the runtime-varying forwarding builtin,
|
|
1424
|
+
// detected by the same function-pointer-identity pattern
|
|
1425
|
+
// as Transform/Color above. Deliberately NO preceding
|
|
1426
|
+
// Op::CheckDebugStatement (unlike emitBuiltinWrap's own
|
|
1427
|
+
// emission): CallChildren's handler fires checkDebug
|
|
1428
|
+
// itself against the SCOPE-WRAPPED ctx, byte-for-byte
|
|
1429
|
+
// matching Op::NativeStatement's own handler -- the
|
|
1430
|
+
// CheckDebugStatement handler passes the un-wrapped ctx,
|
|
1431
|
+
// which would be a subtle behavior change for this node.
|
|
1432
|
+
// See Op::CallChildren's own doc comment (bytecode.hpp).
|
|
1433
|
+
if (dispatchIt != dispatch.end() && dispatchIt->second == &resolveChildren) {
|
|
1434
|
+
out.push_back({Op::CallChildren, internNativeStatement(&stmt), 0, &stmt.position()});
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
// Every other builtin, or a name that didn't resolve to a
|
|
1438
|
+
// user module statically -- native passthrough, exactly
|
|
1439
|
+
// like echo/assert/etc. below. Never the recursion-depth
|
|
1440
|
+
// risk this compiler targets for THESE (see
|
|
1441
|
+
// NativeStatement's own doc comment, bytecode.hpp).
|
|
1429
1442
|
out.push_back({Op::NativeStatement, internNativeStatement(&stmt), 0, &stmt.position()});
|
|
1430
1443
|
return;
|
|
1431
1444
|
}
|
|
@@ -329,6 +329,49 @@ void pushBracketedModuleFrame(Evaluator& ev, const CompiledChunk& chunk, const o
|
|
|
329
329
|
ev.vmCallBrackets_.push_back(std::move(handle));
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
// Op::CallChildren's own push -- a THIRD frame shape, distinct from both
|
|
333
|
+
// existing helpers: splice-owning like pushBracketedModuleFrame's
|
|
334
|
+
// (ownsModuleSplice=true, mirroring evalModularCall's own unconditional
|
|
335
|
+
// splice branch for "children", csg_resolve.cpp) but BRACKETLESS like
|
|
336
|
+
// pushBareFrame's (nullopt in vmCallBrackets_ -- children() never gets a
|
|
337
|
+
// callStack_/profiling entry natively either: only enterUserCall pushes
|
|
338
|
+
// those, and resolveChildren/builtinChildren never call it, so no TRACE
|
|
339
|
+
// frame, no profile site, no $parent_modules bump, exactly matching the
|
|
340
|
+
// native path). driveVm's completion branch and teardownVmCallStackDownTo
|
|
341
|
+
// both already handle this combination -- their bracket (`if (bracket)`)
|
|
342
|
+
// and splice (`if (ownsModuleSplice)`) concerns are independent at both
|
|
343
|
+
// sites. `evalCtx` is prepareChildrenForward's result (the caller-derived,
|
|
344
|
+
// $-forwarded context the children must run under -- see that helper's
|
|
345
|
+
// own doc comment, evaluator.hpp). hopEligible set explicitly false --
|
|
346
|
+
// pushBracketedModuleFrame itself omits the reset (benign there only
|
|
347
|
+
// because module chunks never contain tail-call opcodes); don't inherit
|
|
348
|
+
// a pooled function frame's stale true here either.
|
|
349
|
+
void pushChildrenForwardFrame(Evaluator& ev, const CompiledChunk& chunk, EvalContext evalCtx,
|
|
350
|
+
std::uint64_t randsBefore, const oscad::ASTNode& callNode) {
|
|
351
|
+
if (ev.vmCallStack_.size() >= Evaluator::kMaxVmCallStackDepth) {
|
|
352
|
+
ev.error("Recursion too deep while forwarding children()", callNode);
|
|
353
|
+
}
|
|
354
|
+
auto frame = ev.acquireVmFrame();
|
|
355
|
+
frame->chunk = &chunk;
|
|
356
|
+
frame->code = &chunk.bodyCode;
|
|
357
|
+
frame->pc = 0;
|
|
358
|
+
frame->slots.assign(static_cast<size_t>(chunk.numSlots), Value{});
|
|
359
|
+
frame->stack.clear();
|
|
360
|
+
frame->bound.clear();
|
|
361
|
+
frame->accumStack.clear();
|
|
362
|
+
frame->iterLists.assign(static_cast<size_t>(chunk.numIterLists), IterList{});
|
|
363
|
+
frame->ctxChain.clear();
|
|
364
|
+
frame->ctxChain.push_back(std::move(evalCtx));
|
|
365
|
+
frame->tailHopGuard = 0;
|
|
366
|
+
frame->logicalName.clear();
|
|
367
|
+
frame->hopEligible = false;
|
|
368
|
+
frame->ownsModuleSplice = true;
|
|
369
|
+
frame->moduleRandsBefore = randsBefore;
|
|
370
|
+
frame->moduleSpliceCallNode = &callNode;
|
|
371
|
+
ev.vmCallStack_.push_back(std::move(frame));
|
|
372
|
+
ev.vmCallBrackets_.emplace_back(std::nullopt);
|
|
373
|
+
}
|
|
374
|
+
|
|
332
375
|
// Tears down every frame from vmCallStack_'s own top down to (but not
|
|
333
376
|
// including) `floor`, on the exception path -- releases each VmFrame to
|
|
334
377
|
// the pool, tears down its ctxChain back-to-front (never relying on
|
|
@@ -933,6 +976,71 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
933
976
|
}
|
|
934
977
|
break;
|
|
935
978
|
}
|
|
979
|
+
case Op::CallChildren: {
|
|
980
|
+
// Ordering is load-bearing throughout -- see this op's
|
|
981
|
+
// own doc comment (bytecode.hpp): checkDebug against
|
|
982
|
+
// the SCOPE-WRAPPED ctx (byte-for-byte what Op::
|
|
983
|
+
// NativeStatement does for this same node today);
|
|
984
|
+
// randsBefore BEFORE argument resolution (rands-in-args
|
|
985
|
+
// taint); treeStack_ pushed LAST, immediately before
|
|
986
|
+
// the frame push / native fallback, so an early-out or
|
|
987
|
+
// a throw during arg resolution has nothing to clean
|
|
988
|
+
// up (the native path's own catch{pop;throw} has no
|
|
989
|
+
// equivalent out here -- this reorder IS the
|
|
990
|
+
// exception-safety mechanism; arg resolution never
|
|
991
|
+
// appends CSG nodes, so pushing after it is
|
|
992
|
+
// unobservable).
|
|
993
|
+
const auto* callNode =
|
|
994
|
+
static_cast<const oscad::ModularCall*>(f.chunk->nativeStatements[static_cast<size_t>(ins.a)]);
|
|
995
|
+
EvalContext scopedCtx = ctx.withScope(callNode->scope() ? callNode->scope() : ctx.scope);
|
|
996
|
+
ev.checkDebug(*callNode, scopedCtx);
|
|
997
|
+
const std::uint64_t randsBefore = ev.randsCallCount();
|
|
998
|
+
auto [args, effCtx] = resolveCallArgs(ev, callNode->arguments, scopedCtx);
|
|
999
|
+
std::optional<Evaluator::ChildrenForward> fwd = ev.prepareChildrenForward(args, effCtx);
|
|
1000
|
+
if (!fwd) {
|
|
1001
|
+
// No forwarded children in scope / empty / index
|
|
1002
|
+
// out of range -- a silent no-op, exactly matching
|
|
1003
|
+
// builtinChildren's own early returns.
|
|
1004
|
+
++f.pc;
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
// Pass gate is load-bearing, not defensive -- the
|
|
1008
|
+
// chunk cache is pass-scoped; see inResolvePass()'s
|
|
1009
|
+
// own doc comment (evaluator.hpp).
|
|
1010
|
+
const CompiledChunk* chunk = (ev.useBytecodeVm() && ev.inResolvePass())
|
|
1011
|
+
? ev.lookupOrCompileChildrenListChunk(fwd->nodes)
|
|
1012
|
+
: nullptr;
|
|
1013
|
+
if (chunk) {
|
|
1014
|
+
ev.treeStack_.emplace_back();
|
|
1015
|
+
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode);
|
|
1016
|
+
// f.pc deliberately NOT advanced -- resumes when
|
|
1017
|
+
// the pushed frame completes; driveVm's completion
|
|
1018
|
+
// branch runs the splice (isModule &&
|
|
1019
|
+
// ownsModuleSplice), mirroring evalModularCall's
|
|
1020
|
+
// own "children" splice branch exactly.
|
|
1021
|
+
} else {
|
|
1022
|
+
// Fallback reuses the ALREADY-resolved args --
|
|
1023
|
+
// never evalStatement, which would re-resolve them
|
|
1024
|
+
// (double rands(), double echo/assert side
|
|
1025
|
+
// effects, double expr-level debug stops).
|
|
1026
|
+
// Inlines evalModularCall's own children branch:
|
|
1027
|
+
// push accumulator, run natively, pop, splice.
|
|
1028
|
+
// The native evalChildren still self-gates and
|
|
1029
|
+
// retries tryRunCompiledChildren internally.
|
|
1030
|
+
ev.treeStack_.emplace_back();
|
|
1031
|
+
try {
|
|
1032
|
+
ev.evalChildren(fwd->nodes, fwd->evalCtx);
|
|
1033
|
+
} catch (...) {
|
|
1034
|
+
ev.treeStack_.pop_back();
|
|
1035
|
+
throw;
|
|
1036
|
+
}
|
|
1037
|
+
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
1038
|
+
ev.treeStack_.pop_back();
|
|
1039
|
+
ev.spliceModuleChildren(std::move(children), randsBefore, *callNode);
|
|
1040
|
+
++f.pc;
|
|
1041
|
+
}
|
|
1042
|
+
break;
|
|
1043
|
+
}
|
|
936
1044
|
case Op::PushBuiltinWrap: {
|
|
937
1045
|
const CompiledChunk::BuiltinWrapSite& site = f.chunk->builtinWrapSites[static_cast<size_t>(ins.a)];
|
|
938
1046
|
// Captured BEFORE any argument resolution -- mirrors
|
|
@@ -84,15 +84,29 @@ bool Evaluator::tryRunCompiledAssignmentBlock(const std::vector<const oscad::AST
|
|
|
84
84
|
|
|
85
85
|
bool Evaluator::tryRunCompiledChildren(const std::vector<const oscad::ASTNode*>& children, EvalContext& ctx) {
|
|
86
86
|
if (children.empty() || !useBytecodeVm() || !inResolvePass_) return false;
|
|
87
|
+
const CompiledChunk* chunk = lookupOrCompileChildrenListChunk(children);
|
|
88
|
+
if (!chunk) return false;
|
|
89
|
+
runCompiledModuleBody(*this, *chunk, ctx);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// The cache-lookup half of tryRunCompiledChildren, shared with
|
|
94
|
+
// Op::CallChildren's own runtime handler (bytecode_vm.cpp) -- both need
|
|
95
|
+
// exactly this "list -> eligible chunk or nullptr" step, differing only
|
|
96
|
+
// in how they then RUN the chunk (native runCompiledModuleBody reentry
|
|
97
|
+
// here, a direct vmCallStack_ push there). Caller is responsible for the
|
|
98
|
+
// useBytecodeVm()/inResolvePass_ gate (see childrenListChunkCache_'s own
|
|
99
|
+
// doc comment for why the pass gate is load-bearing, not defensive).
|
|
100
|
+
const CompiledChunk* Evaluator::lookupOrCompileChildrenListChunk(const std::vector<const oscad::ASTNode*>& children) {
|
|
87
101
|
const oscad::ASTNode* first = children.front();
|
|
88
|
-
auto
|
|
102
|
+
const auto key = std::make_pair(first, children.size());
|
|
103
|
+
auto it = childrenListChunkCache_.find(key);
|
|
89
104
|
if (it == childrenListChunkCache_.end()) {
|
|
90
|
-
it = childrenListChunkCache_.emplace(
|
|
105
|
+
it = childrenListChunkCache_.emplace(key, tryCompileChildrenList(children, first->scope())).first;
|
|
91
106
|
if (it->second) flattenNestedLiterals(*it->second);
|
|
92
107
|
}
|
|
93
|
-
if (!it->second || !chunkEligibleNow(*it->second)) return
|
|
94
|
-
|
|
95
|
-
return true;
|
|
108
|
+
if (!it->second || !chunkEligibleNow(*it->second)) return nullptr;
|
|
109
|
+
return &*it->second;
|
|
96
110
|
}
|
|
97
111
|
|
|
98
112
|
const Value* Evaluator::findUpvalue(const oscad::ASTNode* targetDecl, int slot) const {
|
|
@@ -682,13 +696,22 @@ Evaluator::UserCallHandle Evaluator::enterUserCall(const std::string& name, cons
|
|
|
682
696
|
// entirely; for what's left, the margin check is the proven-UNSAFE
|
|
683
697
|
// mechanism on Windows (confirmed via real CI), this fixed count the
|
|
684
698
|
// proven-safe one.
|
|
685
|
-
|
|
699
|
+
//
|
|
700
|
+
// Checked against nativeUserCallDepth_, NOT callStack_.size() -- see
|
|
701
|
+
// that field's own doc comment (evaluator.hpp) for why: callStack_
|
|
702
|
+
// also grows from cheap, zero-native-cost skipDepthGuard=true pushes,
|
|
703
|
+
// which must not count toward this native-stack-safety ceiling.
|
|
704
|
+
if (!skipDepthGuard && nativeUserCallDepth_ >= kMaxUserCallDepth) {
|
|
686
705
|
error("Recursion too deep while calling " + std::string(isModule ? "module" : "function") + " '" + name + "'",
|
|
687
706
|
declNode);
|
|
688
707
|
}
|
|
689
708
|
UserCallHandle h;
|
|
690
709
|
h.kind = kind;
|
|
691
710
|
h.declNode = &declNode;
|
|
711
|
+
if (!skipDepthGuard) {
|
|
712
|
+
++nativeUserCallDepth_;
|
|
713
|
+
h.countedTowardNativeDepth = true;
|
|
714
|
+
}
|
|
692
715
|
h.prof = profileEnter(isModule ? "module" : "function", name, callPos, &declNode.position());
|
|
693
716
|
callStack_.push_back(CallStackFrame{kind, name, callPos, &declNode.position(), &declNode, nullptr, upvalueParent});
|
|
694
717
|
callStack_.back().bodyCtx = &childCtx; // per-frame locals for the debugger
|
|
@@ -710,6 +733,7 @@ void Evaluator::exitUserCallSuccess(const std::string& name, const UserCallHandl
|
|
|
710
733
|
if (fireReturnHook && debugHooks_.returnHook) debugHooks_.returnHook(name, result, static_cast<int>(callStack_.size()));
|
|
711
734
|
callStack_.pop_back();
|
|
712
735
|
if (handle.kind == CallStackFrame::Kind::Module) --moduleCallDepth_;
|
|
736
|
+
if (handle.countedTowardNativeDepth) --nativeUserCallDepth_;
|
|
713
737
|
noteActiveDeclExit(handle.declNode);
|
|
714
738
|
if (handle.prof) profileExit(*handle.prof);
|
|
715
739
|
}
|
|
@@ -717,6 +741,7 @@ void Evaluator::exitUserCallSuccess(const std::string& name, const UserCallHandl
|
|
|
717
741
|
void Evaluator::exitUserCallException(const UserCallHandle& handle) {
|
|
718
742
|
callStack_.pop_back();
|
|
719
743
|
if (handle.kind == CallStackFrame::Kind::Module) --moduleCallDepth_;
|
|
744
|
+
if (handle.countedTowardNativeDepth) --nativeUserCallDepth_;
|
|
720
745
|
noteActiveDeclExit(handle.declNode);
|
|
721
746
|
if (handle.prof) profileExit(*handle.prof);
|
|
722
747
|
}
|
|
@@ -886,15 +911,20 @@ Value Evaluator::parentModuleName(int idx) const {
|
|
|
886
911
|
return Value{modules[static_cast<size_t>(revIdx)]};
|
|
887
912
|
}
|
|
888
913
|
|
|
889
|
-
|
|
914
|
+
std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(const CallArgs& args, EvalContext& ctx) {
|
|
890
915
|
Value idxArg = getArg(args, 0, "index", Value{});
|
|
891
|
-
if (!ctx.childrenNodes || ctx.childrenNodes->empty()) return;
|
|
916
|
+
if (!ctx.childrenNodes || ctx.childrenNodes->empty()) return std::nullopt;
|
|
892
917
|
const EvalContext* callerCtx = ctx.childrenCallerCtx;
|
|
893
|
-
if (!callerCtx) return;
|
|
918
|
+
if (!callerCtx) return std::nullopt;
|
|
894
919
|
|
|
895
920
|
// A children() forwarding chain's own dyn/let_/etc. must alias the
|
|
896
921
|
// *caller's* (not this ctx's) -- see EvalContext::withScope's rationale.
|
|
897
922
|
EvalContext evalCtx = callerCtx->childCtx(nullptr, std::nullopt, callerCtx->childrenNodes, callerCtx->childrenCallerCtx);
|
|
923
|
+
// `ctx` here is the post-resolveCallArgs effCtx, deliberately: a
|
|
924
|
+
// `children($fn=12)`-style named-$ override lives only at effCtx's own
|
|
925
|
+
// trail level, and TrailView::items() is ancestry-visible, so reading
|
|
926
|
+
// from effCtx forwards both the call's own overrides AND everything
|
|
927
|
+
// the wrapper module's body set (`$fn = 100; children();`).
|
|
898
928
|
for (const auto& [k, v] : ctx.dyn->items()) {
|
|
899
929
|
if (!k.empty() && k[0] == '$') evalCtx.dyn->set(k, v);
|
|
900
930
|
}
|
|
@@ -903,8 +933,7 @@ void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
|
903
933
|
}
|
|
904
934
|
|
|
905
935
|
if (std::holds_alternative<std::monostate>(idxArg)) {
|
|
906
|
-
|
|
907
|
-
return;
|
|
936
|
+
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes};
|
|
908
937
|
}
|
|
909
938
|
|
|
910
939
|
// children(N) indexes child *statements*, not output bodies -- a
|
|
@@ -919,8 +948,14 @@ void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
|
919
948
|
geoNodes.push_back(c);
|
|
920
949
|
}
|
|
921
950
|
}
|
|
922
|
-
if (idx < 0 || static_cast<size_t>(idx) >= geoNodes.size()) return;
|
|
923
|
-
|
|
951
|
+
if (idx < 0 || static_cast<size_t>(idx) >= geoNodes.size()) return std::nullopt;
|
|
952
|
+
return ChildrenForward{std::move(evalCtx), {geoNodes[static_cast<size_t>(idx)]}};
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
956
|
+
std::optional<ChildrenForward> fwd = prepareChildrenForward(args, ctx);
|
|
957
|
+
if (!fwd) return;
|
|
958
|
+
evalChildren(fwd->nodes, fwd->evalCtx);
|
|
924
959
|
}
|
|
925
960
|
|
|
926
961
|
} // namespace oscadeval
|