openscad-cpp-evaluator 1.40.0__tar.gz → 1.42.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/bindings/module.cpp +1 -0
  3. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode.hpp +14 -46
  4. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +3 -0
  5. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/colored_body.hpp +32 -1
  6. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/evaluator.hpp +26 -0
  7. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/export.hpp +8 -0
  8. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/segments.hpp +6 -2
  9. openscad_cpp_evaluator-1.42.0/include/openscad_cpp_evaluator/surface_load.hpp +23 -0
  10. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/value.hpp +3 -1
  11. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/pyproject.toml +1 -1
  12. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/python/openscad_cpp_evaluator/__init__.py +3 -2
  13. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/booleans.cpp +44 -12
  14. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/builtins.hpp +13 -0
  15. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/control.cpp +31 -42
  16. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/extrude.cpp +93 -55
  17. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/function_builtins.cpp +188 -77
  18. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/import.cpp +33 -2
  19. openscad_cpp_evaluator-1.42.0/src/builtins/primitives_2d.cpp +242 -0
  20. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/primitives_3d.cpp +130 -48
  21. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/segments.cpp +38 -10
  22. openscad_cpp_evaluator-1.42.0/src/builtins/surface.cpp +118 -0
  23. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/topology.cpp +34 -3
  24. openscad_cpp_evaluator-1.42.0/src/builtins/transforms.cpp +443 -0
  25. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/bytecode_compiler.cpp +77 -119
  26. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/bytecode_vm.cpp +14 -30
  27. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/colored_body.cpp +25 -0
  28. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/csg_generate.cpp +44 -17
  29. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/csg_resolve.cpp +2 -1
  30. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/eval_context.cpp +2 -1
  31. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/export.cpp +61 -14
  32. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/expr_eval.cpp +51 -25
  33. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/import/scene_import.cpp +5 -14
  34. openscad_cpp_evaluator-1.42.0/src/import/surface_load.cpp +132 -0
  35. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/stmt_eval.cpp +36 -15
  36. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/text/freetype_font_provider.cpp +18 -3
  37. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/user_calls.cpp +38 -29
  38. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/value.cpp +94 -39
  39. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/CMakeLists.txt +1 -0
  40. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_booleans.cpp +18 -14
  41. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_bytecode_compiler.cpp +10 -7
  42. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_control_flow.cpp +19 -7
  43. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_eval_context.cpp +2 -1
  44. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_expr_eval.cpp +3 -6
  45. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_import_export.cpp +8 -4
  46. openscad_cpp_evaluator-1.42.0/tests/test_openscad_parity.cpp +483 -0
  47. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_primitives.cpp +29 -5
  48. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_python_bindings.py +9 -6
  49. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_render_expr.cpp +7 -3
  50. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_surface.cpp +49 -18
  51. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_transforms.cpp +12 -5
  52. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/uv.lock +1 -1
  53. openscad_cpp_evaluator-1.40.0/include/openscad_cpp_evaluator/surface_load.hpp +0 -16
  54. openscad_cpp_evaluator-1.40.0/src/builtins/primitives_2d.cpp +0 -152
  55. openscad_cpp_evaluator-1.40.0/src/builtins/surface.cpp +0 -134
  56. openscad_cpp_evaluator-1.40.0/src/builtins/transforms.cpp +0 -417
  57. openscad_cpp_evaluator-1.40.0/src/import/surface_load.cpp +0 -76
  58. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/.github/workflows/ci.yml +0 -0
  59. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/.github/workflows/wheels.yml +0 -0
  60. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/.gitignore +0 -0
  61. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/.gitmodules +0 -0
  62. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/CLAUDE.md +0 -0
  63. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/CMakeLists.txt +0 -0
  64. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/LICENSE +0 -0
  65. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/README.md +0 -0
  66. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/bindings/CMakeLists.txt +0 -0
  67. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/bindings/ast_to_py.cpp +0 -0
  68. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/cmake/embed_font.cmake +0 -0
  69. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/cmake/patch_manifold.cmake +0 -0
  70. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/examples/CMakeLists.txt +0 -0
  71. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/examples/eval_perf_benchmark.cpp +0 -0
  72. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/examples/manifold_cache_reuse.cpp +0 -0
  73. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/examples/minimal_debugger.cpp +0 -0
  74. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  75. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/.gitignore +0 -0
  76. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  77. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  78. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/README.md +0 -0
  79. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  80. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  81. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  82. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  83. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  84. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  85. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  86. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  87. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  88. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  89. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  90. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  91. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  92. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  93. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  94. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  95. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  96. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  97. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  98. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  99. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  100. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  101. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  102. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  103. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  104. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  105. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  106. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  107. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  108. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  109. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  110. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  111. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  112. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  113. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  114. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  115. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  116. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  117. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  118. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  119. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  120. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  121. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  122. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  123. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  124. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  125. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  126. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  127. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  128. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  129. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  130. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  131. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  132. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  133. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  134. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  135. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  136. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  137. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  138. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  139. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  140. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  141. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  142. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  143. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  144. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  145. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  146. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  147. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  148. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  149. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  150. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  151. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  152. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  153. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  154. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  155. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  156. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  157. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  158. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  159. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  160. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  161. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  162. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  163. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  164. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  165. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  166. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  167. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  168. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  169. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  170. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  171. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  172. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  173. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  174. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LICENSE +0 -0
  175. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  176. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  177. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  178. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  179. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/CMakeLists.txt +0 -0
  180. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/call_args.cpp +0 -0
  181. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/color.cpp +0 -0
  182. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/dxf_dim.cpp +0 -0
  183. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/modifiers.cpp +0 -0
  184. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/profile_time.cpp +0 -0
  185. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/registry.cpp +0 -0
  186. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/roof.cpp +0 -0
  187. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/builtins/text.cpp +0 -0
  188. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/coverage.cpp +0 -0
  189. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/css_colors.cpp +0 -0
  190. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/debug/debug_repl.cpp +0 -0
  191. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/debug_profile.cpp +0 -0
  192. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/eval_error.cpp +0 -0
  193. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/eval_use.cpp +0 -0
  194. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/format_closure.cpp +0 -0
  195. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/import/dxf_import.cpp +0 -0
  196. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/import/mesh_import.cpp +0 -0
  197. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/import/svg_import.cpp +0 -0
  198. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/manifold_cache.cpp +0 -0
  199. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/measure_geometry.cpp +0 -0
  200. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/mesh_check.cpp +0 -0
  201. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/text/font_match.cpp +0 -0
  202. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/text/text_metrics.cpp +0 -0
  203. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/utf8.cpp +0 -0
  204. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/xkcd_colors.cpp +0 -0
  205. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/xkcd_colors.hpp +0 -0
  206. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/src/zip_stored.cpp +0 -0
  207. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_children_separate.cpp +0 -0
  208. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_cli.cpp +0 -0
  209. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_coverage.cpp +0 -0
  210. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_csg_tree.cpp +0 -0
  211. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_debug_hooks.cpp +0 -0
  212. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_discretizer.cpp +0 -0
  213. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_dxf_svg_import.cpp +0 -0
  214. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_export.cpp +0 -0
  215. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_extrude_roof.cpp +0 -0
  216. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_feature_detection.cpp +0 -0
  217. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_function_builtins.cpp +0 -0
  218. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_helpers.hpp +0 -0
  219. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_include_cache.cpp +0 -0
  220. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_manifold_cache.cpp +0 -0
  221. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_mesh_check.cpp +0 -0
  222. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_multi_color_merge.cpp +0 -0
  223. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_profile_time.cpp +0 -0
  224. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_profiling.cpp +0 -0
  225. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_scope_trail.cpp +0 -0
  226. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_scoping.cpp +0 -0
  227. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_tail_calls.cpp +0 -0
  228. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_text.cpp +0 -0
  229. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_undef_args.cpp +0 -0
  230. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_unexpected_args.cpp +0 -0
  231. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_use.cpp +0 -0
  232. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_value.cpp +0 -0
  233. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_viewport_params.cpp +0 -0
  234. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tests/test_zip_stored.cpp +0 -0
  235. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/CMakeLists.txt +0 -0
  236. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/cli_lib.cpp +0 -0
  237. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/tools/cli/cli_lib.hpp +0 -0
  238. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.42.0}/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.40.0
