openscad-cpp-evaluator 1.49.0__tar.gz → 1.49.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/bytecode.hpp +6 -1
  3. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/evaluator.hpp +5 -0
  4. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/pyproject.toml +1 -1
  5. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/booleans.cpp +14 -5
  6. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/builtins.hpp +2 -0
  7. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/control.cpp +1 -1
  8. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/bytecode_compiler.cpp +9 -2
  9. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/bytecode_vm.cpp +5 -1
  10. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/stmt_eval.cpp +3 -1
  11. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/zip_stored.cpp +43 -10
  12. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_booleans.cpp +42 -2
  13. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_zip_stored.cpp +87 -0
  14. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/uv.lock +1 -1
  15. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/.github/workflows/ci.yml +0 -0
  16. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/.github/workflows/wheels.yml +0 -0
  17. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/.gitignore +0 -0
  18. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/.gitmodules +0 -0
  19. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/CLAUDE.md +0 -0
  20. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/CMakeLists.txt +0 -0
  21. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/LICENSE +0 -0
  22. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/README.md +0 -0
  23. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/bindings/CMakeLists.txt +0 -0
  24. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/bindings/ast_to_py.cpp +0 -0
  25. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/bindings/module.cpp +0 -0
  26. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/cmake/embed_font.cmake +0 -0
  27. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/cmake/patch_manifold.cmake +0 -0
  28. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/examples/CMakeLists.txt +0 -0
  29. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/examples/eval_perf_benchmark.cpp +0 -0
  30. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/examples/manifold_cache_reuse.cpp +0 -0
  31. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/examples/minimal_debugger.cpp +0 -0
  32. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  33. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/.gitignore +0 -0
  34. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  35. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  36. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/LICENSE +0 -0
  37. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/README.md +0 -0
  38. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  39. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  40. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  41. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  42. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  43. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  44. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  45. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  46. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  47. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  48. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  49. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  50. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  51. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  52. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  53. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  54. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  55. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  56. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
  57. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  58. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  59. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  60. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  61. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  62. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  63. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  64. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  65. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  66. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  67. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  68. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  69. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  70. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  71. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  72. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  73. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
  74. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  75. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  76. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  77. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  78. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  79. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  80. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  81. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  82. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  83. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  84. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  85. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  86. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  87. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  88. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  89. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  90. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  91. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  92. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  93. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  94. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  95. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  96. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  97. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  98. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  99. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  100. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  101. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  102. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  103. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  104. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  105. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  106. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  107. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  108. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  109. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  110. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  111. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  112. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  113. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  114. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  115. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  116. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  117. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  118. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  119. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  120. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
  121. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  122. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  123. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  124. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  125. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  126. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  127. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  128. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  129. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  130. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  131. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  132. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  133. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  134. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  135. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  136. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  137. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
  138. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  139. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/python/openscad_cpp_evaluator/__init__.py +0 -0
  140. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/resources/fonts/LICENSE +0 -0
  141. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  142. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  143. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  144. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  145. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/CMakeLists.txt +0 -0
  146. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/call_args.cpp +0 -0
  147. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/color.cpp +0 -0
  148. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/dxf_dim.cpp +0 -0
  149. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/extrude.cpp +0 -0
  150. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/function_builtins.cpp +0 -0
  151. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/import.cpp +0 -0
  152. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/modifiers.cpp +0 -0
  153. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/primitives_2d.cpp +0 -0
  154. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/primitives_3d.cpp +0 -0
  155. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/profile_time.cpp +0 -0
  156. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/registry.cpp +0 -0
  157. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/roof.cpp +0 -0
  158. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/segments.cpp +0 -0
  159. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/surface.cpp +0 -0
  160. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/text.cpp +0 -0
  161. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/topology.cpp +0 -0
  162. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/builtins/transforms.cpp +0 -0
  163. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/colored_body.cpp +0 -0
  164. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/coverage.cpp +0 -0
  165. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/csg_generate.cpp +0 -0
  166. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/csg_resolve.cpp +0 -0
  167. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/css_colors.cpp +0 -0
  168. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/debug/debug_repl.cpp +0 -0
  169. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/debug_profile.cpp +0 -0
  170. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/eval_context.cpp +0 -0
  171. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/eval_error.cpp +0 -0
  172. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/eval_use.cpp +0 -0
  173. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/export.cpp +0 -0
  174. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/expr_eval.cpp +0 -0
  175. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/format_closure.cpp +0 -0
  176. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/import/dxf_import.cpp +0 -0
  177. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/import/mesh_import.cpp +0 -0
  178. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/import/scene_import.cpp +0 -0
  179. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/import/surface_load.cpp +0 -0
  180. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/import/svg_import.cpp +0 -0
  181. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/manifold_cache.cpp +0 -0
  182. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/measure_geometry.cpp +0 -0
  183. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/mesh_check.cpp +0 -0
  184. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/text/font_match.cpp +0 -0
  185. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/text/freetype_font_provider.cpp +0 -0
  186. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/text/text_metrics.cpp +0 -0
  187. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/user_calls.cpp +0 -0
  188. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/utf8.cpp +0 -0
  189. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/value.cpp +0 -0
  190. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/xkcd_colors.cpp +0 -0
  191. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/src/xkcd_colors.hpp +0 -0
  192. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/CMakeLists.txt +0 -0
  193. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_bytecode_compiler.cpp +0 -0
  194. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_children_separate.cpp +0 -0
  195. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_cli.cpp +0 -0
  196. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_control_flow.cpp +0 -0
  197. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_coverage.cpp +0 -0
  198. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_csg_tree.cpp +0 -0
  199. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_debug_hooks.cpp +0 -0
  200. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_discretizer.cpp +0 -0
  201. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_dxf_svg_import.cpp +0 -0
  202. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_eval_context.cpp +0 -0
  203. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_export.cpp +0 -0
  204. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_expr_eval.cpp +0 -0
  205. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_extrude_roof.cpp +0 -0
  206. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_feature_detection.cpp +0 -0
  207. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_function_builtins.cpp +0 -0
  208. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_helpers.hpp +0 -0
  209. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_import_export.cpp +0 -0
  210. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_include_cache.cpp +0 -0
  211. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_manifold_cache.cpp +0 -0
  212. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_mesh_check.cpp +0 -0
  213. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_multi_color_merge.cpp +0 -0
  214. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_openscad_parity.cpp +0 -0
  215. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_primitives.cpp +0 -0
  216. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_profile_time.cpp +0 -0
  217. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_profiling.cpp +0 -0
  218. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_python_bindings.py +0 -0
  219. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_render_expr.cpp +0 -0
  220. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_scope_trail.cpp +0 -0
  221. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_scoping.cpp +0 -0
  222. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_surface.cpp +0 -0
  223. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_tail_calls.cpp +0 -0
  224. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_text.cpp +0 -0
  225. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_transforms.cpp +0 -0
  226. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_undef_args.cpp +0 -0
  227. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_unexpected_args.cpp +0 -0
  228. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_use.cpp +0 -0
  229. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_value.cpp +0 -0
  230. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tests/test_viewport_params.cpp +0 -0
  231. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tools/cli/CMakeLists.txt +0 -0
  232. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tools/cli/cli_lib.cpp +0 -0
  233. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/tools/cli/cli_lib.hpp +0 -0
  234. {openscad_cpp_evaluator-1.49.0 → openscad_cpp_evaluator-1.49.2}/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.49.0
