openscad-cpp-evaluator 1.44.0__tar.gz → 1.45.1__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.
Files changed (234) hide show
  1. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode.hpp +27 -18
  3. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/evaluator.hpp +14 -7
  4. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/pyproject.toml +1 -1
  5. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/function_builtins.cpp +5 -3
  6. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/roof.cpp +81 -20
  7. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/bytecode_compiler.cpp +40 -20
  8. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/bytecode_vm.cpp +16 -8
  9. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/expr_eval.cpp +1 -3
  10. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/stmt_eval.cpp +59 -21
  11. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/user_calls.cpp +1 -3
  12. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/value.cpp +43 -12
  13. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_bytecode_compiler.cpp +81 -7
  14. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_extrude_roof.cpp +79 -2
  15. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_openscad_parity.cpp +5 -3
  16. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_value.cpp +22 -0
  17. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/uv.lock +1 -1
  18. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/.github/workflows/ci.yml +0 -0
  19. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/.github/workflows/wheels.yml +0 -0
  20. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/.gitignore +0 -0
  21. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/.gitmodules +0 -0
  22. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/CLAUDE.md +0 -0
  23. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/CMakeLists.txt +0 -0
  24. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/LICENSE +0 -0
  25. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/README.md +0 -0
  26. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/bindings/CMakeLists.txt +0 -0
  27. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/bindings/ast_to_py.cpp +0 -0
  28. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/bindings/module.cpp +0 -0
  29. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/cmake/embed_font.cmake +0 -0
  30. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/cmake/patch_manifold.cmake +0 -0
  31. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/examples/CMakeLists.txt +0 -0
  32. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/examples/eval_perf_benchmark.cpp +0 -0
  33. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/examples/manifold_cache_reuse.cpp +0 -0
  34. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/examples/minimal_debugger.cpp +0 -0
  35. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  36. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/.gitignore +0 -0
  37. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  38. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  39. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/LICENSE +0 -0
  40. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/README.md +0 -0
  41. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  42. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  43. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  44. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  45. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  46. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  47. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  48. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  49. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  50. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  51. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  52. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  53. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  54. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  55. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  56. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  57. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  58. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  59. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/api.cpp +0 -0
  60. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  61. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  62. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  63. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  64. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  65. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  66. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  67. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  68. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  69. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  70. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  71. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  72. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  73. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  74. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  75. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  76. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/position.cpp +0 -0
  77. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  78. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  79. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  80. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  81. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  82. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  83. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  84. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  85. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  86. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  87. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  88. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  89. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  90. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  91. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  92. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  93. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  94. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  95. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  96. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  97. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  98. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  99. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  100. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  101. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  102. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  103. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  104. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  105. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  106. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  107. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  108. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  109. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  110. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  111. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  112. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  113. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  114. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  115. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  116. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  117. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  118. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  119. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  120. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  121. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  122. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  123. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/export.hpp +0 -0
  124. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  125. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  126. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  127. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  128. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  129. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  130. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  131. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  132. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  133. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  134. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  135. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  136. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  137. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  138. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  139. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  140. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/value.hpp +0 -0
  141. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  142. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/python/openscad_cpp_evaluator/__init__.py +0 -0
  143. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LICENSE +0 -0
  144. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  145. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  146. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  147. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  148. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/CMakeLists.txt +0 -0
  149. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/booleans.cpp +0 -0
  150. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/builtins.hpp +0 -0
  151. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/call_args.cpp +0 -0
  152. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/color.cpp +0 -0
  153. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/control.cpp +0 -0
  154. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/dxf_dim.cpp +0 -0
  155. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/extrude.cpp +0 -0
  156. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/import.cpp +0 -0
  157. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/modifiers.cpp +0 -0
  158. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/primitives_2d.cpp +0 -0
  159. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/primitives_3d.cpp +0 -0
  160. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/profile_time.cpp +0 -0
  161. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/registry.cpp +0 -0
  162. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/segments.cpp +0 -0
  163. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/surface.cpp +0 -0
  164. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/text.cpp +0 -0
  165. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/topology.cpp +0 -0
  166. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/transforms.cpp +0 -0
  167. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/colored_body.cpp +0 -0
  168. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/coverage.cpp +0 -0
  169. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/csg_generate.cpp +0 -0
  170. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/csg_resolve.cpp +0 -0
  171. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/css_colors.cpp +0 -0
  172. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/debug/debug_repl.cpp +0 -0
  173. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/debug_profile.cpp +0 -0
  174. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/eval_context.cpp +0 -0
  175. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/eval_error.cpp +0 -0
  176. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/eval_use.cpp +0 -0
  177. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/export.cpp +0 -0
  178. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/format_closure.cpp +0 -0
  179. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/import/dxf_import.cpp +0 -0
  180. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/import/mesh_import.cpp +0 -0
  181. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/import/scene_import.cpp +0 -0
  182. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/import/surface_load.cpp +0 -0
  183. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/import/svg_import.cpp +0 -0
  184. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/manifold_cache.cpp +0 -0
  185. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/measure_geometry.cpp +0 -0
  186. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/mesh_check.cpp +0 -0
  187. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/text/font_match.cpp +0 -0
  188. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/text/freetype_font_provider.cpp +0 -0
  189. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/text/text_metrics.cpp +0 -0
  190. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/utf8.cpp +0 -0
  191. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/xkcd_colors.cpp +0 -0
  192. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/xkcd_colors.hpp +0 -0
  193. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/src/zip_stored.cpp +0 -0
  194. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/CMakeLists.txt +0 -0
  195. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_booleans.cpp +0 -0
  196. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_children_separate.cpp +0 -0
  197. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_cli.cpp +0 -0
  198. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_control_flow.cpp +0 -0
  199. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_coverage.cpp +0 -0
  200. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_csg_tree.cpp +0 -0
  201. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_debug_hooks.cpp +0 -0
  202. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_discretizer.cpp +0 -0
  203. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_dxf_svg_import.cpp +0 -0
  204. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_eval_context.cpp +0 -0
  205. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_export.cpp +0 -0
  206. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_expr_eval.cpp +0 -0
  207. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_feature_detection.cpp +0 -0
  208. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_function_builtins.cpp +0 -0
  209. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_helpers.hpp +0 -0
  210. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_import_export.cpp +0 -0
  211. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_include_cache.cpp +0 -0
  212. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_manifold_cache.cpp +0 -0
  213. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_mesh_check.cpp +0 -0
  214. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_multi_color_merge.cpp +0 -0
  215. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_primitives.cpp +0 -0
  216. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_profile_time.cpp +0 -0
  217. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_profiling.cpp +0 -0
  218. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_python_bindings.py +0 -0
  219. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_render_expr.cpp +0 -0
  220. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_scope_trail.cpp +0 -0
  221. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_scoping.cpp +0 -0
  222. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_surface.cpp +0 -0
  223. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_tail_calls.cpp +0 -0
  224. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_text.cpp +0 -0
  225. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_transforms.cpp +0 -0
  226. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_undef_args.cpp +0 -0
  227. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_unexpected_args.cpp +0 -0
  228. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_use.cpp +0 -0
  229. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_viewport_params.cpp +0 -0
  230. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tests/test_zip_stored.cpp +0 -0
  231. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/CMakeLists.txt +0 -0
  232. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/cli_lib.cpp +0 -0
  233. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/cli_lib.hpp +0 -0
  234. {openscad_cpp_evaluator-1.44.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/main.cpp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.44.0
3
+ Version: 1.45.1
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT AND OFL-1.1
@@ -505,7 +505,7 @@ enum class Op {
505
505
  // anything compileStatementList doesn't give its own real bytecode.
506
506
  // (Assignment/ModularEcho/ModularAssert/ModularLet used to fall here
507
507
  // too; they now have their own real bytecode -- Op::StoreModuleVar/
508
- // Op::Echo/Op::AssertStatement/Op::OpenLetScope+StoreLetVar -- purely
508
+ // Op::Echo/Op::AssertPass+AssertFail/Op::OpenLetScope+StoreLetVar -- purely
509
509
  // a throughput change, since none of these were ever the recursion-
510
510
  // depth risk this compiler targets. `#`/`%`/`!` modifiers and
511
511
  // translate/rotate/scale/mirror/multmatrix/resize/color used to fall
@@ -634,14 +634,9 @@ enum class Op {
634
634
  // the position recorded into dynPositions).
635
635
  StoreModuleVar,
636
636
 
637
- // ModularEcho/ModularAssert's own statement form share Op::Echo/a
638
- // dedicated AssertStatement op (below) for the "pop N already-compiled
639
- // argument values" mechanics -- see those ops' own doc comments
640
- // (Op::Echo, above; Op::AssertStatement, below) for why the
641
- // EXPRESSION-form opcodes are directly reusable (statement-shaped
642
- // already: no value pushed, straight fall-through) while assert's
643
- // needs its own op (named-argument support + eager-not-lazy message
644
- // evaluation, both genuinely different from AssertOp's own contract).
637
+ // ModularEcho/ModularAssert's own statement form share Op::Echo and
638
+ // Op::AssertPass/AssertFail (below) with the expression forms: both are
639
+ // statement-shaped already (no value pushed, straight fall-through).
645
640
 
646
641
  // Isolates ONE inline-compiled sub-expression's own `$`-writes from the
647
642
  // rest of this chunk's shared, long-lived ctx -- pushes ctx.
@@ -697,12 +692,15 @@ enum class Op {
697
692
  // the handler itself, kept for consistency/future debugging only).
698
693
  StoreLetVar,
699
694
 
700
- // a = index into CompiledChunk::assertSites. Pops site.argCount values
701
- // (every argument of an assert() statement or expression, pushed in
702
- // source order) and hands them to Evaluator::checkAssert; a statement
703
- // then runs any chained children natively (rare; not worth its own
704
- // compiled path).
705
- AssertStatement,
695
+ // assert(): the condition is compiled first, then JumpIfFalse to the
696
+ // failure path; the passing path never evaluates any other argument
697
+ // (see Evaluator::evalAssert). a = index into CompiledChunk::assertSites.
698
+ // AssertPass prints the site's unexpected-argument warnings and runs a
699
+ // statement's chained children; it is emitted only when the site has
700
+ // either. AssertFail pops every non-condition argument (source order)
701
+ // and throws via Evaluator::failAssert.
702
+ AssertPass,
703
+ AssertFail,
706
704
  // a = nativeStatements index of the AST node whose arm this is. Emitted
707
705
  // only when the Evaluator was built with coverage on (compile-time
708
706
  // flag, and chunks are per-Evaluator): Evaluator::coverHit(node), nothing
@@ -711,6 +709,17 @@ enum class Op {
711
709
  Cover,
712
710
  };
713
711
 
712
+ // Which of an assert() call's arguments are its condition and message, and
713
+ // whether the call has any unexpected argument to warn about -- all fixed by
714
+ // the call's shape, so worked out once per call site (assertLayout,
715
+ // stmt_eval.cpp). -1 = not given.
716
+ struct AssertLayout {
717
+ int cond = -1;
718
+ int msg = -1;
719
+ bool warns = false;
720
+ };
721
+ AssertLayout assertLayout(const std::vector<std::unique_ptr<oscad::Argument>>& arguments);
722
+
714
723
  struct Instruction {
715
724
  Op op;
716
725
  int a = 0;
@@ -1014,10 +1023,10 @@ struct CompiledChunk {
1014
1023
  const oscad::ASTNode* node = nullptr;
1015
1024
  };
1016
1025
 
1017
- // One Op::AssertStatement site. `statement` is null for the expression
1018
- // form, which has no children.
1026
+ // One Op::AssertPass/AssertFail site. `statement` is null for the
1027
+ // expression form, which has no children.
1019
1028
  struct AssertSite {
1020
- int argCount = 0;
1029
+ AssertLayout layout;
1021
1030
  const std::vector<std::unique_ptr<oscad::Argument>>* arguments = nullptr;
1022
1031
  const oscad::ASTNode* node = nullptr;
1023
1032
  const oscad::ModularAssert* statement = nullptr;
@@ -565,13 +565,20 @@ public:
565
565
  void warnUndefinedEscapes(const oscad::StringLiteral& lit, int count);
566
566
  // let() keeps the FIRST binding of a repeated name: OpenSCAD evaluates
567
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);
568
+ // assert(), interpreted: the condition first, and only on failure the
569
+ // message and any other argument -- see the definition (stmt_eval.cpp)
570
+ // for why this deliberately diverges from OpenSCAD. `maybeCompiled`
571
+ // picks evalExprMaybeCompiled (statement form) over evalExpr.
572
+ void evalAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const oscad::ASTNode& node,
573
+ EvalContext& ctx, bool maybeCompiled);
574
+ // The unexpected-argument warnings, which a passing assert still prints.
575
+ void warnAssertArgs(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const AssertLayout& layout);
576
+ // A failed (or condition-less) assert, once every non-condition argument
577
+ // has been evaluated: warns about unexpected arguments, then throws via
578
+ // error(). `message` is null when none was given; it prints as echo()
579
+ // would print it.
580
+ [[noreturn]] void failAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments,
581
+ const AssertLayout& layout, const Value* message, const oscad::ASTNode& node);
575
582
  void warnDuplicateLet(const std::string& name, const Value& v, const oscad::Position* position);
576
583
  template <typename Assignments>
577
584
  static bool repeatsEarlierLetName(const Assignments& assignments, size_t i) {
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.44.0"
7
+ version = "1.45.1"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1242,9 +1242,12 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
1242
1242
  // was 0, concat(a=[1], b=[2]) was [], rands(seed_value=) went unseeded.
1243
1243
  // (textmetrics/fontmetrics -- with declaredParams -- and dxf_dim/
1244
1244
  // dxf_cross bind by name in OpenSCAD too.)
1245
+ // The common all-positional call goes straight through, with no
1246
+ // reordered copy built (or destroyed) on its way.
1245
1247
  const bool byName = declaredParams || id == BuiltinFnId::DxfDim || id == BuiltinFnId::DxfCross;
1248
+ if (byName || args.named.empty()) return evalBuiltinFunctionInOrder(ev, id, name, args, node);
1246
1249
  CallArgs ordered;
1247
- if (!byName && node.kind() == oscad::NodeKind::PrimaryCall && !args.named.empty()) {
1250
+ if (node.kind() == oscad::NodeKind::PrimaryCall) {
1248
1251
  int k = 0, out = 0;
1249
1252
  for (const auto& a : static_cast<const oscad::PrimaryCall&>(node).arguments) {
1250
1253
  const Value* v = nullptr;
@@ -1258,8 +1261,7 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
1258
1261
  ordered.setPositional(out++, v ? *v : Value{});
1259
1262
  }
1260
1263
  }
1261
- const CallArgs& argsInOrder = (!byName && !args.named.empty()) ? ordered : args;
1262
- return evalBuiltinFunctionInOrder(ev, id, name, argsInOrder, node);
1264
+ return evalBuiltinFunctionInOrder(ev, id, name, ordered, node);
1263
1265
  }
1264
1266
 
1265
1267
  Value evalBuiltinFunctionInOrder(Evaluator& ev, BuiltinFnId id, const std::string& name, const CallArgs& args,
@@ -114,10 +114,35 @@ class RoofMesh {
114
114
  }
115
115
  }
116
116
 
117
+ // A vertex no triangle uses -- the far end of an unbounded Voronoi edge
118
+ // outside the outline can lie 10^12 away -- would stretch the bounding
119
+ // box Manifold sizes its tolerance by, and its cleanup would then
120
+ // collapse the whole roof; such vertices are left out. (Only when one
121
+ // lies well beyond the rest: renumbering reorders the output, and one
122
+ // nearer changes the tolerance by no more than a few times.)
117
123
  manifold::Manifold build() {
118
124
  mesh_.numProp = 3;
125
+ const size_t n = mesh_.vertProperties.size() / 3;
126
+ std::vector<bool> used(n, false);
119
127
  for (const auto& t : triangles_) {
120
- for (int i : t) mesh_.triVerts.push_back(static_cast<uint64_t>(i));
128
+ for (int i : t) used[i] = true;
129
+ }
130
+ manifold::Box box;
131
+ for (size_t i = 0; i < n; ++i) {
132
+ if (used[i]) box.Union(manifold::vec3(mesh_.vertProperties[3 * i], mesh_.vertProperties[3 * i + 1], mesh_.vertProperties[3 * i + 2]));
133
+ }
134
+ std::vector<uint64_t> to(n);
135
+ std::vector<double> kept;
136
+ bool stray = false;
137
+ for (size_t i = 0; i < n; ++i) {
138
+ const manifold::vec3 p(mesh_.vertProperties[3 * i], mesh_.vertProperties[3 * i + 1], mesh_.vertProperties[3 * i + 2]);
139
+ stray = stray || (!used[i] && la::maxelem(la::abs(p)) > 16 * box.Scale());
140
+ to[i] = kept.size() / 3;
141
+ if (used[i]) kept.insert(kept.end(), {p.x, p.y, p.z});
142
+ }
143
+ if (stray) mesh_.vertProperties = std::move(kept);
144
+ for (const auto& t : triangles_) {
145
+ for (int i : t) mesh_.triVerts.push_back(stray ? to[i] : static_cast<uint64_t>(i));
121
146
  }
122
147
  manifold::Manifold body(mesh_);
123
148
  if (body.Status() == manifold::Manifold::Error::NoError) return body;
@@ -991,16 +1016,17 @@ void dropSpikes(std::vector<Vec2>& c) {
991
1016
  }
992
1017
  }
993
1018
 
994
- // The outline of `cs` snapped to a grid of 2^30 steps across its largest
995
- // coordinate, with repeated and straight corners dropped. Sets `toGrid`.
996
- std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, double& toGrid) {
1019
+ // The outline of `cs` snapped to a grid of 2^(bits+1) steps across its
1020
+ // largest coordinate, with repeated and straight corners dropped. Sets
1021
+ // `toGrid`.
1022
+ std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, double& toGrid, int bits = 29) {
997
1023
  const manifold::Polygons polys = cs.ToPolygons();
998
1024
  double extent = 0;
999
1025
  for (const auto& poly : polys) {
1000
1026
  for (Vec2 p : poly) extent = std::max({extent, std::abs(p.x), std::abs(p.y)});
1001
1027
  }
1002
1028
  if (!(extent > 0) || !std::isfinite(extent)) return {};
1003
- toGrid = std::ldexp(1.0, 29 - std::ilogb(extent));
1029
+ toGrid = std::ldexp(1.0, bits - std::ilogb(extent));
1004
1030
 
1005
1031
  std::vector<std::vector<Vec2>> contours;
1006
1032
  for (const auto& poly : polys) {
@@ -1016,17 +1042,6 @@ std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, do
1016
1042
  return contours;
1017
1043
  }
1018
1044
 
1019
- // The roof solid over `cs` (its floor at z = 0), discretizing curved parts
1020
- // by `fa`/`fs`.
1021
- manifold::Manifold voronoiRoof(const manifold::CrossSection& cs, double fa, double fs) {
1022
- double toGrid = 1;
1023
- std::vector<std::vector<Vec2>> contours = gridContours(cs, toGrid);
1024
- if (contours.empty()) return manifold::Manifold();
1025
- // $fa/$fs below 0.01 would ask for unbounded detail (computeRoofParams
1026
- // has already clamped them, warning).
1027
- return RoofBuilder(std::move(contours), 1 / toGrid, std::max(fa, 0.01), std::max(fs, 0.01)).build();
1028
- }
1029
-
1030
1045
  // The outline welded where it touches itself: a union can leave pieces
1031
1046
  // that share an edge, or a hole against the outline, as outlines a hairline
1032
1047
  // apart, crossing at nothing Clipper can see. Each corner within kWeld of
@@ -1062,8 +1077,11 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1062
1077
  }
1063
1078
  }
1064
1079
  }
1065
- // ponytail: every corner against every edge, O(n^2); a grid of edges
1066
- // when outlines of tens of thousands of corners matter.
1080
+ // Each edge looks only at the corners in its x range.
1081
+ // ponytail: still O(n^2) for an outline of long edges all spanning one
1082
+ // x range; a grid of edges if that ever matters.
1083
+ const auto byX = [](Vec2 p, Vec2 q) { return p.x != q.x ? p.x < q.x : p.y < q.y; };
1084
+ std::sort(corners.begin(), corners.end(), byX);
1067
1085
  Clipper2Lib::Paths64 paths;
1068
1086
  for (const auto& c : contours) {
1069
1087
  Clipper2Lib::Path64 path;
@@ -1074,8 +1092,10 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1074
1092
  if (len == 0) continue;
1075
1093
  const Vec2 lo = la::min(a, b) - kWeld, hi = la::max(a, b) + kWeld;
1076
1094
  std::vector<std::pair<double, Vec2>> on;
1077
- for (Vec2 q : corners) {
1078
- if (q.x < lo.x || q.y < lo.y || q.x > hi.x || q.y > hi.y || q == a || q == b) continue;
1095
+ for (auto it = std::lower_bound(corners.begin(), corners.end(), Vec2{lo.x, -std::numeric_limits<double>::infinity()}, byX);
1096
+ it != corners.end() && it->x <= hi.x; ++it) {
1097
+ const Vec2 q = *it;
1098
+ if (q.y < lo.y || q.y > hi.y || q == a || q == b) continue;
1079
1099
  const double t = la::dot(q - a, d) / len;
1080
1100
  if (t > 0 && t < len && std::abs(cross2(d, q - a)) / len <= kWeld) on.push_back({t, q});
1081
1101
  }
@@ -1095,6 +1115,47 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1095
1115
  return welded;
1096
1116
  }
1097
1117
 
1118
+ // Each contour rotated to start at its least corner, and the contours sorted:
1119
+ // equal for two outlines that differ only in where Clipper starts them.
1120
+ std::vector<std::vector<Vec2>> canonical(std::vector<std::vector<Vec2>> contours) {
1121
+ const auto less = [](Vec2 a, Vec2 b) { return a.x != b.x ? a.x < b.x : a.y < b.y; };
1122
+ for (auto& c : contours) std::rotate(c.begin(), std::min_element(c.begin(), c.end(), less), c.end());
1123
+ std::sort(contours.begin(), contours.end(), [&](const auto& a, const auto& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), less); });
1124
+ return contours;
1125
+ }
1126
+
1127
+ // The roof solid over `cs` (its floor at z = 0), discretizing curved parts
1128
+ // by `fa`/`fs`.
1129
+ //
1130
+ // Boost's Voronoi builder needs segments that meet only at their ends. A
1131
+ // union's pieces sharing an edge come back as outlines a hairline apart,
1132
+ // which on the grid overlap or cross: the diagram comes out wrong, or the
1133
+ // builder never finishes, allocating without bound. So the outline is
1134
+ // welded first, as for the straight skeleton.
1135
+ //
1136
+ // Even on valid input the builder occasionally gets a near-degenerate
1137
+ // configuration wrong -- a cell left with no finite edges, where four sites
1138
+ // are all but equidistant once the outline is rounded to the grid -- and the
1139
+ // facets built from it do not close. Rounding to a coarser grid perturbs
1140
+ // the outline differently, so the roof is retried there.
1141
+ manifold::Manifold voronoiRoof(const manifold::CrossSection& cs, double fa, double fs) {
1142
+ manifold::Manifold body;
1143
+ for (int bits = 29; bits >= 25; --bits) {
1144
+ double toGrid = 1;
1145
+ std::vector<std::vector<Vec2>> contours = gridContours(cs, toGrid, bits);
1146
+ std::vector<std::vector<Vec2>> welded = weldContours(contours);
1147
+ // An outline welding leaves as it was keeps its own order, so its
1148
+ // roof is the same, vertex for vertex, as without welding.
1149
+ if (canonical(welded) != canonical(contours)) contours = std::move(welded);
1150
+ if (contours.empty()) return manifold::Manifold();
1151
+ // $fa/$fs below 0.01 would ask for unbounded detail
1152
+ // (computeRoofParams has already clamped them, warning).
1153
+ body = RoofBuilder(std::move(contours), 1 / toGrid, std::max(fa, 0.01), std::max(fs, 0.01)).build();
1154
+ if (body.Status() == manifold::Manifold::Error::NoError && !body.IsEmpty()) break;
1155
+ }
1156
+ return body;
1157
+ }
1158
+
1098
1159
  manifold::Manifold straightRoof(const manifold::CrossSection& cs) {
1099
1160
  double toGrid = 1;
1100
1161
  std::vector<std::vector<Vec2>> contours = weldContours(gridContours(cs, toGrid));
@@ -913,17 +913,10 @@ public:
913
913
  }