3
+ Version: 1.42.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -134,6 +134,7 @@ const char* roleToString(oscadeval::BodyRole role) {
134
134
  case oscadeval::BodyRole::Highlight: return "highlight";
135
135
  case oscadeval::BodyRole::Background: return "background";
136
136
  case oscadeval::BodyRole::ShowOnly: return "show_only";
137
+ case oscadeval::BodyRole::HighlightGhost: return "highlight_ghost";
137
138
  case oscadeval::BodyRole::Normal:
138
139
  default: return "normal";
139
140
  }
@@ -43,6 +43,7 @@ enum class Op {
43
43
  StoreLocal, // a = slot index (pops)
44
44
  LoadDyn, // a = name pool index ($-prefixed)
45
45
  StoreDyn, // a = name pool index (pops; also marks dynExplicit)
46
+ WarnDuplicateLet, // a = name pool index (pops; warns, binds nothing -- see Evaluator::warnDuplicateLet)
46
47
  LoadFree, // a = name pool index -- Evaluator::evalIdentifier fallback (warnIfUndef=true)
47
48
  // Same as LoadFree, but Evaluator::evalIdentifier's warnIfUndef=false --
48
49
  // only ever emitted for a PrimaryCall's own callee probe (bytecode_
@@ -240,20 +241,6 @@ enum class Op {
240
241
  // there's no branch to emit here).
241
242
  Echo,
242
243
 
243
- // Only ever emitted for a non-empty-argument AssertOp (see
244
- // bytecode_compiler.cpp's own AssertOp case -- a zero-argument
245
- // assert() is unconditionally true and compiles straight through with
246
- // no check at all). Reached only on the condition-false path (guarded
247
- // by a JumpIfTrue the compiler emits around it, mirroring LogicalOrOp's
248
- // own jump-then-patch shape) -- always throws via Evaluator::error(),
249
- // i.e. [[noreturn]] at runtime. a = 1 if a message Value was compiled
250
- // and pushed (pop it), else 0. b = constant-pool index of condText
251
- // (the condition expression's own source text, interned ONCE at
252
- // compile time via its toString() -- cheaper than the interpreter,
253
- // which recomputes this on every failing call). pos/node: same
254
- // Evaluator::error() TRACE-walk need CheckIterLimit already has.
255
- AssertFail,
256
-
257
244
  // -- Module-body compilation (Stage 2) --------------------------------
258
245
  // A call to a user module resolved to a specific ModuleDeclaration AT
259
246
  // COMPILE TIME (see CompiledChunk::ModuleCallSite) -- the module-side
@@ -717,16 +704,10 @@ enum class Op {
717
704
  StoreLetVar,
718
705
 
719
706
  // a = index into CompiledChunk::assertSites. Pops site.argCount values
720
- // (all of this statement's own arguments, already compiled+pushed in
721
- // source order via compileExpr -- EVERY one, not just condition/
722
- // message, mirrors evalAssertStatement's own eager resolveArgs() over
723
- // AssertOp's lazy-message contract) and replicates
724
- // Evaluator::evalAssertStatement exactly: named "condition"/"message"
725
- // win over positional 0/1 (resolved at COMPILE time into
726
- // AssertSite::conditionArgIndex/messageArgIndex -- the argument SHAPE
727
- // is static, only values vary per call), throws via Evaluator::error()
728
- // on failure, otherwise runs any chained node.children natively (rare;
729
- // not worth its own compiled path -- see AssertSite's own doc comment).
707
+ // (every argument of an assert() statement or expression, pushed in
708
+ // source order) and hands them to Evaluator::checkAssert; a statement
709
+ // then runs any chained children natively (rare; not worth its own
710
+ // compiled path).
730
711
  AssertStatement,
731
712
  // a = nativeStatements index of the AST node whose arm this is. Emitted
732
713
  // only when the Evaluator was built with coverage on (compile-time
@@ -763,6 +744,10 @@ struct Instruction {
763
744
  // applyDefaults()'s existing sibling-isolated defaultCtx; empty if that
764
745
  // parameter has no default. `bodyCode` is the function's own expression body.
765
746
  struct CompiledChunk {
747
+ // String literals whose text holds an escape OpenSCAD calls undefined,
748
+ // with how many: the Evaluator warns for them once, when the chunk is
749
+ // compiled (it has the warning channel; the compiler does not).
750
+ std::vector<std::pair<const oscad::StringLiteral*, int>> undefinedEscapeLiterals;
766
751
  struct Param {
767
752
  std::string name;
768
753
  int slot = 0; // unused when isDyn is true -- $-params are never slot-addressed
@@ -1036,30 +1021,13 @@ struct CompiledChunk {
1036
1021
  const oscad::ASTNode* node = nullptr;
1037
1022
  };
1038
1023
 
1039
- // One Op::AssertStatement site -- see that op's own doc comment for
1040
- // the full contract. `conditionArgIndex`/`messageArgIndex` are indices
1041
- // into the site's own argCount-sized popped-argument array (source
1042
- // order), resolved at COMPILE time via the same "named wins over
1043
- // positional 0/1" priority Evaluator::getArg applies at runtime --
1044
- // nullopt means "no argument supplies this logical parameter" (mirrors
1045
- // getArg's own defaultValue fallback: absent condition reads as
1046
- // `Value{true}`, absent message means no ": ..." suffix).
1047
- // `condTextConstIdx`: constants[] index of the condition argument's own
1048
- // source text (or "false" when no condition argument exists, matching
1049
- // evalAssertStatement's `node.arguments.empty() ? "false" : ...`),
1050
- // interned once at compile time. `node`: for both Evaluator::error()'s
1051
- // TRACE walk and the (rare) chained-children fallback below.
1052
- //
1053
- // ponytail: a script with TWO named args of the SAME name (e.g.
1054
- // `assert(condition=true, condition=false)`) would resolve to the
1055
- // LAST one here, not getArg's own first-match; not worth the extra
1056
- // bookkeeping to fix for input that's already nonsensical.
1024
+ // One Op::AssertStatement site. `statement` is null for the expression
1025
+ // form, which has no children.
1057
1026
  struct AssertSite {
1058
1027
  int argCount = 0;
1059
- std::optional<int> conditionArgIndex;
1060
- std::optional<int> messageArgIndex;
1061
- int condTextConstIdx = -1;
1062
- const oscad::ModularAssert* node = nullptr;
1028
+ const std::vector<std::unique_ptr<oscad::Argument>>* arguments = nullptr;
1029
+ const oscad::ASTNode* node = nullptr;
1030
+ const oscad::ModularAssert* statement = nullptr;
1063
1031
  };
1064
1032
 
1065
1033
  // Every distinct chunk this SPECIFIC CompiledChunk owns is either a
@@ -71,6 +71,9 @@ struct PendingCsgWrap {
71
71
  // Parallel to groupSizes: whether a group that came out EMPTY is still
72
72
  // an operand. See Op::CsgGroupEnd's `a`.
73
73
  std::vector<Value> emptyIsAGroup;
74
+ // Parallel too: whether the statement was a `%` one, which is never an
75
+ // operand. See Op::CsgGroupEnd's `a` (bit 2).
76
+ std::vector<Value> backgroundStmt;
74
77
  size_t groupStartSize = 0;
75
78
  };
76
79
 
@@ -12,7 +12,16 @@
12
12
 
13
13
  namespace oscadeval {
14
14
 
15
- enum class BodyRole { Normal, Highlight, Background, ShowOnly };
15
+ // HighlightGhost is the see-through copy of a `#` operand that an operation
16
+ // (difference, intersection, hull, ...) emits beside its result so the
17
+ // viewport can still show the operand. The operand itself was merged into
18
+ // the result; the ghost is drawing only. It is never an operand again and
19
+ // never exported -- it used to be a plain Highlight body, so an outer
20
+ // boolean used it twice and export wrote it as real geometry:
21
+ // difference(){ cube(2); #translate([1,1,1]) cube(2); } exported volume 15
22
+ // where OpenSCAD writes 7. A `#` with nothing merging it stays Highlight,
23
+ // and exports like any other geometry, as it does upstream.
24
+ enum class BodyRole { Normal, Highlight, Background, ShowOnly, HighlightGhost };
16
25
 
17
26
  // A single piece of evaluated geometry: exactly one of `body` (3D) or
18
27
  // `section` (2D) is set, never both -- mirrors the Python reference's
@@ -178,4 +187,26 @@ inline constexpr double kTopLevel2dHeight = 1.0;
178
187
  std::vector<ColoredBody> toRenderableBodies(const std::vector<ColoredBody>& bodies,
179
188
  double flatHeight = kTopLevel2dHeight);
180
189
 
190
+ // A 3D affine transform as it acts on the XY plane: rows x and y, columns
191
+ // x, y and translation -- what OpenSCAD's GeometryEvaluator applies to 2D
192
+ // geometry (z, and everything out of the plane, simply drops away).
193
+ manifold::mat2x3 projectTo2d(const manifold::mat3x4& m);
194
+
195
+ // Moves a section's carried transform (ColoredBody::sectionXform) into the
196
+ // CrossSection itself, projected onto the plane, and resets it. Every 2D
197
+ // operation does this to its children before it reads them: OpenSCAD's F6
198
+ // has already projected each transform by then, and an operation that
199
+ // ignored the carried one -- union, offset, hull, linear_extrude -- used the
200
+ // shape as if the transform had never happened. False if the projection
201
+ // was singular and the shape was removed (the caller warns).
202
+ bool projectSectionXform(ColoredBody& b);
203
+
204
+ // Applies `m`, projected onto the plane, to a CrossSection. A singular
205
+ // projection -- scale([0,1]), a quarter turn about X -- empties it, as
206
+ // upstream's Polygon2d::transform does, and returns false.
207
+ bool transformSection(manifold::CrossSection& cs, const manifold::mat3x4& m);
208
+
209
+ // Upstream's warning for that case, word for word.
210
+ inline constexpr const char* kZeroScale2dWarning = "Scaling a 2D object with 0 - removing object";
211
+
181
212
  } // namespace oscadeval
@@ -2,6 +2,8 @@
2
2
 
3
3
  #include "openscad_cpp_evaluator/bound_args.hpp"
4
4
  #include "openscad_cpp_evaluator/bytecode.hpp"
5
+
6
+ #include <unordered_set>
5
7
  #include "openscad_cpp_evaluator/bytecode_vm.hpp"
6
8
  #include "openscad_cpp_evaluator/call_args.hpp"
7
9
  #include "openscad_cpp_evaluator/csg_node.hpp"
@@ -557,6 +559,30 @@ public:
557
559
  // Public: builtins/import.cpp's not-manifold warning is emitted from a
558
560
  // free function, same reasoning as tagGenerated()/builtinChildren().
559
561
  void warn(const std::string& message, const oscad::Position* position);
562
+ // OpenSCAD's lexer warns "Undefined escape sequence" once per bad escape
563
+ // in the source. This warns for a literal the first time it is
564
+ // evaluated or compiled, and never again for that literal.
565
+ void warnUndefinedEscapes(const oscad::StringLiteral& lit, int count);
566
+ // let() keeps the FIRST binding of a repeated name: OpenSCAD evaluates
567
+ // the later right-hand side, warns with its value, and discards it.
568
+ // OpenSCAD's Assert::performAssert, given every argument's value in
569
+ // source order -- it evaluates them all, pass or fail, so a passing
570
+ // `assert(true, nosuch)` still warns. Warns about unexpected arguments;
571
+ // throws via error() when the condition is false or missing (`assert()`
572
+ // fails). The message prints as echo() would print it.
573
+ void checkAssert(const std::vector<std::unique_ptr<oscad::Argument>>& arguments, const std::vector<Value>& values,
574
+ const oscad::ASTNode& node);
575
+ void warnDuplicateLet(const std::string& name, const Value& v, const oscad::Position* position);
576
+ template <typename Assignments>
577
+ static bool repeatsEarlierLetName(const Assignments& assignments, size_t i) {
578
+ for (size_t j = 0; j < i; ++j)
579
+ if (assignments[j]->name->name == assignments[i]->name->name) return true;
580
+ return false;
581
+ }
582
+ std::unordered_set<const oscad::StringLiteral*> undefinedEscapesWarned_;
583
+ void warnUndefinedEscapes(const CompiledChunk& chunk) {
584
+ for (const auto& [lit, n] : chunk.undefinedEscapeLiterals) warnUndefinedEscapes(*lit, n);
585
+ }
560
586
  // Hands one already-formatted warning line to echoFn_, recording it in
561
587
  // warnCapture first when one is active. Every warning path goes through
562
588
  // here, including a ManifoldCache hit replaying a cached line.
@@ -52,6 +52,14 @@ struct ExportObject {
52
52
  // A body Manifold rejected (an open shell is not a solid) can take part in
53
53
  // none of that: it keeps its own triangles and its own object, and its
54
54
  // 1-based index is appended to `openParts` for the caller to warn about.
55
+ // The dimension OpenSCAD's render gives these top-level bodies: that of the
56
+ // first one with geometry (2 or 3), or 0 for none.
57
+ int topLevelDimension(const std::vector<ColoredBody>& bodies);
58
+
59
+ // OpenSCAD's render warnings for a top level that mixes 2D and 3D; export
60
+ // writes only the first object's dimension.
61
+ std::vector<std::string> mixedDimensionWarnings(const std::vector<ColoredBody>& bodies);
62
+
55
63
  std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& bodies,
56
64
  std::vector<int>* openParts = nullptr,
57
65
  bool splitComponents = false,
@@ -5,7 +5,9 @@
5
5
 
6
6
  #include <manifold/common.h>
7
7
 
8
+ #include <functional>
8
9
  #include <optional>
10
+ #include <string>
9
11
 
10
12
  namespace oscadeval {
11
13
 
@@ -27,7 +29,8 @@ struct Discretizer {
27
29
  double fa = 12.0;
28
30
  double fs = 2.0;
29
31
 
30
- static Discretizer fromCtx(const EvalContext& ctx);
32
+ // `warn`, when given, receives upstream's clamping warnings.
33
+ static Discretizer fromCtx(const EvalContext& ctx, const std::function<void(const std::string&)>& warn = {});
31
34
  // Stored in, and read back from, a node's params -- they are part of its
32
35
  // cache key, and generate has only the params to go on.
33
36
  static Discretizer fromParams(const CSGParams& params);
@@ -53,6 +56,7 @@ struct Discretizer {
53
56
 
54
57
  // Full-circle segment count from ctx's $fn/$fe/$fa/$fs at radius r;
55
58
  // upstream's primitives fall back to 3.
56
- int fnSegmentsFromCtx(const EvalContext& ctx, double r = 0.0);
59
+ int fnSegmentsFromCtx(const EvalContext& ctx, double r = 0.0,
60
+ const std::function<void(const std::string&)>& warn = {});
57
61
 
58
62
  } // namespace oscadeval
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <vector>
5
+
6
+ namespace oscadeval {
7
+
8
+ // Height data for surface(), read as upstream's SurfaceNode reads it: a
9
+ // PNG (by its signature) as 16-bit luminance scaled to 0-100, negated by
10
+ // `invert`, bottom image row at y = 0; anything else as a .dat grid, first
11
+ // line at y = 0, short rows padded with 0. Never throws: a file that cannot
12
+ // be read gives no heights and upstream's warning, and the script carries
13
+ // on. `heights[row * cols + col]`; `minVal` is what the base sits 1 below.
14
+ struct SurfaceData {
15
+ std::vector<double> heights;
16
+ int rows = 0;
17
+ int cols = 0;
18
+ double minVal = 0;
19
+ std::vector<std::string> warnings;
20
+ };
21
+ SurfaceData loadSurface(const std::string& path, bool invert);
22
+
23
+ } // namespace oscadeval
@@ -306,7 +306,9 @@ std::string formatNumber(double v);
306
306
  //
307
307
  // A trailing lone backslash is kept as itself. It can only occur in an
308
308
  // unterminated literal, which is a parse error long before this runs.
309
- std::string unescapeStringLiteral(const std::string& raw);
309
+ // `undefinedEscapes`, when given, counts the escapes OpenSCAD's lexer calls
310
+ // undefined (it warns once for each).
311
+ std::string unescapeStringLiteral(const std::string& raw, int* undefinedEscapes = nullptr);
310
312
 
311
313
  // echo()/str()/assert-message display format: "undef" | "true"/"false" |
312
314
  // "[start : step : end]" (range) | formatNumber() (number) | "[e1, e2, ...]"
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.40.0"
7
+ version = "1.42.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -249,7 +249,8 @@ def _summarize_param(value, max_items: int = 6, max_len: int = 40) -> str:
249
249
  # of kind -- pure internal bookkeeping or already represented structurally
250
250
  # elsewhere in the tree. Mirrors the reference's _DUMP_HIDDEN_PARAM_KEYS.
251
251
  _DUMP_HIDDEN_PARAM_KEYS = frozenset(
252
- {"color", "op", "name", "group_sizes", "empty_is_a_group"})
252
+ {"color", "op", "name", "group_sizes", "empty_is_a_group", "background_stmt",
253
+ "m", "remove"})
253
254
 
254
255
  # Auto-generated tessellation data (not user-authored) for every kind except
255
256
  # polyhedron, where the equivalent data *is* the user's own points/faces.
@@ -520,7 +521,7 @@ class ColoredBody:
520
521
  section: object = None # kept for API parity (always None here)
521
522
  flat_preview: bool = False
522
523
  tri_colors: Optional[object] = None # (numTri, 4) float32 ndarray, real multi-color CSG merges only
523
- role: str = "normal" # "normal" | "highlight" | "background" | "show_only"
524
+ role: str = "normal" # "normal" | "highlight" | "highlight_ghost" | "background" | "show_only"
524
525
 
525
526
 
526
527
  def bodies_from_dicts(body_dicts) -> list:
@@ -33,17 +33,28 @@ RoleSplit splitByRole(const std::vector<ColoredBody>& bodies) {
33
33
  // boolean would silently zero the whole operation (the same failure
34
34
  // mode invalid operands caused before they were filtered out).
35
35
  for (const ColoredBody& c : bodies) {
36
- if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly) {
36
+ if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly &&
37
+ c.role != BodyRole::HighlightGhost) {
37
38
  r.displayOnly.push_back(c);
38
39
  }
39
40
  }
40
41
  for (const ColoredBody& c : bodies) {
41
- if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && !c.isDisplayOnly()) {
42
+ if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && c.role != BodyRole::HighlightGhost &&
43
+ !c.isDisplayOnly()) {
42
44
  r.foreground.push_back(c);
43
45
  }
44
46
  }
47
+ // A `#` operand is merged like any other (it is in `foreground` above)
48
+ // AND drawn again as a ghost; a ghost from deeper down just rides along.
45
49
  for (const ColoredBody& c : r.foreground) {
46
- if (c.role == BodyRole::Highlight) r.highlight.push_back(c);
50
+ if (c.role == BodyRole::Highlight) {
51
+ ColoredBody ghost = c;
52
+ ghost.role = BodyRole::HighlightGhost;
53
+ r.highlight.push_back(std::move(ghost));
54
+ }
55
+ }
56
+ for (const ColoredBody& c : bodies) {
57
+ if (c.role == BodyRole::HighlightGhost) r.highlight.push_back(c);
47
58
  }
48
59
  for (const ColoredBody& c : bodies) {
49
60
  if (c.role == BodyRole::ShowOnly) r.showOnly.push_back(c);
@@ -82,6 +93,13 @@ std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBo
82
93
  // alongside real ManifoldCache/provenance work if per-triangle color
83
94
  // through a merge is needed).
84
95
 
96
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt) {
97
+ const oscad::NodeKind k = stmt.kind();
98
+ return k == oscad::NodeKind::ModularCall || k == oscad::NodeKind::ModularFor ||
99
+ k == oscad::NodeKind::ModularIntersectionFor || k == oscad::NodeKind::ModularLet ||
100
+ k == oscad::NodeKind::ModularModifierShowOnly || k == oscad::NodeKind::ModularModifierHighlight;
101
+ }
102
+
85
103
  CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
86
104
  const std::string& op = node.name->name;
87
105
  // union/difference/intersection take no positional arguments in real
@@ -110,6 +128,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
110
128
 
111
129
  std::vector<Value> groupSizes;
112
130
  std::vector<Value> emptyIsAGroup;
131
+ std::vector<Value> backgroundStmt;
113
132
  groupSizes.reserve(geoNodes.size());
114
133
  emptyIsAGroup.reserve(geoNodes.size());
115
134
  for (const oscad::ASTNode* geoNode : geoNodes) {
@@ -130,15 +149,8 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
130
149
  // for `if(false) sphere(6)`, `{ }` and `*cube(1)`, and comes out
131
150
  // empty for `for(i=[1:0]) sphere(6)`, `union(){}`, `group(){}` and
132
151
  // a call to an empty user module.
133
- const oscad::NodeKind k = geoNode->kind();
134
- emptyIsAGroup.push_back(Value{
135
- k == oscad::NodeKind::ModularCall ||
136
- k == oscad::NodeKind::ModularFor ||
137
- k == oscad::NodeKind::ModularIntersectionFor ||
138
- k == oscad::NodeKind::ModularLet ||
139
- k == oscad::NodeKind::ModularModifierShowOnly ||
140
- k == oscad::NodeKind::ModularModifierHighlight ||
141
- k == oscad::NodeKind::ModularModifierBackground});
152
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*geoNode)});
153
+ backgroundStmt.push_back(Value{geoNode->kind() == oscad::NodeKind::ModularModifierBackground});
142
154
  }
143
155
 
144
156
  CSGParams params;
@@ -146,6 +158,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
146
158
  params["group_sizes"] = Value{makeList(std::move(groupSizes))};
147
159
  params["empty_is_a_group"] =
148
160
  Value{makeList(std::move(emptyIsAGroup))};
161
+ params["background_stmt"] = Value{makeList(std::move(backgroundStmt))};
149
162
  return params;
150
163
  }
151
164
 
@@ -314,6 +327,11 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
314
327
  const std::string& op = std::get<std::string>(params.at("op"));
315
328
  const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
316
329
  const auto emptyIsAGroupIt = params.find("empty_is_a_group");
330
+ const auto backgroundStmtIt = params.find("background_stmt");
331
+ const auto* backgroundStmt =
332
+ backgroundStmtIt != params.end() && std::holds_alternative<ListPtr>(backgroundStmtIt->second)
333
+ ? &std::get<ListPtr>(backgroundStmtIt->second)->items
334
+ : nullptr;
317
335
  const ListItems* emptyIsAGroup =
318
336
  emptyIsAGroupIt == params.end()
319
337
  ? nullptr
@@ -374,6 +392,20 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
374
392
  }
375
393
 
376
394
  RoleSplit split = splitByRole(stmtBodies);
395
+ // A `%` statement is scenery, not an operand: upstream leaves it out
396
+ // of the CSG entirely (collectChildren skips isBackground()), so the
397
+ // NEXT statement is the minuend of a difference(), and an
398
+ // intersection() is not cancelled by it. It was taken as an empty
399
+ // operand, which emptied both. Only the `%` statement itself: a
400
+ // module or union() holding nothing but `%` is still an (empty)
401
+ // operand there.
402
+ const bool isBackgroundStmt = backgroundStmt && thisStmt < backgroundStmt->size() &&
403
+ std::holds_alternative<bool>((*backgroundStmt)[thisStmt]) &&
404
+ std::get<bool>((*backgroundStmt)[thisStmt]);
405
+ if (isBackgroundStmt) {
406
+ allBg.insert(allBg.end(), split.background.begin(), split.background.end());
407
+ continue;
408
+ }
377
409
  allBg.insert(allBg.end(), split.background.begin(), split.background.end());
378
410
  allHi.insert(allHi.end(), split.highlight.begin(), split.highlight.end());
379
411
  allSo.insert(allSo.end(), split.showOnly.begin(), split.showOnly.end());
@@ -267,6 +267,19 @@ std::vector<ColoredBody> generateSurface(Evaluator& ev, const CSGParams& params,
267
267
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
268
268
 
269
269
  // text() -- text.cpp.
270
+ // Whether a statement that produced no geometry still counts as a boolean
271
+ // operand (and so empties an intersection) -- see resolveCsg.
272
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt);
273
+
274
+ // OpenSCAD's sin_degrees/cos_degrees: exact at multiples of 30 and 45 degrees.
275
+ double sinDeg(double x);
276
+ double cosDeg(double x);
277
+
278
+ // OpenSCAD's lookup_radius() (primitives_2d.cpp): `d` beats `r`, numbers only.
279
+ std::optional<double> lookupRadius(Evaluator& ev, const CallArgs& args, std::optional<int> rPos,
280
+ std::optional<int> dPos, const std::string& rName, const std::string& dName,
281
+ const oscad::Position* where);
282
+
270
283
  CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
271
284
 
272
285
  // The font size text()/textmetrics()/fontmetrics() draw at: `size`
@@ -106,6 +106,8 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
106
106
  const std::vector<const oscad::ASTNode*> bodyNodes = ev.expandChildStatements(node.body, ctx);
107
107
 
108
108
  std::vector<Value> groupSizes;
109
+ std::vector<Value> emptyIsAGroup;
110
+ std::vector<Value> backgroundStmt;
109
111
 
110
112
  // Each dimension's own RHS is evaluated against `parentCtx` (not
111
113
  // upfront against the original `ctx`), re-evaluated on every entry
@@ -116,14 +118,31 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
116
118
  // needs `i` visible in `j`'s own range expression).
117
119
  std::function<void(size_t, EvalContext&)> recurse = [&](size_t depth, EvalContext& parentCtx) {
118
120
  if (depth == node.assignments.size()) {
121
+ if (depth == 0) return; // for() with no loop variables iterates zero times in OpenSCAD, not once.
119
122
  // One body-entry marker per full cartesian-product iteration
120
123
  // and nothing per individual variable binding (unlike
121
124
  // evalFor) -- mirrors _resolve_intersection_for's single
122
125
  // `_check_debug(body_node[0], loop_ctx, expr_level=True)`.
123
126
  if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
124
- const size_t before = ev.currentTreeFrameSize();
125
- ev.evalChildren(bodyNodes, parentCtx);
126
- groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
127
+ // One operand per child STATEMENT of every iteration: upstream
128
+ // instantiates the children straight into the intersection
129
+ // node (control.cc), so they are intersected flat, not
130
+ // unioned per iteration first.
131
+ std::vector<const oscad::ASTNode*> assigns, stmts;
132
+ for (const oscad::ASTNode* stmt : bodyNodes) {
133
+ if (stmt->kind() == oscad::NodeKind::Assignment) assigns.push_back(stmt);
134
+ else if (stmt->kind() != oscad::NodeKind::ModuleDeclaration &&
135
+ stmt->kind() != oscad::NodeKind::FunctionDeclaration)
136
+ stmts.push_back(stmt);
137
+ }
138
+ if (!assigns.empty()) ev.evalChildren(assigns, parentCtx);
139
+ for (const oscad::ASTNode* stmt : stmts) {
140
+ const size_t before = ev.currentTreeFrameSize();
141
+ ev.evalChildren(std::vector<const oscad::ASTNode*>{stmt}, parentCtx);
142
+ groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
143
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*stmt)});
144
+ backgroundStmt.push_back(Value{stmt->kind() == oscad::NodeKind::ModularModifierBackground});
145
+ }
127
146
  return;
128
147
  }