3
+ Version: 1.49.2
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT AND OFL-1.1
@@ -406,9 +406,14 @@ enum class Op {
406
406
  // for an attachable()-style multi-body operand) and appends it, as a
407
407
  // Value, onto csgWrapStack.back().groupSizes -- exactly one entry per
408
408
  // top-level geometry statement, in source order, mirroring resolveCsg's
409
- // own `groupSizes.push_back(Value{...})` loop.
409
+ // own `groupSizes.push_back(Value{...})` loop. Bit 4 of `a`: the statement is an `if` (no else), an operand
410
+ // exactly when it took its branch, read from ev.lastIfTaken.
410
411
  CsgGroupEnd,
411
412
 
413
+ // Sets ev.lastIfTaken = (a != 0) as an `if` (no else) finishes. See
414
+ // Evaluator::lastIfTaken.
415
+ SetLastIfTaken,
416
+
412
417
  // One `children(..., separate=true)` statement inside a CSG bracket.
413
418
  // `a` interns the ModularCall in nativeStatements.
414
419
  //
@@ -228,6 +228,11 @@ public:
228
228
  // contributed by comparing this before/after evaluating just that one
229
229
  // statement.
230
230
  size_t currentTreeFrameSize() const { return treeStack_.back().size(); }
231
+ // Whether the last `if` (no else) to finish took its branch. Written as
232
+ // the statement ENDS, so after evaluating an outer `if` it describes
233
+ // that one and not an `if` nested inside it. Read by the CSG operand
234
+ // rule (emptyStatementIsAnOperand), which is its only reason to exist.
235
+ bool lastIfTaken = false;
231
236
 
232
237
 
233
238
  // Generate pass: walks `tree` bottom-up (children before their own
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.49.0"
7
+ version = "1.49.2"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -97,7 +97,12 @@ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt) {
97
97
  const oscad::NodeKind k = stmt.kind();
98
98
  return k == oscad::NodeKind::ModularCall || k == oscad::NodeKind::ModularFor ||
99
99
  k == oscad::NodeKind::ModularIntersectionFor || k == oscad::NodeKind::ModularLet ||
100
- k == oscad::NodeKind::ModularModifierShowOnly || k == oscad::NodeKind::ModularModifierHighlight;
100
+ k == oscad::NodeKind::ModularModifierShowOnly || k == oscad::NodeKind::ModularModifierHighlight ||
101
+ k == oscad::NodeKind::ModularIfElse;
102
+ }
103
+
104
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt, bool ifTaken) {
105
+ return emptyStatementIsAnOperand(stmt) || (stmt.kind() == oscad::NodeKind::ModularIf && ifTaken);
101
106
  }
