openscad-cpp-evaluator 0.8.1__tar.gz → 0.9.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.8.1 → openscad_cpp_evaluator-0.9.1}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/bytecode.hpp +21 -4
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/bytecode_compiler.cpp +157 -48
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/bytecode_vm.cpp +23 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_bytecode_compiler.cpp +76 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/README.md +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tools/cli/main.cpp +0 -0
|
@@ -131,16 +131,33 @@ enum class Op {
|
|
|
131
131
|
// chunk actually running Op::MakeClosure), and constructs
|
|
132
132
|
// Closure{node, capturedTrail} -- reusing Closure::capturedLet (value.hpp)
|
|
133
133
|
// and callCtxFor's existing capturedLet-rooting (user_calls.cpp)
|
|
134
|
-
// UNCHANGED: invoking this closure later
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
134
|
+
// UNCHANGED: invoking this closure later works through the exact same
|
|
135
|
+
// machinery any interpreter-created escaping closure always has, no new
|
|
136
|
+
// invocation-side code needed at all (its own body may itself run
|
|
137
|
+
// compiled too now, see Evaluator::lookupCompiledLiteralChunk). Replaces
|
|
138
138
|
// Op::PushConst's frozen `Closure{&n, nullptr}` specifically for a
|
|
139
139
|
// literal whose (transitively merged) capture set is non-empty; a
|
|
140
140
|
// literal that closes over nothing at all -- even transitively -- still
|
|
141
141
|
// takes the cheaper PushConst path, unchanged.
|
|
142
142
|
MakeClosure,
|
|
143
143
|
|
|
144
|
+
// Letrec support for TWO OR MORE sibling `let`-bound closures that
|
|
145
|
+
// reference each other by name (fnliterals.scad-style mutual
|
|
146
|
+
// recursion, e.g. isEven/isOdd each calling the other) -- see the
|
|
147
|
+
// LetOp compile case's own doc comment (bytecode_compiler.cpp) for why
|
|
148
|
+
// a forward reference (an EARLIER closure referencing a LATER sibling
|
|
149
|
+
// that doesn't exist yet at the point the earlier one is constructed)
|
|
150
|
+
// can't be resolved by Op::MakeClosure itself the way a self-reference
|
|
151
|
+
// is: there's nothing to read OR self-patch into, since the later
|
|
152
|
+
// sibling hasn't even been created yet. a = consumer's own local slot
|
|
153
|
+
// (already holds a MakeClosure-created closure, via a preceding
|
|
154
|
+
// Op::StoreLocal), b = name pool index (the captured name, inside the
|
|
155
|
+
// consumer's own capturedTrail, that's finally ready), c = the local
|
|
156
|
+
// slot the just-constructed sibling was JUST stored into (also via a
|
|
157
|
+
// preceding Op::StoreLocal) -- patches slots[a]'s own capturedTrail
|
|
158
|
+
// with slots[c], keyed by name b.
|
|
159
|
+
PatchClosureCapture,
|
|
160
|
+
|
|
144
161
|
// A call whose callee isn't statically resolvable to a builtin or a
|
|
145
162
|
// named FunctionDeclaration (see CallFn) -- the callee expression is
|
|
146
163
|
// compiled to push its own Value first, THEN each argument (so at
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
#include <functional>
|
|
12
12
|
#include <unordered_map>
|
|
13
|
+
#include <unordered_set>
|
|
13
14
|
|
|
14
15
|
namespace oscadeval {
|
|
15
16
|
|
|
@@ -68,27 +69,31 @@ void bubbleEscapingCaptures(const CompiledChunk::ClosureSite& site, const oscad:
|
|
|
68
69
|
// True if any instruction in `chunk`'s own body/defaults is Op::LoadFree --
|
|
69
70
|
// i.e. an identifier that resolved to neither a local, a statically-known
|
|
70
71
|
// enclosing upvalue, nor a dyn ($-prefixed) name at compile time (see
|
|
71
|
-
// compileExpr's own Identifier case).
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// capturedLet
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
72
|
+
// compileExpr's own Identifier case). A `let(a = function(...) ...
|
|
73
|
+
// a(...) ...)` self-reference, mutual recursion between two-or-more
|
|
74
|
+
// sibling `let`-bound closures (fnliterals.scad-style isEven/isOdd, each
|
|
75
|
+
// calling the other), and either of those wrapped in a ternary (`let(a =
|
|
76
|
+
// cond ? function(...) ...a(...)... : function(...) ...)`, every reachable
|
|
77
|
+
// branch unambiguously a closure) no longer hit this -- see the LetOp
|
|
78
|
+
// case's own letrec pre-declare, below, and collectLetrecCandidateLiterals'
|
|
79
|
+
// own doc comment for exactly which RHS shapes qualify. Anything the
|
|
80
|
+
// pre-declare doesn't cover still does: a reference buried in something
|
|
81
|
+
// other than a direct-or-ternary closure RHS (`let(a = some_call() ?
|
|
82
|
+
// function(...) ...a(...)... : function(...) ...)`, a non-ternary
|
|
83
|
+
// conditional shape, etc.), or any other free variable this phase simply
|
|
84
|
+
// can't resolve statically. For any of those, Evaluator::evalIdentifier's
|
|
85
|
+
// own ctx.scope->lookupVariable() fallback re-evaluates the let-binding's
|
|
86
|
+
// RHS FRESH on every single call, producing a new Closure whose
|
|
87
|
+
// capturedLet is THIS invocation's own ctx.let_ (see expr_eval.cpp's
|
|
88
|
+
// FunctionLiteral case) rather than a stable snapshot -- registering such
|
|
89
|
+
// a chunk for compiled invocation would still be functionally correct,
|
|
90
|
+
// but each recursive call's own capturedLet->openChild() then nests ONE
|
|
91
|
+
// level deeper than the last (confirmed empirically: an O(n) list
|
|
92
|
+
// reduce() degrading to O(n^2) once compiled, before the letrec pre-
|
|
93
|
+
// declare existed), since nothing about that repeated fresh-derivation
|
|
94
|
+
// ever re-roots the trail. Excluding a LoadFree-containing chunk from
|
|
95
|
+
// registration leaves it running interpreted exactly as before --
|
|
96
|
+
// correct, if not optimized.
|
|
92
97
|
bool containsLoadFree(const std::vector<Instruction>& code) {
|
|
93
98
|
for (const Instruction& ins : code) {
|
|
94
99
|
if (ins.op == Op::LoadFree) return true;
|
|
@@ -104,6 +109,38 @@ bool containsLoadFree(const CompiledChunk& chunk) {
|
|
|
104
109
|
return false;
|
|
105
110
|
}
|
|
106
111
|
|
|
112
|
+
// Recursively collects every FunctionLiteral `expr` could actually
|
|
113
|
+
// evaluate to at runtime -- a bare literal, or a ternary (or nested
|
|
114
|
+
// ternaries) whose branches ALL recursively qualify, e.g. `cond ?
|
|
115
|
+
// function(...) ...a(...)... : function(...) ...` (the ternary-wrapped
|
|
116
|
+
// self/mutual-reference case the direct-RHS-only letrec pre-declare,
|
|
117
|
+
// below, doesn't reach on its own). Returns std::nullopt -- not just an
|
|
118
|
+
// empty vector -- the moment ANY reachable branch ISN'T reliably a
|
|
119
|
+
// closure (a plain value, a call, anything else): letrec pre-declaration
|
|
120
|
+
// only makes sense when EVERY runtime path through `expr` really does
|
|
121
|
+
// produce a fresh closure that might reference the let-binding's own
|
|
122
|
+
// name, never a mix. A CommentedExpr wrapper is transparent, matching
|
|
123
|
+
// compileExpr's own handling of it everywhere else.
|
|
124
|
+
std::optional<std::vector<const oscad::FunctionLiteral*>> collectLetrecCandidateLiterals(const oscad::ASTNode& expr) {
|
|
125
|
+
using oscad::NodeKind;
|
|
126
|
+
if (expr.kind() == NodeKind::CommentedExpr) {
|
|
127
|
+
return collectLetrecCandidateLiterals(*static_cast<const oscad::CommentedExpr&>(expr).expr);
|
|
128
|
+
}
|
|
129
|
+
if (expr.kind() == NodeKind::FunctionLiteral) {
|
|
130
|
+
return std::vector<const oscad::FunctionLiteral*>{static_cast<const oscad::FunctionLiteral*>(&expr)};
|
|
131
|
+
}
|
|
132
|
+
if (expr.kind() == NodeKind::TernaryOp) {
|
|
133
|
+
auto& t = static_cast<const oscad::TernaryOp&>(expr);
|
|
134
|
+
auto trueLits = collectLetrecCandidateLiterals(*t.trueExpr);
|
|
135
|
+
if (!trueLits) return std::nullopt;
|
|
136
|
+
auto falseLits = collectLetrecCandidateLiterals(*t.falseExpr);
|
|
137
|
+
if (!falseLits) return std::nullopt;
|
|
138
|
+
trueLits->insert(trueLits->end(), falseLits->begin(), falseLits->end());
|
|
139
|
+
return trueLits;
|
|
140
|
+
}
|
|
141
|
+
return std::nullopt;
|
|
142
|
+
}
|
|
143
|
+
|
|
107
144
|
// Compile-time name -> slot resolution, mirroring the LetOp/nested-scope
|
|
108
145
|
// shadowing rules callCtx()/letChildCtx() apply at runtime: one frame per
|
|
109
146
|
// LetOp (pushed/popped around its own assignments+body), innermost frame
|
|
@@ -566,35 +603,96 @@ public:
|
|
|
566
603
|
size_t placeholderIdx = out.size();
|
|
567
604
|
out.push_back({Op::OpenLocalScope, 0, 0, nullptr});
|
|
568
605
|
int slotStart = nextSlot_;
|
|
569
|
-
|
|
606
|
+
// Letrec pre-pass: every assignment whose RHS is GUARANTEED
|
|
607
|
+
// to evaluate to a closure -- a direct `name =
|
|
608
|
+
// function(...) ...`, or `name = cond ? function(...) ... :
|
|
609
|
+
// function(...) ...` (or nested ternaries of the same
|
|
610
|
+
// shape) -- gets its own slot declared up front, before ANY
|
|
611
|
+
// of them are compiled -- not just so a closure can
|
|
612
|
+
// reference itself (see the self-reference handling
|
|
613
|
+
// below), but so an EARLIER one can also reference a LATER
|
|
614
|
+
// sibling (mutual recursion, e.g. fnliterals.scad-style
|
|
615
|
+
// isEven/isOdd calling each other). `letrecSlot[i]` stays
|
|
616
|
+
// -1 for anything else, which keeps the existing after-the-
|
|
617
|
+
// fact declareLocal path below completely unchanged
|
|
618
|
+
// (`let(x = x + 1)` must still see the OUTER x, not a
|
|
619
|
+
// fresh, not-yet-assigned local shadowing it -- only an
|
|
620
|
+
// RHS that's UNAMBIGUOUSLY always a closure has "see
|
|
621
|
+
// myself/a sibling" as a sensible reading at all; see
|
|
622
|
+
// collectLetrecCandidateLiterals' own doc comment, above,
|
|
623
|
+
// for why a mixed/uncertain RHS shape doesn't qualify).
|
|
624
|
+
// `letrecCandidates[i]` is every FunctionLiteral node `i`'s
|
|
625
|
+
// own RHS could actually construct at runtime -- more than
|
|
626
|
+
// one for a ternary -- each independently checked for a
|
|
627
|
+
// self/sibling reference below, since either one might be
|
|
628
|
+
// the value `name` ends up holding.
|
|
629
|
+
std::vector<int> letrecSlot(n.assignments.size(), -1);
|
|
630
|
+
std::vector<std::vector<const oscad::FunctionLiteral*>> letrecCandidates(n.assignments.size());
|
|
631
|
+
std::unordered_set<int> pendingLetrecSlots;
|
|
632
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
633
|
+
const auto& assign = n.assignments[i];
|
|
634
|
+
const std::string& name = assign->name->name;
|
|
635
|
+
if (name.empty() || name[0] == '$') continue;
|
|
636
|
+
if (auto candidates = collectLetrecCandidateLiterals(*assign->expr)) {
|
|
637
|
+
letrecSlot[i] = declareLocal(scope, name);
|
|
638
|
+
letrecCandidates[i] = std::move(*candidates);
|
|
639
|
+
pendingLetrecSlots.insert(letrecSlot[i]);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
// consumerSlot/name pairs an EARLIER closure's own
|
|
643
|
+
// Op::MakeClosure left unresolved because they targeted a
|
|
644
|
+
// sibling that didn't exist yet at that point -- resolved
|
|
645
|
+
// (an Op::PatchClosureCapture emitted) the moment that
|
|
646
|
+
// sibling's own StoreLocal runs, below.
|
|
647
|
+
std::unordered_map<int, std::vector<std::pair<int, std::string>>> pendingWaiters;
|
|
648
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
649
|
+
const auto& assign = n.assignments[i];
|
|
570
650
|
const std::string& name = assign->name->name;
|
|
571
|
-
|
|
572
|
-
|
|
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);
|
|
651
|
+
const int preDeclaredSlot = letrecSlot[i];
|
|
652
|
+
const bool selfBinding = preDeclaredSlot >= 0;
|
|
593
653
|
compileExpr(*assign->expr, out, scope); // RHS is never tail
|
|
594
|
-
|
|
595
|
-
CompiledChunk::ClosureSite
|
|
596
|
-
for (auto&
|
|
597
|
-
if (
|
|
654
|
+
for (const oscad::FunctionLiteral* candidate : letrecCandidates[i]) {
|
|
655
|
+
CompiledChunk::ClosureSite* site = nullptr;
|
|
656
|
+
for (auto& s : chunk_.closureSites) {
|
|
657
|
+
if (s.node == candidate) {
|
|
658
|
+
site = &s;
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// No entry at all means this particular candidate
|
|
663
|
+
// (e.g. one branch of a ternary) never referenced
|
|
664
|
+
// itself/a sibling/anything else -- zero captures,
|
|
665
|
+
// still the cheaper Op::PushConst path, nothing
|
|
666
|
+
// here to patch.
|
|
667
|
+
if (!site) continue;
|
|
668
|
+
auto& captures = site->captures;
|
|
669
|
+
for (auto it = captures.begin(); it != captures.end();) {
|
|
670
|
+
if (it->targetDecl != selfDecl_ || !pendingLetrecSlots.count(it->slot)) {
|
|
671
|
+
++it;
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (it->slot == preDeclaredSlot) {
|
|
675
|
+
// See Op::MakeClosure's own runtime handler
|
|
676
|
+
// (bytecode_vm.cpp): the closure being
|
|
677
|
+
// created doesn't exist yet at the moment
|
|
678
|
+
// its own captures are normally snapshotted,
|
|
679
|
+
// so this one is deferred and patched in
|
|
680
|
+
// right after construction instead of read
|
|
681
|
+
// eagerly like every other capture.
|
|
682
|
+
it->isSelfReference = true;
|
|
683
|
+
++it;
|
|
684
|
+
} else {
|
|
685
|
+
// Forward reference to a sibling that hasn't
|
|
686
|
+
// been constructed AT ALL yet -- unlike the
|
|
687
|
+
// self-reference case above, there's nothing
|
|
688
|
+
// to read OR self-patch into here. Left out
|
|
689
|
+
// of `captures` entirely (nothing for
|
|
690
|
+
// Op::MakeClosure to even attempt) and
|
|
691
|
+
// deferred to a real Op::PatchClosureCapture
|
|
692
|
+
// once that sibling's own StoreLocal runs.
|
|
693
|
+
pendingWaiters[it->slot].emplace_back(preDeclaredSlot, it->name);
|
|
694
|
+
it = captures.erase(it);
|
|
695
|
+
}
|
|
598
696
|
}
|
|
599
697
|
}
|
|
600
698
|
if (!name.empty() && name[0] == '$') {
|
|
@@ -602,6 +700,17 @@ public:
|
|
|
602
700
|
} else {
|
|
603
701
|
int slot = selfBinding ? preDeclaredSlot : declareLocal(scope, name);
|
|
604
702
|
out.push_back({Op::StoreLocal, slot, 0, &assign->position()});
|
|
703
|
+
if (selfBinding) {
|
|
704
|
+
pendingLetrecSlots.erase(slot);
|
|
705
|
+
auto waitersIt = pendingWaiters.find(slot);
|
|
706
|
+
if (waitersIt != pendingWaiters.end()) {
|
|
707
|
+
for (const auto& [consumerSlot, capName] : waitersIt->second) {
|
|
708
|
+
out.push_back({Op::PatchClosureCapture, consumerSlot, internName(capName),
|
|
709
|
+
&assign->position(), nullptr, slot});
|
|
710
|
+
}
|
|
711
|
+
pendingWaiters.erase(waitersIt);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
605
714
|
}
|
|
606
715
|
}
|
|
607
716
|
out[placeholderIdx].a = slotStart;
|
|
@@ -203,6 +203,29 @@ Value runChunk(Evaluator& ev, const CompiledChunk& chunk, const std::vector<Inst
|
|
|
203
203
|
++pc;
|
|
204
204
|
break;
|
|
205
205
|
}
|
|
206
|
+
case Op::PatchClosureCapture: {
|
|
207
|
+
// Mutual-recursion support (see the LetOp compile case's
|
|
208
|
+
// own doc comment, bytecode_compiler.cpp): `slots[ins.a]`
|
|
209
|
+
// (the consumer, e.g. isEven) already holds a real
|
|
210
|
+
// MakeClosure-created closure whose own capturedTrail is
|
|
211
|
+
// missing this ONE entry -- it was left out entirely at
|
|
212
|
+
// compile time because the sibling it names (e.g. isOdd)
|
|
213
|
+
// hadn't been constructed yet. `slots[ins.c]` (that
|
|
214
|
+
// sibling's own slot) does now, since this instruction only
|
|
215
|
+
// ever runs immediately after that sibling's own
|
|
216
|
+
// Op::StoreLocal. Mutates the SAME shared TrailView the
|
|
217
|
+
// consumer's own capturedLet already points at -- visible
|
|
218
|
+
// to it exactly like every other capture, no different
|
|
219
|
+
// from Op::MakeClosure's own self-reference patch, above.
|
|
220
|
+
const Value& consumerVal = slots[static_cast<size_t>(ins.a)];
|
|
221
|
+
if (const auto* closurePtr = std::get_if<ClosurePtr>(&consumerVal); closurePtr && *closurePtr) {
|
|
222
|
+
if (auto trail = capturedLetTrail(**closurePtr)) {
|
|
223
|
+
trail->set(chunk.names[static_cast<size_t>(ins.b)], slots[static_cast<size_t>(ins.c)]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
++pc;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
206
229
|
case Op::Range: {
|
|
207
230
|
Value step = std::move(stack.back());
|
|
208
231
|
stack.pop_back();
|
{openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/tests/test_bytecode_compiler.cpp
RENAMED
|
@@ -659,6 +659,82 @@ TEST(BytecodeCompiler, PlainLetSelfReferenceStillSeesTheOuterBindingNotItself) {
|
|
|
659
659
|
EXPECT_EQ(runCapturingEcho("x = 100;\nfunction f() = let(x = x + 1) x;\necho(f());"), "ECHO: 101");
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
+
TEST(BytecodeCompiler, MutualRecursionBetweenSiblingLetBoundClosuresResolvesCorrectly) {
|
|
663
|
+
ScopedVm vm(true);
|
|
664
|
+
// fnliterals.scad-style isEven()/isOdd(): TWO sibling closures in the
|
|
665
|
+
// SAME let(), each calling the OTHER by name. `isEven` (compiled
|
|
666
|
+
// FIRST) references `isOdd`, which doesn't exist at all yet at that
|
|
667
|
+
// point -- unlike a self-reference, there's nothing to read OR self-
|
|
668
|
+
// patch into (see Op::PatchClosureCapture's own doc comment,
|
|
669
|
+
// bytecode.hpp): resolved instead by a real patch instruction emitted
|
|
670
|
+
// right after `isOdd`'s own StoreLocal, once it actually exists.
|
|
671
|
+
// 3 stops, not one per logical call (isEvenTest's own entry, plus one
|
|
672
|
+
// per level of isEven(6)->isOdd(5)->isEven(4)->...->isEven(0)):
|
|
673
|
+
// isEven<->isOdd calling each other in tail position is exactly what
|
|
674
|
+
// the tail-call trampoline collapses into ONE evalUserFunctionCore
|
|
675
|
+
// invocation for the WHOLE chain (see runCompiledFunctionTrampoline,
|
|
676
|
+
// bytecode_vm.cpp) -- its own unconditional body-entry checkDebug()
|
|
677
|
+
// fires once for that entire loop, not once per hop. isEvenTest's own
|
|
678
|
+
// entry (1) + that one trampoline loop (1) + the top-level echo()
|
|
679
|
+
// statement's own stop (module code is never compiled) = 3.
|
|
680
|
+
const int stops = countDebugHookStops(
|
|
681
|
+
"function isEvenTest(n) = let(isEven = function(k) k==0 ? true : isOdd(k-1), isOdd = function(k) "
|
|
682
|
+
"k==0 ? false : isEven(k-1)) isEven(n);\n"
|
|
683
|
+
"echo(isEvenTest(6));",
|
|
684
|
+
std::unordered_map<std::string, std::set<int>>{});
|
|
685
|
+
EXPECT_EQ(stops, 3);
|
|
686
|
+
EXPECT_EQ(runCapturingEcho("function isEvenTest(n) = let(isEven = function(k) k==0 ? true : isOdd(k-1), "
|
|
687
|
+
"isOdd = function(k) k==0 ? false : isEven(k-1)) isEven(n);\n"
|
|
688
|
+
"echo(isEvenTest(6));\necho(isEvenTest(7));"),
|
|
689
|
+
"ECHO: true\nECHO: false");
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
TEST(BytecodeCompiler, ThreeWaySiblingMutualRecursionResolvesCorrectly) {
|
|
693
|
+
ScopedVm vm(true);
|
|
694
|
+
// The patch mechanism isn't hardcoded to pairs -- a THIRD sibling
|
|
695
|
+
// (f3, itself forward-referencing f1, the FIRST one compiled) proves
|
|
696
|
+
// pendingWaiters/Op::PatchClosureCapture generalizes to an arbitrary
|
|
697
|
+
// cycle length, not just mutual (2-closure) recursion specifically.
|
|
698
|
+
EXPECT_EQ(runCapturingEcho("function test(n) = let(f1 = function(k) k==0 ? \"f1\" : f2(k-1), f2 = "
|
|
699
|
+
"function(k) k==0 ? \"f2\" : f3(k-1), f3 = function(k) k==0 ? \"f3\" : "
|
|
700
|
+
"f1(k-1)) f1(n);\n"
|
|
701
|
+
"echo(test(9));\necho(test(10));\necho(test(11));"),
|
|
702
|
+
"ECHO: \"f1\"\nECHO: \"f2\"\nECHO: \"f3\"");
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
TEST(BytecodeCompiler, TernaryWrappedSelfReferenceResolvesAsUpvalue) {
|
|
706
|
+
ScopedVm vm(true);
|
|
707
|
+
// The letrec pre-declare's own eligibility check isn't limited to a
|
|
708
|
+
// bare `name = function(...) ...` RHS -- `cond ? function(...) ... :
|
|
709
|
+
// function(...) ...` (EVERY reachable branch is unambiguously a
|
|
710
|
+
// closure, see collectLetrecCandidateLiterals' own doc comment,
|
|
711
|
+
// bytecode_compiler.cpp) also pre-declares, and BOTH branches'
|
|
712
|
+
// FunctionLiteral nodes are independently found and marked afterward
|
|
713
|
+
// (a ternary can produce two structurally distinct closures, not just
|
|
714
|
+
// one). Deep, genuinely TAIL-recursive (`acc` accumulates on the way
|
|
715
|
+
// down, not after the recursive call returns -- see this file's own
|
|
716
|
+
// DeepSelfTailRecursionUnderVmDoesNotOverflowTheNativeStack, above, for
|
|
717
|
+
// why that distinction matters at this depth) to prove it actually
|
|
718
|
+
// runs compiled, not just correctly-but-slowly interpreted.
|
|
719
|
+
const std::string script =
|
|
720
|
+
"function make(n) = let(a = n > 0 ? function(k, acc) k<=0 ? acc : a(k-1, acc+n) : function(k, acc) acc) "
|
|
721
|
+
"a(200000, 0);\necho(make(1));";
|
|
722
|
+
EXPECT_EQ(runCapturingEcho(script), "ECHO: 200000");
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
TEST(BytecodeCompiler, TernaryWrappedMutualRecursionResolvesCorrectly) {
|
|
726
|
+
ScopedVm vm(true);
|
|
727
|
+
// Same ternary-wrapped-RHS eligibility as the self-reference case
|
|
728
|
+
// above, but for TWO siblings that reference each other -- both
|
|
729
|
+
// Op::PatchClosureCapture's forward-reference deferral and the
|
|
730
|
+
// ternary's own multi-candidate handling apply simultaneously.
|
|
731
|
+
const std::string script =
|
|
732
|
+
"function test(n) = let(isEven = n >= 0 ? function(k) k==0 ? true : isOdd(k-1) : function(k) undef, "
|
|
733
|
+
"isOdd = n >= 0 ? function(k) k==0 ? false : isEven(k-1) : function(k) undef) isEven(n);\n"
|
|
734
|
+
"echo(test(10));\necho(test(7));";
|
|
735
|
+
EXPECT_EQ(runCapturingEcho(script), "ECHO: true\nECHO: false");
|
|
736
|
+
}
|
|
737
|
+
|
|
662
738
|
TEST(BytecodeCompiler, ClosureWithDollarParameterStillBailsContainer) {
|
|
663
739
|
ScopedVm vm(true);
|
|
664
740
|
// 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.8.1 → openscad_cpp_evaluator-0.9.1}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.1}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.8.1 → openscad_cpp_evaluator-0.9.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
|
|
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
|