openscad-cpp-evaluator 0.8.0__tar.gz → 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/bytecode.hpp +32 -4
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/bytecode_compiler.cpp +108 -26
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/bytecode_vm.cpp +41 -1
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_bytecode_compiler.cpp +83 -16
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/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
|
|
@@ -266,6 +283,17 @@ struct CompiledChunk {
|
|
|
266
283
|
const oscad::ASTNode* targetDecl = nullptr;
|
|
267
284
|
int slot = 0;
|
|
268
285
|
std::string name;
|
|
286
|
+
// Set only when this entry is a `let(name = function(...) ...)`
|
|
287
|
+
// closure's own reference to ITSELF (bytecode_compiler.cpp's LetOp
|
|
288
|
+
// case, the letrec-style pre-declared-slot path) -- Op::MakeClosure
|
|
289
|
+
// can't read this one out of `slots` the way it does every other
|
|
290
|
+
// capture: at the moment it runs, the closure it's building hasn't
|
|
291
|
+
// been constructed yet (StoreLocal for `name` hasn't executed), so
|
|
292
|
+
// `slots[slot]` would still hold whatever was there before this
|
|
293
|
+
// call. See Op::MakeClosure's own runtime doc comment
|
|
294
|
+
// (bytecode_vm.cpp) for how this is actually resolved (deferred,
|
|
295
|
+
// then patched in after construction).
|
|
296
|
+
bool isSelfReference = false;
|
|
269
297
|
};
|
|
270
298
|
|
|
271
299
|
// One FunctionLiteral's own capture list for Op::MakeClosure, computed
|
|
@@ -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,25 +69,27 @@ 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). A
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// (
|
|
88
|
-
//
|
|
89
|
-
//
|
|
72
|
+
// compileExpr's own Identifier case). A DIRECT `let(a = function(...)
|
|
73
|
+
// ... a(...) ...)` self-reference (reduce()/accumulate()/while()'s own
|
|
74
|
+
// idiom) and mutual recursion between two-or-more sibling DIRECT
|
|
75
|
+
// `let`-bound closures (fnliterals.scad-style isEven/isOdd, each calling
|
|
76
|
+
// the other) no longer hit this -- see the LetOp case's own letrec
|
|
77
|
+
// pre-declare, below -- but anything the pre-declare doesn't cover still
|
|
78
|
+
// does: `a` wrapped in a ternary/let/anything other than a bare
|
|
79
|
+
// FunctionLiteral RHS (`let(a = cond ? function(...) ...a(...)... :
|
|
80
|
+
// function(...) ...)`), or any other free variable this phase simply can't
|
|
81
|
+
// resolve statically. For any of those, Evaluator::evalIdentifier's own
|
|
82
|
+
// ctx.scope->lookupVariable() fallback re-evaluates the let-binding's RHS
|
|
83
|
+
// FRESH on every single call, producing a new Closure whose capturedLet is
|
|
84
|
+
// THIS invocation's own ctx.let_ (see expr_eval.cpp's FunctionLiteral case)
|
|
85
|
+
// rather than a stable snapshot -- registering such a chunk for compiled
|
|
86
|
+
// invocation would still be functionally correct, but each recursive
|
|
87
|
+
// call's own capturedLet->openChild() then nests ONE level deeper than the
|
|
88
|
+
// last (confirmed empirically: an O(n) list reduce() degrading to O(n^2)
|
|
89
|
+
// once compiled, before the letrec pre-declare existed), since nothing
|
|
90
|
+
// about that repeated fresh-derivation ever re-roots the trail. Excluding
|
|
91
|
+
// a LoadFree-containing chunk from registration leaves it running
|
|
92
|
+
// interpreted exactly as before -- correct, if not optimized.
|
|
90
93
|
bool containsLoadFree(const std::vector<Instruction>& code) {
|
|
91
94
|
for (const Instruction& ins : code) {
|
|
92
95
|
if (ins.op == Op::LoadFree) return true;
|
|
@@ -350,10 +353,14 @@ public:
|
|
|
350
353
|
// below), and for a captures-having one only when its own
|
|
351
354
|
// body contains no Op::LoadFree -- see containsLoadFree's
|
|
352
355
|
// own doc comment, above, for why a LoadFree-containing
|
|
353
|
-
// captures-having closure
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
//
|
|
356
|
+
// captures-having closure must still be left interpreted:
|
|
357
|
+
// its own capturedLet-chaining, once registered, degrades
|
|
358
|
+
// an O(n) reduction into O(n^2). (The reduce()/
|
|
359
|
+
// accumulate()/while() idiom itself -- a closure directly
|
|
360
|
+
// assigned via `let` that calls itself by name -- no longer
|
|
361
|
+
// hits this: see the LetOp case's own letrec pre-declare,
|
|
362
|
+
// below, which lets that specific self-reference resolve as
|
|
363
|
+
// a real upvalue instead of falling through to LoadFree.)
|
|
357
364
|
// Everything else (Op::LoadUpvalue/Op::MakeClosure inside a
|
|
358
365
|
// REGISTERED captures-having chunk) is no longer assumed to
|
|
359
366
|
// resolve only against a still-live creator frame (see
|
|
@@ -560,14 +567,89 @@ public:
|
|
|
560
567
|
size_t placeholderIdx = out.size();
|
|
561
568
|
out.push_back({Op::OpenLocalScope, 0, 0, nullptr});
|
|
562
569
|
int slotStart = nextSlot_;
|
|
563
|
-
|
|
564
|
-
|
|
570
|
+
// Letrec pre-pass: every DIRECT `name = function(...) ...`
|
|
571
|
+
// assignment in this LetOp gets its own slot declared up
|
|
572
|
+
// front, before ANY of them are compiled -- not just so a
|
|
573
|
+
// closure can reference itself (see the self-reference
|
|
574
|
+
// handling below), but so an EARLIER one can also reference
|
|
575
|
+
// a LATER sibling (mutual recursion, e.g. fnliterals.scad-
|
|
576
|
+
// style isEven/isOdd calling each other). `letrecSlot[i]`
|
|
577
|
+
// stays -1 for anything else, which keeps the existing
|
|
578
|
+
// after-the-fact declareLocal path below completely
|
|
579
|
+
// unchanged (`let(x = x + 1)` must still see the OUTER x,
|
|
580
|
+
// not a fresh, not-yet-assigned local shadowing it -- only
|
|
581
|
+
// a function-literal RHS has "see myself/a sibling" as a
|
|
582
|
+
// sensible reading at all).
|
|
583
|
+
std::vector<int> letrecSlot(n.assignments.size(), -1);
|
|
584
|
+
std::unordered_set<int> pendingLetrecSlots;
|
|
585
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
586
|
+
const auto& assign = n.assignments[i];
|
|
587
|
+
const std::string& name = assign->name->name;
|
|
588
|
+
if (!name.empty() && name[0] != '$' && assign->expr->kind() == oscad::NodeKind::FunctionLiteral) {
|
|
589
|
+
letrecSlot[i] = declareLocal(scope, name);
|
|
590
|
+
pendingLetrecSlots.insert(letrecSlot[i]);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// consumerSlot/name pairs an EARLIER closure's own
|
|
594
|
+
// Op::MakeClosure left unresolved because they targeted a
|
|
595
|
+
// sibling that didn't exist yet at that point -- resolved
|
|
596
|
+
// (an Op::PatchClosureCapture emitted) the moment that
|
|
597
|
+
// sibling's own StoreLocal runs, below.
|
|
598
|
+
std::unordered_map<int, std::vector<std::pair<int, std::string>>> pendingWaiters;
|
|
599
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
600
|
+
const auto& assign = n.assignments[i];
|
|
565
601
|
const std::string& name = assign->name->name;
|
|
602
|
+
const int preDeclaredSlot = letrecSlot[i];
|
|
603
|
+
const bool selfBinding = preDeclaredSlot >= 0;
|
|
604
|
+
compileExpr(*assign->expr, out, scope); // RHS is never tail
|
|
605
|
+
if (selfBinding && out.back().op == Op::MakeClosure) {
|
|
606
|
+
CompiledChunk::ClosureSite& site = chunk_.closureSites[static_cast<size_t>(out.back().a)];
|
|
607
|
+
auto& captures = site.captures;
|
|
608
|
+
for (auto it = captures.begin(); it != captures.end();) {
|
|
609
|
+
if (it->targetDecl != selfDecl_ || !pendingLetrecSlots.count(it->slot)) {
|
|
610
|
+
++it;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (it->slot == preDeclaredSlot) {
|
|
614
|
+
// See Op::MakeClosure's own runtime handler
|
|
615
|
+
// (bytecode_vm.cpp): the closure being
|
|
616
|
+
// created doesn't exist yet at the moment
|
|
617
|
+
// its own captures are normally snapshotted,
|
|
618
|
+
// so this one is deferred and patched in
|
|
619
|
+
// right after construction instead of read
|
|
620
|
+
// eagerly like every other capture.
|
|
621
|
+
it->isSelfReference = true;
|
|
622
|
+
++it;
|
|
623
|
+
} else {
|
|
624
|
+
// Forward reference to a sibling that hasn't
|
|
625
|
+
// been constructed AT ALL yet -- unlike the
|
|
626
|
+
// self-reference case above, there's nothing
|
|
627
|
+
// to read OR self-patch into here. Left out
|
|
628
|
+
// of `captures` entirely (nothing for
|
|
629
|
+
// Op::MakeClosure to even attempt) and
|
|
630
|
+
// deferred to a real Op::PatchClosureCapture
|
|
631
|
+
// once that sibling's own StoreLocal runs.
|
|
632
|
+
pendingWaiters[it->slot].emplace_back(preDeclaredSlot, it->name);
|
|
633
|
+
it = captures.erase(it);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
566
637
|
if (!name.empty() && name[0] == '$') {
|
|
567
638
|
out.push_back({Op::StoreDyn, internName(name), 0, &assign->position()});
|
|
568
639
|
} else {
|
|
569
|
-
int slot = declareLocal(scope, name);
|
|
640
|
+
int slot = selfBinding ? preDeclaredSlot : declareLocal(scope, name);
|
|
570
641
|
out.push_back({Op::StoreLocal, slot, 0, &assign->position()});
|
|
642
|
+
if (selfBinding) {
|
|
643
|
+
pendingLetrecSlots.erase(slot);
|
|
644
|
+
auto waitersIt = pendingWaiters.find(slot);
|
|
645
|
+
if (waitersIt != pendingWaiters.end()) {
|
|
646
|
+
for (const auto& [consumerSlot, capName] : waitersIt->second) {
|
|
647
|
+
out.push_back({Op::PatchClosureCapture, consumerSlot, internName(capName),
|
|
648
|
+
&assign->position(), nullptr, slot});
|
|
649
|
+
}
|
|
650
|
+
pendingWaiters.erase(waitersIt);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
571
653
|
}
|
|
572
654
|
}
|
|
573
655
|
out[placeholderIdx].a = slotStart;
|
|
@@ -173,7 +173,20 @@ Value runChunk(Evaluator& ev, const CompiledChunk& chunk, const std::vector<Inst
|
|
|
173
173
|
// created escaping closure already uses, unchanged.
|
|
174
174
|
const CompiledChunk::ClosureSite& site = chunk.closureSites[static_cast<size_t>(ins.a)];
|
|
175
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;
|
|
176
185
|
for (const auto& cap : site.captures) {
|
|
186
|
+
if (cap.isSelfReference) {
|
|
187
|
+
selfNames.push_back(&cap.name);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
177
190
|
if (cap.targetDecl == chunk.selfDecl) {
|
|
178
191
|
capturedTrail->set(cap.name, slots[static_cast<size_t>(cap.slot)]);
|
|
179
192
|
continue;
|
|
@@ -182,7 +195,34 @@ Value runChunk(Evaluator& ev, const CompiledChunk& chunk, const std::vector<Inst
|
|
|
182
195
|
if (!v) v = ctx.let_->find(cap.name);
|
|
183
196
|
capturedTrail->set(cap.name, v ? *v : Value{});
|
|
184
197
|
}
|
|
185
|
-
|
|
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});
|
|
201
|
+
}
|
|
202
|
+
stack.push_back(Value{std::move(closure)});
|
|
203
|
+
++pc;
|
|
204
|
+
break;
|
|
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
|
+
}
|
|
186
226
|
++pc;
|
|
187
227
|
break;
|
|
188
228
|
}
|
{openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/tests/test_bytecode_compiler.cpp
RENAMED
|
@@ -608,33 +608,100 @@ TEST(BytecodeCompiler, MultiLevelCurriedClosureInvocationRunsCompiled) {
|
|
|
608
608
|
"ECHO: 42\nECHO: 20");
|
|
609
609
|
}
|
|
610
610
|
|
|
611
|
-
TEST(BytecodeCompiler,
|
|
612
|
-
ScopedVm vm(true);
|
|
613
|
-
// reduce()'s own idiom: `a` calls itself by name
|
|
614
|
-
//
|
|
615
|
-
//
|
|
616
|
-
//
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
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).
|
|
626
638
|
const int stops = countDebugHookStops(
|
|
627
639
|
"function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) i<l? "
|
|
628
640
|
"a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
629
641
|
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));",
|
|
630
642
|
std::unordered_map<std::string, std::set<int>>{});
|
|
631
|
-
|
|
643
|
+
EXPECT_EQ(stops, 11);
|
|
632
644
|
EXPECT_EQ(runCapturingEcho("function reduce(func, list, init=0) = let(l = len(list), a = function (x,i) "
|
|
633
645
|
"i<l? a(func(x,list[i]), i+1) : x) a(init,0);\n"
|
|
634
646
|
"echo(reduce(function(p,q) p+q, [1,2,3,4], 0));"),
|
|
635
647
|
"ECHO: 10");
|
|
636
648
|
}
|
|
637
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
|
+
|
|
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
|
+
|
|
638
705
|
TEST(BytecodeCompiler, ClosureWithDollarParameterStillBailsContainer) {
|
|
639
706
|
ScopedVm vm(true);
|
|
640
707
|
// 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.0 → openscad_cpp_evaluator-0.9.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.8.0 → openscad_cpp_evaluator-0.9.0}/external/openscad_cpp_parser/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|