openscad-cpp-evaluator 0.9.0__tar.gz → 0.9.2__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.9.0 → openscad_cpp_evaluator-0.9.2}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/evaluator.hpp +41 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/bytecode_compiler.cpp +99 -38
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_bytecode_compiler.cpp +33 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_tail_calls.cpp +61 -4
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/README.md +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tools/cli/main.cpp +0 -0
|
@@ -633,6 +633,47 @@ private:
|
|
|
633
633
|
Value evalUserFunctionCore(const std::string& name, const oscad::ASTNode& declNode, const oscad::Expression& bodyExpr,
|
|
634
634
|
EvalContext& childCtx, const oscad::Position* callPos, int upvalueParent,
|
|
635
635
|
F&& computeResult) {
|
|
636
|
+
// Guards against a genuinely non-tail-recursive user function --
|
|
637
|
+
// each logical call HERE is a real, unavoidable C++ recursive call
|
|
638
|
+
// (a trampolined tail call never re-enters this function at all,
|
|
639
|
+
// see evalFunctionBodyTrampoline/runCompiledFunctionTrampoline) --
|
|
640
|
+
// silently overflowing the native stack: a hard, unrecoverable
|
|
641
|
+
// process crash with no C++ exception to catch. Confirmed present
|
|
642
|
+
// (before this guard existed) for a plain, closure-free `function
|
|
643
|
+
// f(n) = n<=0 ? 0 : 1+f(n-1);`, compiled OR interpreted.
|
|
644
|
+
//
|
|
645
|
+
// kMaxUserCallDepth is a conservative, heuristic cap, NOT a
|
|
646
|
+
// precisely-calibrated one -- and specifically calibrated against
|
|
647
|
+
// the WORST measured platform, not the best. Two rounds of CI
|
|
648
|
+
// diagnostics (temporary test builds that recursed to increasing
|
|
649
|
+
// depths, printing success after each one so the CI log itself
|
|
650
|
+
// would show exactly where a crash happened) found: (1) this
|
|
651
|
+
// evaluator's own C++ recursion is safe into the THOUSANDS on an
|
|
652
|
+
// ordinary macOS/Linux desktop main-thread stack, but only into
|
|
653
|
+
// the low HUNDREDS on CI's windows-latest runner (smaller default
|
|
654
|
+
// thread stack and/or larger MSVC-compiled call frames than
|
|
655
|
+
// Clang's); (2) actually THROWING from that depth and unwinding
|
|
656
|
+
// back out through that many nested try/catch frames (this guard
|
|
657
|
+
// fires from inside evalUserFunctionCore, which every level of
|
|
658
|
+
// the recursion has its own try/catch in) costs meaningfully MORE
|
|
659
|
+
// native stack than simply being that deep without throwing --
|
|
660
|
+
// 300 survived on Windows without throwing, but throwing+
|
|
661
|
+
// unwinding through as few as 100 nested frames did not (80 was
|
|
662
|
+
// the last depth that survived). 50 leaves real margin below that
|
|
663
|
+
// 80 figure for whatever's already on the stack from this call's
|
|
664
|
+
// own caller, and for a smaller stack still (e.g. BelfrySCAD's own
|
|
665
|
+
// debug-session worker thread, plausibly smaller than any CI
|
|
666
|
+
// runner's main thread) that this evaluator has no way to probe
|
|
667
|
+
// for directly. A real OpenSCAD/BOSL2 recursive function is
|
|
668
|
+
// overwhelmingly tail-recursive in practice anyway (exactly why
|
|
669
|
+
// reduce()/accumulate()/while() and this evaluator's own
|
|
670
|
+
// trampolines exist) -- genuine non-tail recursion even
|
|
671
|
+
// approaching this depth is already the rare, likely-runaway case
|
|
672
|
+
// a controlled error serves far better than a crash.
|
|
673
|
+
static constexpr size_t kMaxUserCallDepth = 50;
|
|
674
|
+
if (callStack_.size() >= kMaxUserCallDepth) {
|
|
675
|
+
error("Recursion too deep while calling function '" + name + "'", declNode);
|
|
676
|
+
}
|
|
636
677
|
std::optional<ProfileHandle> prof = profileEnter("function", name, callPos, &declNode.position());
|
|
637
678
|
callStack_.push_back(CallStackFrame{CallStackFrame::Kind::Function, name, callPos, &declNode.position(), &declNode,
|
|
638
679
|
nullptr, upvalueParent});
|
|
@@ -69,27 +69,31 @@ void bubbleEscapingCaptures(const CompiledChunk::ClosureSite& site, const oscad:
|
|
|
69
69
|
// True if any instruction in `chunk`'s own body/defaults is Op::LoadFree --
|
|
70
70
|
// i.e. an identifier that resolved to neither a local, a statically-known
|
|
71
71
|
// enclosing upvalue, nor a dyn ($-prefixed) name at compile time (see
|
|
72
|
-
// compileExpr's own Identifier case). A
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
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.
|
|
93
97
|
bool containsLoadFree(const std::vector<Instruction>& code) {
|
|
94
98
|
for (const Instruction& ins : code) {
|
|
95
99
|
if (ins.op == Op::LoadFree) return true;
|
|
@@ -105,6 +109,38 @@ bool containsLoadFree(const CompiledChunk& chunk) {
|
|
|
105
109
|
return false;
|
|
106
110
|
}
|
|
107
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
|
+
|
|
108
144
|
// Compile-time name -> slot resolution, mirroring the LetOp/nested-scope
|
|
109
145
|
// shadowing rules callCtx()/letChildCtx() apply at runtime: one frame per
|
|
110
146
|
// LetOp (pushed/popped around its own assignments+body), innermost frame
|
|
@@ -567,26 +603,39 @@ public:
|
|
|
567
603
|
size_t placeholderIdx = out.size();
|
|
568
604
|
out.push_back({Op::OpenLocalScope, 0, 0, nullptr});
|
|
569
605
|
int slotStart = nextSlot_;
|
|
570
|
-
// Letrec pre-pass: every
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
//
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
//
|
|
582
|
-
//
|
|
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.
|
|
583
629
|
std::vector<int> letrecSlot(n.assignments.size(), -1);
|
|
630
|
+
std::vector<std::vector<const oscad::FunctionLiteral*>> letrecCandidates(n.assignments.size());
|
|
584
631
|
std::unordered_set<int> pendingLetrecSlots;
|
|
585
632
|
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
586
633
|
const auto& assign = n.assignments[i];
|
|
587
634
|
const std::string& name = assign->name->name;
|
|
588
|
-
if (
|
|
635
|
+
if (name.empty() || name[0] == '$') continue;
|
|
636
|
+
if (auto candidates = collectLetrecCandidateLiterals(*assign->expr)) {
|
|
589
637
|
letrecSlot[i] = declareLocal(scope, name);
|
|
638
|
+
letrecCandidates[i] = std::move(*candidates);
|
|
590
639
|
pendingLetrecSlots.insert(letrecSlot[i]);
|
|
591
640
|
}
|
|
592
641
|
}
|
|
@@ -602,9 +651,21 @@ public:
|
|
|
602
651
|
const int preDeclaredSlot = letrecSlot[i];
|
|
603
652
|
const bool selfBinding = preDeclaredSlot >= 0;
|
|
604
653
|
compileExpr(*assign->expr, out, scope); // RHS is never tail
|
|
605
|
-
|
|
606
|
-
CompiledChunk::ClosureSite
|
|
607
|
-
auto&
|
|
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;
|
|
608
669
|
for (auto it = captures.begin(); it != captures.end();) {
|
|
609
670
|
if (it->targetDecl != selfDecl_ || !pendingLetrecSlots.count(it->slot)) {
|
|
610
671
|
++it;
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_bytecode_compiler.cpp
RENAMED
|
@@ -702,6 +702,39 @@ TEST(BytecodeCompiler, ThreeWaySiblingMutualRecursionResolvesCorrectly) {
|
|
|
702
702
|
"ECHO: \"f1\"\nECHO: \"f2\"\nECHO: \"f3\"");
|
|
703
703
|
}
|
|
704
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
|
+
|
|
705
738
|
TEST(BytecodeCompiler, ClosureWithDollarParameterStillBailsContainer) {
|
|
706
739
|
ScopedVm vm(true);
|
|
707
740
|
// Residual, deliberate limitation: a FunctionLiteral with its OWN
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
// Every test here explicitly forces the interpreter path via ScopedVm(false)
|
|
10
10
|
// (not the OSCAD_BYTECODE_VM env var, which is cached forever after its
|
|
11
11
|
// first read within a test binary -- see Evaluator::
|
|
12
|
-
// setBytecodeVmEnabledForTesting's own doc comment)
|
|
13
|
-
// call machinery (Phase B
|
|
14
|
-
//
|
|
15
|
-
//
|
|
12
|
+
// setBytecodeVmEnabledForTesting's own doc comment). Both the interpreter
|
|
13
|
+
// AND the bytecode VM's own call machinery (Phase B) do genuine C++
|
|
14
|
+
// recursion for a NON-tail call (there is no other way to implement one --
|
|
15
|
+
// see NonTailRecursionIsUnaffectedByTheTrampoline, below) -- a sufficiently
|
|
16
|
+
// deep one used to silently overflow the native stack and crash the whole
|
|
17
|
+
// process; evalUserFunctionCore's own depth guard (evaluator.hpp) now turns
|
|
18
|
+
// that into a controlled EvalError well before that point, shared by both
|
|
19
|
+
// paths, exercised by both compiled- and interpreted-path variants of the
|
|
20
|
+
// same test at the bottom of this file.
|
|
16
21
|
|
|
17
22
|
#include "openscad_cpp_evaluator/eval_error.hpp"
|
|
18
23
|
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
@@ -267,3 +272,55 @@ TEST(TailCalls, DebugHookFiresPerHopInsideATailChain) {
|
|
|
267
272
|
// single body-entry stop.
|
|
268
273
|
EXPECT_EQ(bodyEntry, 501 + 500 + 1);
|
|
269
274
|
}
|
|
275
|
+
|
|
276
|
+
TEST(TailCalls, DeepNonTailRecursionHitsAControlledErrorInsteadOfCrashingInterpreted) {
|
|
277
|
+
ScopedVm vm(false);
|
|
278
|
+
// `1 + f(n-1)` is NOT a tail position (the addition happens after the
|
|
279
|
+
// recursive call returns) -- there is no trampoline for this, ever
|
|
280
|
+
// (see NonTailRecursionIsUnaffectedByTheTrampoline, above): every
|
|
281
|
+
// logical call is a real, unavoidable C++ recursive call through
|
|
282
|
+
// evalUserFunctionCore. Before its own depth guard existed, a script
|
|
283
|
+
// shaped exactly like this one reliably segfaulted the whole process
|
|
284
|
+
// (confirmed present in the wild -- a plain, closure-free
|
|
285
|
+
// FunctionDeclaration, nothing specific to closures/letrec/tail-call
|
|
286
|
+
// machinery at all). Interpreted-path variant; see the compiled-path
|
|
287
|
+
// one below. f(500) is comfortably past kMaxUserCallDepth (50, see its
|
|
288
|
+
// own doc comment, evaluator.hpp) -- the actual native recursion never
|
|
289
|
+
// gets anywhere near 500, since the guard fires at 50 regardless of
|
|
290
|
+
// what depth the script asks for.
|
|
291
|
+
Evaluator ev;
|
|
292
|
+
auto ast = parseSrc("function f(n) = n <= 0 ? 0 : 1 + f(n - 1);\nresult = f(500);");
|
|
293
|
+
auto scope = oscad::buildScopes(ast);
|
|
294
|
+
EvalContext ctx = EvalContext::makeRoot(scope.get());
|
|
295
|
+
try {
|
|
296
|
+
ev.resolveTree(ast, ctx);
|
|
297
|
+
FAIL() << "expected EvalError";
|
|
298
|
+
} catch (const EvalError& e) {
|
|
299
|
+
EXPECT_NE(std::string(e.what()).find("Recursion too deep"), std::string::npos);
|
|
300
|
+
EXPECT_NE(std::string(e.what()).find("'f'"), std::string::npos);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
TEST(TailCalls, DeepNonTailRecursionHitsAControlledErrorInsteadOfCrashingCompiled) {
|
|
305
|
+
ScopedVm vm(true);
|
|
306
|
+
// Same script, same guard (evalUserFunctionCore is shared by both the
|
|
307
|
+
// interpreter and the bytecode VM's own compiled call path) -- the
|
|
308
|
+
// compiled path's own real per-call native stack usage is actually
|
|
309
|
+
// larger (more C++ frames between one logical call and the next, see
|
|
310
|
+
// runChunk/runCompiledFunctionFromBound/runCompiledFunctionFromBoundTrampoline),
|
|
311
|
+
// so this is the MORE exposed of the two paths, not a lesser check.
|
|
312
|
+
Evaluator ev;
|
|
313
|
+
auto ast = parseSrc("function f(n) = n <= 0 ? 0 : 1 + f(n - 1);\nresult = f(500);");
|
|
314
|
+
auto scope = oscad::buildScopes(ast);
|
|
315
|
+
EvalContext ctx = EvalContext::makeRoot(scope.get());
|
|
316
|
+
EXPECT_THROW(ev.resolveTree(ast, ctx), EvalError);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
TEST(TailCalls, ShallowNonTailRecursionStillWorksUnderTheDepthGuard) {
|
|
320
|
+
ScopedVm vm(true);
|
|
321
|
+
// The guard must not fire for perfectly ordinary, shallow non-tail
|
|
322
|
+
// recursion -- the overwhelmingly common real-world shape (a handful
|
|
323
|
+
// to a few dozen levels, e.g. walking a small nested data structure).
|
|
324
|
+
const std::string script = "function fact(n) = n <= 1 ? 1 : n * fact(n - 1);\necho(fact(10));";
|
|
325
|
+
EXPECT_EQ(runCapturingEcho(script), "ECHO: 3.6288e+6");
|
|
326
|
+
}
|
|
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.9.0 → openscad_cpp_evaluator-0.9.2}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/external/openscad_cpp_parser/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/function_builtins.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/primitives_2d.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/builtins/primitives_3d.cpp
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
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/src/text/stb_font_provider.cpp
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
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_function_builtins.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_multi_color_merge.cpp
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
|
{openscad_cpp_evaluator-0.9.0 → openscad_cpp_evaluator-0.9.2}/tests/test_viewport_params.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|