914
914
 
915
915
  case NodeKind::AssertOp: {
916
- // Every argument is evaluated, pass or fail, as OpenSCAD
917
- // does -- see Evaluator::checkAssert.
916
+ // Only the condition unless it fails -- see Evaluator::evalAssert.
918
917
  auto& n = static_cast<const oscad::AssertOp&>(node);
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()});
918
+ compileAssert(n.arguments, n, nullptr, out,
919
+ [&](const oscad::Expression& e) { compileExpr(e, out, scope); }); // never tail
927
920
  compileExpr(*n.body, out, scope, tail);
928
921
  return;
929
922
  }
@@ -1313,6 +1306,40 @@ public:
1313
1306
  out.push_back({Op::CloseExprScope, 0, 0, nullptr});
1314
1307
  }
1315
1308
 
1309
+ // assert(), either form, mirroring Evaluator::evalAssert:
1310
+ // <condition> JumpIfFalse fail [AssertPass] Jump end
1311
+ // fail: <every other argument, source order> AssertFail
1312
+ // end:
1313
+ // AssertPass only when there is something for it to do; with no
1314
+ // condition at all, straight to the failure path.
1315
+ template <typename CompileArg>
1316
+ void compileAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const oscad::ASTNode& node,
1317
+ const oscad::ModularAssert* statement, std::vector<Instruction>& out, CompileArg compileArg) {
1318
+ CompiledChunk::AssertSite site;
1319
+ site.layout = assertLayout(arguments);
1320
+ site.node = &node;
1321
+ site.statement = statement;
1322
+ site.arguments = &arguments;
1323
+ const int siteIdx = static_cast<int>(chunk_.assertSites.size());
1324
+ chunk_.assertSites.push_back(site);
1325
+ const int cond = site.layout.cond;
1326
+ std::optional<size_t> jumpEnd;
1327
+ if (cond >= 0) {
1328
+ compileArg(*argExpr(*arguments[static_cast<size_t>(cond)]));
1329
+ const size_t jumpFail = out.size();
1330
+ out.push_back({Op::JumpIfFalse, 0, 0, nullptr});
1331
+ if (site.layout.warns || (statement && !statement->children.empty()))
1332
+ out.push_back({Op::AssertPass, siteIdx, 0, &node.position()});
1333
+ jumpEnd = out.size();
1334
+ out.push_back({Op::Jump, 0, 0, nullptr});
1335
+ out[jumpFail].a = static_cast<int>(out.size());
1336
+ }
1337
+ for (size_t i = 0; i < arguments.size(); ++i)
1338
+ if (static_cast<int>(i) != cond) compileArg(*argExpr(*arguments[i]));
1339
+ out.push_back({Op::AssertFail, siteIdx, 0, &node.position()});
1340
+ if (jumpEnd) out[*jumpEnd].a = static_cast<int>(out.size());
1341
+ }
1342
+
1316
1343
  // Shared by ModularCall's Transform/Color-kind branch and the 3 real