102
107
 
103
108
  CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
@@ -140,16 +145,20 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
140
145
  //
141
146
  // The reference builds a node for a module instantiation and for a
142
147
  // loop whatever they contain, so an empty one is an empty operand
143
- // and annihilates an intersection. An `if` that takes no branch, a
144
- // bare block, and a `*`-disabled statement build no node at all, so
145
- // they are not operands and must be skipped.
148
+ // and annihilates an intersection. So does an `if` that TAKES a
149
+ // branch, even one that draws nothing -- `if (true) {}` empties an
150
+ // intersection, and so does BOSL2's partition() when its child
151
+ // draws only one half (`if ($children>0) children();`). An `if`
152
+ // that takes no branch, a bare block, and a `*`-disabled statement
153
+ // build no node at all, so they are not operands and must be
154
+ // skipped. An if/else always takes one.
146
155
  //
147
156
  // Every line of this was checked against OpenSCAD rather than
148
157
  // reasoned about -- `intersection(){ cube(10); X; }` keeps the cube
149
158
  // for `if(false) sphere(6)`, `{ }` and `*cube(1)`, and comes out
150
159
  // empty for `for(i=[1:0]) sphere(6)`, `union(){}`, `group(){}` and
151
160
  // a call to an empty user module.
152
- emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*geoNode)});
161
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*geoNode, ev.lastIfTaken)});
153
162
  backgroundStmt.push_back(Value{geoNode->kind() == oscad::NodeKind::ModularModifierBackground});
154
163
  }
155
164
 
@@ -264,6 +264,8 @@ std::vector<ColoredBody> generateSurface(Evaluator& ev, const CSGParams& params,
264
264
  // Whether a statement that produced no geometry still counts as a boolean
265
265
  // operand (and so empties an intersection) -- see resolveCsg.
266
266
  bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt);
267
+ // The same, for a statement just evaluated: `ifTaken` is ev.lastIfTaken.
268
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt, bool ifTaken);
267
269
 
268
270
  // OpenSCAD's sin_degrees/cos_degrees/tan_degrees/atan2_degrees: exact at
