openscad-cpp-evaluator 1.41.0__tar.gz → 1.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-1.41.0 → openscad_cpp_evaluator-1.42.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode.hpp +14 -46
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/evaluator.hpp +26 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/value.hpp +3 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/control.cpp +1 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/function_builtins.cpp +116 -62
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/bytecode_compiler.cpp +38 -80
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/bytecode_vm.cpp +9 -28
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/eval_context.cpp +2 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/expr_eval.cpp +51 -25
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/stmt_eval.cpp +36 -15
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/text/freetype_font_provider.cpp +18 -3
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/user_calls.cpp +38 -29
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/value.cpp +94 -39
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_bytecode_compiler.cpp +10 -7
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_control_flow.cpp +10 -3
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_eval_context.cpp +2 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_expr_eval.cpp +3 -6
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_openscad_parity.cpp +113 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/uv.lock +1 -1
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/cmake/patch_manifold.cmake +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/import/scene_import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/xkcd_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/xkcd_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_discretizer.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_undef_args.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/main.cpp +0 -0
|
@@ -43,6 +43,7 @@ enum class Op {
|
|
|
43
43
|
StoreLocal, // a = slot index (pops)
|
|
44
44
|
LoadDyn, // a = name pool index ($-prefixed)
|
|
45
45
|
StoreDyn, // a = name pool index (pops; also marks dynExplicit)
|
|
46
|
+
WarnDuplicateLet, // a = name pool index (pops; warns, binds nothing -- see Evaluator::warnDuplicateLet)
|
|
46
47
|
LoadFree, // a = name pool index -- Evaluator::evalIdentifier fallback (warnIfUndef=true)
|
|
47
48
|
// Same as LoadFree, but Evaluator::evalIdentifier's warnIfUndef=false --
|
|
48
49
|
// only ever emitted for a PrimaryCall's own callee probe (bytecode_
|
|
@@ -240,20 +241,6 @@ enum class Op {
|
|
|
240
241
|
// there's no branch to emit here).
|
|
241
242
|
Echo,
|
|
242
243
|
|
|
243
|
-
// Only ever emitted for a non-empty-argument AssertOp (see
|
|
244
|
-
// bytecode_compiler.cpp's own AssertOp case -- a zero-argument
|
|
245
|
-
// assert() is unconditionally true and compiles straight through with
|
|
246
|
-
// no check at all). Reached only on the condition-false path (guarded
|
|
247
|
-
// by a JumpIfTrue the compiler emits around it, mirroring LogicalOrOp's
|
|
248
|
-
// own jump-then-patch shape) -- always throws via Evaluator::error(),
|
|
249
|
-
// i.e. [[noreturn]] at runtime. a = 1 if a message Value was compiled
|
|
250
|
-
// and pushed (pop it), else 0. b = constant-pool index of condText
|
|
251
|
-
// (the condition expression's own source text, interned ONCE at
|
|
252
|
-
// compile time via its toString() -- cheaper than the interpreter,
|
|
253
|
-
// which recomputes this on every failing call). pos/node: same
|
|
254
|
-
// Evaluator::error() TRACE-walk need CheckIterLimit already has.
|
|
255
|
-
AssertFail,
|
|
256
|
-
|
|
257
244
|
// -- Module-body compilation (Stage 2) --------------------------------
|
|
258
245
|
// A call to a user module resolved to a specific ModuleDeclaration AT
|
|
259
246
|
// COMPILE TIME (see CompiledChunk::ModuleCallSite) -- the module-side
|
|
@@ -717,16 +704,10 @@ enum class Op {
|
|
|
717
704
|
StoreLetVar,
|
|
718
705
|
|
|
719
706
|
// a = index into CompiledChunk::assertSites. Pops site.argCount values
|
|
720
|
-
// (
|
|
721
|
-
// source order
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
// Evaluator::evalAssertStatement exactly: named "condition"/"message"
|
|
725
|
-
// win over positional 0/1 (resolved at COMPILE time into
|
|
726
|
-
// AssertSite::conditionArgIndex/messageArgIndex -- the argument SHAPE
|
|
727
|
-
// is static, only values vary per call), throws via Evaluator::error()
|
|
728
|
-
// on failure, otherwise runs any chained node.children natively (rare;
|
|
729
|
-
// not worth its own compiled path -- see AssertSite's own doc comment).
|
|
707
|
+
// (every argument of an assert() statement or expression, pushed in
|
|
708
|
+
// source order) and hands them to Evaluator::checkAssert; a statement
|
|
709
|
+
// then runs any chained children natively (rare; not worth its own
|
|
710
|
+
// compiled path).
|
|
730
711
|
AssertStatement,
|
|
731
712
|
// a = nativeStatements index of the AST node whose arm this is. Emitted
|
|
732
713
|
// only when the Evaluator was built with coverage on (compile-time
|
|
@@ -763,6 +744,10 @@ struct Instruction {
|
|
|
763
744
|
// applyDefaults()'s existing sibling-isolated defaultCtx; empty if that
|
|
764
745
|
// parameter has no default. `bodyCode` is the function's own expression body.
|
|
765
746
|
struct CompiledChunk {
|
|
747
|
+
// String literals whose text holds an escape OpenSCAD calls undefined,
|
|
748
|
+
// with how many: the Evaluator warns for them once, when the chunk is
|
|
749
|
+
// compiled (it has the warning channel; the compiler does not).
|
|
750
|
+
std::vector<std::pair<const oscad::StringLiteral*, int>> undefinedEscapeLiterals;
|
|
766
751
|
struct Param {
|
|
767
752
|
std::string name;
|
|
768
753
|
int slot = 0; // unused when isDyn is true -- $-params are never slot-addressed
|
|
@@ -1036,30 +1021,13 @@ struct CompiledChunk {
|
|
|
1036
1021
|
const oscad::ASTNode* node = nullptr;
|
|
1037
1022
|
};
|
|
1038
1023
|
|
|
1039
|
-
// One Op::AssertStatement site
|
|
1040
|
-
//
|
|
1041
|
-
// into the site's own argCount-sized popped-argument array (source
|
|
1042
|
-
// order), resolved at COMPILE time via the same "named wins over
|
|
1043
|
-
// positional 0/1" priority Evaluator::getArg applies at runtime --
|
|
1044
|
-
// nullopt means "no argument supplies this logical parameter" (mirrors
|
|
1045
|
-
// getArg's own defaultValue fallback: absent condition reads as
|
|
1046
|
-
// `Value{true}`, absent message means no ": ..." suffix).
|
|
1047
|
-
// `condTextConstIdx`: constants[] index of the condition argument's own
|
|
1048
|
-
// source text (or "false" when no condition argument exists, matching
|
|
1049
|
-
// evalAssertStatement's `node.arguments.empty() ? "false" : ...`),
|
|
1050
|
-
// interned once at compile time. `node`: for both Evaluator::error()'s
|
|
1051
|
-
// TRACE walk and the (rare) chained-children fallback below.
|
|
1052
|
-
//
|
|
1053
|
-
// ponytail: a script with TWO named args of the SAME name (e.g.
|
|
1054
|
-
// `assert(condition=true, condition=false)`) would resolve to the
|
|
1055
|
-
// LAST one here, not getArg's own first-match; not worth the extra
|
|
1056
|
-
// bookkeeping to fix for input that's already nonsensical.
|
|
1024
|
+
// One Op::AssertStatement site. `statement` is null for the expression
|
|
1025
|
+
// form, which has no children.
|
|
1057
1026
|
struct AssertSite {
|
|
1058
1027
|
int argCount = 0;
|
|
1059
|
-
std::
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const oscad::ModularAssert* node = nullptr;
|
|
1028
|
+
const std::vector<std::unique_ptr<oscad::Argument>>* arguments = nullptr;
|
|
1029
|
+
const oscad::ASTNode* node = nullptr;
|
|
1030
|
+
const oscad::ModularAssert* statement = nullptr;
|
|
1063
1031
|
};
|
|
1064
1032
|
|
|
1065
1033
|
// Every distinct chunk this SPECIFIC CompiledChunk owns is either a
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
#include "openscad_cpp_evaluator/bound_args.hpp"
|
|
4
4
|
#include "openscad_cpp_evaluator/bytecode.hpp"
|
|
5
|
+
|
|
6
|
+
#include <unordered_set>
|
|
5
7
|
#include "openscad_cpp_evaluator/bytecode_vm.hpp"
|
|
6
8
|
#include "openscad_cpp_evaluator/call_args.hpp"
|
|
7
9
|
#include "openscad_cpp_evaluator/csg_node.hpp"
|
|
@@ -557,6 +559,30 @@ public:
|
|
|
557
559
|
// Public: builtins/import.cpp's not-manifold warning is emitted from a
|
|
558
560
|
// free function, same reasoning as tagGenerated()/builtinChildren().
|
|
559
561
|
void warn(const std::string& message, const oscad::Position* position);
|
|
562
|
+
// OpenSCAD's lexer warns "Undefined escape sequence" once per bad escape
|
|
563
|
+
// in the source. This warns for a literal the first time it is
|
|
564
|
+
// evaluated or compiled, and never again for that literal.
|
|
565
|
+
void warnUndefinedEscapes(const oscad::StringLiteral& lit, int count);
|
|
566
|
+
// let() keeps the FIRST binding of a repeated name: OpenSCAD evaluates
|
|
567
|
+
// the later right-hand side, warns with its value, and discards it.
|
|
568
|
+
// OpenSCAD's Assert::performAssert, given every argument's value in
|
|
569
|
+
// source order -- it evaluates them all, pass or fail, so a passing
|
|
570
|
+
// `assert(true, nosuch)` still warns. Warns about unexpected arguments;
|
|
571
|
+
// throws via error() when the condition is false or missing (`assert()`
|
|
572
|
+
// fails). The message prints as echo() would print it.
|
|
573
|
+
void checkAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const std::vector<Value>& values,
|
|
574
|
+
const oscad::ASTNode& node);
|
|
575
|
+
void warnDuplicateLet(const std::string& name, const Value& v, const oscad::Position* position);
|
|
576
|
+
template <typename Assignments>
|
|
577
|
+
static bool repeatsEarlierLetName(const Assignments& assignments, size_t i) {
|
|
578
|
+
for (size_t j = 0; j < i; ++j)
|
|
579
|
+
if (assignments[j]->name->name == assignments[i]->name->name) return true;
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
std::unordered_set<const oscad::StringLiteral*> undefinedEscapesWarned_;
|
|
583
|
+
void warnUndefinedEscapes(const CompiledChunk& chunk) {
|
|
584
|
+
for (const auto& [lit, n] : chunk.undefinedEscapeLiterals) warnUndefinedEscapes(*lit, n);
|
|
585
|
+
}
|
|
560
586
|
// Hands one already-formatted warning line to echoFn_, recording it in
|
|
561
587
|
// warnCapture first when one is active. Every warning path goes through
|
|
562
588
|
// here, including a ManifoldCache hit replaying a cached line.
|
|
@@ -306,7 +306,9 @@ std::string formatNumber(double v);
|
|
|
306
306
|
//
|
|
307
307
|
// A trailing lone backslash is kept as itself. It can only occur in an
|
|
308
308
|
// unterminated literal, which is a parse error long before this runs.
|
|
309
|
-
|
|
309
|
+
// `undefinedEscapes`, when given, counts the escapes OpenSCAD's lexer calls
|
|
310
|
+
// undefined (it warns once for each).
|
|
311
|
+
std::string unescapeStringLiteral(const std::string& raw, int* undefinedEscapes = nullptr);
|
|
310
312
|
|
|
311
313
|
// echo()/str()/assert-message display format: "undef" | "true"/"false" |
|
|
312
314
|
// "[start : step : end]" (range) | formatNumber() (number) | "[e1, e2, ...]"
|
|
@@ -118,6 +118,7 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
|
|
|
118
118
|
// needs `i` visible in `j`'s own range expression).
|
|
119
119
|
std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
|
|
120
120
|
if (depth == node.assignments.size()) {
|
|
121
|
+
if (depth == 0) return; // for() with no loop variables iterates zero times in OpenSCAD, not once.
|
|
121
122
|
// One body-entry marker per full cartesian-product iteration
|
|
122
123
|
// and nothing per individual variable binding (unlike
|
|
123
124
|
// evalFor) -- mirrors _resolve_intersection_for's single
|
{openscad_cpp_evaluator-1.41.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -246,23 +246,6 @@ Value builtinPow(double a, double b) {
|
|
|
246
246
|
|
|
247
247
|
// -- cross/rands/search/lookup --------------------------------------------
|
|
248
248
|
|
|
249
|
-
Value builtinCross(const Value& aArg, const Value& bArg) {
|
|
250
|
-
const auto a = allNumericList(aArg);
|
|
251
|
-
const auto b = allNumericList(bArg);
|
|
252
|
-
if (!a || !b) return Value{};
|
|
253
|
-
for (double x : *a) {
|
|
254
|
-
if (!std::isfinite(x)) return Value{};
|
|
255
|
-
}
|
|
256
|
-
for (double x : *b) {
|
|
257
|
-
if (!std::isfinite(x)) return Value{};
|
|
258
|
-
}
|
|
259
|
-
if (a->size() == 2 && b->size() == 2) return Value{(*a)[0] * (*b)[1] - (*a)[1] * (*b)[0]};
|
|
260
|
-
if (a->size() == 3 && b->size() == 3) {
|
|
261
|
-
return numList({(*a)[1] * (*b)[2] - (*a)[2] * (*b)[1], (*a)[2] * (*b)[0] - (*a)[0] * (*b)[2],
|
|
262
|
-
(*a)[0] * (*b)[1] - (*a)[1] * (*b)[0]});
|
|
263
|
-
}
|
|
264
|
-
return Value{};
|
|
265
|
-
}
|
|
266
249
|
|
|
267
250
|
// -- linear_solve(A, b) --------------------------------------------------
|
|
268
251
|
//
|
|
@@ -784,36 +767,49 @@ Value builtinSearch(const CallArgs& args, Evaluator& ev, const oscad::Position*
|
|
|
784
767
|
return Value{};
|
|
785
768
|
}
|
|
786
769
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
770
|
+
// upstream builtin_lookup, line for line: a non-finite key warns; the
|
|
771
|
+
// first row must be exactly two numbers or the answer is undef; later rows
|
|
772
|
+
// that aren't are skipped; the low/high candidates are picked in table
|
|
773
|
+
// order (the first of equal keys wins), then interpolated. This used to
|
|
774
|
+
// sort the table, coerce malformed rows, and accept inf/nan keys silently.
|
|
775
|
+
Value builtinLookup(Evaluator& ev, const CallArgs& args, const oscad::Position* pos) {
|
|
792
776
|
const Value keyArg = getArg(args, 0, "key", Value{});
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (!tablePtr || !*tablePtr) return Value{};
|
|
798
|
-
|
|
799
|
-
std::vector<std::pair<double, double>> pairs;
|
|
800
|
-
for (const Value& row : (*tablePtr)->items) {
|
|
801
|
-
const ListPtr* rowPtr = std::get_if<ListPtr>(&row);
|
|
802
|
-
if (!rowPtr || !*rowPtr || (*rowPtr)->items.size() < 2) continue;
|
|
803
|
-
pairs.emplace_back(toDoubleLenient((*rowPtr)->items[0]), toDoubleLenient((*rowPtr)->items[1]));
|
|
777
|
+
const double p = std::get<double>(keyArg); // checkBuiltinArgs: a number
|
|
778
|
+
if (!std::isfinite(p)) {
|
|
779
|
+
ev.warn("lookup(" + fmtValue(keyArg) + ", ...) first argument is not a number", pos);
|
|
780
|
+
return Value{};
|
|
804
781
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
const double
|
|
811
|
-
if (
|
|
812
|
-
|
|
813
|
-
|
|
782
|
+
const auto& vec = std::get<ListPtr>(getArg(args, 1, "table", Value{}))->items; // checkBuiltinArgs: a vector
|
|
783
|
+
const auto vec2 = [](const Value& v, double& a, double& b) {
|
|
784
|
+
const ListPtr* l = std::get_if<ListPtr>(&v);
|
|
785
|
+
if (!l || !*l || (*l)->items.size() != 2) return false;
|
|
786
|
+
const double* x = std::get_if<double>(&(*l)->items[0]);
|
|
787
|
+
const double* y = std::get_if<double>(&(*l)->items[1]);
|
|
788
|
+
if (!x || !y) return false;
|
|
789
|
+
a = *x;
|
|
790
|
+
b = *y;
|
|
791
|
+
return true;
|
|
792
|
+
};
|
|
793
|
+
double lowP, lowV, highP, highV;
|
|
794
|
+
if (vec.empty() || !vec2(vec[0], lowP, lowV)) return Value{};
|
|
795
|
+
highP = lowP;
|
|
796
|
+
highV = lowV;
|
|
797
|
+
for (size_t k = 1; k < vec.size(); ++k) {
|
|
798
|
+
double thisP, thisV;
|
|
799
|
+
if (!vec2(vec[k], thisP, thisV)) continue;
|
|
800
|
+
if (thisP <= p && (thisP > lowP || lowP > p)) {
|
|
801
|
+
lowP = thisP;
|
|
802
|
+
lowV = thisV;
|
|
803
|
+
}
|
|
804
|
+
if (thisP >= p && (thisP < highP || highP < p)) {
|
|
805
|
+
highP = thisP;
|
|
806
|
+
highV = thisV;
|
|
814
807
|
}
|
|
815
808
|
}
|
|
816
|
-
return Value{
|
|
809
|
+
if (p <= lowP) return Value{highV};
|
|
810
|
+
if (p >= highP) return Value{lowV};
|
|
811
|
+
const double f = (p - lowP) / (highP - lowP);
|
|
812
|
+
return Value{highV * f + lowV * (1 - f)};
|
|
817
813
|
}
|
|
818
814
|
|
|
819
815
|
std::string asStringOr(const Value& v, const std::string& fallback) {
|
|
@@ -1155,12 +1151,14 @@ const std::unordered_map<int, BuiltinCheck>& builtinChecks() {
|
|
|
1155
1151
|
std::unordered_map<int, BuiltinCheck> m;
|
|
1156
1152
|
const auto add = [&m](BuiltinFnId id, BuiltinCheck c) { m.emplace(static_cast<int>(id), std::move(c)); };
|
|
1157
1153
|
for (BuiltinFnId id : {BuiltinFnId::Abs, BuiltinFnId::Sign, BuiltinFnId::Ceil, BuiltinFnId::Floor,
|
|
1158
|
-
BuiltinFnId::Round, BuiltinFnId::Sqrt, BuiltinFnId::Ln,
|
|
1154
|
+
BuiltinFnId::Round, BuiltinFnId::Sqrt, BuiltinFnId::Ln,
|
|
1159
1155
|
BuiltinFnId::Exp, BuiltinFnId::Sin, BuiltinFnId::Cos, BuiltinFnId::Tan,
|
|
1160
1156
|
BuiltinFnId::Asin, BuiltinFnId::Acos, BuiltinFnId::Atan}) {
|
|
1161
1157
|
add(id, {1, 1, "1", {kNum}});
|
|
1162
1158
|
}
|
|
1163
1159
|
add(BuiltinFnId::Atan2, {2, 2, "2", {kNum, kNum}});
|
|
1160
|
+
// log(x) or log(base, x); upstream's count warning names 2.
|
|
1161
|
+
add(BuiltinFnId::Log, {1, 2, "2", {kNum, kNum}});
|
|
1164
1162
|
add(BuiltinFnId::Pow, {2, 2, "2", {kNum, kNum}});
|
|
1165
1163
|
add(BuiltinFnId::Cross, {2, 2, "2", {kVec, kVec}});
|
|
1166
1164
|
add(BuiltinFnId::Lookup, {2, 2, "2", {kNum, kVec}});
|
|
@@ -1275,6 +1273,9 @@ BuiltinFnId builtinFnIdFor(const std::string& name) {
|
|
|
1275
1273
|
return it == ids.end() ? BuiltinFnId::None : it->second;
|
|
1276
1274
|
}
|
|
1277
1275
|
|
|
1276
|
+
Value evalBuiltinFunctionInOrder(Evaluator& ev, BuiltinFnId id, const std::string& name, const CallArgs& args,
|
|
1277
|
+
const oscad::ASTNode& node);
|
|
1278
|
+
|
|
1278
1279
|
Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs& args, const oscad::ASTNode& node) {
|
|
1279
1280
|
return evalBuiltinFunctionResolved(ev, builtinFnIdFor(name), builtinParamNames(name), name, args, node);
|
|
1280
1281
|
}
|
|
@@ -1297,6 +1298,36 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1297
1298
|
}
|
|
1298
1299
|
}
|
|
1299
1300
|
|
|
1301
|
+
// Every other builtin function reads its arguments IN ORDER and ignores
|
|
1302
|
+
// their names, exactly as upstream's builtin_* functions index
|
|
1303
|
+
// `arguments[i]`: sin(a=90) is sin(90), pow(y=3, x=2) is 3^2, and
|
|
1304
|
+
// rands(0, 1, 2, seed_value=5) is seeded. Names used to bind by this
|
|
1305
|
+
// port's own spelling and drop the rest silently -- sin(a=90) was 0,
|
|
1306
|
+
// concat(a=[1], b=[2]) was [], rands(seed_value=) went unseeded.
|
|
1307
|
+
// (textmetrics/fontmetrics -- with declaredParams -- and dxf_dim/
|
|
1308
|
+
// dxf_cross parse names upstream, through Parameters::parse.)
|
|
1309
|
+
const bool byName = declaredParams || id == BuiltinFnId::DxfDim || id == BuiltinFnId::DxfCross;
|
|
1310
|
+
CallArgs ordered;
|
|
1311
|
+
if (!byName && node.kind() == oscad::NodeKind::PrimaryCall && !args.named.empty()) {
|
|
1312
|
+
int k = 0, out = 0;
|
|
1313
|
+
for (const auto& a : static_cast<const oscad::PrimaryCall&>(node).arguments) {
|
|
1314
|
+
const Value* v = nullptr;
|
|
1315
|
+
if (a->kind() == oscad::NodeKind::PositionalArgument) {
|
|
1316
|
+
v = args.findPositional(k++);
|
|
1317
|
+
} else {
|
|
1318
|
+
const std::string& n = static_cast<const oscad::NamedArgument&>(*a).name->name;
|
|
1319
|
+
if (isConfigVariable(n)) continue; // a $-override, not an argument
|
|
1320
|
+
v = args.findNamed(n);
|
|
1321
|
+
}
|
|
1322
|
+
ordered.setPositional(out++, v ? *v : Value{});
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
const CallArgs& argsInOrder = (!byName && !args.named.empty()) ? ordered : args;
|
|
1326
|
+
return evalBuiltinFunctionInOrder(ev, id, name, argsInOrder, node);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
Value evalBuiltinFunctionInOrder(Evaluator& ev, BuiltinFnId id, const std::string& name, const CallArgs& args,
|
|
1330
|
+
const oscad::ASTNode& node) {
|
|
1300
1331
|
// Arity and argument types, with the reference's own two diagnostics.
|
|
1301
1332
|
// This replaced a silent version of the same gate (scalarNumericArity /
|
|
1302
1333
|
// numericOnlyNames), which returned undef without ever saying why.
|
|
@@ -1321,8 +1352,10 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1321
1352
|
}
|
|
1322
1353
|
case BuiltinFnId::Round: {
|
|
1323
1354
|
const double x = toDoubleLenient(getArg(args, 0, "x", Value{}));
|
|
1324
|
-
|
|
1325
|
-
|
|
1355
|
+
// std::round, as upstream: halves away from zero, exactly. The
|
|
1356
|
+
// floor(x + 0.5) this was rounded 0.49999999999999994 up to 1
|
|
1357
|
+
// (the sum rounds to 1.0) and broke integers above 2^52.
|
|
1358
|
+
return Value{std::round(x)};
|
|
1326
1359
|
}
|
|
1327
1360
|
case BuiltinFnId::Sqrt: {
|
|
1328
1361
|
const double x = toDoubleLenient(getArg(args, 0, "x", Value{}));
|
|
@@ -1334,9 +1367,13 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1334
1367
|
return Value{x < 0 ? std::numeric_limits<double>::quiet_NaN() : std::log(x)};
|
|
1335
1368
|
}
|
|
1336
1369
|
case BuiltinFnId::Log: {
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1370
|
+
// upstream builtin_log: log(y) / log(base), base 10 by default --
|
|
1371
|
+
// that formula, not log10(), so results agree to the last bit.
|
|
1372
|
+
// The two-argument form was missing (log(2, 8) was undef).
|
|
1373
|
+
const bool twoArgs = positionalCount(args) == 2;
|
|
1374
|
+
const double base = twoArgs ? toDoubleLenient(getArg(args, 0, "base", Value{})) : 10.0;
|
|
1375
|
+
const double y = toDoubleLenient(getArg(args, twoArgs ? 1 : 0, "x", Value{}));
|
|
1376
|
+
return Value{std::log(y) / std::log(base)};
|
|
1340
1377
|
}
|
|
1341
1378
|
case BuiltinFnId::Exp: return Value{std::exp(toDoubleLenient(getArg(args, 0, "x", Value{})))};
|
|
1342
1379
|
case BuiltinFnId::Sin: return Value{sinDegrees(toDoubleLenient(getArg(args, 0, "x", Value{})))};
|
|
@@ -1371,25 +1408,42 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1371
1408
|
return Value{std::sqrt(sum)};
|
|
1372
1409
|
}
|
|
1373
1410
|
case BuiltinFnId::Cross: {
|
|
1411
|
+
// upstream builtin_cross, check for check: two 2-vectors are
|
|
1412
|
+
// multiplied as they are (a non-number counts as 0, inf and nan
|
|
1413
|
+
// propagate -- no checks at all); otherwise both must be
|
|
1414
|
+
// 3-vectors, and each element pair is checked in order for a
|
|
1415
|
+
// non-number, then NaN, then infinity, each with its own warning.
|
|
1374
1416
|
const Value a = getArg(args, 0, "a", Value{});
|
|
1375
1417
|
const Value b = getArg(args, 1, "b", Value{});
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
return (l && *l) ? (*l)->items.size() : size_t{0};
|
|
1418
|
+
const auto& va = std::get<ListPtr>(a)->items;
|
|
1419
|
+
const auto& vb = std::get<ListPtr>(b)->items;
|
|
1420
|
+
const auto num = [](const Value& v) {
|
|
1421
|
+
const double* d = std::get_if<double>(&v);
|
|
1422
|
+
return d ? *d : 0.0;
|
|
1382
1423
|
};
|
|
1383
|
-
|
|
1384
|
-
if (
|
|
1424
|
+
if (va.size() == 2 && vb.size() == 2) return Value{num(va[0]) * num(vb[1]) - num(va[1]) * num(vb[0])};
|
|
1425
|
+
if (va.size() != 3 || vb.size() != 3) {
|
|
1385
1426
|
ev.warn("Invalid vector size of parameter for cross()", &node.position());
|
|
1386
1427
|
return Value{};
|
|
1387
1428
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1429
|
+
for (size_t k = 0; k < 3; ++k) {
|
|
1430
|
+
if (!std::holds_alternative<double>(va[k]) || !std::holds_alternative<double>(vb[k])) {
|
|
1431
|
+
ev.warn("Invalid value in parameter vector for cross()", &node.position());
|
|
1432
|
+
return Value{};
|
|
1433
|
+
}
|
|
1434
|
+
const double d0 = std::get<double>(va[k]), d1 = std::get<double>(vb[k]);
|
|
1435
|
+
if (std::isnan(d0) || std::isnan(d1)) {
|
|
1436
|
+
ev.warn("Invalid value (NaN) in parameter vector for cross()", &node.position());
|
|
1437
|
+
return Value{};
|
|
1438
|
+
}
|
|
1439
|
+
if (std::isinf(d0) || std::isinf(d1)) {
|
|
1440
|
+
ev.warn("Invalid value (INF) in parameter vector for cross()", &node.position());
|
|
1441
|
+
return Value{};
|
|
1442
|
+
}
|
|
1391
1443
|
}
|
|
1392
|
-
return
|
|
1444
|
+
return numList({num(va[1]) * num(vb[2]) - num(va[2]) * num(vb[1]),
|
|
1445
|
+
num(va[2]) * num(vb[0]) - num(va[0]) * num(vb[2]),
|
|
1446
|
+
num(va[0]) * num(vb[1]) - num(va[1]) * num(vb[0])});
|
|
1393
1447
|
}
|
|
1394
1448
|
case BuiltinFnId::Rands: {
|
|
1395
1449
|
ev.noteRandsCall();
|
|
@@ -1493,7 +1547,7 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1493
1547
|
return Value{std::holds_alternative<ObjectPtr>(x) && std::get<ObjectPtr>(x) != nullptr};
|
|
1494
1548
|
}
|
|
1495
1549
|
case BuiltinFnId::Search: return builtinSearch(args, ev, &node.position());
|
|
1496
|
-
case BuiltinFnId::Lookup: return builtinLookup(args);
|
|
1550
|
+
case BuiltinFnId::Lookup: return builtinLookup(ev, args, &node.position());
|
|
1497
1551
|
case BuiltinFnId::HasKey: {
|
|
1498
1552
|
const Value objArg = getArg(args, 0, "object", Value{});
|
|
1499
1553
|
const ObjectPtr* obj = std::get_if<ObjectPtr>(&objArg);
|
|
@@ -404,13 +404,14 @@ public:
|
|
|
404
404
|
case NodeKind::BooleanLiteral:
|
|
405
405
|
out.push_back({Op::PushBool, static_cast<const oscad::BooleanLiteral&>(node).val ? 1 : 0, 0, nullptr});
|
|
406
406
|
return;
|
|
407
|
-
case NodeKind::StringLiteral:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
407
|
+
case NodeKind::StringLiteral: {
|
|
408
|
+
const auto& lit = static_cast<const oscad::StringLiteral&>(node);
|
|
409
|
+
int undefinedEscapes = 0;
|
|
410
|
+
Value v{unescapeStringLiteral(lit.val, &undefinedEscapes)};
|
|
411
|
+
if (undefinedEscapes) chunk_.undefinedEscapeLiterals.emplace_back(&lit, undefinedEscapes);
|
|
412
|
+
out.push_back({Op::PushConst, internConst(std::move(v)), 0, nullptr});
|
|
413
413
|
return;
|
|
414
|
+
}
|
|
414
415
|
case NodeKind::UndefinedLiteral:
|
|
415
416
|
out.push_back({Op::PushConst, internConst(Value{}), 0, nullptr});
|
|
416
417
|
return;
|
|
@@ -797,7 +798,7 @@ public:
|
|
|
797
798
|
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
798
799
|
const auto& assign = n.assignments[i];
|
|
799
800
|
const std::string& name = assign->name->name;
|
|
800
|
-
if (name.empty() || name[0] == '$') continue;
|
|
801
|
+
if (name.empty() || name[0] == '$' || Evaluator::repeatsEarlierLetName(n.assignments, i)) continue;
|
|
801
802
|
if (auto candidates = collectLetrecCandidateLiterals(*assign->expr)) {
|
|
802
803
|
letrecSlot[i] = declareLocal(scope, name);
|
|
803
804
|
letrecCandidates[i] = std::move(*candidates);
|
|
@@ -860,7 +861,9 @@ public:
|
|
|
860
861
|
}
|
|
861
862
|
}
|
|
862
863
|
}
|
|
863
|
-
if (
|
|
864
|
+
if (Evaluator::repeatsEarlierLetName(n.assignments, i)) {
|
|
865
|
+
out.push_back({Op::WarnDuplicateLet, internName(name), 0, &n.position()});
|
|
866
|
+
} else if (!name.empty() && name[0] == '$') {
|
|
864
867
|
out.push_back({Op::StoreDyn, internName(name), 0, &assign->position()});
|
|
865
868
|
} else {
|
|
866
869
|
int slot = selfBinding ? preDeclaredSlot : declareLocal(scope, name);
|
|
@@ -910,37 +913,17 @@ public:
|
|
|
910
913
|
}
|
|
911
914
|
|
|
912
915
|
case NodeKind::AssertOp: {
|
|
916
|
+
// Every argument is evaluated, pass or fail, as OpenSCAD
|
|
917
|
+
// does -- see Evaluator::checkAssert.
|
|
913
918
|
auto& n = static_cast<const oscad::AssertOp&>(node);
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}
|
|
923
|
-
compileExpr(*argExpr(*n.arguments[0]), out, scope); // condition, never tail
|
|
924
|
-
size_t jumpPassed = out.size();
|
|
925
|
-
out.push_back({Op::JumpIfTrue, 0, 0, nullptr});
|
|
926
|
-
const bool hasMessage = n.arguments.size() > 1;
|
|
927
|
-
// Lazily compiled: only reachable on the condition-false
|
|
928
|
-
// path (guarded by the JumpIfTrue above) -- mirrors
|
|
929
|
-
// evalAssertExpr's own lazy evaluation of the message
|
|
930
|
-
// argument exactly (only evaluated when the assertion
|
|
931
|
-
// actually fails). Slot resolution is unaffected by which
|
|
932
|
-
// runtime path reaches this code -- CompileScope is purely
|
|
933
|
-
// a compile-time name/index table, same as every other
|
|
934
|
-
// conditionally-executed branch this compiler already
|
|
935
|
-
// handles (Ternary, LogicalAnd/Or, ListCompIf).
|
|
936
|
-
if (hasMessage) compileExpr(*argExpr(*n.arguments[1]), out, scope); // message, never tail
|
|
937
|
-
// Precomputed ONCE at compile time (cheaper than the
|
|
938
|
-
// interpreter, which recomputes this on every failing
|
|
939
|
-
// call) -- toString() is a pure, ctx-free AST-to-text
|
|
940
|
-
// operation.
|
|
941
|
-
int condTextIdx = internConst(Value{argExpr(*n.arguments[0])->toString()});
|
|
942
|
-
out.push_back({Op::AssertFail, hasMessage ? 1 : 0, condTextIdx, &n.position(), &n});
|
|
943
|
-
out[jumpPassed].a = static_cast<int>(out.size());
|
|
919
|
+
CompiledChunk::AssertSite site;
|
|
920
|
+
site.node = &n;
|
|
921
|
+
site.arguments = &n.arguments;
|
|
922
|
+
site.argCount = static_cast<int>(n.arguments.size());
|
|
923
|
+
for (const auto& arg : n.arguments) compileExpr(*argExpr(*arg), out, scope); // never tail
|
|
924
|
+
int siteIdx = static_cast<int>(chunk_.assertSites.size());
|
|
925
|
+
chunk_.assertSites.push_back(std::move(site));
|
|
926
|
+
out.push_back({Op::AssertStatement, siteIdx, 0, &n.position()});
|
|
944
927
|
compileExpr(*n.body, out, scope, tail);
|
|
945
928
|
return;
|
|
946
929
|
}
|
|
@@ -1202,10 +1185,13 @@ public:
|
|
|
1202
1185
|
size_t placeholderIdx = out.size();
|
|
1203
1186
|
out.push_back({Op::OpenLocalScope, 0, 0, nullptr});
|
|
1204
1187
|
int slotStart = nextSlot_;
|
|
1205
|
-
for (
|
|
1188
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
1189
|
+
const auto& assign = n.assignments[i];
|
|
1206
1190
|
compileExpr(*assign->expr, out, scope);
|
|
1207
1191
|
const std::string& name = assign->name->name;
|
|
1208
|
-
if (
|
|
1192
|
+
if (Evaluator::repeatsEarlierLetName(n.assignments, i)) {
|
|
1193
|
+
out.push_back({Op::WarnDuplicateLet, internName(name), 0, &n.position()});
|
|
1194
|
+
} else if (!name.empty() && name[0] == '$') {
|
|
1209
1195
|
out.push_back({Op::StoreDyn, internName(name), 0, &assign->position()});
|
|
1210
1196
|
} else {
|
|
1211
1197
|
int slot = declareLocal(scope, name);
|
|
@@ -1488,6 +1474,7 @@ public:
|
|
|
1488
1474
|
const size_t numDims = n.assignments.size();
|
|
1489
1475
|
std::function<void(size_t)> emitDim = [&](size_t d) {
|
|
1490
1476
|
if (d == numDims) {
|
|
1477
|
+
if (d == 0) return; // for() with no loop variables iterates zero times in OpenSCAD, not once.
|
|
1491
1478
|
if (!n.body.empty()) {
|
|
1492
1479
|
out.push_back({Op::NativeCheckDebugExprLevel, internNativeStatement(n.body.front().get()), 0, nullptr});
|
|
1493
1480
|
}
|
|
@@ -1612,50 +1599,16 @@ public:
|
|
|
1612
1599
|
return;
|
|
1613
1600
|
}
|
|
1614
1601
|
case NodeKind::ModularAssert: {
|
|
1615
|
-
//
|
|
1616
|
-
// form (Op::AssertFail): the statement form supports named
|
|
1617
|
-
// arguments AND evaluates every argument EAGERLY (mirrors
|
|
1618
|
-
// Evaluator::evalAssertStatement's own resolveArgs() call
|
|
1619
|
-
// exactly -- unlike AssertOp's lazily-compiled message,
|
|
1620
|
-
// guarded by a runtime JumpIfTrue), so every argument is
|
|
1621
|
-
// compiled+pushed here unconditionally, in source order.
|
|
1602
|
+
// Like AssertOp's compiled form, plus chained children.
|
|
1622
1603
|
auto& n = static_cast<const oscad::ModularAssert&>(stmt);
|
|
1623
1604
|
out.push_back({Op::CheckDebugStatement, internNativeStatement(&stmt), 0, nullptr});
|
|
1624
1605
|
CompiledChunk::AssertSite site;
|
|
1625
1606
|
site.node = &n;
|
|
1607
|
+
site.statement = &n;
|
|
1608
|
+
site.arguments = &n.arguments;
|
|
1626
1609
|
site.argCount = static_cast<int>(n.arguments.size());
|
|
1627
1610
|
CompileScope exprScope;
|
|
1628
|
-
for (
|
|
1629
|
-
compileIsolatedExpr(*argExpr(*n.arguments[i]), out, exprScope);
|
|
1630
|
-
if (n.arguments[i]->kind() == NodeKind::NamedArgument) {
|
|
1631
|
-
auto& na = static_cast<const oscad::NamedArgument&>(*n.arguments[i]);
|
|
1632
|
-
if (na.name->name == "condition") site.conditionArgIndex = static_cast<int>(i);
|
|
1633
|
-
else if (na.name->name == "message") site.messageArgIndex = static_cast<int>(i);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
// Second pass: positional 0/1 fill whichever logical
|
|
1637
|
-
// parameter a named arg didn't already claim -- run AFTER
|
|
1638
|
-
// the named pass above (not interleaved) so a named arg
|
|
1639
|
-
// wins regardless of its position relative to its
|
|
1640
|
-
// positional counterpart in source, matching
|
|
1641
|
-
// Evaluator::getArg's own "named first" priority exactly.
|
|
1642
|
-
int posCounter = 0;
|
|
1643
|
-
for (size_t i = 0; i < n.arguments.size(); ++i) {
|
|
1644
|
-
if (n.arguments[i]->kind() == NodeKind::NamedArgument) continue;
|
|
1645
|
-
if (posCounter == 0 && !site.conditionArgIndex) site.conditionArgIndex = static_cast<int>(i);
|
|
1646
|
-
else if (posCounter == 1 && !site.messageArgIndex) site.messageArgIndex = static_cast<int>(i);
|
|
1647
|
-
++posCounter;
|
|
1648
|
-
}
|
|
1649
|
-
// Precomputed once, like AssertFail's own condText --
|
|
1650
|
-
// mirrors evalAssertStatement's `node.arguments.empty() ?
|
|
1651
|
-
// "false" : argExpr(*node.arguments[0])->toString()`
|
|
1652
|
-
// exactly (a MISSING condition arg -- e.g. a bare
|
|
1653
|
-
// `assert(message="x");` -- reads the same as an EMPTY
|
|
1654
|
-
// arg list here: no arg supplies "condition" either way).
|
|
1655
|
-
site.condTextConstIdx = internConst(Value{
|
|
1656
|
-
site.conditionArgIndex
|
|
1657
|
-
? argExpr(*n.arguments[static_cast<size_t>(*site.conditionArgIndex)])->toString()
|
|
1658
|
-
: std::string("false")});
|
|
1611
|
+
for (const auto& arg : n.arguments) compileIsolatedExpr(*argExpr(*arg), out, exprScope);
|
|
1659
1612
|
int siteIdx = static_cast<int>(chunk_.assertSites.size());
|
|
1660
1613
|
chunk_.assertSites.push_back(std::move(site));
|
|
1661
1614
|
out.push_back({Op::AssertStatement, siteIdx, 0, &n.position()});
|
|
@@ -1683,10 +1636,14 @@ public:
|
|
|
1683
1636
|
auto& n = static_cast<const oscad::ModularLet&>(stmt);
|
|
1684
1637
|
CompileScope exprScope;
|
|
1685
1638
|
out.push_back({Op::OpenLetScope, 0, 0, nullptr});
|
|
1686
|
-
for (
|
|
1639
|
+
for (size_t i = 0; i < n.assignments.size(); ++i) {
|
|
1640
|
+
const auto& assign = n.assignments[i];
|
|
1687
1641
|
out.push_back({Op::CheckDebugStatement, internNativeStatement(assign.get()), 0, nullptr});
|
|
1688
1642
|
compileIsolatedExpr(*assign->expr, out, exprScope);
|
|
1689
|
-
|
|
1643
|
+
if (Evaluator::repeatsEarlierLetName(n.assignments, i))
|
|
1644
|
+
out.push_back({Op::WarnDuplicateLet, internName(assign->name->name), 0, &n.position()});
|
|
1645
|
+
else
|
|
1646
|
+
out.push_back({Op::StoreLetVar, internName(assign->name->name), 0, &assign->position()});
|
|
1690
1647
|
}
|
|
1691
1648
|
compileStatementList(n.children, out);
|
|
1692
1649
|
out.push_back({Op::CloseExprScope, 0, 0, nullptr});
|
|
@@ -1897,6 +1854,7 @@ public:
|
|
|
1897
1854
|
const size_t numDims = n.assignments.size();
|
|
1898
1855
|
std::function<void(size_t)> emitDim = [&](size_t d) {
|
|
1899
1856
|
if (d == numDims) {
|
|
1857
|
+
if (d == 0) return; // for() with no loop variables iterates zero times in OpenSCAD, not once.
|
|
1900
1858
|
const oscad::ASTNode* marker = n.body.empty() ? static_cast<const oscad::ASTNode*>(&n) : n.body.front().get();
|
|
1901
1859
|
out.push_back({Op::NativeCheckDebugExprLevel, internNativeStatement(marker), 0, nullptr});
|
|
1902
1860
|
compileStatementList(n.body, out);
|