1317
1344
  // modifier cases (ModularModifierHighlight/Background/ShowOnly),
1318
1345
  // below -- emits one Op::PushBuiltinWrap/PopBuiltinWrap bracket around
@@ -1544,7 +1571,7 @@ public:
1544
1571
  return;
1545
1572
  // Assignment/ModularEcho/ModularAssert: real bytecode instead
1546
1573
  // of Op::NativeStatement -- a throughput improvement (see
1547
- // CheckDebugStatement/StoreModuleVar/AssertStatement's own doc
1574
+ // CheckDebugStatement/StoreModuleVar/AssertPass+AssertFail's own doc
1548
1575
  // comments, bytecode.hpp), NOT a recursion-safety one (these
1549
1576
  // were never the risk Stage 2 targeted -- see NativeStatement's
1550
1577
  // own doc comment). Assignment specifically closes a real
@@ -1602,16 +1629,9 @@ public:
1602
1629
  // Like AssertOp's compiled form, plus chained children.
1603
1630
  auto& n = static_cast<const oscad::ModularAssert&>(stmt);
1604
1631
  out.push_back({Op::CheckDebugStatement, internNativeStatement(&stmt), 0, nullptr});
1605
- CompiledChunk::AssertSite site;
1606
- site.node = &n;
1607
- site.statement = &n;
1608
- site.arguments = &n.arguments;
1609
- site.argCount = static_cast<int>(n.arguments.size());
1610
1632
  CompileScope exprScope;