269
271
  // multiples of 30 and 45 degrees.
@@ -138,7 +138,7 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
138
138
  const size_t before = ev.currentTreeFrameSize();
139
139
  ev.evalChildren(std::vector<const oscad::ASTNode*>{stmt}, parentCtx);
140
140
  groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
141
- emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*stmt)});
141
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*stmt, ev.lastIfTaken)});
142
142
  backgroundStmt.push_back(Value{stmt->kind() == oscad::NodeKind::ModularModifierBackground});
143
143
  }
144
144
  return;
@@ -1480,9 +1480,11 @@ public:
1480
1480
  compileStatementList(std::vector<const oscad::ASTNode*>{geoNode}, out);
1481
1481
  // `a` = whether a group that turns out EMPTY is still an
1482
1482
  // operand. See emptyStatementIsAnOperand (booleans.cpp).
1483
- // and bit 2 = it is a `%` statement, never an operand at all.
1483
+ // and bit 2 = it is a `%` statement, never an operand at all,
1484
+ // and bit 4 = an `if`, decided at run time.
1484
1485
  const int flags = (emptyStatementIsAnOperand(*geoNode) ? 1 : 0) |
1485
- (geoNode->kind() == oscad::NodeKind::ModularModifierBackground ? 2 : 0);
1486
+ (geoNode->kind() == oscad::NodeKind::ModularModifierBackground ? 2 : 0) |
1487
+ (geoNode->kind() == oscad::NodeKind::ModularIf ? 4 : 0);
1486
1488
  out.push_back({Op::CsgGroupEnd, flags, 0, nullptr});
1487
1489
  }
1488
1490
  }
@@ -1794,7 +1796,12 @@ public:
1794
1796
  out.push_back({Op::OpenLetScope, 0, 0, nullptr});
1795
1797
  compileStatementList(n.trueBranch, out);
1796
1798
  out.push_back({Op::CloseExprScope, 0, 0, nullptr});
1799
+ out.push_back({Op::SetLastIfTaken, 1, 0, nullptr});
1800
+ const int jumpEndIdx = static_cast<int>(out.size());
1801
+ out.push_back({Op::Jump, 0, 0, nullptr});
1797
1802
  out[static_cast<size_t>(jumpFalseIdx)].b = static_cast<int>(out.size());
1803
+ out.push_back({Op::SetLastIfTaken, 0, 0, nullptr});
1804
+ out[static_cast<size_t>(jumpEndIdx)].a = static_cast<int>(out.size());
1798
1805
  return;
1799
1806
  }
