openscad-cpp-evaluator 0.40.0__tar.gz → 0.42.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.40.0 → openscad_cpp_evaluator-0.42.0}/CLAUDE.md +4 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +10 -2
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/expression.cpp +4 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +4 -2
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +3 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +13 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +4 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/csg_node.hpp +18 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/evaluator.hpp +35 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/value.hpp +1 -16
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/booleans.cpp +7 -3
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/control.cpp +1 -4
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/function_builtins.cpp +1 -5
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/registry.cpp +1 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/bytecode_compiler.cpp +1 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/bytecode_vm.cpp +15 -9
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/csg_resolve.cpp +6 -1
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/expr_eval.cpp +24 -4
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/stmt_eval.cpp +0 -2
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/user_calls.cpp +11 -5
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/value.cpp +6 -18
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-0.42.0/tests/test_children_separate.cpp +278 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_control_flow.cpp +41 -16
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/uv.lock +0 -0
|
@@ -481,7 +481,10 @@ grep for `ponytail:`.
|
|
|
481
481
|
lexically nested inside an already-active call," picking `childCtx()` vs `callCtx()`
|
|
482
482
|
accordingly; read its doc comment before touching it, it's the second-trickiest mechanism in this
|
|
483
483
|
codebase after the CSG tree stack), `evalUserModule`/`evalUserFunction`/`evalFunctionLiteral`,
|
|
484
|
-
and `builtinChildren` (children()/children(N), deferred evaluation
|
|
484
|
+
and `builtinChildren` (children()/children(N), deferred evaluation; `children(separate=true)`
|
|
485
|
+
additionally marks each forwarded node `separateOperand` so the enclosing
|
|
486
|
+
union/difference/intersection treats them as separate operands rather than one grouped one --
|
|
487
|
+
a BelfrySCAD extension, see `Evaluator::appendGroupSizes`). `evalFunctionCall`'s
|
|
485
488
|
precedence order (checked in this exact sequence): `import` (special-cased, its own
|
|
486
489
|
module/expression-context split) → `isBuiltinFunctionName` (function_builtins.hpp — always wins
|
|
487
490
|
if true) → user function lookup → function-literal *value* probe → "unknown function" warning.
|
|
@@ -80,14 +80,22 @@ public:
|
|
|
80
80
|
class RangeLiteral : public Primary {
|
|
81
81
|
public:
|
|
82
82
|
RangeLiteral(Position position, std::unique_ptr<Expression> start, std::unique_ptr<Expression> end,
|
|
83
|
-
std::unique_ptr<Expression> step)
|
|
83
|
+
std::unique_ptr<Expression> step, bool implicitStep = false)
|
|
84
84
|
: Primary(NodeKind::RangeLiteral, std::move(position)), start(std::move(start)), end(std::move(end)),
|
|
85
|
-
step(std::move(step)) {}
|
|
85
|
+
step(std::move(step)), implicitStep(implicitStep) {}
|
|
86
86
|
|
|
87
87
|
std::unique_ptr<Expression> start;
|
|
88
88
|
std::unique_ptr<Expression> end;
|
|
89
89
|
std::unique_ptr<Expression> step;
|
|
90
90
|
|
|
91
|
+
// True when the source wrote the two-argument form `[a:b]` and the step
|
|
92
|
+
// node below is the literal 1.0 this parser synthesized for it. Consumers
|
|
93
|
+
// that only need the value can ignore this and read `step` as always
|
|
94
|
+
// present; it exists because "the author did not choose a step" is not
|
|
95
|
+
// recoverable from the synthesized node, and the evaluator's backwards-range
|
|
96
|
+
// warning fires only for that case (an explicit step is taken as deliberate).
|
|
97
|
+
bool implicitStep = false;
|
|
98
|
+
|
|
91
99
|
std::string toString() const override;
|
|
92
100
|
void buildScope(Scope& parentScope) override;
|
|
93
101
|
};
|
|
@@ -22,6 +22,10 @@ std::string NumberLiteral::toString() const {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
std::string RangeLiteral::toString() const {
|
|
25
|
+
// Print back the form that was written. Emitting the synthesized step for
|
|
26
|
+
// a two-argument range would round-trip `[5:0]` into `[5 : 1 : 0]`, which
|
|
27
|
+
// reads identically but suppresses the evaluator's backwards-range warning.
|
|
28
|
+
if (implicitStep) return "[" + start->toString() + " : " + end->toString() + "]";
|
|
25
29
|
return "[" + start->toString() + " : " + step->toString() + " : " + end->toString() + "]";
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -46,11 +46,13 @@ NodePtr makeUndefinedLiteral(ParserDriver& driver, const OscadLocation& loc) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
NodePtr makeRangeLiteral(ParserDriver& driver, const OscadLocation& loc, NodePtr start, NodePtr end, NodePtr step) {
|
|
49
|
-
|
|
49
|
+
const bool implicitStep = !step;
|
|
50
|
+
if (implicitStep) {
|
|
50
51
|
step = std::make_unique<NumberLiteral>(driver.toPosition(loc), 1.0);
|
|
51
52
|
}
|
|
52
53
|
return std::make_unique<RangeLiteral>(driver.toPosition(loc), nodeCast<Expression>(std::move(start)),
|
|
53
|
-
nodeCast<Expression>(std::move(end)), nodeCast<Expression>(std::move(step))
|
|
54
|
+
nodeCast<Expression>(std::move(end)), nodeCast<Expression>(std::move(step)),
|
|
55
|
+
implicitStep);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
NodePtr makePositionalArgument(ParserDriver& driver, const OscadLocation& loc, NodePtr expr) {
|
|
@@ -112,6 +112,7 @@ json toJsonImpl(const ASTNode& node, bool includePos) {
|
|
|
112
112
|
j["start"] = valueToJson(n.start.get(), includePos);
|
|
113
113
|
j["end"] = valueToJson(n.end.get(), includePos);
|
|
114
114
|
j["step"] = valueToJson(n.step.get(), includePos);
|
|
115
|
+
if (n.implicitStep) j["implicitStep"] = true;
|
|
115
116
|
break;
|
|
116
117
|
}
|
|
117
118
|
case NodeKind::ParameterDeclaration: {
|
|
@@ -410,7 +411,8 @@ const std::unordered_map<std::string, Builder>& registry() {
|
|
|
410
411
|
{"RangeLiteral",
|
|
411
412
|
[](const json& j, Position pos) -> std::unique_ptr<ASTNode> {
|
|
412
413
|
return std::make_unique<RangeLiteral>(std::move(pos), childFromJson<Expression>(j, "start"),
|
|
413
|
-
childFromJson<Expression>(j, "end"), childFromJson<Expression>(j, "step")
|
|
414
|
+
childFromJson<Expression>(j, "end"), childFromJson<Expression>(j, "step"),
|
|
415
|
+
j.value("implicitStep", false));
|
|
414
416
|
}},
|
|
415
417
|
{"ParameterDeclaration",
|
|
416
418
|
[](const json& j, Position pos) -> std::unique_ptr<ASTNode> {
|
|
@@ -515,3 +515,16 @@ TEST(PrettyPrint, AssignmentRhsWithLeadingCommentAndTrailingLineComment) {
|
|
|
515
515
|
// no other translation unit -- including this test file -- can name them.
|
|
516
516
|
// Left as a known, permanent coverage ceiling rather than weakening the
|
|
517
517
|
// encapsulation just to reach 100%.
|
|
518
|
+
|
|
519
|
+
// The two-argument range keeps its shape through a print/reparse cycle.
|
|
520
|
+
// It would be easy to always print the synthesized step, and the result
|
|
521
|
+
// would still be a correct program -- but `[5:0]` and `[5:1:0]` mean
|
|
522
|
+
// different things to the evaluator's backwards-range warning, so
|
|
523
|
+
// reformatting a file must not quietly convert one into the other.
|
|
524
|
+
TEST(PrettyPrint, ImplicitRangeStepSurvivesRoundTrip) {
|
|
525
|
+
auto ast = parseAst("a = [5:0];\nb = [5:1:0];\n");
|
|
526
|
+
const std::string printed = toOpenscad(ast);
|
|
527
|
+
EXPECT_NE(printed.find("[5 : 0]"), std::string::npos) << printed;
|
|
528
|
+
EXPECT_NE(printed.find("[5 : 1 : 0]"), std::string::npos) << printed;
|
|
529
|
+
expectStablePrint("a = [5:0];\nb = [5:1:0];\n");
|
|
530
|
+
}
|
|
@@ -219,6 +219,10 @@ struct VmFrame {
|
|
|
219
219
|
// mirrors evalModularCall's own `&node` (csg_resolve.cpp). Only
|
|
220
220
|
// meaningful when ownsModuleSplice is true.
|
|
221
221
|
const oscad::ASTNode* moduleSpliceCallNode = nullptr;
|
|
222
|
+
// children(separate=true) on the call this frame is forwarding for.
|
|
223
|
+
// Only meaningful while ownsModuleSplice is true, same as the two
|
|
224
|
+
// fields above; reset in releaseVmFrame for the same pooling reason.
|
|
225
|
+
bool separateChildren = false;
|
|
222
226
|
|
|
223
227
|
// Whether callStack_.back() (at push time) genuinely IS this frame's
|
|
224
228
|
// own logical call, and therefore safe for a tail hop inside this
|
|
@@ -34,6 +34,16 @@ struct CSGNode {
|
|
|
34
34
|
CSGParams params; // resolve step's plain-data output
|
|
35
35
|
bool uncacheable = false; // set by a later phase (ManifoldCache, Phase 8)
|
|
36
36
|
|
|
37
|
+
// Set only by children(separate=true): this node begins its OWN operand
|
|
38
|
+
// group in an enclosing union/difference/intersection/intersection_for,
|
|
39
|
+
// instead of merging into the single group its enclosing statement
|
|
40
|
+
// would otherwise form. See Evaluator::appendGroupSizes.
|
|
41
|
+
//
|
|
42
|
+
// Deliberately absent from cacheKey()'s allowlist (manifold_cache.cpp):
|
|
43
|
+
// it changes the PARENT's hashed "group_sizes" param, never this node's
|
|
44
|
+
// own geometry, so the parent already re-keys and this node must not.
|
|
45
|
+
bool separateOperand = false;
|
|
46
|
+
|
|
37
47
|
// The call site that entered this node's call chain from the top
|
|
38
48
|
// level, captured at RESOLVE time -- non-owning, AST-lifetime-bound
|
|
39
49
|
// like `node`. nullptr for a node resolved at top level.
|
|
@@ -73,4 +83,12 @@ struct CSGNode {
|
|
|
73
83
|
std::optional<std::string> cachedKey;
|
|
74
84
|
};
|
|
75
85
|
|
|
86
|
+
// Marks every node from `from` onward as starting its own operand group --
|
|
87
|
+
// what children(separate=true) does to the geometry it just forwarded.
|
|
88
|
+
// A free function, not a member, so all three splice sites (user_calls.cpp
|
|
89
|
+
// and bytecode_vm.cpp's two) can reach it from this header alone.
|
|
90
|
+
inline void markSeparateOperands(std::vector<std::unique_ptr<CSGNode>>& nodes, size_t from) {
|
|
91
|
+
for (size_t i = from; i < nodes.size(); ++i) nodes[i]->separateOperand = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
76
94
|
} // namespace oscadeval
|
|
@@ -190,6 +190,30 @@ public:
|
|
|
190
190
|
// statement.
|
|
191
191
|
size_t currentTreeFrameSize() const { return treeStack_.back().size(); }
|
|
192
192
|
|
|
193
|
+
// Records the group(s) one child statement contributed, given the frame
|
|
194
|
+
// size captured before it ran. Normally that is exactly one group, of
|
|
195
|
+
// however many nodes the statement pushed -- including a group of size
|
|
196
|
+
// ZERO for a statement that produced no geometry (a disabled `*cube()`),
|
|
197
|
+
// which generateCsg relies on to reset intersection() and to bail
|
|
198
|
+
// difference(). Only children(separate=true) produces more than one:
|
|
199
|
+
// each node it marked starts a fresh group, so its forwarded children
|
|
200
|
+
// reach the enclosing operator as separate operands.
|
|
201
|
+
//
|
|
202
|
+
// Shared by all four group builders -- resolveCsg, resolveIntersectionFor
|
|
203
|
+
// and the VM's Op::CsgGroupEnd (which serves both) -- because
|
|
204
|
+
// "group_sizes" is otherwise built twice, once per engine, and would
|
|
205
|
+
// drift.
|
|
206
|
+
void appendGroupSizes(std::vector<Value>& groupSizes, size_t before) const {
|
|
207
|
+
const std::vector<std::unique_ptr<CSGNode>>& frame = treeStack_.back();
|
|
208
|
+
size_t start = before;
|
|
209
|
+
for (size_t i = before + 1; i < frame.size(); ++i) {
|
|
210
|
+
if (!frame[i]->separateOperand) continue;
|
|
211
|
+
groupSizes.push_back(Value{static_cast<double>(i - start)});
|
|
212
|
+
start = i;
|
|
213
|
+
}
|
|
214
|
+
groupSizes.push_back(Value{static_cast<double>(frame.size() - start)});
|
|
215
|
+
}
|
|
216
|
+
|
|
193
217
|
// Generate pass: walks `tree` bottom-up (children before their own
|
|
194
218
|
// node), calling each node's registered GenerateFn (falling back to
|
|
195
219
|
// concatenating children's bodies for a kind with none registered).
|
|
@@ -342,6 +366,11 @@ public:
|
|
|
342
366
|
struct ChildrenForward {
|
|
343
367
|
EvalContext evalCtx;
|
|
344
368
|
std::vector<const oscad::ASTNode*> nodes;
|
|
369
|
+
// children(separate=true): hand these to the enclosing union/
|
|
370
|
+
// difference/intersection as SEPARATE operands rather than as one
|
|
371
|
+
// grouped operand. Acted on after the nodes are evaluated, by
|
|
372
|
+
// marking the CSGNodes they produced -- see markSeparateOperands.
|
|
373
|
+
bool separate = false;
|
|
345
374
|
};
|
|
346
375
|
std::optional<ChildrenForward> prepareChildrenForward(const CallArgs& args, EvalContext& ctx);
|
|
347
376
|
|
|
@@ -392,7 +421,12 @@ public:
|
|
|
392
421
|
Value applyUnaryOp(oscad::NodeKind kind, const Value& v, const oscad::Position& pos);
|
|
393
422
|
Value applyIndexAccess(const Value& obj, const Value& idx);
|
|
394
423
|
Value applyMemberAccess(const Value& obj, const std::string& member);
|
|
395
|
-
|
|
424
|
+
// `implicitStep` is the RangeLiteral's own flag: true when the source
|
|
425
|
+
// wrote `[a:b]` and the parser supplied the 1.0. It only affects whether
|
|
426
|
+
// the backwards-range warning fires; the resulting value is the same
|
|
427
|
+
// either way. `pos` locates that warning.
|
|
428
|
+
Value applyRange(const Value& startV, const Value& endV, const Value& stepV, bool implicitStep = false,
|
|
429
|
+
const oscad::Position* pos = nullptr);
|
|
396
430
|
|
|
397
431
|
// Entry point for a call site resolved INSIDE compiled bytecode (the
|
|
398
432
|
// CALL_FN opcode, bytecode_vm.cpp): `bound` is already fully evaluated
|
|
@@ -355,20 +355,6 @@ private:
|
|
|
355
355
|
// it, keeping expandIterable() itself free of any Evaluator/echo coupling.
|
|
356
356
|
using RangeTooManyFn = std::function<void(size_t count)>;
|
|
357
357
|
|
|
358
|
-
// Called when a range's step points AWAY from its end -- begin > end with a
|
|
359
|
-
// positive step, or begin < end with a negative step. Such a range is
|
|
360
|
-
// naturally empty, and the reference warns rather than iterating zero times
|
|
361
|
-
// in silence. `stepPositive` picks which of its two messages applies; use
|
|
362
|
-
// rangeDirectionWarning() to build the text.
|
|
363
|
-
//
|
|
364
|
-
// Separate from RangeTooManyFn for the same reason that one exists: it
|
|
365
|
-
// keeps expandIterable() free of any Evaluator/echo coupling.
|
|
366
|
-
using RangeDirectionFn = std::function<void(bool stepPositive)>;
|
|
367
|
-
|
|
368
|
-
// The reference's own wording, quoted verbatim, for a range whose step
|
|
369
|
-
// points away from its end. Shared so the five call sites cannot drift.
|
|
370
|
-
std::string rangeDirectionWarning(bool stepPositive);
|
|
371
|
-
|
|
372
358
|
// Converts a for()/intersection_for() loop assignment's evaluated RHS into
|
|
373
359
|
// the sequence of values to iterate: undef -> empty, range -> a LAZY
|
|
374
360
|
// sequence (matching OscRange's own start/step/end iteration, half-open
|
|
@@ -394,8 +380,7 @@ std::string rangeDirectionWarning(bool stepPositive);
|
|
|
394
380
|
// one with a live consumer (BelfrySCAD) that surfaced it. The count is
|
|
395
381
|
// computed in closed form (not IterableValues::size()'s O(n) walk) so a
|
|
396
382
|
// legitimate huge-but-under-the-limit range never pays an eager pass.
|
|
397
|
-
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany = nullptr
|
|
398
|
-
const RangeDirectionFn& onWrongDirection = nullptr);
|
|
383
|
+
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany = nullptr);
|
|
399
384
|
|
|
400
385
|
// `each <body>`'s own flatten-one-level rule, shared by the AST interpreter
|
|
401
386
|
// (evalListLiteral/evalListElement's ListCompEach handling, expr_eval.cpp)
|
|
@@ -68,7 +68,12 @@ std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBo
|
|
|
68
68
|
// operand (unioned together), and each subsequent statement's bodies are
|
|
69
69
|
// unioned then subtracted -- a flat evaluation would lose this grouping and
|
|
70
70
|
// misbehave when e.g. BOSL2's attachable() returns multiple bodies (parent
|
|
71
|
-
// + attached children) as one operand.
|
|
71
|
+
// + attached children) as one operand.
|
|
72
|
+
//
|
|
73
|
+
// One statement can contribute MORE than one group: children(separate=true)
|
|
74
|
+
// marks the nodes it forwards so each starts its own operand group, which is
|
|
75
|
+
// how `difference() children(separate=true)` subtracts children 1..n from
|
|
76
|
+
// child 0. See Evaluator::appendGroupSizes, which both engines share. Mirrors _resolve_csg/_generate_csg,
|
|
72
77
|
// minus _attach_tri_colors' multi-color-merge provenance (ponytail: a
|
|
73
78
|
// merged body always takes its first contributing child's color, matching
|
|
74
79
|
// this evaluator's own pre-tri_colors baseline behavior -- revisit
|
|
@@ -101,8 +106,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
|
|
|
101
106
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
102
107
|
const size_t before = ev.currentTreeFrameSize();
|
|
103
108
|
ev.evalChildren(std::vector<const oscad::ASTNode*>{geoNode}, effCtx);
|
|
104
|
-
|
|
105
|
-
groupSizes.push_back(Value{static_cast<double>(after - before)});
|
|
109
|
+
ev.appendGroupSizes(groupSizes, before);
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
CSGParams params;
|
|
@@ -119,8 +119,7 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
119
119
|
if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
|
|
120
120
|
const size_t before = ev.currentTreeFrameSize();
|
|
121
121
|
ev.evalChildren(bodyNodes, parentCtx);
|
|
122
|
-
|
|
123
|
-
groupSizes.push_back(Value{static_cast<double>(after - before)});
|
|
122
|
+
ev.appendGroupSizes(groupSizes, before);
|
|
124
123
|
return;
|
|
125
124
|
}
|
|
126
125
|
const auto& assign = node.assignments[depth];
|
|
@@ -128,8 +127,6 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
128
127
|
const oscad::Position* pos = &assign->position();
|
|
129
128
|
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
130
129
|
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
131
|
-
}, [&](bool stepPositive) {
|
|
132
|
-
ev.warn(rangeDirectionWarning(stepPositive), pos);
|
|
133
130
|
});
|
|
134
131
|
for (const Value& val : iter) {
|
|
135
132
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
{openscad_cpp_evaluator-0.40.0 → openscad_cpp_evaluator-0.42.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -952,11 +952,7 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
|
|
|
952
952
|
}
|
|
953
953
|
if (const OscRange* r = std::get_if<OscRange>(&c)) {
|
|
954
954
|
std::string out;
|
|
955
|
-
|
|
956
|
-
// as much a typo as for(i=[70:1:65]) would be.
|
|
957
|
-
const IterableValues seq = expandIterable(Value{*r}, nullptr, [&](bool stepPositive) {
|
|
958
|
-
ev.warn(rangeDirectionWarning(stepPositive), &node.position());
|
|
959
|
-
});
|
|
955
|
+
const IterableValues seq = expandIterable(Value{*r});
|
|
960
956
|
for (const Value& item : seq) out += encode(item);
|
|
961
957
|
return out;
|
|
962
958
|
}
|
|
@@ -112,7 +112,7 @@ const std::vector<std::string>* builtinParamNames(const std::string& name) {
|
|
|
112
112
|
{"intersection", {}},
|
|
113
113
|
{"hull", {}},
|
|
114
114
|
{"minkowski", {"convexity"}},
|
|
115
|
-
{"children", {"index"}},
|
|
115
|
+
{"children", {"index", "separate"}},
|
|
116
116
|
{"render", {"convexity"}},
|
|
117
117
|
// "repair" is this port's own addition, not an upstream parameter.
|
|
118
118
|
{"import",
|
|
@@ -466,7 +466,7 @@ public:
|
|
|
466
466
|
compileExpr(*n.start, out, scope);
|
|
467
467
|
compileExpr(*n.end, out, scope);
|
|
468
468
|
compileExpr(*n.step, out, scope);
|
|
469
|
-
out.push_back({Op::Range, 0, 0, &n.position()});
|
|
469
|
+
out.push_back({Op::Range, n.implicitStep ? 1 : 0, 0, &n.position()});
|
|
470
470
|
return;
|
|
471
471
|
}
|
|
472
472
|
case NodeKind::PrimaryIndex: {
|
|
@@ -360,7 +360,7 @@ void pushBracketedModuleFrame(Evaluator& ev, const CompiledChunk& chunk, const o
|
|
|
360
360
|
// because module chunks never contain tail-call opcodes); don't inherit
|
|
361
361
|
// a pooled function frame's stale true here either.
|
|
362
362
|
void pushChildrenForwardFrame(Evaluator& ev, const CompiledChunk& chunk, EvalContext evalCtx,
|
|
363
|
-
std::uint64_t randsBefore, const oscad::ASTNode& callNode) {
|
|
363
|
+
std::uint64_t randsBefore, const oscad::ASTNode& callNode, bool separate) {
|
|
364
364
|
if (ev.vmCallStack_.size() >= Evaluator::kMaxVmCallStackDepth) {
|
|
365
365
|
ev.error("Recursion too deep while forwarding children()", callNode);
|
|
366
366
|
}
|
|
@@ -381,6 +381,7 @@ void pushChildrenForwardFrame(Evaluator& ev, const CompiledChunk& chunk, EvalCon
|
|
|
381
381
|
frame->ownsModuleSplice = true;
|
|
382
382
|
frame->moduleRandsBefore = randsBefore;
|
|
383
383
|
frame->moduleSpliceCallNode = &callNode;
|
|
384
|
+
frame->separateChildren = separate;
|
|
384
385
|
ev.vmCallStack_.push_back(std::move(frame));
|
|
385
386
|
ev.vmCallBrackets_.emplace_back(std::nullopt);
|
|
386
387
|
}
|
|
@@ -505,6 +506,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
505
506
|
const bool ownsModuleSplice = finished->ownsModuleSplice;
|
|
506
507
|
const std::uint64_t moduleRandsBefore = finished->moduleRandsBefore;
|
|
507
508
|
const oscad::ASTNode* moduleSpliceCallNode = finished->moduleSpliceCallNode;
|
|
509
|
+
const bool separateChildren = finished->separateChildren;
|
|
508
510
|
while (!finished->ctxChain.empty()) finished->ctxChain.pop_back();
|
|
509
511
|
// Module frames never fire returnHook (native evalUserModule
|
|
510
512
|
// never did either -- a module call has no "return value"
|
|
@@ -514,6 +516,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
514
516
|
if (isModule && ownsModuleSplice) {
|
|
515
517
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
516
518
|
ev.treeStack_.pop_back();
|
|
519
|
+
if (separateChildren) markSeparateOperands(children, 0);
|
|
517
520
|
ev.spliceModuleChildren(std::move(children), moduleRandsBefore, *moduleSpliceCallNode);
|
|
518
521
|
}
|
|
519
522
|
if (isFloorFrame) {
|
|
@@ -634,7 +637,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
634
637
|
f.stack.pop_back();
|
|
635
638
|
Value start = std::move(f.stack.back());
|
|
636
639
|
f.stack.pop_back();
|
|
637
|
-
f.stack.push_back(ev.applyRange(start, end, step));
|
|
640
|
+
f.stack.push_back(ev.applyRange(start, end, step, ins.a != 0, ins.pos));
|
|
638
641
|
++f.pc;
|
|
639
642
|
break;
|
|
640
643
|
}
|
|
@@ -740,8 +743,6 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
740
743
|
il.values = expandIterable(v, [&](size_t count) {
|
|
741
744
|
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")",
|
|
742
745
|
ins.pos);
|
|
743
|
-
}, [&](bool stepPositive) {
|
|
744
|
-
ev.warn(rangeDirectionWarning(stepPositive), ins.pos);
|
|
745
746
|
});
|
|
746
747
|
il.index = 0;
|
|
747
748
|
il.total = il.values.size();
|
|
@@ -1025,6 +1026,11 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1025
1026
|
static_cast<const oscad::ModularCall*>(f.chunk->nativeStatements[static_cast<size_t>(ins.a)]);
|
|
1026
1027
|
EvalContext scopedCtx = ctx.withScope(callNode->scope() ? callNode->scope() : ctx.scope);
|
|
1027
1028
|
ev.checkDebug(*callNode, scopedCtx);
|
|
1029
|
+
// Same order as evalModularCall's own (csg_resolve.cpp):
|
|
1030
|
+
// warn, then resolve. Without this a children() typo
|
|
1031
|
+
// warns only under the interpreter, so no test for that
|
|
1032
|
+
// warning could run under both engines.
|
|
1033
|
+
warnUnexpectedBuiltinArgs(ev, *callNode);
|
|
1028
1034
|
const std::uint64_t randsBefore = ev.randsCallCount();
|
|
1029
1035
|
auto [args, effCtx] = resolveCallArgs(ev, callNode->arguments, scopedCtx);
|
|
1030
1036
|
std::optional<Evaluator::ChildrenForward> fwd = ev.prepareChildrenForward(args, effCtx);
|
|
@@ -1041,9 +1047,11 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1041
1047
|
const CompiledChunk* chunk = (ev.useBytecodeVm() && ev.inResolvePass())
|
|
1042
1048
|
? ev.lookupOrCompileChildrenListChunk(fwd->nodes)
|
|
1043
1049
|
: nullptr;
|
|
1050
|
+
// Read before fwd->evalCtx is moved from.
|
|
1051
|
+
const bool separate = fwd->separate;
|
|
1044
1052
|
if (chunk) {
|
|
1045
1053
|
ev.treeStack_.emplace_back();
|
|
1046
|
-
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode);
|
|
1054
|
+
pushChildrenForwardFrame(ev, *chunk, std::move(fwd->evalCtx), randsBefore, *callNode, separate);
|
|
1047
1055
|
// f.pc deliberately NOT advanced -- resumes when
|
|
1048
1056
|
// the pushed frame completes; driveVm's completion
|
|
1049
1057
|
// branch runs the splice (isModule &&
|
|
@@ -1067,6 +1075,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1067
1075
|
}
|
|
1068
1076
|
std::vector<std::unique_ptr<CSGNode>> children = std::move(ev.treeStack_.back());
|
|
1069
1077
|
ev.treeStack_.pop_back();
|
|
1078
|
+
if (separate) markSeparateOperands(children, 0);
|
|
1070
1079
|
ev.spliceModuleChildren(std::move(children), randsBefore, *callNode);
|
|
1071
1080
|
++f.pc;
|
|
1072
1081
|
}
|
|
@@ -1306,8 +1315,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1306
1315
|
}
|
|
1307
1316
|
case Op::CsgGroupEnd: {
|
|
1308
1317
|
PendingCsgWrap& pending = f.csgWrapStack.back();
|
|
1309
|
-
|
|
1310
|
-
pending.groupSizes.push_back(Value{static_cast<double>(after - pending.groupStartSize)});
|
|
1318
|
+
ev.appendGroupSizes(pending.groupSizes, pending.groupStartSize);
|
|
1311
1319
|
++f.pc;
|
|
1312
1320
|
break;
|
|
1313
1321
|
}
|
|
@@ -1466,8 +1474,6 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1466
1474
|
il.values = expandIterable(v, [&](size_t count) {
|
|
1467
1475
|
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")",
|
|
1468
1476
|
ins.pos);
|
|
1469
|
-
}, [&](bool stepPositive) {
|
|
1470
|
-
ev.warn(rangeDirectionWarning(stepPositive), ins.pos);
|
|
1471
1477
|
});
|
|
1472
1478
|
il.index = 0;
|
|
1473
1479
|
il.total = il.values.size();
|
|
@@ -158,7 +158,12 @@ void Evaluator::spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> child
|
|
|
158
158
|
// landed on.
|
|
159
159
|
for (auto& c : children) c->uncacheable = true;
|
|
160
160
|
}
|
|
161
|
-
|
|
161
|
+
// children(separate=true) marked these to start their own operand
|
|
162
|
+
// groups, and the group walk only inspects the enclosing frame's top
|
|
163
|
+
// level -- so the wrapper would hide the marks. Splice instead.
|
|
164
|
+
const bool anySeparate =
|
|
165
|
+
std::any_of(children.begin(), children.end(), [](const auto& c) { return c->separateOperand; });
|
|
166
|
+
if (children.size() > 1 && !anySeparate) {
|
|
162
167
|
auto unionNode = std::make_unique<CSGNode>();
|
|
163
168
|
unionNode->kind = "union";
|
|
164
169
|
unionNode->node = &callNode;
|
|
@@ -177,8 +177,6 @@ void Evaluator::evalListElement(const oscad::ASTNode& elem, EvalContext& ctx, st
|
|
|
177
177
|
const oscad::Position* pos = &assign->position();
|
|
178
178
|
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
179
179
|
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
180
|
-
}, [&](bool stepPositive) {
|
|
181
|
-
warn(rangeDirectionWarning(stepPositive), pos);
|
|
182
180
|
});
|
|
183
181
|
for (const Value& val : iter) {
|
|
184
182
|
EvalContext childCtx = parentCtx.letChildCtx();
|
|
@@ -294,16 +292,38 @@ Value Evaluator::evalListLiteral(const oscad::ListComprehension& node, EvalConte
|
|
|
294
292
|
}
|
|
295
293
|
|
|
296
294
|
Value Evaluator::evalRangeLiteral(const oscad::RangeLiteral& node, EvalContext& ctx) {
|
|
297
|
-
return applyRange(evalExpr(*node.start, ctx), evalExpr(*node.end, ctx), evalExpr(*node.step, ctx)
|
|
295
|
+
return applyRange(evalExpr(*node.start, ctx), evalExpr(*node.end, ctx), evalExpr(*node.step, ctx),
|
|
296
|
+
node.implicitStep, &node.position());
|
|
298
297
|
}
|
|
299
298
|
|
|
300
299
|
// Shared with the bytecode VM's RANGE opcode -- see applyBinaryOp's own
|
|
301
300
|
// comment on why these are factored out as plain Value x Value x Value ->
|
|
302
301
|
// Value functions.
|
|
303
|
-
Value Evaluator::applyRange(const Value& startV, const Value& endV, const Value& stepV
|
|
302
|
+
Value Evaluator::applyRange(const Value& startV, const Value& endV, const Value& stepV, bool implicitStep,
|
|
303
|
+
const oscad::Position* pos) {
|
|
304
304
|
double start = std::holds_alternative<std::monostate>(startV) ? 0.0 : toDoubleLenient(startV);
|
|
305
305
|
double end = std::holds_alternative<std::monostate>(endV) ? 0.0 : toDoubleLenient(endV);
|
|
306
306
|
double step = std::holds_alternative<std::monostate>(stepV) ? 1.0 : toDoubleLenient(stepV);
|
|
307
|
+
// A range whose begin is already past its end iterates zero times, which
|
|
308
|
+
// is almost always a typo -- [5:0] where [5:-1:0] was meant. Reported
|
|
309
|
+
// here, at construction, because that is where the reference reports it:
|
|
310
|
+
// `r = [5:0];` warns even if nothing ever iterates r.
|
|
311
|
+
//
|
|
312
|
+
// ponytail: only an IMPLICIT step is checked -- a deliberate divergence
|
|
313
|
+
// from the reference, which warns for [5:1:0] and [0:-1:5] as well.
|
|
314
|
+
// Writing the step out is taken as a statement of intent; the warning is
|
|
315
|
+
// for the author who wrote [5:0] meaning [5:-1:0] and got a silent empty
|
|
316
|
+
// loop. An implicit step is always exactly 1, so the reference's other
|
|
317
|
+
// wording ("begin is smaller than the end, but step is negative") cannot
|
|
318
|
+
// arise here and no longer exists in this port -- if it is ever needed
|
|
319
|
+
// again, this gate has been widened back to explicit steps.
|
|
320
|
+
//
|
|
321
|
+
// The epsilon matches the one the iteration path used before this check
|
|
322
|
+
// moved here, so a range built from float arithmetic that lands a hair
|
|
323
|
+
// past its end is still treated as empty-but-fine rather than a typo.
|
|
324
|
+
if (implicitStep && (start - end) > 1e-10) {
|
|
325
|
+
warn("begin is greater than the end, but step is positive", pos);
|
|
326
|
+
}
|
|
307
327
|
return Value{OscRange{start, step, end}};
|
|
308
328
|
}
|
|
309
329
|
|
|
@@ -112,8 +112,6 @@ void Evaluator::evalFor(const oscad::ModularFor& node, EvalContext& ctx) {
|
|
|
112
112
|
const oscad::Position* pos = &assign->position();
|
|
113
113
|
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
114
114
|
warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")", pos);
|
|
115
|
-
}, [&](bool stepPositive) {
|
|
116
|
-
warn(rangeDirectionWarning(stepPositive), pos);
|
|
117
115
|
});
|
|
118
116
|
for (const Value& val : iter) {
|
|
119
117
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
|
@@ -179,6 +179,7 @@ void Evaluator::releaseVmFrame(std::unique_ptr<VmFrame> frame) {
|
|
|
179
179
|
frame->ownsModuleSplice = false;
|
|
180
180
|
frame->moduleRandsBefore = 0;
|
|
181
181
|
frame->moduleSpliceCallNode = nullptr;
|
|
182
|
+
frame->separateChildren = false;
|
|
182
183
|
vmFramePool_.push_back(std::move(frame));
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -932,6 +933,11 @@ Value Evaluator::parentModuleName(int idx) const {
|
|
|
932
933
|
|
|
933
934
|
std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(const CallArgs& args, EvalContext& ctx) {
|
|
934
935
|
Value idxArg = getArg(args, 0, "index", Value{});
|
|
936
|
+
// Positional slot 1 is accepted as well as the name: adding "separate"
|
|
937
|
+
// to the builtin's parameter list already suppresses the "Too many
|
|
938
|
+
// unnamed arguments" warning for children(0, true), so reading it
|
|
939
|
+
// named-only would silently ignore an argument the author wrote.
|
|
940
|
+
const bool separate = truthy(getArg(args, 1, "separate", Value{false}));
|
|
935
941
|
if (!ctx.childrenNodes || ctx.childrenNodes->empty()) return std::nullopt;
|
|
936
942
|
const EvalContext* callerCtx = ctx.childrenCallerCtx;
|
|
937
943
|
if (!callerCtx) return std::nullopt;
|
|
@@ -977,7 +983,7 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
977
983
|
}
|
|
978
984
|
|
|
979
985
|
if (std::holds_alternative<std::monostate>(idxArg)) {
|
|
980
|
-
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes};
|
|
986
|
+
return ChildrenForward{std::move(evalCtx), *ctx.childrenNodes, separate};
|
|
981
987
|
}
|
|
982
988
|
|
|
983
989
|
// children(N) indexes child *statements*, not output bodies -- a
|
|
@@ -1006,9 +1012,7 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
1006
1012
|
if (std::holds_alternative<double>(idxArg)) {
|
|
1007
1013
|
indexValues.push_back(idxArg);
|
|
1008
1014
|
} else if (std::holds_alternative<ListPtr>(idxArg) || std::holds_alternative<OscRange>(idxArg)) {
|
|
1009
|
-
const IterableValues iter = expandIterable(idxArg
|
|
1010
|
-
warn(rangeDirectionWarning(stepPositive), currentWarnEntry());
|
|
1011
|
-
});
|
|
1015
|
+
const IterableValues iter = expandIterable(idxArg);
|
|
1012
1016
|
for (const Value& v : iter) indexValues.push_back(v);
|
|
1013
1017
|
} else {
|
|
1014
1018
|
warn("Bad parameter type (" + fmtValue(idxArg) +
|
|
@@ -1043,13 +1047,15 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
1043
1047
|
picked.push_back(geoNodes[static_cast<size_t>(idx)]);
|
|
1044
1048
|
}
|
|
1045
1049
|
if (picked.empty()) return std::nullopt;
|
|
1046
|
-
return ChildrenForward{std::move(evalCtx), std::move(picked)};
|
|
1050
|
+
return ChildrenForward{std::move(evalCtx), std::move(picked), separate};
|
|
1047
1051
|
}
|
|
1048
1052
|
|
|
1049
1053
|
void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
1050
1054
|
std::optional<ChildrenForward> fwd = prepareChildrenForward(args, ctx);
|
|
1051
1055
|
if (!fwd) return;
|
|
1056
|
+
const size_t before = currentTreeFrameSize();
|
|
1052
1057
|
evalChildren(fwd->nodes, fwd->evalCtx);
|
|
1058
|
+
if (fwd->separate) markSeparateOperands(treeStack_.back(), before);
|
|
1053
1059
|
}
|
|
1054
1060
|
|
|
1055
1061
|
} // namespace oscadeval
|
|
@@ -490,30 +490,18 @@ std::optional<size_t> rangeElementCount(const OscRange& r) {
|
|
|
490
490
|
return static_cast<size_t>(std::floor(n + 1e-10)) + 1;
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
-
|
|
494
|
-
return stepPositive ? "begin is greater than the end, but step is positive"
|
|
495
|
-
: "begin is smaller than the end, but step is negative";
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany,
|
|
499
|
-
const RangeDirectionFn& onWrongDirection) {
|
|
493
|
+
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany) {
|
|
500
494
|
if (std::holds_alternative<std::monostate>(v)) return IterableValues{};
|
|
501
495
|
if (const OscRange* r = std::get_if<OscRange>(&v)) {
|
|
502
496
|
if (const std::optional<size_t> count = rangeElementCount(*r); count && *count >= 1'000'000) {
|
|
503
497
|
if (onTooMany) onTooMany(*count);
|
|
504
498
|
return IterableValues{};
|
|
505
499
|
}
|
|
506
|
-
// A step pointing away from the end yields nothing
|
|
507
|
-
// always a typo --
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
// failure (the reference calls it "too many elements") and shares
|
|
512
|
-
// rangeElementCount's nullopt with this case only by coincidence.
|
|
513
|
-
if (onWrongDirection && r->step != 0.0) {
|
|
514
|
-
const double n = (r->end - r->start) / r->step;
|
|
515
|
-
if (n < -1e-10) onWrongDirection(r->step > 0.0);
|
|
516
|
-
}
|
|
500
|
+
// A step pointing away from the end yields nothing, and that is
|
|
501
|
+
// almost always a typo -- but the warning for it belongs to the
|
|
502
|
+
// range's CONSTRUCTION, not its iteration: only the range literal
|
|
503
|
+
// knows whether the author chose the step or the parser supplied
|
|
504
|
+
// it. See Evaluator::applyRange.
|
|
517
505
|
// Lazy -- IterableValues itself reproduces this exact
|
|
518
506
|
// termination condition (a zero step is naturally empty: neither
|
|
519
507
|
// `x <= end` nor `x >= end` branch ever fires for it) without
|