1611
- for (const auto& arg : n.arguments) compileIsolatedExpr(*argExpr(*arg), out, exprScope);
1612
- int siteIdx = static_cast<int>(chunk_.assertSites.size());
1613
- chunk_.assertSites.push_back(std::move(site));
1614
- out.push_back({Op::AssertStatement, siteIdx, 0, &n.position()});
1633
+ compileAssert(n.arguments, n, &n, out,
1634
+ [&](const oscad::Expression& e) { compileIsolatedExpr(e, out, exprScope); });
1615
1635
  return;
1616
1636
  }
1617
1637
  case NodeKind::ModularLet: {
@@ -1105,7 +1105,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
1105
1105
  ev.emitEcho(pairs);
1106
1106
  // The STATEMENT form can carry children and the
1107
1107
  // reference renders them; same tail as
1108
- // Op::AssertStatement below. Null node = the expression
1108
+ // Op::AssertPass below. Null node = the expression
1109
1109
  // form (`echo(...) 1+1`), which has none.
1110
1110
  if (site.node && !site.node->children.empty())
1111
1111
  ev.evalChildren(site.node->children, ctx);
@@ -1567,14 +1567,9 @@ Value driveVm(Evaluator& ev, size_t floor) {
1567
1567
  ++f.pc;
1568
1568
  break;
1569
1569
  }
1570
- case Op::AssertStatement: {
1570
+ case Op::AssertPass: {
1571
1571
  const CompiledChunk::AssertSite& site = f.chunk->assertSites[static_cast<size_t>(ins.a)];
1572
- std::vector<Value> args(static_cast<size_t>(site.argCount));
1573
- for (int i = site.argCount - 1; i >= 0; --i) {
1574
- args[static_cast<size_t>(i)] = std::move(f.stack.back());
1575
- f.stack.pop_back();
1576
- }
1577
- ev.checkAssert(*site.arguments, args, *site.node);
1572
+ ev.warnAssertArgs(*site.arguments, site.layout);
1578
1573
  // Rare (assert(...) translate(...) children();-shaped) --
1579
1574
  // not worth its own compiled path; evalChildren already
1580
1575
  // tries ITS OWN compiled fast path internally regardless.
@@ -1583,6 +1578,19 @@ Value driveVm(Evaluator& ev, size_t floor) {
1583
1578
  ++f.pc;
1584
1579
  break;
1585
1580
  }
1581
+ case Op::AssertFail: {
1582
+ // Every argument but the condition is on the stack, in
1583
+ // source order; only the message's value is wanted.
1584
+ const CompiledChunk::AssertSite& site = f.chunk->assertSites[static_cast<size_t>(ins.a)];
1585
+ const AssertLayout& layout = site.layout;
1586
+ Value message;
1587
+ for (int i = static_cast<int>(site.arguments->size()) - 1; i >= 0; --i) {
1588
+ if (i == layout.cond) continue;
1589
+ if (i == layout.msg) message = std::move(f.stack.back());
1590
+ f.stack.pop_back();
1591
+ }
1592
+ ev.failAssert(*site.arguments, layout, layout.msg >= 0 ? &message : nullptr, *site.node);
1593
+ }
1586
1594
  case Op::NativeCondJumpIfFalse: {
1587
1595
  const oscad::Expression* cond = f.chunk->nativeExprs[static_cast<size_t>(ins.a)];
1588
1596
  const bool truthyVal = truthy(ev.evalExprMaybeCompiled(*cond, ctx));
@@ -492,9 +492,7 @@ Value Evaluator::evalProfileTimeExpr(const oscad::ProfileTimeOp& node, EvalConte
492
492
 
493
493
  Value Evaluator::evalAssertExpr(const oscad::AssertOp& node, EvalContext& ctx) {
494
494
  checkDebug(node, ctx); // _expr_assert, before the condition is evaluated
495
- std::vector<Value> values;
496
- for (const auto& arg : node.arguments) values.push_back(evalExpr(*argExpr(*arg), ctx));
497
- checkAssert(node.arguments, values, node);
495
+ evalAssert(node.arguments, node, ctx, /*maybeCompiled=*/false);
498
496
  return evalExpr(*node.body, ctx);
499
497
  }
500
498
 
@@ -74,41 +74,79 @@ void Evaluator::doEcho(const std::vector<std::unique_ptr<oscad::Argument>>& argu
74
74
  emitEcho(pairs);
75
75
  }
76
76
 
77
- void Evaluator::checkAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments,
78
- const std::vector<Value>& values, const oscad::ASTNode& node) {
79
- static const std::vector<std::string> kParams{"condition", "message"};
80
- warnUnexpectedArgs(*this, kParams, arguments);
77
+ namespace {
78
+ const std::vector<std::string> kAssertParams{"condition", "message"};
79
+ }
80
+
81
+ AssertLayout assertLayout(const std::vector<std::unique_ptr<oscad::Argument>>& arguments) {
81
82
  // A named argument wins; positional 0/1 fill whichever is left.
82
- std::optional<size_t> cond, msg;
83
+ AssertLayout layout;
83
84
  for (size_t i = 0; i < arguments.size(); ++i) {
84
85
  if (arguments[i]->kind() != oscad::NodeKind::NamedArgument) continue;
85
86
  const std::string& name = static_cast<const oscad::NamedArgument&>(*arguments[i]).name->name;
86
- if (name == "condition" && !cond) cond = i;
87
- else if (name == "message" && !msg) msg = i;
87
+ if (name == "condition" && layout.cond < 0) layout.cond = static_cast<int>(i);
88
+ else if (name == "message" && layout.msg < 0) layout.msg = static_cast<int>(i);
89
+ else if (name != "condition" && name != "message" && !isConfigVariable(name)) layout.warns = true;
88
90
  }
89
- size_t positional = 0;
91
+ int positional = 0;
90
92
  for (size_t i = 0; i < arguments.size(); ++i) {
91
93
  if (arguments[i]->kind() == oscad::NodeKind::NamedArgument) continue;
92
- if (positional == 0 && !cond) cond = i;
93
- else if (positional == 1 && !msg) msg = i;
94
- ++positional;
94
+ if (positional == 0 && layout.cond < 0) layout.cond = static_cast<int>(i);
95
+ else if (positional == 1 && layout.msg < 0) layout.msg = static_cast<int>(i);
96
+ if (++positional > static_cast<int>(kAssertParams.size())) layout.warns = true;
95
97
  }
96
- if (cond && truthy(values[*cond])) return;
98
+ return layout;
99
+ }
100
+
101
+ void Evaluator::warnAssertArgs(const std::vector<std::unique_ptr<oscad::Argument>>& arguments,
102
+ const AssertLayout& layout) {
103
+ if (layout.warns) warnUnexpectedArgs(*this, kAssertParams, arguments);
104
+ }
105
+
106
+ void Evaluator::failAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments,
107
+ const AssertLayout& layout, const Value* message, const oscad::ASTNode& node) {
108
+ warnAssertArgs(arguments, layout);
97
109
  std::string err = "Assertion";
98
- if (cond) err += " '" + formatExpression(*argExpr(*arguments[*cond])) + "'";
110
+ if (layout.cond >= 0) err += " '" + formatExpression(*argExpr(*arguments[static_cast<size_t>(layout.cond)])) + "'";
99
111
  err += " failed";
100
- if (msg) err += ": " + fmtValue(values[*msg]);
112
+ if (message) err += ": " + fmtValue(*message);
101
113
  error(err, node, "assert");
102
114
  }
103
115
 
116
+ // DELIBERATE DIVERGENCE FROM OPENSCAD: a passing assert() evaluates its
117
+ // condition and nothing else, the way `||` skips its right operand.
118
+ // OpenSCAD's Assert::performAssert evaluates every argument first, so there
119
+ // a passing `assert(true, echo("e") "m")` echoes, `assert(true, nosuch)`
120
+ // warns, and a message calling a user function runs it; here none of them
121
+ // does. BOSL2 validates nearly every call with `assert(cond, str(...))`,
122
+ // and building those never-shown messages was ~4% of its evaluation time.
123
+ // A failing (or condition-less) assert evaluates every other argument, in
124
+ // source order, after the condition, so its output is unchanged; the
125
+ // unexpected-argument warnings depend only on the call's shape and still
126
+ // print on every call. The compiled form (Op::AssertPass/AssertFail) does
127
+ // the same.
128
+ void Evaluator::evalAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const oscad::ASTNode& node,
129
+ EvalContext& ctx, bool maybeCompiled) {
130
+ const AssertLayout layout = assertLayout(arguments);
131
+ auto eval = [&](size_t i) {
132
+ const oscad::Expression& e = *argExpr(*arguments[i]);
133
+ return maybeCompiled ? evalExprMaybeCompiled(e, ctx) : evalExpr(e, ctx);
134
+ };
135
+ if (layout.cond >= 0 && truthy(eval(static_cast<size_t>(layout.cond)))) {
136
+ warnAssertArgs(arguments, layout);
137
+ return;
138
+ }
139
+ Value message;
140
+ for (size_t i = 0; i < arguments.size(); ++i) {
141
+ if (static_cast<int>(i) == layout.cond) continue;
142
+ Value v = eval(i);
143
+ if (static_cast<int>(i) == layout.msg) message = std::move(v);
144
+ }
145
+ failAssert(arguments, layout, layout.msg >= 0 ? &message : nullptr, node);
146
+ }
147
+
104
148
  void Evaluator::evalAssertStatement(const oscad::ModularAssert& node, EvalContext& ctx) {
105
- // The statement form supports named arguments (assert(condition=...,
106
- // message=...)), unlike the expression form's raw positional indexing
107
- // -- see evalAssertExpr. Mirrors _eval_statement_impl's ModularAssert
108
- // branch exactly.
109
- std::vector<Value> values;
110
- for (const auto& arg : node.arguments) values.push_back(evalExprMaybeCompiled(*argExpr(*arg), ctx));
111
- checkAssert(node.arguments, values, node);
149
+ evalAssert(node.arguments, node, ctx, /*maybeCompiled=*/true);
112
150
  // Assertion passed -- propagate any chained child geometry (e.g.
113
151
  // `assert(...) translate(...) children();`).
114
152
  if (!node.children.empty()) evalChildren(node.children, ctx);
@@ -532,9 +532,7 @@ std::variant<Value, Evaluator::TailStep, Evaluator::NotTailStep> Evaluator::simp
532
532
  // Mirrors evalAssertExpr.
533
533
  auto& n = static_cast<const oscad::AssertOp&>(node);
534
534
  checkDebug(n, ctx);
535
- std::vector<Value> values;
536
- for (const auto& arg : n.arguments) values.push_back(evalExpr(*argExpr(*arg), ctx));
537
- checkAssert(n.arguments, values, n);
535
+ evalAssert(n.arguments, n, ctx, /*maybeCompiled=*/false);
538
536
  TailStep step;
539
537
  step.nextExpr = n.body.get();
540
538
  step.ctx = ctx;