openscad-cpp-evaluator 0.7.0__tar.gz → 0.8.1__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.1}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/bytecode.hpp +37 -17
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/bytecode_compiler.cpp +105 -26
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/bytecode_vm.cpp +59 -16
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/user_calls.cpp +14 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_bytecode_compiler.cpp +87 -1
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/README.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/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.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/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.1}/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.1}/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.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/tools/cli/main.cpp +0 -0
|
@@ -266,6 +266,17 @@ struct CompiledChunk {
|
|
|
266
266
|
const oscad::ASTNode* targetDecl = nullptr;
|
|
267
267
|
int slot = 0;
|
|
268
268
|
std::string name;
|
|
269
|
+
// Set only when this entry is a `let(name = function(...) ...)`
|
|
270
|
+
// closure's own reference to ITSELF (bytecode_compiler.cpp's LetOp
|
|
271
|
+
// case, the letrec-style pre-declared-slot path) -- Op::MakeClosure
|
|
272
|
+
// can't read this one out of `slots` the way it does every other
|
|
273
|
+
// capture: at the moment it runs, the closure it's building hasn't
|
|
274
|
+
// been constructed yet (StoreLocal for `name` hasn't executed), so
|
|
275
|
+
// `slots[slot]` would still hold whatever was there before this
|
|
276
|
+
// call. See Op::MakeClosure's own runtime doc comment
|
|
277
|
+
// (bytecode_vm.cpp) for how this is actually resolved (deferred,
|
|
278
|
+
// then patched in after construction).
|
|
279
|
+
bool isSelfReference = false;
|
|
269
280
|
};
|
|
270
281
|
|
|
271
282
|
// One FunctionLiteral's own capture list for Op::MakeClosure, computed
|
|
@@ -276,24 +287,24 @@ struct CompiledChunk {
|
|
|
276
287
|
// literal's own ClosureSite still needed from beyond `node`'s own scope
|
|
277
288
|
// (i.e. any capture whose resolution target isn't `node` itself). This
|
|
278
289
|
// "bubbling" is what makes a closure nested inside another compiled-
|
|
279
|
-
// creating closure resolve correctly
|
|
280
|
-
// is
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
290
|
+
// creating closure resolve correctly: at the OUTERMOST level a given
|
|
291
|
+
// capture is actually snapshotted (see Op::MakeClosure's own runtime
|
|
292
|
+
// doc comment, bytecode_vm.cpp), `captures`'s entries resolve against
|
|
293
|
+
// that running chunk's own `slots` array whenever `targetDecl` matches
|
|
294
|
+
// its own declaration -- and, when it doesn't (a capture bubbled up
|
|
295
|
+
// from an even-more-deeply-nested literal), against the enclosing
|
|
296
|
+
// frame via Evaluator::findUpvalue or, failing that, `ctx.let_`
|
|
297
|
+
// (rooted at that OUTER closure's own capturedLet whenever it's itself
|
|
298
|
+
// an escaped invocation) -- regardless of how many literal-within-
|
|
299
|
+
// literal levels `node` was originally nested through in the source.
|
|
286
300
|
//
|
|
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.
|
|
301
|
+
// `node`'s own body IS also registered (Evaluator::
|
|
302
|
+
// lookupCompiledLiteralChunk finds a real cache entry for it, same as
|
|
303
|
+
// a zero-capture literal), so a closure invocation can run compiled
|
|
304
|
+
// too, not just its creation: Op::LoadUpvalue/Op::MakeClosure inside
|
|
305
|
+
// that body fall back to `ctx.let_` exactly as described above
|
|
306
|
+
// whenever the live-call-stack walk misses, which is precisely what
|
|
307
|
+
// happens once this closure has actually escaped its creator.
|
|
297
308
|
struct ClosureSite {
|
|
298
309
|
const oscad::FunctionLiteral* node = nullptr;
|
|
299
310
|
std::vector<UpvalueRef> captures;
|
|
@@ -307,6 +318,15 @@ struct CompiledChunk {
|
|
|
307
318
|
std::vector<std::optional<std::string>> argNames;
|
|
308
319
|
};
|
|
309
320
|
|
|
321
|
+
// The FunctionDeclaration/FunctionLiteral this chunk's own body was
|
|
322
|
+
// compiled from (bytecode_compiler.cpp's compileFunctionLike sets this
|
|
323
|
+
// to its own `selfDecl` parameter) -- Op::MakeClosure's runtime handler
|
|
324
|
+
// (bytecode_vm.cpp) compares a ClosureSite capture's own `targetDecl`
|
|
325
|
+
// against this to tell "genuinely local to the running chunk" (read
|
|
326
|
+
// `slots` directly) from "bubbled up from a nested literal" (needs the
|
|
327
|
+
// enclosing-frame/capturedLet fallback) apart.
|
|
328
|
+
const oscad::ASTNode* selfDecl = nullptr;
|
|
329
|
+
|
|
310
330
|
std::vector<Param> params;
|
|
311
331
|
std::vector<std::vector<Instruction>> defaultCode;
|
|
312
332
|
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,45 @@ 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). The direct `let(a = function(...)
|
|
72
|
+
// ... a(...) ...)` self-reference (reduce()/accumulate()/while()'s own
|
|
73
|
+
// idiom) no longer hits this -- see the LetOp case's own letrec pre-declare,
|
|
74
|
+
// below -- but anything the pre-declare doesn't cover still does: `a`
|
|
75
|
+
// wrapped in a ternary/let/anything other than a bare FunctionLiteral RHS
|
|
76
|
+
// (`let(a = cond ? function(...) ...a(...)... : function(...) ...)`),
|
|
77
|
+
// mutual recursion between two sibling let-bound closures (each references
|
|
78
|
+
// the OTHER, which isn't declared yet when compiling the first), or any
|
|
79
|
+
// other free variable this phase simply can't resolve statically. For any
|
|
80
|
+
// of those, Evaluator::evalIdentifier's own ctx.scope->lookupVariable()
|
|
81
|
+
// fallback re-evaluates the let-binding's RHS FRESH on every single call,
|
|
82
|
+
// producing a new Closure whose capturedLet is THIS invocation's own
|
|
83
|
+
// ctx.let_ (see expr_eval.cpp's FunctionLiteral case) rather than a stable
|
|
84
|
+
// snapshot -- registering such a chunk for compiled invocation would still
|
|
85
|
+
// be functionally correct, but each recursive call's own
|
|
86
|
+
// capturedLet->openChild() then nests ONE level deeper than the last
|
|
87
|
+
// (confirmed empirically: an O(n) list reduce() degrading to O(n^2) once
|
|
88
|
+
// compiled, before the letrec pre-declare existed), since nothing about
|
|
89
|
+
// that repeated fresh-derivation ever re-roots the trail. Excluding a
|
|
90
|
+
// LoadFree-containing chunk from registration leaves it running
|
|
91
|
+
// interpreted exactly as before -- correct, if not optimized.
|
|
92
|
+
bool containsLoadFree(const std::vector<Instruction>& code) {
|
|
93
|
+
for (const Instruction& ins : code) {
|
|
94
|
+
if (ins.op == Op::LoadFree) return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
bool containsLoadFree(const CompiledChunk& chunk) {
|
|
100
|
+
if (containsLoadFree(chunk.bodyCode)) return true;
|
|
101
|
+
for (const auto& defaultCode : chunk.defaultCode) {
|
|
102
|
+
if (containsLoadFree(defaultCode)) return true;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
70
107
|
// Compile-time name -> slot resolution, mirroring the LetOp/nested-scope
|
|
71
108
|
// shadowing rules callCtx()/letChildCtx() apply at runtime: one frame per
|
|
72
109
|
// LetOp (pushed/popped around its own assignments+body), innermost frame
|
|
@@ -306,32 +343,45 @@ public:
|
|
|
306
343
|
for (const auto& nestedSite : literalChunk.closureSites) {
|
|
307
344
|
bubbleEscapingCaptures(nestedSite, &n, effectiveCaptures);
|
|
308
345
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
346
|
+
// Registered (Evaluator::lookupCompiledLiteralChunk finds
|
|
347
|
+
// this by node pointer whenever the closure is later
|
|
348
|
+
// invoked, whether that's a plain PushConst-created value
|
|
349
|
+
// below or a MakeClosure-snapshotted one) whenever it's
|
|
350
|
+
// actually safe to run compiled: always for a zero-capture
|
|
351
|
+
// literal (a single frozen constant, unaffected by anything
|
|
352
|
+
// below), and for a captures-having one only when its own
|
|
353
|
+
// body contains no Op::LoadFree -- see containsLoadFree's
|
|
354
|
+
// own doc comment, above, for why a LoadFree-containing
|
|
355
|
+
// captures-having closure must still be left interpreted:
|
|
356
|
+
// its own capturedLet-chaining, once registered, degrades
|
|
357
|
+
// an O(n) reduction into O(n^2). (The reduce()/
|
|
358
|
+
// accumulate()/while() idiom itself -- a closure directly
|
|
359
|
+
// assigned via `let` that calls itself by name -- no longer
|
|
360
|
+
// hits this: see the LetOp case's own letrec pre-declare,
|
|
361
|
+
// below, which lets that specific self-reference resolve as
|
|
362
|
+
// a real upvalue instead of falling through to LoadFree.)
|
|
363
|
+
// Everything else (Op::LoadUpvalue/Op::MakeClosure inside a
|
|
364
|
+
// REGISTERED captures-having chunk) is no longer assumed to
|
|
365
|
+
// resolve only against a still-live creator frame (see
|
|
366
|
+
// those opcodes' own runtime fallback, bytecode_vm.cpp):
|
|
367
|
+
// when the live-call-stack walk misses (the creator's frame
|
|
368
|
+
// is gone -- a genuinely escaped closure), they fall back to
|
|
369
|
+
// `ctx.let_`, which callCtxFor roots at this exact closure's
|
|
370
|
+
// own capturedLet snapshot whenever it's invoked -- the same
|
|
371
|
+
// snapshot `effectiveCaptures` describes below.
|
|
372
|
+
if (effectiveCaptures.empty() || !containsLoadFree(literalChunk)) {
|
|
317
373
|
chunk_.nestedLiterals.emplace_back(&n, std::move(literalChunk));
|
|
374
|
+
}
|
|
375
|
+
if (effectiveCaptures.empty()) {
|
|
376
|
+
// Closes over nothing at all, even transitively -- a
|
|
377
|
+
// single frozen constant works for every invocation, no
|
|
378
|
+
// per-call snapshot needed.
|
|
318
379
|
out.push_back(
|
|
319
380
|
{Op::PushConst, internConst(Value{std::make_shared<const Closure>(Closure{&n, nullptr})}), 0,
|
|
320
381
|
nullptr});
|
|
321
382
|
return;
|
|
322
383
|
}
|
|
323
384
|
// 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
385
|
int siteIdx = static_cast<int>(chunk_.closureSites.size());
|
|
336
386
|
chunk_.closureSites.push_back(CompiledChunk::ClosureSite{&n, std::move(effectiveCaptures)});
|
|
337
387
|
out.push_back({Op::MakeClosure, siteIdx, 0, nullptr});
|
|
@@ -517,12 +567,40 @@ public:
|
|
|
517
567
|
out.push_back({Op::OpenLocalScope, 0, 0, nullptr});
|
|
518
568
|
int slotStart = nextSlot_;
|
|
519
569
|
for (const auto& assign : n.assignments) {
|
|
520
|
-
compileExpr(*assign->expr, out, scope); // RHS is never tail
|
|
521
570
|
const std::string& name = assign->name->name;
|
|
571
|
+
// A DIRECT `name = function(...) ...` RHS -- the
|
|
572
|
+
// reduce()/accumulate()/while() idiom, and count_to()-
|
|
573
|
+
// style helpers generally -- gets its own slot declared
|
|
574
|
+
// BEFORE compiling that RHS (letrec-style), so a
|
|
575
|
+
// self-reference inside the closure's own body resolves
|
|
576
|
+
// as a genuine upvalue (Op::LoadUpvalue) instead of
|
|
577
|
+
// falling through to Op::LoadFree. Every other RHS shape
|
|
578
|
+
// keeps the existing after-the-fact declareLocal below
|
|
579
|
+
// unchanged (`let(x = x + 1)` must still see the OUTER
|
|
580
|
+
// x, not a fresh, not-yet-assigned local shadowing it --
|
|
581
|
+
// only a function-literal RHS has "see myself" as a
|
|
582
|
+
// sensible reading at all). See Op::MakeClosure's own
|
|
583
|
+
// runtime handler (bytecode_vm.cpp) for how the
|
|
584
|
+
// resulting self-capture is actually resolved -- the
|
|
585
|
+
// closure being created doesn't exist yet at the moment
|
|
586
|
+
// its own captures are normally snapshotted, so this
|
|
587
|
+
// one is deferred and patched in after construction
|
|
588
|
+
// instead of read eagerly like every other capture.
|
|
589
|
+
const bool selfBinding = !name.empty() && name[0] != '$' &&
|
|
590
|
+
assign->expr->kind() == oscad::NodeKind::FunctionLiteral;
|
|
591
|
+
int preDeclaredSlot = -1;
|
|
592
|
+
if (selfBinding) preDeclaredSlot = declareLocal(scope, name);
|
|
593
|
+
compileExpr(*assign->expr, out, scope); // RHS is never tail
|
|
594
|
+
if (selfBinding && out.back().op == Op::MakeClosure) {
|
|
595
|
+
CompiledChunk::ClosureSite& site = chunk_.closureSites[static_cast<size_t>(out.back().a)];
|
|
596
|
+
for (auto& cap : site.captures) {
|
|
597
|
+
if (cap.targetDecl == selfDecl_ && cap.slot == preDeclaredSlot) cap.isSelfReference = true;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
522
600
|
if (!name.empty() && name[0] == '$') {
|
|
523
601
|
out.push_back({Op::StoreDyn, internName(name), 0, &assign->position()});
|
|
524
602
|
} else {
|
|
525
|
-
int slot = declareLocal(scope, name);
|
|
603
|
+
int slot = selfBinding ? preDeclaredSlot : declareLocal(scope, name);
|
|
526
604
|
out.push_back({Op::StoreLocal, slot, 0, &assign->position()});
|
|
527
605
|
}
|
|
528
606
|
}
|
|
@@ -896,6 +974,7 @@ bool compileFunctionLike(CompiledChunk& chunk, const oscad::Scope* staticScope,
|
|
|
896
974
|
if (!p->name->name.empty() && p->name->name[0] == '$') return false;
|
|
897
975
|
}
|
|
898
976
|
|
|
977
|
+
chunk.selfDecl = selfDecl;
|
|
899
978
|
Compiler compiler(chunk, staticScope, selfDecl, std::move(enclosing));
|
|
900
979
|
CompileScope bodyScope;
|
|
901
980
|
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,26 +151,55 @@ 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();
|
|
176
|
+
// A letrec-style self-reference (UpvalueRef::isSelfReference,
|
|
177
|
+
// see its own doc comment) is skipped here, not read -- the
|
|
178
|
+
// closure it names is THIS instruction's own result, which
|
|
179
|
+
// doesn't exist until the shared_ptr below is constructed.
|
|
180
|
+
// Patched in immediately afterward via the exact same
|
|
181
|
+
// capturedTrail (a live, shared TrailView -- mutating it
|
|
182
|
+
// after `closure` wraps it is exactly as visible to that
|
|
183
|
+
// closure's own later invocations as any other entry).
|
|
184
|
+
std::vector<const std::string*> selfNames;
|
|
156
185
|
for (const auto& cap : site.captures) {
|
|
157
|
-
|
|
186
|
+
if (cap.isSelfReference) {
|
|
187
|
+
selfNames.push_back(&cap.name);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (cap.targetDecl == chunk.selfDecl) {
|
|
191
|
+
capturedTrail->set(cap.name, slots[static_cast<size_t>(cap.slot)]);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const Value* v = ev.findUpvalue(cap.targetDecl, cap.slot);
|
|
195
|
+
if (!v) v = ctx.let_->find(cap.name);
|
|
196
|
+
capturedTrail->set(cap.name, v ? *v : Value{});
|
|
197
|
+
}
|
|
198
|
+
auto closure = std::make_shared<const Closure>(Closure{site.node, capturedTrail});
|
|
199
|
+
for (const std::string* selfName : selfNames) {
|
|
200
|
+
capturedTrail->set(*selfName, Value{closure});
|
|
158
201
|
}
|
|
159
|
-
stack.push_back(Value{std::
|
|
202
|
+
stack.push_back(Value{std::move(closure)});
|
|
160
203
|
++pc;
|
|
161
204
|
break;
|
|
162
205
|
}
|
|
@@ -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.1}/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,84 @@ 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, SelfReferentialRecursiveClosureNowResolvesAsUpvalueAndRunsCompiled) {
|
|
612
|
+
ScopedVm vm(true);
|
|
613
|
+
// reduce()'s own idiom: `a` calls itself by name. A direct
|
|
614
|
+
// `let(a = function(...) ... a(...) ...)` RHS gets `a`'s own slot
|
|
615
|
+
// pre-declared BEFORE compiling that RHS (bytecode_compiler.cpp's
|
|
616
|
+
// LetOp case), letrec-style -- so this self-reference now resolves as
|
|
617
|
+
// a genuine upvalue (Op::LoadUpvalue) instead of falling through to
|
|
618
|
+
// Op::LoadFree, and `a`'s own body is eligible for registration
|
|
619
|
+
// (containsLoadFree no longer sees any unresolved reference in it).
|
|
620
|
+
// Op::MakeClosure's own runtime handler defers this ONE capture
|
|
621
|
+
// (the closure being built doesn't exist yet when its own captures
|
|
622
|
+
// are normally snapshotted) and patches it in immediately after
|
|
623
|
+
// constructing the real closure -- see its own doc comment,
|
|
624
|
+
// bytecode_vm.cpp. This is also what fixed a real O(n) -> O(n^2)
|
|
625
|
+
// regression found while building this feature: every recursive call
|
|
626
|
+
// used to re-derive a FRESH closure via Evaluator::evalIdentifier's
|
|
627
|
+
// ctx.scope->lookupVariable() fallback, nesting its own capturedLet
|
|
628
|
+
// one level deeper than the last -- confirmed via the CLI against a
|
|
629
|
+
// 32,000-element list (7+ seconds -> 0.05s once `a` genuinely
|
|
630
|
+
// resolves itself as an upvalue instead).
|
|
631
|
+
//
|
|
632
|
+
// 11 stops, not 30 (confirmed by diffing against the previous,
|
|
633
|
+
// containsLoadFree-excluded behavior with the same script): `reduce`'s
|
|
634
|
+
// own body-entry (1) + `a`'s own 5 recursive calls (1 each, compiled)
|
|
635
|
+
// + `func`'s own 4 calls (1 each, already compiled even before this --
|
|
636
|
+
// zero captures) + the top-level echo() statement's own stop (module
|
|
637
|
+
// code is never compiled).
|
|
638
|
+
const int stops = countDebugHookStops(
|
|
639
|
+
"function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) i<l? "
|
|
640
|
+
"a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
641
|
+
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));",
|
|
642
|
+
std::unordered_map<std::string, std::set<int>>{});
|
|
643
|
+
EXPECT_EQ(stops, 11);
|
|
644
|
+
EXPECT_EQ(runCapturingEcho("function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) "
|
|
645
|
+
"i<l? a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
646
|
+
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));"),
|
|
647
|
+
"ECHO: 10");
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
TEST(BytecodeCompiler, PlainLetSelfReferenceStillSeesTheOuterBindingNotItself) {
|
|
651
|
+
ScopedVm vm(true);
|
|
652
|
+
// The letrec pre-declare above is gated on the RHS being a DIRECT
|
|
653
|
+
// FunctionLiteral specifically because a non-function `let(x = x + 1)`
|
|
654
|
+
// must keep seeing the OUTER x (real OpenSCAD/letOp shadowing
|
|
655
|
+
// semantics -- each assignment's RHS sees only what preceded it in the
|
|
656
|
+
// same let, never itself), not a fresh, not-yet-assigned local
|
|
657
|
+
// shadowing it. Confirms that ordinary case is untouched by the
|
|
658
|
+
// FunctionLiteral-only pre-declare.
|
|
659
|
+
EXPECT_EQ(runCapturingEcho("x = 100;\nfunction f() = let(x = x + 1) x;\necho(f());"), "ECHO: 101");
|
|
660
|
+
}
|
|
661
|
+
|
|
576
662
|
TEST(BytecodeCompiler, ClosureWithDollarParameterStillBailsContainer) {
|
|
577
663
|
ScopedVm vm(true);
|
|
578
664
|
// 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.1}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/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.1}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.7.0 → openscad_cpp_evaluator-0.8.1}/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
|