openscad-cpp-evaluator 0.7.0__tar.gz → 0.8.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.7.0 → openscad_cpp_evaluator-0.8.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/bytecode.hpp +26 -17
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/bytecode_compiler.cpp +69 -24
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/bytecode_vm.cpp +41 -15
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/user_calls.cpp +14 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_bytecode_compiler.cpp +63 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tools/cli/main.cpp +0 -0
|
@@ -276,24 +276,24 @@ struct CompiledChunk {
|
|
|
276
276
|
// literal's own ClosureSite still needed from beyond `node`'s own scope
|
|
277
277
|
// (i.e. any capture whose resolution target isn't `node` itself). This
|
|
278
278
|
// "bubbling" is what makes a closure nested inside another compiled-
|
|
279
|
-
// creating closure resolve correctly
|
|
280
|
-
// is
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
279
|
+
// creating closure resolve correctly: at the OUTERMOST level a given
|
|
280
|
+
// capture is actually snapshotted (see Op::MakeClosure's own runtime
|
|
281
|
+
// doc comment, bytecode_vm.cpp), `captures`'s entries resolve against
|
|
282
|
+
// that running chunk's own `slots` array whenever `targetDecl` matches
|
|
283
|
+
// its own declaration -- and, when it doesn't (a capture bubbled up
|
|
284
|
+
// from an even-more-deeply-nested literal), against the enclosing
|
|
285
|
+
// frame via Evaluator::findUpvalue or, failing that, `ctx.let_`
|
|
286
|
+
// (rooted at that OUTER closure's own capturedLet whenever it's itself
|
|
287
|
+
// an escaped invocation) -- regardless of how many literal-within-
|
|
288
|
+
// literal levels `node` was originally nested through in the source.
|
|
286
289
|
//
|
|
287
|
-
// `node`'s own
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
// closure's own body additionally getting compiled too (its captures
|
|
295
|
-
// would need to read from this snapshot instead of a live-stack walk)
|
|
296
|
-
// is a natural follow-on, not attempted here.
|
|
290
|
+
// `node`'s own body IS also registered (Evaluator::
|
|
291
|
+
// lookupCompiledLiteralChunk finds a real cache entry for it, same as
|
|
292
|
+
// a zero-capture literal), so a closure invocation can run compiled
|
|
293
|
+
// too, not just its creation: Op::LoadUpvalue/Op::MakeClosure inside
|
|
294
|
+
// that body fall back to `ctx.let_` exactly as described above
|
|
295
|
+
// whenever the live-call-stack walk misses, which is precisely what
|
|
296
|
+
// happens once this closure has actually escaped its creator.
|
|
297
297
|
struct ClosureSite {
|
|
298
298
|
const oscad::FunctionLiteral* node = nullptr;
|
|
299
299
|
std::vector<UpvalueRef> captures;
|
|
@@ -307,6 +307,15 @@ struct CompiledChunk {
|
|
|
307
307
|
std::vector<std::optional<std::string>> argNames;
|
|
308
308
|
};
|
|
309
309
|
|
|
310
|
+
// The FunctionDeclaration/FunctionLiteral this chunk's own body was
|
|
311
|
+
// compiled from (bytecode_compiler.cpp's compileFunctionLike sets this
|
|
312
|
+
// to its own `selfDecl` parameter) -- Op::MakeClosure's runtime handler
|
|
313
|
+
// (bytecode_vm.cpp) compares a ClosureSite capture's own `targetDecl`
|
|
314
|
+
// against this to tell "genuinely local to the running chunk" (read
|
|
315
|
+
// `slots` directly) from "bubbled up from a nested literal" (needs the
|
|
316
|
+
// enclosing-frame/capturedLet fallback) apart.
|
|
317
|
+
const oscad::ASTNode* selfDecl = nullptr;
|
|
318
|
+
|
|
310
319
|
std::vector<Param> params;
|
|
311
320
|
std::vector<std::vector<Instruction>> defaultCode;
|
|
312
321
|
std::vector<Instruction> bodyCode;
|
|
@@ -44,11 +44,9 @@ bool isListCompClauseKind(oscad::NodeKind kind) {
|
|
|
44
44
|
// `owner` itself (targetDecl != owner) -- see ClosureSite's own doc comment
|
|
45
45
|
// (bytecode.hpp) for why this "bubbling" is necessary: a literal nested
|
|
46
46
|
// inside `owner` may need something from further out than `owner`'s own
|
|
47
|
-
// scope,
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
// the inner literal's interpreter-resolved capturedLet ancestry, rooted at
|
|
51
|
-
// whatever `owner` itself captured, would simply never contain it.
|
|
47
|
+
// scope, so `owner`'s OWN Op::MakeClosure must snapshot that name too --
|
|
48
|
+
// otherwise the inner literal's own capturedLet, rooted at whatever `owner`
|
|
49
|
+
// itself captured, would simply never contain it.
|
|
52
50
|
// Dedupes by (targetDecl, slot): the same enclosing binding reached through
|
|
53
51
|
// two different nested literals (or the same literal referencing it twice)
|
|
54
52
|
// is still one capture to make.
|
|
@@ -67,6 +65,43 @@ void bubbleEscapingCaptures(const CompiledChunk::ClosureSite& site, const oscad:
|
|
|
67
65
|
}
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
// True if any instruction in `chunk`'s own body/defaults is Op::LoadFree --
|
|
69
|
+
// i.e. an identifier that resolved to neither a local, a statically-known
|
|
70
|
+
// enclosing upvalue, nor a dyn ($-prefixed) name at compile time (see
|
|
71
|
+
// compileExpr's own Identifier case). A self-referential recursive closure
|
|
72
|
+
// (`let(a = function(x,i) ... a(...) ...)`, the reduce()/accumulate()/
|
|
73
|
+
// while() idiom) hits exactly this: LetOp's own declareLocal for `a` runs
|
|
74
|
+
// only AFTER compiling `a`'s RHS, so `a`'s reference to itself can't
|
|
75
|
+
// resolve as an upvalue at compile time and falls through to LoadFree --
|
|
76
|
+
// Evaluator::evalIdentifier's own ctx.scope->lookupVariable() fallback,
|
|
77
|
+
// which re-evaluates the let-binding's RHS FRESH on every single call,
|
|
78
|
+
// producing a new Closure whose capturedLet is THIS invocation's own
|
|
79
|
+
// ctx.let_ (see expr_eval.cpp's FunctionLiteral case) rather than a stable
|
|
80
|
+
// snapshot. Registering such a chunk for compiled invocation (see the
|
|
81
|
+
// FunctionLiteral case below) would still be functionally correct -- but
|
|
82
|
+
// each recursive call's own capturedLet->openChild() then nests ONE level
|
|
83
|
+
// deeper than the last (confirmed empirically: an O(n) list reduce()
|
|
84
|
+
// degrading to O(n^2) once compiled), since nothing about that repeated
|
|
85
|
+
// fresh-derivation ever re-roots the trail. Excluding a LoadFree-containing
|
|
86
|
+
// chunk from registration leaves it running interpreted exactly as before
|
|
87
|
+
// (this compile-time gap itself isn't fixed here) -- a real, if imperfect,
|
|
88
|
+
// scope for now; closing it -- letting `a` resolve as a genuine upvalue of
|
|
89
|
+
// its own declaring LetOp -- is future work, not bundled into this change.
|
|
90
|
+
bool containsLoadFree(const std::vector<Instruction>& code) {
|
|
91
|
+
for (const Instruction& ins : code) {
|
|
92
|
+
if (ins.op == Op::LoadFree) return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
bool containsLoadFree(const CompiledChunk& chunk) {
|
|
98
|
+
if (containsLoadFree(chunk.bodyCode)) return true;
|
|
99
|
+
for (const auto& defaultCode : chunk.defaultCode) {
|
|
100
|
+
if (containsLoadFree(defaultCode)) return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
70
105
|
// Compile-time name -> slot resolution, mirroring the LetOp/nested-scope
|
|
71
106
|
// shadowing rules callCtx()/letChildCtx() apply at runtime: one frame per
|
|
72
107
|
// LetOp (pushed/popped around its own assignments+body), innermost frame
|
|
@@ -306,32 +341,41 @@ public:
|
|
|
306
341
|
for (const auto& nestedSite : literalChunk.closureSites) {
|
|
307
342
|
bubbleEscapingCaptures(nestedSite, &n, effectiveCaptures);
|
|
308
343
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
344
|
+
// Registered (Evaluator::lookupCompiledLiteralChunk finds
|
|
345
|
+
// this by node pointer whenever the closure is later
|
|
346
|
+
// invoked, whether that's a plain PushConst-created value
|
|
347
|
+
// below or a MakeClosure-snapshotted one) whenever it's
|
|
348
|
+
// actually safe to run compiled: always for a zero-capture
|
|
349
|
+
// literal (a single frozen constant, unaffected by anything
|
|
350
|
+
// below), and for a captures-having one only when its own
|
|
351
|
+
// body contains no Op::LoadFree -- see containsLoadFree's
|
|
352
|
+
// own doc comment, above, for why a LoadFree-containing
|
|
353
|
+
// captures-having closure (the reduce()/accumulate()/
|
|
354
|
+
// while() self-referential-recursion idiom) must still be
|
|
355
|
+
// left interpreted: its own capturedLet-chaining, once
|
|
356
|
+
// registered, degrades an O(n) reduction into O(n^2).
|
|
357
|
+
// Everything else (Op::LoadUpvalue/Op::MakeClosure inside a
|
|
358
|
+
// REGISTERED captures-having chunk) is no longer assumed to
|
|
359
|
+
// resolve only against a still-live creator frame (see
|
|
360
|
+
// those opcodes' own runtime fallback, bytecode_vm.cpp):
|
|
361
|
+
// when the live-call-stack walk misses (the creator's frame
|
|
362
|
+
// is gone -- a genuinely escaped closure), they fall back to
|
|
363
|
+
// `ctx.let_`, which callCtxFor roots at this exact closure's
|
|
364
|
+
// own capturedLet snapshot whenever it's invoked -- the same
|
|
365
|
+
// snapshot `effectiveCaptures` describes below.
|
|
366
|
+
if (effectiveCaptures.empty() || !containsLoadFree(literalChunk)) {
|
|
317
367
|
chunk_.nestedLiterals.emplace_back(&n, std::move(literalChunk));
|
|
368
|
+
}
|
|
369
|
+
if (effectiveCaptures.empty()) {
|
|
370
|
+
// Closes over nothing at all, even transitively -- a
|
|
371
|
+
// single frozen constant works for every invocation, no
|
|
372
|
+
// per-call snapshot needed.
|
|
318
373
|
out.push_back(
|
|
319
374
|
{Op::PushConst, internConst(Value{std::make_shared<const Closure>(Closure{&n, nullptr})}), 0,
|
|
320
375
|
nullptr});
|
|
321
376
|
return;
|
|
322
377
|
}
|
|
323
378
|
// Escaping-closure support (Op::MakeClosure, bytecode.hpp).
|
|
324
|
-
// `literalChunk`'s own bytecode is discarded here -- its own
|
|
325
|
-
// upvalue reads would resolve via the live-call-stack walk
|
|
326
|
-
// (Op::LoadUpvalue), which is wrong for a closure that
|
|
327
|
-
// outlives its creator -- so this literal always runs
|
|
328
|
-
// interpreted when invoked instead (Evaluator::
|
|
329
|
-
// lookupCompiledLiteralChunk finds no cache entry for it),
|
|
330
|
-
// using the exact same Closure::capturedLet machinery every
|
|
331
|
-
// other escaping closure the interpreter creates directly
|
|
332
|
-
// already relies on. Only `effectiveCaptures` (the names/
|
|
333
|
-
// slots to snapshot right now) survives from the discarded
|
|
334
|
-
// compile attempt.
|
|
335
379
|
int siteIdx = static_cast<int>(chunk_.closureSites.size());
|
|
336
380
|
chunk_.closureSites.push_back(CompiledChunk::ClosureSite{&n, std::move(effectiveCaptures)});
|
|
337
381
|
out.push_back({Op::MakeClosure, siteIdx, 0, nullptr});
|
|
@@ -896,6 +940,7 @@ bool compileFunctionLike(CompiledChunk& chunk, const oscad::Scope* staticScope,
|
|
|
896
940
|
if (!p->name->name.empty() && p->name->name[0] == '$') return false;
|
|
897
941
|
}
|
|
898
942
|
|
|
943
|
+
chunk.selfDecl = selfDecl;
|
|
899
944
|
Compiler compiler(chunk, staticScope, selfDecl, std::move(enclosing));
|
|
900
945
|
CompileScope bodyScope;
|
|
901
946
|
bodyScope.push();
|
|
@@ -127,8 +127,22 @@ Value runChunk(Evaluator& ev, const CompiledChunk& chunk, const std::vector<Inst
|
|
|
127
127
|
++pc;
|
|
128
128
|
break;
|
|
129
129
|
case Op::LoadUpvalue: {
|
|
130
|
+
// findUpvalue walks the LIVE call stack -- correct as long
|
|
131
|
+
// as the declaring call is still active, however many
|
|
132
|
+
// upvalue levels out `uv.targetDecl` sits (an ordinary,
|
|
133
|
+
// not-yet-escaped nested closure, e.g. reduce()'s own
|
|
134
|
+
// self-recursive accumulator). If that frame is gone
|
|
135
|
+
// (this chunk is running as an ESCAPED closure's own body
|
|
136
|
+
// -- see the FunctionLiteral case's own doc comment,
|
|
137
|
+
// bytecode_compiler.cpp), fall back to `ctx.let_`: for any
|
|
138
|
+
// closure invocation with a non-null capturedLet,
|
|
139
|
+
// callCtxFor roots `ctx.let_` at that exact snapshot, which
|
|
140
|
+
// is guaranteed (by construction -- effectiveCaptures is a
|
|
141
|
+
// superset of this chunk's own upvalues) to contain this
|
|
142
|
+
// name.
|
|
130
143
|
const CompiledChunk::UpvalueRef& uv = chunk.upvalues[static_cast<size_t>(ins.a)];
|
|
131
144
|
const Value* v = ev.findUpvalue(uv.targetDecl, uv.slot);
|
|
145
|
+
if (!v) v = ctx.let_->find(uv.name);
|
|
132
146
|
stack.push_back(v ? *v : Value{});
|
|
133
147
|
++pc;
|
|
134
148
|
break;
|
|
@@ -137,24 +151,36 @@ Value runChunk(Evaluator& ev, const CompiledChunk& chunk, const std::vector<Inst
|
|
|
137
151
|
// Builds a FRESH captured environment every time this
|
|
138
152
|
// instruction actually runs (never a compile-time constant
|
|
139
153
|
// -- a loop creating one closure per iteration must capture
|
|
140
|
-
// THAT iteration's own values, not share one snapshot)
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
+
// THAT iteration's own values, not share one snapshot).
|
|
155
|
+
// Each capture is genuinely local to the CURRENTLY-RUNNING
|
|
156
|
+
// chunk only when its own `targetDecl` matches this chunk's
|
|
157
|
+
// `selfDecl` (this literal's direct free-variable
|
|
158
|
+
// references) -- read straight out of `slots` in that case.
|
|
159
|
+
// Anything else is a capture bubbled up from a literal
|
|
160
|
+
// nested even deeper (see ClosureSite's own doc comment,
|
|
161
|
+
// bytecode.hpp): resolved the same way Op::LoadUpvalue
|
|
162
|
+
// resolves any upvalue reference, above -- the live call
|
|
163
|
+
// stack first (still live if THIS closure hasn't itself
|
|
164
|
+
// escaped yet), `ctx.let_` otherwise (this chunk's own
|
|
165
|
+
// capturedLet, when it's running as an escaped closure's
|
|
166
|
+
// body). The resulting Closure::capturedLet is a real,
|
|
167
|
+
// standalone TrailView (isolated root -- nothing else
|
|
168
|
+
// shares it, and it owes nothing to `ctx.let_` itself,
|
|
169
|
+
// which a compiled call never writes to directly -- see
|
|
170
|
+
// bindCompiledArgs' own doc comment), so invoking this
|
|
171
|
+
// closure later works through the EXACT same
|
|
172
|
+
// callCtxFor/capturedLetTrail machinery every interpreter-
|
|
173
|
+
// created escaping closure already uses, unchanged.
|
|
154
174
|
const CompiledChunk::ClosureSite& site = chunk.closureSites[static_cast<size_t>(ins.a)];
|
|
155
175
|
auto capturedTrail = TrailView<Value>::makeRoot();
|
|
156
176
|
for (const auto& cap : site.captures) {
|
|
157
|
-
|
|
177
|
+
if (cap.targetDecl == chunk.selfDecl) {
|
|
178
|
+
capturedTrail->set(cap.name, slots[static_cast<size_t>(cap.slot)]);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const Value* v = ev.findUpvalue(cap.targetDecl, cap.slot);
|
|
182
|
+
if (!v) v = ctx.let_->find(cap.name);
|
|
183
|
+
capturedTrail->set(cap.name, v ? *v : Value{});
|
|
158
184
|
}
|
|
159
185
|
stack.push_back(Value{std::make_shared<const Closure>(Closure{site.node, std::move(capturedTrail)})});
|
|
160
186
|
++pc;
|
|
@@ -152,8 +152,21 @@ EvalContext Evaluator::callCtxFor(const oscad::ASTNode& decl, EvalContext& ctx,
|
|
|
152
152
|
|
|
153
153
|
std::optional<EvalContext> Evaluator::isolatedCallCtxFor(const oscad::ASTNode& declNode, EvalContext& ctx,
|
|
154
154
|
const std::shared_ptr<TrailView<Value>>& capturedLet) {
|
|
155
|
+
// `declNode.scope()`, not `ctx.scope` -- matches every other call-
|
|
156
|
+
// resolution function's own `fnScope = decl.scope() ? decl.scope() :
|
|
157
|
+
// ctx.scope` pattern (evalUserFunction/evalUserFunctionFromBound/
|
|
158
|
+
// evalFunctionLiteral/evalFunctionLiteralFromBound). Mismatching here
|
|
159
|
+
// was invisible until a captures-having FunctionLiteral's own body
|
|
160
|
+
// could ever actually be trampolined into (Op::MakeClosure's own
|
|
161
|
+
// registration -- bytecode_compiler.cpp's FunctionLiteral case): a
|
|
162
|
+
// self-referential closure's free-variable resolution can fall through
|
|
163
|
+
// to evalIdentifier's ctx.scope->lookupVariable() fallback (see its own
|
|
164
|
+
// doc comment, expr_eval.cpp), which needs the CALLEE's own lexical
|
|
165
|
+
// scope to walk outward from -- the caller's scope at the call site
|
|
166
|
+
// has no relation to it at all.
|
|
155
167
|
bool usedChildCtx = false;
|
|
156
|
-
|
|
168
|
+
const oscad::Scope* declScope = declNode.scope() ? declNode.scope() : ctx.scope;
|
|
169
|
+
EvalContext result = callCtxFor(declNode, ctx, declScope, nullptr, nullptr, &usedChildCtx, capturedLet);
|
|
157
170
|
if (usedChildCtx) return std::nullopt;
|
|
158
171
|
return result;
|
|
159
172
|
}
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/tests/test_bytecode_compiler.cpp
RENAMED
|
@@ -511,10 +511,18 @@ TEST(BytecodeCompiler, MakeClosureLetsContainerCompileDespiteNonEscapingClosure)
|
|
|
511
511
|
// above), so fast-continue must be enabled (an empty breakpoint map --
|
|
512
512
|
// fast-continue "on", nothing set) to actually observe whether `make`
|
|
513
513
|
// runs compiled here.
|
|
514
|
+
//
|
|
515
|
+
// 3 stops, not 4: `make`'s own body-entry (1), `g`'s own body-entry
|
|
516
|
+
// (1) -- `g` itself now also runs compiled (its captures-having chunk
|
|
517
|
+
// is registered too, not discarded -- see the FunctionLiteral case's
|
|
518
|
+
// own doc comment, bytecode_compiler.cpp), so it costs exactly one
|
|
519
|
+
// stop instead of the extra sub-expression checkpoint an interpreted
|
|
520
|
+
// call used to add on top -- plus the top-level echo() statement's own
|
|
521
|
+
// stop (module-level code is never compiled).
|
|
514
522
|
const int stops = countDebugHookStops("function make(x) = let(g = function(y) y + x) g(5);\n"
|
|
515
523
|
"echo(make(10));",
|
|
516
524
|
std::unordered_map<std::string, std::set<int>>{});
|
|
517
|
-
EXPECT_EQ(stops,
|
|
525
|
+
EXPECT_EQ(stops, 3);
|
|
518
526
|
}
|
|
519
527
|
|
|
520
528
|
TEST(BytecodeCompiler, MakeClosureLetsContainerCompileDespiteEscapingClosure) {
|
|
@@ -573,6 +581,60 @@ TEST(BytecodeCompiler, MakeClosureBubblesCaptureThroughAnIntermediateClosureLeve
|
|
|
573
581
|
EXPECT_EQ(runCapturingEcho(script), "ECHO: 111");
|
|
574
582
|
}
|
|
575
583
|
|
|
584
|
+
TEST(BytecodeCompiler, MultiLevelCurriedClosureInvocationRunsCompiled) {
|
|
585
|
+
ScopedVm vm(true);
|
|
586
|
+
// fnliterals.scad's f_1arg()-style curry adapter: a closure that
|
|
587
|
+
// returns ANOTHER closure nested inside it, both with real captures.
|
|
588
|
+
// This is exactly the two-level-nesting case Op::MakeClosure's own
|
|
589
|
+
// runtime handler (bytecode_vm.cpp) has to get right when a captures-
|
|
590
|
+
// having chunk's OWN body is registered too -- the inner literal's own
|
|
591
|
+
// MakeClosure instruction runs as part of the OUTER closure's later,
|
|
592
|
+
// separate invocation (not inline within f_1arg's own call, the way a
|
|
593
|
+
// single-level closure's capture always does), so its own captures
|
|
594
|
+
// (bubbled up from `f_1arg` at compile time) are no longer local to
|
|
595
|
+
// whatever frame happens to be running -- they resolve via
|
|
596
|
+
// Evaluator::findUpvalue/`ctx.let_`, not `slots` directly. Correctness
|
|
597
|
+
// (not a stop count -- several calls chain here, and not every shape
|
|
598
|
+
// adds its own extra interpreted-only checkpoint, so the total isn't a
|
|
599
|
+
// reliable compiled-vs-interpreted signal for this particular script)
|
|
600
|
+
// is what actually matters: a wrong result here is exactly what a
|
|
601
|
+
// missed/misdirected capture read would produce.
|
|
602
|
+
EXPECT_EQ(runCapturingEcho("function f_1arg(target_func) = function(a) a==undef? function(x) target_func(x) : "
|
|
603
|
+
"function() target_func(a);\n"
|
|
604
|
+
"function double(x) = x * 2;\n"
|
|
605
|
+
"adder = f_1arg(function(x) double(x));\n"
|
|
606
|
+
"echo(adder(21)());\n"
|
|
607
|
+
"echo(adder(undef)(10));"),
|
|
608
|
+
"ECHO: 42\nECHO: 20");
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
TEST(BytecodeCompiler, SelfReferentialRecursiveClosureStillRunsInterpretedAndCorrectly) {
|
|
612
|
+
ScopedVm vm(true);
|
|
613
|
+
// reduce()'s own idiom: `a` calls itself by name, which LetOp's own
|
|
614
|
+
// declareLocal-after-compiling-the-RHS ordering means never resolves as
|
|
615
|
+
// a genuine upvalue at compile time (falls through to Op::LoadFree
|
|
616
|
+
// instead -- see containsLoadFree's own doc comment, bytecode_compiler.cpp).
|
|
617
|
+
// Registering such a chunk for compiled invocation is what previously
|
|
618
|
+
// (empirically, against a real list) turned an O(n) reduce() into
|
|
619
|
+
// O(n^2): every recursive call re-derives a fresh closure via
|
|
620
|
+
// Evaluator::evalIdentifier's ctx.scope->lookupVariable() fallback,
|
|
621
|
+
// nesting its own capturedLet one level deeper than the last every
|
|
622
|
+
// time. `containsLoadFree` excludes exactly this case from
|
|
623
|
+
// registration, so `a` keeps running interpreted -- more than 1 stop
|
|
624
|
+
// for its own call proves that, and the actual sum must still come out
|
|
625
|
+
// right either way.
|
|
626
|
+
const int stops = countDebugHookStops(
|
|
627
|
+
"function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) i<l? "
|
|
628
|
+
"a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
629
|
+
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));",
|
|
630
|
+
std::unordered_map<std::string, std::set<int>>{});
|
|
631
|
+
EXPECT_GT(stops, 2);
|
|
632
|
+
EXPECT_EQ(runCapturingEcho("function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) "
|
|
633
|
+
"i<l? a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
634
|
+
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));"),
|
|
635
|
+
"ECHO: 10");
|
|
636
|
+
}
|
|
637
|
+
|
|
576
638
|
TEST(BytecodeCompiler, ClosureWithDollarParameterStillBailsContainer) {
|
|
577
639
|
ScopedVm vm(true);
|
|
578
640
|
// Residual, deliberate limitation: a FunctionLiteral with its OWN
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.0}/external/openscad_cpp_parser/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|