129
148
  const auto& assign = node.assignments[depth];
@@ -142,49 +161,19 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
142
161
 
143
162
  CSGParams params;
144
163
  params["group_sizes"] = Value{makeList(std::move(groupSizes))};
164
+ params["empty_is_a_group"] = Value{makeList(std::move(emptyIsAGroup))};
165
+ params["background_stmt"] = Value{makeList(std::move(backgroundStmt))};
145
166
  return params;
146
167
  }
147
168
 
148
- std::vector<ColoredBody> generateIntersectionFor(Evaluator&, const CSGParams& params,
169
+ std::vector<ColoredBody> generateIntersectionFor(Evaluator& ev, const CSGParams& params,
149
170
  const std::vector<std::unique_ptr<CSGNode>>& children,
150
- const oscad::ASTNode&) {
151
- const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
152
- std::vector<ColoredBody> iterations;
153
- size_t idx = 0;
154
- for (const Value& sv : groupSizes) {
155
- const size_t size = static_cast<size_t>(std::get<double>(sv));
156
- std::vector<ColoredBody> stmtBodies = flattenCsgTree(children, idx, size);
157
- idx += size;
158
- if (!stmtBodies.empty()) iterations.push_back(combineBodies(stmtBodies));
159
- }
160
- if (iterations.empty()) return {};
161
-
162
- std::vector<ColoredBody> bodies3d;
163
- for (const ColoredBody& c : iterations) {
164
- if (c.body) bodies3d.push_back(c);
165
- }
166
- if (!bodies3d.empty()) {
167
- manifold::Manifold result = *bodies3d.front().body;
168
- for (size_t i = 1; i < bodies3d.size(); ++i) result = result ^ *bodies3d[i].body;
169
- ColoredBody cb;
170
- cb.body = std::move(result);
171
- cb.color = bodies3d.front().color;
172
- return {cb};
173
- }
174
-
175
- std::vector<ColoredBody> sections;
176
- for (const ColoredBody& c : iterations) {
177
- if (c.section) sections.push_back(c);
178
- }
179
- if (!sections.empty()) {
180
- manifold::CrossSection result = *sections.front().section;
181
- for (size_t i = 1; i < sections.size(); ++i) result = result ^ *sections[i].section;
182
- ColoredBody cb;
183
- cb.section = std::move(result);
184
- cb.color = iterations.front().color;
185
- return {cb};
186
- }
187
- return {};
171
+ const oscad::ASTNode& node) {
172
+ // The same operand rules as intersection() itself -- empty statements,
173
+ // `%` scenery, `#` ghosts, 2D vs 3D -- over the flat statement list.
174
+ CSGParams p = params;
175
+ p["op"] = Value{std::string("intersection")};
176
+ return generateCsg(ev, p, children, node);
188
177
  }
189
178
 
190
179
  } // namespace oscadeval