openscad-cpp-evaluator 0.38.1__tar.gz → 0.40.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.38.1 → openscad_cpp_evaluator-0.40.0}/CLAUDE.md +14 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/function_builtins.hpp +4 -2
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/value.hpp +16 -1
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/control.cpp +2 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/function_builtins.cpp +95 -15
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/primitives_3d.cpp +31 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/bytecode_vm.cpp +5 -1
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/expr_eval.cpp +2 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/stmt_eval.cpp +2 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/user_calls.cpp +54 -4
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/value.cpp +18 -1
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_control_flow.cpp +244 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_expr_eval.cpp +106 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_render_expr.cpp +35 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/uv.lock +0 -0
|
@@ -1128,6 +1128,20 @@ vector and `oscEqual` is order-sensitive):
|
|
|
1128
1128
|
`vnf` is the `[vertices, faces]` 2-list BOSL2 functions actually take.
|
|
1129
1129
|
`polyhedron()` and `polygon()` also accept the object directly, and will accept
|
|
1130
1130
|
*any* object carrying the right keys, not just one `render()` produced.
|
|
1131
|
+
`polyhedron()` additionally accepts the bare `[vertices, faces]` 2-list, so a
|
|
1132
|
+
BOSL2 VNF goes straight in — all four of these are the same call:
|
|
1133
|
+
|
|
1134
|
+
```openscad
|
|
1135
|
+
polyhedron(obj); // the object
|
|
1136
|
+
polyhedron(obj.vnf); // the 2-list
|
|
1137
|
+
polyhedron(obj.vertices, obj.faces); // the halves
|
|
1138
|
+
polyhedron(spheroid(d=30)); // any BOSL2 VNF
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
The 2-list form is only considered when `faces` was not given separately, so the
|
|
1142
|
+
two-argument call can never be reinterpreted. The discriminator is BOSL2's own
|
|
1143
|
+
`is_vnf` test — a VNF's second element is a list of *lists*, where a plain points
|
|
1144
|
+
list has a point (bare numbers) there.
|
|
1131
1145
|
|
|
1132
1146
|
### Things that will bite
|
|
1133
1147
|
|
|
@@ -41,7 +41,8 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
|
|
|
41
41
|
// evaluated exactly once (resolving into a CallArgs first and then
|
|
42
42
|
// re-evaluating from the raw list here would run every argument expression
|
|
43
43
|
// twice -- wrong for anything with a side effect, e.g. rands()).
|
|
44
|
-
Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx
|
|
44
|
+
Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx,
|
|
45
|
+
const oscad::ASTNode& node);
|
|
45
46
|
|
|
46
47
|
// The shared merge core builtinObject wraps: given ALREADY-EVALUATED
|
|
47
48
|
// (name-or-nullopt, Value) pairs in exact call-site order, merges them the
|
|
@@ -52,6 +53,7 @@ Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argu
|
|
|
52
53
|
// logic against its own already-evaluated (argNames[i], args[i]) pairs
|
|
53
54
|
// (already in call-site order by construction -- see CallSite::argNames)
|
|
54
55
|
// without re-deriving the merge rules or touching raw AST nodes.
|
|
55
|
-
Value mergeObjectArgs(const std::vector<std::pair<std::optional<std::string>, Value>>& evaluated
|
|
56
|
+
Value mergeObjectArgs(Evaluator& ev, const std::vector<std::pair<std::optional<std::string>, Value>>& evaluated,
|
|
57
|
+
const oscad::Position* pos);
|
|
56
58
|
|
|
57
59
|
} // namespace oscadeval
|
|
@@ -355,6 +355,20 @@ 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
|
+
|
|
358
372
|
// Converts a for()/intersection_for() loop assignment's evaluated RHS into
|
|
359
373
|
// the sequence of values to iterate: undef -> empty, range -> a LAZY
|
|
360
374
|
// sequence (matching OscRange's own start/step/end iteration, half-open
|
|
@@ -380,7 +394,8 @@ using RangeTooManyFn = std::function<void(size_t count)>;
|
|
|
380
394
|
// one with a live consumer (BelfrySCAD) that surfaced it. The count is
|
|
381
395
|
// computed in closed form (not IterableValues::size()'s O(n) walk) so a
|
|
382
396
|
// legitimate huge-but-under-the-limit range never pays an eager pass.
|
|
383
|
-
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany = nullptr
|
|
397
|
+
IterableValues expandIterable(const Value& v, const RangeTooManyFn& onTooMany = nullptr,
|
|
398
|
+
const RangeDirectionFn& onWrongDirection = nullptr);
|
|
384
399
|
|
|
385
400
|
// `each <body>`'s own flatten-one-level rule, shared by the AST interpreter
|
|
386
401
|
// (evalListLiteral/evalListElement's ListCompEach handling, expr_eval.cpp)
|
|
@@ -128,6 +128,8 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
128
128
|
const oscad::Position* pos = &assign->position();
|
|
129
129
|
IterableValues iter = expandIterable(values, [&](size_t count) {
|
|
130
130
|
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);
|
|
131
133
|
});
|
|
132
134
|
for (const Value& val : iter) {
|
|
133
135
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
{openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -454,7 +454,33 @@ bool isBuiltinFunctionName(const std::string& name) {
|
|
|
454
454
|
return names.count(name) > 0;
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
// object(...) argument merging, matching the reference's own semantics and
|
|
458
|
+
// diagnostics (Builtins.cc's builtin_object).
|
|
459
|
+
//
|
|
460
|
+
// An unnamed argument is either another object (its keys are merged in) or
|
|
461
|
+
// a LIST of entries, where each entry is:
|
|
462
|
+
// [key, value] -- set (or overwrite) that key
|
|
463
|
+
// [key] -- DELETE that key
|
|
464
|
+
//
|
|
465
|
+
// The single-element delete form is the part that is easy to miss. Deleting
|
|
466
|
+
// removes the key outright rather than blanking it, so a later re-set
|
|
467
|
+
// appends at the end: object(a, [["b"], ["b", 99]]) puts b last, while
|
|
468
|
+
// object(a, [["b", 99], ["b"]]) has no b at all. That ordering is
|
|
469
|
+
// observable -- ValueObject is insertion-ordered and oscEqual is
|
|
470
|
+
// order-sensitive.
|
|
471
|
+
//
|
|
472
|
+
// Deleting a key that is not there is a silent no-op, as it is upstream.
|
|
473
|
+
// Every malformed entry warns and abandons the whole call (returning undef),
|
|
474
|
+
// stopping at the first one. The warning text is quoted verbatim from the
|
|
475
|
+
// reference, including its own inconsistent spacing -- the "not a list"
|
|
476
|
+
// case really does put spaces inside the parens where the others do not,
|
|
477
|
+
// and the "unnamed argument" case really does end with a trailing space.
|
|
478
|
+
Value mergeObjectArgs(Evaluator& ev, const std::vector<std::pair<std::optional<std::string>, Value>>& evaluated,
|
|
479
|
+
const oscad::Position* pos) {
|
|
480
|
+
static const char* kEntryRules =
|
|
481
|
+
" In an unnamed list, entries must be [key,value] to set or [key] to delete."
|
|
482
|
+
" The key must be <string>.";
|
|
483
|
+
|
|
458
484
|
std::vector<std::pair<std::string, Value>> result;
|
|
459
485
|
const auto setKey = [&](const std::string& k, const Value& v) {
|
|
460
486
|
for (auto& [ek, ev2] : result) {
|
|
@@ -465,30 +491,79 @@ Value mergeObjectArgs(const std::vector<std::pair<std::optional<std::string>, Va
|
|
|
465
491
|
}
|
|
466
492
|
result.emplace_back(k, v);
|
|
467
493
|
};
|
|
468
|
-
|
|
494
|
+
const auto deleteKey = [&](const std::string& k) {
|
|
495
|
+
for (auto it = result.begin(); it != result.end(); ++it) {
|
|
496
|
+
if (it->first == k) {
|
|
497
|
+
result.erase(it);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
// Deleting an absent key is deliberately silent.
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
for (size_t argIdx = 0; argIdx < evaluated.size(); ++argIdx) {
|
|
505
|
+
const auto& [name, v] = evaluated[argIdx];
|
|
469
506
|
if (name) {
|
|
470
507
|
setKey(*name, v);
|
|
471
508
|
continue;
|
|
472
509
|
}
|
|
510
|
+
const std::string argPrefix = "object(Argument " + std::to_string(argIdx) + " ";
|
|
473
511
|
if (const ObjectPtr* o = std::get_if<ObjectPtr>(&v); o && *o) {
|
|
474
512
|
for (const auto& [k, kv] : (*o)->items) setKey(k, kv);
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
} else if (!std::holds_alternative<std::monostate>(v)) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
const ListPtr* l = std::get_if<ListPtr>(&v);
|
|
516
|
+
if (!l || !*l) {
|
|
517
|
+
// undef is accepted and contributes nothing, as upstream.
|
|
518
|
+
if (std::holds_alternative<std::monostate>(v)) continue;
|
|
519
|
+
ev.warn(argPrefix + "<" + oscTypeName(v) + ">) An unnamed argument must be either <object> or"
|
|
520
|
+
" <list>, it is <" + oscTypeName(v) + ">. ",
|
|
521
|
+
pos);
|
|
485
522
|
return Value{};
|
|
486
523
|
}
|
|
524
|
+
for (size_t elemIdx = 0; elemIdx < (*l)->items.size(); ++elemIdx) {
|
|
525
|
+
const Value& entry = (*l)->items[elemIdx];
|
|
526
|
+
const std::string where = "[Element " + std::to_string(elemIdx) + " ";
|
|
527
|
+
const ListPtr* pair = std::get_if<ListPtr>(&entry);
|
|
528
|
+
if (!pair || !*pair) {
|
|
529
|
+
// Note the spaces inside the parens: upstream's own quirk.
|
|
530
|
+
ev.warn("object( Argument " + std::to_string(argIdx) + " " + where + "<" + oscTypeName(entry) +
|
|
531
|
+
">] ) Entry type is not a list, it is <" + oscTypeName(entry) + ">." + kEntryRules,
|
|
532
|
+
pos);
|
|
533
|
+
return Value{};
|
|
534
|
+
}
|
|
535
|
+
const size_t n = (*pair)->items.size();
|
|
536
|
+
if (n == 0) {
|
|
537
|
+
ev.warn(argPrefix + where + "[]]) Entry is empty." + kEntryRules, pos);
|
|
538
|
+
return Value{};
|
|
539
|
+
}
|
|
540
|
+
if (n > 2) {
|
|
541
|
+
ev.warn(argPrefix + where + "[...]]) Entry length is " + std::to_string(n) +
|
|
542
|
+
", must be 1 [key] or 2 [key,value]." + kEntryRules,
|
|
543
|
+
pos);
|
|
544
|
+
return Value{};
|
|
545
|
+
}
|
|
546
|
+
const Value& key = (*pair)->items[0];
|
|
547
|
+
if (!std::holds_alternative<std::string>(key)) {
|
|
548
|
+
const std::string shape = n == 2 ? "[<" + oscTypeName(key) + ">,value]"
|
|
549
|
+
: "[<" + oscTypeName(key) + ">]";
|
|
550
|
+
ev.warn(argPrefix + where + shape + "]) The key of the entry is not <string> but <" +
|
|
551
|
+
oscTypeName(key) + ">." + kEntryRules,
|
|
552
|
+
pos);
|
|
553
|
+
return Value{};
|
|
554
|
+
}
|
|
555
|
+
if (n == 2) {
|
|
556
|
+
setKey(std::get<std::string>(key), (*pair)->items[1]);
|
|
557
|
+
} else {
|
|
558
|
+
deleteKey(std::get<std::string>(key));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
487
561
|
}
|
|
488
562
|
return Value{std::make_shared<const ValueObject>(ValueObject{std::move(result)})};
|
|
489
563
|
}
|
|
490
564
|
|
|
491
|
-
Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx
|
|
565
|
+
Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argument>>& arguments, EvalContext& ctx,
|
|
566
|
+
const oscad::ASTNode& node) {
|
|
492
567
|
std::vector<std::pair<std::optional<std::string>, Value>> evaluated;
|
|
493
568
|
evaluated.reserve(arguments.size());
|
|
494
569
|
for (const auto& argPtr : arguments) {
|
|
@@ -499,7 +574,7 @@ Value builtinObject(Evaluator& ev, const std::vector<std::unique_ptr<oscad::Argu
|
|
|
499
574
|
}
|
|
500
575
|
evaluated.emplace_back(std::move(name), std::move(v));
|
|
501
576
|
}
|
|
502
|
-
return mergeObjectArgs(evaluated);
|
|
577
|
+
return mergeObjectArgs(ev, evaluated, &node.position());
|
|
503
578
|
}
|
|
504
579
|
|
|
505
580
|
namespace {
|
|
@@ -877,7 +952,12 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
|
|
|
877
952
|
}
|
|
878
953
|
if (const OscRange* r = std::get_if<OscRange>(&c)) {
|
|
879
954
|
std::string out;
|
|
880
|
-
|
|
955
|
+
// The reference warns here too -- chr([70:1:65]) is
|
|
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
|
+
});
|
|
960
|
+
for (const Value& item : seq) out += encode(item);
|
|
881
961
|
return out;
|
|
882
962
|
}
|
|
883
963
|
return {};
|
{openscad_cpp_evaluator-0.38.1 → openscad_cpp_evaluator-0.40.0}/src/builtins/primitives_3d.cpp
RENAMED
|
@@ -630,6 +630,37 @@ CSGParams resolvePolyhedron(Evaluator& ev, const oscad::ModularCall& node, EvalC
|
|
|
630
630
|
facesArg = std::move(newFaces);
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
+
// polyhedron(vnf) -- BOSL2's [vertices, faces] 2-list, which is what
|
|
634
|
+
// every BOSL2 function passes around and what obj.vnf holds. Only
|
|
635
|
+
// considered when `faces` was not given separately, so the two-argument
|
|
636
|
+
// form always wins and can never be reinterpreted.
|
|
637
|
+
//
|
|
638
|
+
// The discriminator is BOSL2's own is_vnf test: a VNF's second element
|
|
639
|
+
// is a list of FACES, i.e. a list of lists. A plain points list of
|
|
640
|
+
// length 2 has a point there instead -- bare numbers, not lists -- and
|
|
641
|
+
// is left alone. (Two points cannot describe a polyhedron anyway, so
|
|
642
|
+
// nothing legitimate is being taken over.)
|
|
643
|
+
if (isUndef(facesArg)) {
|
|
644
|
+
if (const ListPtr* outer = std::get_if<ListPtr>(&pointsArg); outer && *outer &&
|
|
645
|
+
(*outer)->items.size() == 2) {
|
|
646
|
+
const ListPtr* maybeVerts = std::get_if<ListPtr>(&(*outer)->items[0]);
|
|
647
|
+
const ListPtr* maybeFaces = std::get_if<ListPtr>(&(*outer)->items[1]);
|
|
648
|
+
const bool facesAreLists =
|
|
649
|
+
maybeFaces && *maybeFaces && !(*maybeFaces)->items.empty() &&
|
|
650
|
+
std::holds_alternative<ListPtr>((*maybeFaces)->items[0]);
|
|
651
|
+
const bool vertsArePoints =
|
|
652
|
+
maybeVerts && *maybeVerts && !(*maybeVerts)->items.empty() &&
|
|
653
|
+
std::holds_alternative<ListPtr>((*maybeVerts)->items[0]);
|
|
654
|
+
if (facesAreLists && vertsArePoints) {
|
|
655
|
+
// Copy before assigning: both borrow into pointsArg's list.
|
|
656
|
+
Value newPoints = (*outer)->items[0];
|
|
657
|
+
Value newFaces = (*outer)->items[1];
|
|
658
|
+
pointsArg = std::move(newPoints);
|
|
659
|
+
facesArg = std::move(newFaces);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
633
664
|
const ListPtr* pointsList = std::get_if<ListPtr>(&pointsArg);
|
|
634
665
|
const ListPtr* facesList = std::get_if<ListPtr>(&facesArg);
|
|
635
666
|
if (!pointsList || !*pointsList || !facesList || !*facesList) {
|
|
@@ -740,6 +740,8 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
740
740
|
il.values = expandIterable(v, [&](size_t count) {
|
|
741
741
|
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")",
|
|
742
742
|
ins.pos);
|
|
743
|
+
}, [&](bool stepPositive) {
|
|
744
|
+
ev.warn(rangeDirectionWarning(stepPositive), ins.pos);
|
|
743
745
|
});
|
|
744
746
|
il.index = 0;
|
|
745
747
|
il.total = il.values.size();
|
|
@@ -787,7 +789,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
787
789
|
std::vector<std::pair<std::optional<std::string>, Value>> pairs;
|
|
788
790
|
pairs.reserve(argCount);
|
|
789
791
|
for (size_t i = 0; i < argCount; ++i) pairs.emplace_back(site.argNames[i], std::move(args[i]));
|
|
790
|
-
f.stack.push_back(mergeObjectArgs(pairs));
|
|
792
|
+
f.stack.push_back(mergeObjectArgs(ev, pairs, &site.callNode->position()));
|
|
791
793
|
++f.pc;
|
|
792
794
|
} else if (site.isBuiltin) {
|
|
793
795
|
CallArgs callArgs = buildCallArgs(site, args, argCount);
|
|
@@ -1464,6 +1466,8 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1464
1466
|
il.values = expandIterable(v, [&](size_t count) {
|
|
1465
1467
|
ev.warn("Bad range parameter in for statement: too many elements (" + std::to_string(count) + ")",
|
|
1466
1468
|
ins.pos);
|
|
1469
|
+
}, [&](bool stepPositive) {
|
|
1470
|
+
ev.warn(rangeDirectionWarning(stepPositive), ins.pos);
|
|
1467
1471
|
});
|
|
1468
1472
|
il.index = 0;
|
|
1469
1473
|
il.total = il.values.size();
|
|
@@ -177,6 +177,8 @@ 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);
|
|
180
182
|
});
|
|
181
183
|
for (const Value& val : iter) {
|
|
182
184
|
EvalContext childCtx = parentCtx.letChildCtx();
|
|
@@ -112,6 +112,8 @@ 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);
|
|
115
117
|
});
|
|
116
118
|
for (const Value& val : iter) {
|
|
117
119
|
EvalContext childCtx = parentCtx.childCtx(nullptr, std::nullopt, ctx.childrenNodes, ctx.childrenCallerCtx);
|
|
@@ -886,7 +886,7 @@ Value Evaluator::evalFunctionCall(const oscad::PrimaryCall& node, EvalContext& c
|
|
|
886
886
|
// call-site interleaved order (see builtinObject's own
|
|
887
887
|
// comment) -- called directly, before resolveArgs, so
|
|
888
888
|
// arguments aren't evaluated twice.
|
|
889
|
-
if (leftId->name == "object") return builtinObject(*this, node.arguments, ctx);
|
|
889
|
+
if (leftId->name == "object") return builtinObject(*this, node.arguments, ctx, node);
|
|
890
890
|
CallArgs args = resolveArgs(*this, node.arguments, ctx);
|
|
891
891
|
return evalBuiltinFunction(*this, leftId->name, args, node);
|
|
892
892
|
}
|
|
@@ -984,7 +984,6 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
984
984
|
// filtered statement may produce 0 bodies, which would shift every
|
|
985
985
|
// subsequent body-index lookup, so the Nth statement is evaluated
|
|
986
986
|
// directly instead.
|
|
987
|
-
const int idx = static_cast<int>(toDoubleLenient(idxArg));
|
|
988
987
|
std::vector<const oscad::ASTNode*> geoNodes;
|
|
989
988
|
for (const oscad::ASTNode* c : *ctx.childrenNodes) {
|
|
990
989
|
if (c->kind() != oscad::NodeKind::Assignment && c->kind() != oscad::NodeKind::ModuleDeclaration &&
|
|
@@ -992,8 +991,59 @@ std::optional<Evaluator::ChildrenForward> Evaluator::prepareChildrenForward(cons
|
|
|
992
991
|
geoNodes.push_back(c);
|
|
993
992
|
}
|
|
994
993
|
}
|
|
995
|
-
|
|
996
|
-
|
|
994
|
+
|
|
995
|
+
// The argument is a number, a VECTOR of numbers, or a RANGE --
|
|
996
|
+
// children([3:1:5]) is children(3); children(4); children(5), and
|
|
997
|
+
// children([3:-1:1]) is 3, 2, 1 in that order. Only a plain number was
|
|
998
|
+
// handled before, and toDoubleLenient collapses a list or a range to 0,
|
|
999
|
+
// so every vector/range form silently rendered child 0 instead.
|
|
1000
|
+
//
|
|
1001
|
+
// Ranges go through expandIterable, the same path a for-loop uses, so
|
|
1002
|
+
// step direction, fractional steps and naturally-empty ranges all
|
|
1003
|
+
// behave identically in both places rather than growing a second
|
|
1004
|
+
// interpretation here.
|
|
1005
|
+
std::vector<Value> indexValues;
|
|
1006
|
+
if (std::holds_alternative<double>(idxArg)) {
|
|
1007
|
+
indexValues.push_back(idxArg);
|
|
1008
|
+
} else if (std::holds_alternative<ListPtr>(idxArg) || std::holds_alternative<OscRange>(idxArg)) {
|
|
1009
|
+
const IterableValues iter = expandIterable(idxArg, nullptr, [&](bool stepPositive) {
|
|
1010
|
+
warn(rangeDirectionWarning(stepPositive), currentWarnEntry());
|
|
1011
|
+
});
|
|
1012
|
+
for (const Value& v : iter) indexValues.push_back(v);
|
|
1013
|
+
} else {
|
|
1014
|
+
warn("Bad parameter type (" + fmtValue(idxArg) +
|
|
1015
|
+
") for children, only accept: empty, number, vector, range.",
|
|
1016
|
+
currentWarnEntry());
|
|
1017
|
+
return std::nullopt;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// Order is preserved and duplicates are kept: children([2,2,2]) really
|
|
1021
|
+
// does evaluate child 2 three times, and the order shows through in the
|
|
1022
|
+
// CSG tree even though a union usually hides it.
|
|
1023
|
+
std::vector<const oscad::ASTNode*> picked;
|
|
1024
|
+
picked.reserve(indexValues.size());
|
|
1025
|
+
for (const Value& v : indexValues) {
|
|
1026
|
+
if (!std::holds_alternative<double>(v)) {
|
|
1027
|
+
warn("Bad parameter type (" + fmtValue(v) +
|
|
1028
|
+
") for children, only accept: empty, number, vector, range.",
|
|
1029
|
+
currentWarnEntry());
|
|
1030
|
+
return std::nullopt;
|
|
1031
|
+
}
|
|
1032
|
+
// Truncates, matching the reference: children([1.7]) is child 1.
|
|
1033
|
+
const long long idx = static_cast<long long>(std::get<double>(v));
|
|
1034
|
+
if (idx < 0 || static_cast<size_t>(idx) >= geoNodes.size()) {
|
|
1035
|
+
// An out-of-range index is skipped, not fatal -- children([0,99])
|
|
1036
|
+
// still draws child 0. Warned about either way; this used to
|
|
1037
|
+
// return silently.
|
|
1038
|
+
warn("Children index (" + fmtValue(v) + ") out of bounds (" +
|
|
1039
|
+
std::to_string(geoNodes.size()) + " children)",
|
|
1040
|
+
currentWarnEntry());
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
picked.push_back(geoNodes[static_cast<size_t>(idx)]);
|
|
1044
|
+
}
|
|
1045
|
+
if (picked.empty()) return std::nullopt;
|
|
1046
|
+
return ChildrenForward{std::move(evalCtx), std::move(picked)};
|
|
997
1047
|
}
|
|
998
1048
|
|
|
999
1049
|
void Evaluator::builtinChildren(const CallArgs& args, EvalContext& ctx) {
|
|
@@ -490,13 +490,30 @@ 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
|
-
|
|
493
|
+
std::string rangeDirectionWarning(bool stepPositive) {
|
|
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) {
|
|
494
500
|
if (std::holds_alternative<std::monostate>(v)) return IterableValues{};
|
|
495
501
|
if (const OscRange* r = std::get_if<OscRange>(&v)) {
|
|
496
502
|
if (const std::optional<size_t> count = rangeElementCount(*r); count && *count >= 1'000'000) {
|
|
497
503
|
if (onTooMany) onTooMany(*count);
|
|
498
504
|
return IterableValues{};
|
|
499
505
|
}
|
|
506
|
+
// A step pointing away from the end yields nothing. That is almost
|
|
507
|
+
// always a typo -- [1:0] where [1:-1:0] was meant -- so the
|
|
508
|
+
// reference says so rather than silently running zero times.
|
|
509
|
+
//
|
|
510
|
+
// A zero step is deliberately NOT reported here: it is a different
|
|
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
517
|
// Lazy -- IterableValues itself reproduces this exact
|
|
501
518
|
// termination condition (a zero step is naturally empty: neither
|
|
502
519
|
// `x <= end` nor `x >= end` branch ever fires for it) without
|