1800
1807
  case NodeKind::ModularIfElse: {
@@ -1444,11 +1444,15 @@ Value driveVm(Evaluator& ev, size_t floor) {
1444
1444
  ++f.pc;
1445
1445
  break;
1446
1446
  }
1447
+ case Op::SetLastIfTaken:
1448
+ ev.lastIfTaken = ins.a != 0;
1449
+ ++f.pc;
1450
+ break;
1447
1451
  case Op::CsgGroupEnd: {
1448
1452
  PendingCsgWrap& pending = f.csgWrapStack.back();
1449
1453
  const size_t after = ev.treeStack_.back().size();
1450
1454
  pending.groupSizes.push_back(Value{static_cast<double>(after - pending.groupStartSize)});
1451
- pending.emptyIsAGroup.push_back(Value{(ins.a & 1) != 0});
1455
+ pending.emptyIsAGroup.push_back(Value{(ins.a & 1) != 0 || ((ins.a & 4) != 0 && ev.lastIfTaken)});
1452
1456
  pending.backgroundStmt.push_back(Value{(ins.a & 2) != 0});
1453
1457
  ++f.pc;
1454
1458
  break;
@@ -279,12 +279,14 @@ void Evaluator::evalStatement(const oscad::ASTNode& node, EvalContext& ctx) {
279
279
  // `_check_debug(branch[0] if branch else node, ctx, expr_level=True)`.
280
280
  case oscad::NodeKind::ModularIf: {
281
281
  auto& n = static_cast<const oscad::ModularIf&>(node);
282
- if (truthy(evalExprMaybeCompiled(*n.condition, ctx))) {
282
+ const bool taken = truthy(evalExprMaybeCompiled(*n.condition, ctx));
283
+ if (taken) {
283
284
  checkDebug(n.trueBranch.empty() ? node : *n.trueBranch.front(), ctx, /*forced=*/false,
284
285
  /*exprLevel=*/true);
285
286
  EvalContext branchCtx = blockScope(ctx);
286
287
  evalChildren(n.trueBranch, branchCtx);
287
288
  }
289
+ lastIfTaken = taken;
288
290
  return;
289
291
  }
290
292
  case oscad::NodeKind::ModularIfElse: {
@@ -52,6 +52,7 @@ uint16_t readU16(const uint8_t* p) { return static_cast<uint16_t>(p[0] | (p[1] <
52
52
  uint32_t readU32(const uint8_t* p) {
53
53
  return static_cast<uint32_t>(p[0] | (p[1] << 8) | (p[2] << 16) | (static_cast<uint32_t>(p[3]) << 24));
54
54
  }
55
+ uint64_t readU64(const uint8_t* p) { return readU32(p) | (static_cast<uint64_t>(readU32(p + 4)) << 32); }
55
56
 
56
57
  // A fixed, valid DOS date/time (2020-01-01 00:00:00) -- the exact instant
57
58
  // doesn't matter for a generated 3MF, just that it's a well-formed DOS
@@ -156,9 +157,9 @@ void writeZipEntries(const std::string& path, const std::vector<PlacedEntry>& en
156
157
  struct CentralDirEntry {
157
158
  std::string name;
158
159
  uint16_t method;
159
- uint32_t compressedSize;
160
- uint32_t uncompressedSize;
161
- uint32_t localHeaderOffset;
160
+ uint64_t compressedSize;
161
+ uint64_t uncompressedSize;
162
+ uint64_t localHeaderOffset;
162
163
  };
163
164
 
164
165
  std::vector<uint8_t> readWholeFile(const std::string& path) {
@@ -189,25 +190,57 @@ std::vector<CentralDirEntry> parseCentralDirectory(const std::vector<uint8_t>& f
189
190
  }
190
191
  if (eocd == std::string::npos) throw std::runtime_error("'" + path + "' is not a valid ZIP archive (no EOCD)");
191
192
 
192
- const uint16_t entryCount = readU16(&file[eocd + 10]);
193
- const uint32_t cdOffset = readU32(&file[eocd + 16]);
193
+ uint64_t entryCount = readU16(&file[eocd + 10]);
194
+ uint64_t cdOffset = readU32(&file[eocd + 16]);
195
+ // ZIP64: a field too big for the classic record is all ones, and the
196
+ // real value is in the ZIP64 end record the locator just before it
197
+ // points to. lib3mf -- behind OpenSCAD's and most slicers' 3MF export --
198
+ // writes one even for a tiny file, so without this nearly every 3MF
199
+ // read as "corrupt central directory offset" (BelfrySCAD #800).
200
+ if ((entryCount == 0xFFFFu || cdOffset == 0xFFFFFFFFu) && eocd >= 20 &&
201
+ readU32(&file[eocd - 20]) == 0x07064b50u) {
202
+ const uint64_t z64 = readU64(&file[eocd - 20 + 8]);
203
+ if (z64 + 56 > file.size() || readU32(&file[z64]) != 0x06064b50u) {
204
+ throw std::runtime_error("'" + path + "': corrupt ZIP64 end of central directory");
205
+ }
206
+ entryCount = readU64(&file[z64 + 32]);
207
+ cdOffset = readU64(&file[z64 + 48]);
208
+ }
194
209
  if (cdOffset >= file.size()) throw std::runtime_error("'" + path + "': corrupt central directory offset");
195
210
 
196
211
  std::vector<CentralDirEntry> entries;
197
212
  size_t p = cdOffset;
198
- for (uint16_t i = 0; i < entryCount; ++i) {
213
+ for (uint64_t i = 0; i < entryCount; ++i) {
199
214
  if (p + 46 > file.size() || readU32(&file[p]) != 0x02014b50u) {
200
215
  throw std::runtime_error("'" + path + "': corrupt central directory entry");
201
216
  }
202
217
  const uint16_t method = readU16(&file[p + 10]);
203
- const uint32_t compressedSize = readU32(&file[p + 20]);
204
- const uint32_t uncompressedSize = readU32(&file[p + 24]);
218
+ uint64_t compressedSize = readU32(&file[p + 20]);
219
+ uint64_t uncompressedSize = readU32(&file[p + 24]);
205
220
  const uint16_t nameLen = readU16(&file[p + 28]);
206
221
  const uint16_t extraLen = readU16(&file[p + 30]);
207
222
  const uint16_t commentLen = readU16(&file[p + 32]);
208
- const uint32_t localHeaderOffset = readU32(&file[p + 42]);
209
- if (p + 46 + nameLen > file.size()) throw std::runtime_error("'" + path + "': corrupt central directory entry name");
223
+ uint64_t localHeaderOffset = readU32(&file[p + 42]);
224
+ if (p + 46 + nameLen + extraLen > file.size()) throw std::runtime_error("'" + path + "': corrupt central directory entry name");
210
225
  std::string name(reinterpret_cast<const char*>(&file[p + 46]), nameLen);
226
+ // A ZIP64 extra field (id 1) holds, in this order, only the values
227
+ // whose 32-bit field above is all ones.
228
+ for (size_t x = p + 46 + nameLen, xEnd = x + extraLen; x + 4 <= xEnd;) {
229
+ const uint16_t id = readU16(&file[x]);
230
+ const uint16_t len = readU16(&file[x + 2]);
231
+ size_t q = x + 4;
232
+ const size_t qEnd = std::min<size_t>(q + len, xEnd);
233
+ if (id == 0x0001u) {
234
+ for (uint64_t* v : {&uncompressedSize, &compressedSize, &localHeaderOffset}) {
235
+ if (*v != 0xFFFFFFFFu) continue;
236
+ if (q + 8 > qEnd) throw std::runtime_error("'" + path + "': corrupt ZIP64 extra field");
237
+ *v = readU64(&file[q]);
238
+ q += 8;
239
+ }
240
+ break;
241
+ }
242
+ x = q + len;
243
+ }
211
244
  entries.push_back(CentralDirEntry{std::move(name), method, compressedSize, uncompressedSize, localHeaderOffset});
212
245
  p += 46 + nameLen + extraLen + commentLen;
213
246
  }
@@ -11,6 +11,14 @@
11
11
  using namespace oscadeval;
12
12
  using namespace oscadeval::test;
13
13
 
14
+ namespace {
15
+ class ScopedVm {
16
+ public:
17
+ explicit ScopedVm(bool enabled) { Evaluator::setBytecodeVmEnabledForTesting(enabled); }
18
+ ~ScopedVm() { Evaluator::setBytecodeVmEnabledForTesting(std::nullopt); }
19
+ };
20
+ } // namespace
21
+
14
22
  // -- difference / intersection -------------------------------------------
15
23
 
16
24
  TEST(Difference, SubtractsInnerCubeVolume) {
@@ -66,10 +74,17 @@ TEST(Intersection, EmptyStatementsFollowTheReferenceExactly) {
66
74
  // falls out: a module instantiation or a loop builds a node whatever it
67
75
  // contains, so an empty one is an empty operand and annihilates; an
68
76
  // `if` with no branch taken, a bare block and a `*`-disabled statement
69
- // build no node at all and are not operands.
77
+ // build no node at all and are not operands. An `if` that takes a
78
+ // branch is one, whatever the branch draws.
70
79
  struct Case { const char* stmt; bool keepsTheCube; };
71
80
  const Case cases[] = {
72
81
  {"if (false) sphere(6);", true},
82
+ {"if (true) { }", false},
83
+ {"if (true) if (false) sphere(6);", false},
84
+ {"if (true) { x = 1; }", false},
85
+ {"if (false) sphere(6); else { }", false},
86
+ {"if (false) sphere(6); else if (false) sphere(6);", false},
87
+ {"{ if (false) sphere(6); }", true},
73
88
  {"{ }", true},
74
89
  {"*cube(1);", true},
75
90
  {"for (i = [1:0]) sphere(6);", false},
@@ -78,9 +93,16 @@ TEST(Intersection, EmptyStatementsFollowTheReferenceExactly) {
78
93
  {"let(x = 1) { }", false},
79
94
  {"#union() { }", false},
80
95
  };
96
+ // Each at top level and inside a module body, under both the
97
+ // interpreter and the VM, which decide an `if` separately.
98
+ for (const bool vm : {false, true})
99
+ for (const char* wrap : {"%s", "module w() { %s } w();"})
81
100
  for (const Case& c : cases) {
82
- const std::string src =
101
+ ScopedVm scoped(vm);
102
+ const std::string inner =
83
103
  std::string("intersection() { cube(10, center=true); ") + c.stmt + " }";
104
+ std::string src = wrap;
105
+ src.replace(src.find("%s"), 2, inner);
84
106
  Evaluated e = evalSrc(src);
85
107
  if (c.keepsTheCube) {
86
108
  ASSERT_EQ(e.bodies.size(), 1u) << src;
@@ -94,6 +116,24 @@ TEST(Intersection, EmptyStatementsFollowTheReferenceExactly) {
94
116
  }
95
117
  }
96
118
 
119
+ TEST(Intersection, BOSL2PartitionShowsOnlyTheHalfItsChildDraws) {
120
+ // partition()'s own shape: `intersection() { if ($children>0)
121
+ // children(); mask }`, once per half. A child drawing nothing for one
122
+ // half must empty that half, not leave its mask behind -- which is what
123
+ // `partition() if ($idx==0) cylinder(...)` drew. Verified against
124
+ // OpenSCAD: only the cube's own volume.
125
+ for (const bool vm : {false, true}) {
126
+ ScopedVm scoped(vm);
127
+ Evaluated e = evalSrc(
128
+ "module m() { intersection() { if ($children > 0) children(); cube(10); } }"
129
+ "m() if (false) sphere(5);");
130
+ const bool anyVolume = std::any_of(
131
+ e.bodies.begin(), e.bodies.end(),
132
+ [](const ColoredBody& b) { return b.body && !b.body->IsEmpty(); });
133
+ EXPECT_FALSE(anyVolume) << "vm=" << vm;
134
+ }
135
+ }
136
+
97
137
  TEST(Intersection, AnEmptyUserModuleIsStillAnOperand) {
98
138
  // The reference builds a node for a module instantiation whatever the
99
139
  // module's body does, so calling one that draws nothing empties the
@@ -253,3 +253,90 @@ TEST(ZipStored, StoredZipWritesMethod0) {
253
253
  EXPECT_EQ(centralDirMethodBySuffix(path.string(), "3dmodel.model"), 0);
254
254
  std::filesystem::remove(path);
255
255
  }
256
+
257
+ TEST(ZipStored, ReadsZip64Archive) {
258
+ // The shape lib3mf writes (BelfrySCAD #800): every size and offset in the
259
+ // central directory and classic end record all ones, the real values in a
260
+ // ZIP64 extra field and a ZIP64 end record found through its locator.
261
+ const std::string name = "3D/3dmodel.model";
262
+ const std::string content = "zip64 payload";
263
+ std::vector<uint8_t> out;
264
+
265
+ putLE<uint32_t>(out, 0x04034b50u);
266
+ putLE<uint16_t>(out, 45);
267
+ putLE<uint16_t>(out, 0);
268
+ putLE<uint16_t>(out, 0);
269
+ putLE<uint16_t>(out, 0);
270
+ putLE<uint16_t>(out, 0);
271
+ putLE<uint32_t>(out, 0);
272
+ putLE<uint32_t>(out, static_cast<uint32_t>(content.size()));
273
+ putLE<uint32_t>(out, static_cast<uint32_t>(content.size()));
274
+ putLE<uint16_t>(out, static_cast<uint16_t>(name.size()));
275
+ putLE<uint16_t>(out, 0);
276
+ out.insert(out.end(), name.begin(), name.end());
277
+ out.insert(out.end(), content.begin(), content.end());
278
+
279
+ const uint64_t cdStart = out.size();
280
+ putLE<uint32_t>(out, 0x02014b50u);
281
+ putLE<uint16_t>(out, 45);
282
+ putLE<uint16_t>(out, 45);
283
+ putLE<uint16_t>(out, 0);
284
+ putLE<uint16_t>(out, 0);
285
+ putLE<uint16_t>(out, 0);
286
+ putLE<uint16_t>(out, 0);
287
+ putLE<uint32_t>(out, 0);
288
+ putLE<uint32_t>(out, 0xFFFFFFFFu);
289
+ putLE<uint32_t>(out, 0xFFFFFFFFu);
290
+ putLE<uint16_t>(out, static_cast<uint16_t>(name.size()));
291
+ putLE<uint16_t>(out, 4 + 24 + 4 + 4); // an unrelated field first, then ZIP64
292
+ putLE<uint16_t>(out, 0);
293
+ putLE<uint16_t>(out, 0);
294
+ putLE<uint16_t>(out, 0);
295
+ putLE<uint32_t>(out, 0);
296
+ putLE<uint32_t>(out, 0xFFFFFFFFu);
297
+ out.insert(out.end(), name.begin(), name.end());
298
+ putLE<uint16_t>(out, 0x5455);
299
+ putLE<uint16_t>(out, 4);
300
+ putLE<uint32_t>(out, 0);
301
+ putLE<uint16_t>(out, 0x0001);
302
+ putLE<uint16_t>(out, 24);
303
+ putLE<uint64_t>(out, content.size());
304
+ putLE<uint64_t>(out, content.size());
305
+ putLE<uint64_t>(out, 0);
306
+ const uint64_t cdSize = out.size() - cdStart;
307
+
308
+ const uint64_t z64 = out.size();
309
+ putLE<uint32_t>(out, 0x06064b50u);
310
+ putLE<uint64_t>(out, 44);
311
+ putLE<uint16_t>(out, 45);
312
+ putLE<uint16_t>(out, 45);
313
+ putLE<uint32_t>(out, 0);
314
+ putLE<uint32_t>(out, 0);
315
+ putLE<uint64_t>(out, 1);
316
+ putLE<uint64_t>(out, 1);
317
+ putLE<uint64_t>(out, cdSize);
318
+ putLE<uint64_t>(out, cdStart);
319
+
320
+ putLE<uint32_t>(out, 0x07064b50u);
321
+ putLE<uint32_t>(out, 0);
322
+ putLE<uint64_t>(out, z64);
323
+ putLE<uint32_t>(out, 1);
324
+
325
+ putLE<uint32_t>(out, 0x06054b50u);
326
+ putLE<uint16_t>(out, 0);
327
+ putLE<uint16_t>(out, 0);
328
+ putLE<uint16_t>(out, 0xFFFF);
329
+ putLE<uint16_t>(out, 0xFFFF);
330
+ putLE<uint32_t>(out, 0xFFFFFFFFu);
331
+ putLE<uint32_t>(out, 0xFFFFFFFFu);
332
+ putLE<uint16_t>(out, 0);
333
+
334
+ const auto path = tempPath("zip64.zip");
335
+ {
336
+ std::ofstream f(path, std::ios::binary);
337
+ f.write(reinterpret_cast<const char*>(out.data()), static_cast<std::streamsize>(out.size()));
338
+ }
339
+ const std::vector<uint8_t> read = readStoredZipEntry(path.string(), name);
340
+ EXPECT_EQ(std::string(read.begin(), read.end()), content);
341
+ std::filesystem::remove(path);
342
+ }
@@ -55,7 +55,7 @@ wheels = [
55
55
 
56
56
  [[package]]
57
57
  name = "openscad-cpp-evaluator"
58
- version = "1.49.0"
58
+ version = "1.49.2"
59
59
  source = { editable = "." }
60
60
  dependencies = [
61
61
  { name = "numpy" },