openscad-cpp-evaluator 0.29.3__tar.gz → 0.31.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 (203) hide show
  1. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/CLAUDE.md +23 -1
  2. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/PKG-INFO +1 -1
  3. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/bindings/module.cpp +48 -2
  4. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/dispatch.hpp +19 -0
  5. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/eval_error.hpp +35 -0
  6. openscad_cpp_evaluator-0.31.0/include/openscad_cpp_evaluator/export.hpp +144 -0
  7. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/pyproject.toml +1 -1
  8. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/python/openscad_cpp_evaluator/__init__.py +44 -1
  9. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/function_builtins.cpp +13 -0
  10. openscad_cpp_evaluator-0.31.0/src/builtins/registry.cpp +142 -0
  11. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/bytecode_vm.cpp +20 -6
  12. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/csg_resolve.cpp +1 -0
  13. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/eval_error.cpp +37 -0
  14. openscad_cpp_evaluator-0.31.0/src/export.cpp +974 -0
  15. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/user_calls.cpp +8 -1
  16. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/CMakeLists.txt +1 -0
  17. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_cli.cpp +71 -2
  18. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_import_export.cpp +12 -8
  19. openscad_cpp_evaluator-0.31.0/tests/test_unexpected_args.cpp +151 -0
  20. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tools/cli/cli_lib.cpp +16 -15
  21. openscad_cpp_evaluator-0.29.3/include/openscad_cpp_evaluator/export.hpp +0 -51
  22. openscad_cpp_evaluator-0.29.3/src/builtins/registry.cpp +0 -81
  23. openscad_cpp_evaluator-0.29.3/src/export.cpp +0 -242
  24. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/.github/workflows/ci.yml +0 -0
  25. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/.github/workflows/wheels.yml +0 -0
  26. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/.gitignore +0 -0
  27. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/.gitmodules +0 -0
  28. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/CMakeLists.txt +0 -0
  29. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/LICENSE +0 -0
  30. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/README.md +0 -0
  31. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/bindings/CMakeLists.txt +0 -0
  32. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/bindings/ast_to_py.cpp +0 -0
  33. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/cmake/embed_font.cmake +0 -0
  34. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/examples/CMakeLists.txt +0 -0
  35. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/examples/eval_perf_benchmark.cpp +0 -0
  36. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/examples/manifold_cache_reuse.cpp +0 -0
  37. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/examples/minimal_debugger.cpp +0 -0
  38. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  39. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/.gitignore +0 -0
  40. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  41. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  42. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/README.md +0 -0
  43. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  44. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  45. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  46. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  47. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  48. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  49. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  50. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  51. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  52. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  53. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  54. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  55. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  56. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  57. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  58. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  59. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  60. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  61. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  62. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  63. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  64. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  65. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  66. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  67. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  68. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  69. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  70. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  71. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  72. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  73. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  74. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  75. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  76. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  77. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  78. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  79. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  80. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  81. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  82. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  83. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  84. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  85. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  86. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  87. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  88. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  89. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  90. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  91. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  92. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  93. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  94. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  95. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  96. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  97. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  98. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  99. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  100. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  101. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  102. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  103. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  104. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  105. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  106. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  107. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  108. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  109. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  110. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  111. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  112. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  113. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  114. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  115. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  116. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  117. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  118. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  119. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  120. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  121. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  122. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  123. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  124. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  125. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  126. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  127. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  128. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
  129. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  130. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  131. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  132. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  133. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/resources/fonts/LICENSE +0 -0
  134. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  135. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/CMakeLists.txt +0 -0
  136. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/booleans.cpp +0 -0
  137. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/builtins.hpp +0 -0
  138. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/call_args.cpp +0 -0
  139. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/color.cpp +0 -0
  140. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/control.cpp +0 -0
  141. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/extrude.cpp +0 -0
  142. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/import.cpp +0 -0
  143. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/modifiers.cpp +0 -0
  144. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/primitives_2d.cpp +0 -0
  145. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/primitives_3d.cpp +0 -0
  146. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/roof.cpp +0 -0
  147. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/segments.cpp +0 -0
  148. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/surface.cpp +0 -0
  149. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/text.cpp +0 -0
  150. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/topology.cpp +0 -0
  151. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/builtins/transforms.cpp +0 -0
  152. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/bytecode_compiler.cpp +0 -0
  153. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/colored_body.cpp +0 -0
  154. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/csg_generate.cpp +0 -0
  155. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/css_colors.cpp +0 -0
  156. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/debug/debug_repl.cpp +0 -0
  157. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/debug_profile.cpp +0 -0
  158. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/eval_context.cpp +0 -0
  159. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/eval_use.cpp +0 -0
  160. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/expr_eval.cpp +0 -0
  161. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/import/dxf_import.cpp +0 -0
  162. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/import/mesh_import.cpp +0 -0
  163. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/import/surface_load.cpp +0 -0
  164. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/import/svg_import.cpp +0 -0
  165. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/manifold_cache.cpp +0 -0
  166. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/mesh_check.cpp +0 -0
  167. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/stmt_eval.cpp +0 -0
  168. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/text/stb_font_provider.cpp +0 -0
  169. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/text/text_metrics.cpp +0 -0
  170. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/value.cpp +0 -0
  171. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/src/zip_stored.cpp +0 -0
  172. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_booleans.cpp +0 -0
  173. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_bytecode_compiler.cpp +0 -0
  174. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_control_flow.cpp +0 -0
  175. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_csg_tree.cpp +0 -0
  176. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_debug_hooks.cpp +0 -0
  177. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_dxf_svg_import.cpp +0 -0
  178. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_eval_context.cpp +0 -0
  179. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_export.cpp +0 -0
  180. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_expr_eval.cpp +0 -0
  181. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_extrude_roof.cpp +0 -0
  182. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_function_builtins.cpp +0 -0
  183. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_helpers.hpp +0 -0
  184. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_manifold_cache.cpp +0 -0
  185. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_mesh_check.cpp +0 -0
  186. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_multi_color_merge.cpp +0 -0
  187. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_primitives.cpp +0 -0
  188. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_profiling.cpp +0 -0
  189. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_python_bindings.py +0 -0
  190. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_scope_trail.cpp +0 -0
  191. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_scoping.cpp +0 -0
  192. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_surface.cpp +0 -0
  193. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_tail_calls.cpp +0 -0
  194. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_text.cpp +0 -0
  195. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_transforms.cpp +0 -0
  196. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_use.cpp +0 -0
  197. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_value.cpp +0 -0
  198. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_viewport_params.cpp +0 -0
  199. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tests/test_zip_stored.cpp +0 -0
  200. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tools/cli/CMakeLists.txt +0 -0
  201. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tools/cli/cli_lib.hpp +0 -0
  202. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/tools/cli/main.cpp +0 -0
  203. {openscad_cpp_evaluator-0.29.3 → openscad_cpp_evaluator-0.31.0}/uv.lock +0 -0
@@ -424,7 +424,29 @@ grep for `ponytail:`.
424
424
  give sibling statements in the same block correct assignment visibility (see the header comment
425
425
  before reworking this; it's not an arbitrary choice).
426
426
  - `include/openscad_cpp_evaluator/eval_error.hpp`, `src/eval_error.cpp` — `EvalError` and the
427
- exact ERROR/TRACE string formatting real OpenSCAD produces.
427
+ exact ERROR/TRACE string formatting real OpenSCAD produces. Also the **unexpected-argument
428
+ warnings** (`warnUnexpectedNamedArg`/`warnTooManyPositionalArgs`/`warnUnexpectedArgs`), the port
429
+ of real OpenSCAD's `Parameters.cc` `parse_without_defaults`: `variable X not specified as
430
+ parameter` for a named argument the callee doesn't declare, and `Too many unnamed arguments
431
+ supplied` once per call for positional arguments past the last parameter. `$`-prefixed names
432
+ other than `$children` are exempt (`isConfigVariable`, mirroring
433
+ `ContextFrame::is_config_variable` — a `$`-name is a dynamic-scope override, never a parameter).
434
+ The check has to be repeated at **every** argument-binding path, since there are five and none of
435
+ them share a choke point: `bindArgs` (interpreter, `user_calls.cpp`),
436
+ `buildBoundArgs`/`bindAstArgsIntoFrame` (bytecode VM, `bytecode_vm.cpp`), `evalModularCall`
437
+ (builtin modules, `csg_resolve.cpp`) and the VM's own `Op::PushBuiltinWrap`/`Op::PushCsgWrap`
438
+ handlers — the transform/color/hull/minkowski/render/extrude/projection/offset/roof/CSG family
439
+ bypasses `evalModularCall` entirely once compiled, which is exactly the gap
440
+ `tests/test_unexpected_args.cpp` runs every case twice (VM off and on) to catch. Builtin
441
+ parameter names live in `builtinParamNames` (`registry.cpp`): each list is the union of real
442
+ OpenSCAD's own `Parameters::parse` declaration and any extra name this port reads via `getArg`,
443
+ so the port never warns about an argument it goes on to honour — **add to it whenever a builtin
444
+ gains a parameter**, or that parameter starts warning. Builtin *functions* deliberately have no
445
+ entries beyond `textmetrics`/`fontmetrics`: upstream reads their arguments positionally without
446
+ `Parameters::parse`, so `sin(bogus=30)` warns about nothing there (verified against 2022.08.22)
447
+ and warning here would be a divergence. Not ported: the reference's `argument X supplied more
448
+ than once` / `argument X overrides positional argument`, separate conditions this port's simpler
449
+ positional-matching rule doesn't track.
428
450
  - `include/openscad_cpp_evaluator/evaluator.hpp`, `src/expr_eval.cpp`, `src/stmt_eval.cpp`,
429
451
  `src/user_calls.cpp` — the `Evaluator` class. Expression/statement dispatch is a `switch` on
430
452
  `NodeKind` (matches `openscad_cpp_parser`'s own dispatch convention, not a visitor).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.29.3
3
+ Version: 0.31.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -22,6 +22,7 @@
22
22
  #include "openscad_cpp_evaluator/eval_context.hpp"
23
23
  #include "openscad_cpp_evaluator/eval_use.hpp"
24
24
  #include "openscad_cpp_evaluator/evaluator.hpp"
25
+ #include "openscad_cpp_evaluator/export.hpp"
25
26
  #include "openscad_cpp_evaluator/mesh_check.hpp"
26
27
  #include "openscad_cpp_evaluator/manifold_cache.hpp"
27
28
  #include "openscad_cpp_evaluator/profile.hpp"
@@ -340,6 +341,36 @@ std::pair<nb::dict, nb::object> dynStateToPy(const oscadeval::EvalContext& ctx)
340
341
  // message as a Python exception on ParseError/EvalError (nanobind maps
341
342
  // std::exception -> RuntimeError, whose str() is the already-formatted
342
343
  // "ERROR:..."/caret diagnostic; the facade re-raises as EvalError).
344
+ // The evaluated bodies, kept on the C++ side.
345
+ //
346
+ // bodyToDict flattens every Manifold into numpy arrays for the renderer,
347
+ // which is all the renderer needs -- but export has to do real CSG (the
348
+ // union, the per-colour claim, decompose), and rebuilding Manifolds from
349
+ // those arrays to do it costs ~146ms on a 224k-triangle model and throws
350
+ // away Manifold's own provenance. Handing back an opaque handle instead
351
+ // means geometry never round-trips through Python at all.
352
+ struct Geometry {
353
+ std::vector<oscadeval::ColoredBody> bodies;
354
+ };
355
+
356
+ // exportModel, with the path/format/warnings marshalling. Releases the GIL:
357
+ // a large export is seconds of Manifold work with no Python involved.
358
+ nb::list exportModelPy(const std::string& path, const Geometry& geom, const std::string& format, bool asciiStl,
359
+ bool stripSlivers) {
360
+ std::vector<std::string> warnings;
361
+ {
362
+ nb::gil_scoped_release rel;
363
+ oscadeval::ExportOptions opts;
364
+ opts.format = format;
365
+ opts.asciiStl = asciiStl;
366
+ opts.stripSlivers = stripSlivers;
367
+ warnings = oscadeval::exportModel(path, geom.bodies, opts);
368
+ }
369
+ nb::list out;
370
+ for (const std::string& w : warnings) out.append(w);
371
+ return out;
372
+ }
373
+
343
374
  nb::object evaluate(const std::string& path, nb::dict viewportParams,
344
375
  std::shared_ptr<oscadeval::ManifoldCache> manifoldCache, bool profile) {
345
376
  std::unordered_map<std::string, oscadeval::Value> vp = toViewportParams(viewportParams);
@@ -370,8 +401,10 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
370
401
 
371
402
  nb::list echoList;
372
403
  for (const std::string& s : echoes) echoList.append(s);
373
- return nb::make_tuple(bodiesToList(bodies), echoList, idSpansToDict(idSpans), csgTreeToPy(csgTree),
374
- profileResultToPy(profileResult), dyn, dynExplicit);
404
+ auto geom = std::make_shared<Geometry>();
405
+ geom->bodies = std::move(bodies);
406
+ return nb::make_tuple(bodiesToList(geom->bodies), echoList, idSpansToDict(idSpans), csgTreeToPy(csgTree),
407
+ profileResultToPy(profileResult), dyn, dynExplicit, geom);
375
408
  }
376
409
 
377
410
  // ------------------------------------------------------------------------
@@ -721,6 +754,19 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
721
754
  .def(nb::init<>())
722
755
  .def("request", &FastContinueSignal::request);
723
756
 
757
+ nb::class_<Geometry>(m, "Geometry",
758
+ "Opaque handle to the evaluated bodies, kept on the C++ side so export never has to "
759
+ "rebuild Manifolds from the renderer's flattened arrays. Hand it to export_model().")
760
+ .def("__len__", [](const Geometry& g) { return g.bodies.size(); })
761
+ .def("is_empty", [](const Geometry& g) { return g.bodies.empty(); });
762
+
763
+ m.def("export_model", &exportModelPy, nb::arg("path"), nb::arg("geometry"), nb::arg("format") = std::string(),
764
+ nb::arg("ascii_stl") = false, nb::arg("strip_slivers") = true,
765
+ "Write `geometry` to `path`, format taken from the extension unless `format` says otherwise. "
766
+ "Returns the warnings to surface (open shells, mesh problems, slivers removed) rather than "
767
+ "logging them. Raises RuntimeError when there is no geometry, the format is unknown, or the "
768
+ "file cannot be opened.");
769
+
724
770
  m.def("evaluate", &evaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("manifold_cache") = nullptr,
725
771
  nb::arg("profile") = false,
726
772
  "Evaluate a .scad file; return (bodies, echoes, id_to_node, csg_tree, profile_result, dyn, dyn_explicit).");
@@ -54,6 +54,25 @@ using GenerateFn = std::vector<ColoredBody> (*)(Evaluator&, const CSGParams&, co
54
54
  const std::unordered_map<std::string_view, ResolveFn>& resolveDispatch();
55
55
  const std::unordered_map<std::string_view, GenerateFn>& generateDispatch();
56
56
 
57
+ // Every parameter name a builtin accepts, for the unexpected-argument
58
+ // warning (see eval_error.hpp). Returns nullptr for a name with no entry,
59
+ // which suppresses the check rather than warning about everything.
60
+ //
61
+ // Each list is the UNION of real OpenSCAD's own Parameters::parse
62
+ // declaration for that builtin (2022.08.22 -- the authority on what warns
63
+ // upstream) and any extra name this port itself reads via getArg, so this
64
+ // port never warns about an argument it goes on to honour.
65
+ const std::vector<std::string>* builtinParamNames(const std::string& name);
66
+
67
+ // builtinParamNames + warnUnexpectedArgs for one builtin module call. Must
68
+ // be invoked from EVERY path a builtin call can take: evalModularCall
69
+ // (interpreter, and Op::NativeStatement) plus the bytecode VM's own
70
+ // Op::PushBuiltinWrap/Op::PushCsgWrap handlers, which bypass
71
+ // evalModularCall entirely for the transform/color/hull/extrude/CSG family.
72
+ // Silently does nothing for a node that isn't a ModularCall (a `#`/`%`/`!`
73
+ // modifier shares BuiltinWrapSite but carries no arguments).
74
+ void warnUnexpectedBuiltinArgs(Evaluator& ev, const oscad::ASTNode& callNode);
75
+
57
76
  // Concatenates every top-level node's already-generated `.bodies` (does NOT
58
77
  // recurse into `.children` -- a parent's `.bodies` is already the fully
59
78
  // combined result of its children). Mirrors the reference's
@@ -2,12 +2,15 @@
2
2
 
3
3
  #include "openscad_cpp_parser/position.hpp"
4
4
 
5
+ #include <memory>
5
6
  #include <stdexcept>
6
7
  #include <string>
7
8
  #include <vector>
8
9
 
9
10
  namespace oscad {
10
11
  class ASTNode;
12
+ class Argument;
13
+ class ParameterDeclaration;
11
14
  } // namespace oscad
12
15
 
13
16
  namespace oscadeval {
@@ -129,4 +132,36 @@ std::string formatError(const std::string& msg, const oscad::Position* nodePosit
129
132
  std::string formatWarning(const std::string& msg, const oscad::Position* nodePosition,
130
133
  const std::vector<CallStackFrame>& callStack);
131
134
 
135
+ // -- Unexpected-argument warnings -----------------------------------------
136
+ //
137
+ // Real OpenSCAD (Parameters.cc's parse_without_defaults) warns for a named
138
+ // argument the callee doesn't declare, and once per call for positional
139
+ // arguments past the last parameter. Both are silently dropped otherwise,
140
+ // which makes a typo'd argument name invisible -- the call still runs, the
141
+ // parameter just keeps its default. Wording is verbatim from the reference
142
+ // (2022.08.22, which quotes neither name nor message).
143
+ //
144
+ // NOT covered here (separate reference warnings, separate conditions):
145
+ // "argument X supplied more than once" and "argument X overrides positional
146
+ // argument".
147
+ class Evaluator;
148
+
149
+ // ContextFrame::is_config_variable: a $-prefixed name other than $children
150
+ // is a dynamic-scope override, never a declared parameter, so it is exempt.
151
+ bool isConfigVariable(const std::string& name);
152
+
153
+ // Linear scan -- ponytail: parameter lists are single-digit in practice, so
154
+ // a per-call set/map would cost more than it saves.
155
+ bool declaresParam(const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params, const std::string& name);
156
+
157
+ void warnUnexpectedNamedArg(Evaluator& ev, const std::string& name, const oscad::Position* pos);
158
+ void warnTooManyPositionalArgs(Evaluator& ev, const oscad::Position* pos);
159
+
160
+ // Both warnings at once for a callee whose parameter names are a fixed list
161
+ // rather than a declaration -- i.e. a builtin (see builtinParamNames,
162
+ // dispatch.hpp). Reports against each argument's own position, which is the
163
+ // call's own line in every case that isn't a multi-line argument list.
164
+ void warnUnexpectedArgs(Evaluator& ev, const std::vector<std::string>& params,
165
+ const std::vector<std::unique_ptr<oscad::Argument>>& arguments);
166
+
132
167
  } // namespace oscadeval
@@ -0,0 +1,144 @@
1
+ #pragma once
2
+
3
+ #include "openscad_cpp_evaluator/colored_body.hpp"
4
+
5
+ #include <array>
6
+ #include <cstdint>
7
+ #include <string>
8
+ #include <vector>
9
+
10
+ namespace oscadeval {
11
+
12
+ // The colour every object falls back to when the script gave none.
13
+ inline constexpr std::array<float, 4> kDefaultExportColor = {0.8f, 0.8f, 0.8f, 1.0f};
14
+
15
+ // One object in a file format that can hold more than one -- 3MF, OBJ,
16
+ // VRML, X3D. `triColors` is empty for the ordinary flat-coloured object,
17
+ // or one RGBA per triangle when the surface came out of a multi-colour CSG
18
+ // merge (see splitBodiesForExport).
19
+ struct ExportObject {
20
+ std::vector<float> verts; // xyz triples
21
+ std::vector<uint32_t> tris; // vertex-index triples
22
+ std::array<float, 4> color = kDefaultExportColor;
23
+ std::vector<std::array<float, 4>> triColors;
24
+ };
25
+
26
+ // The implicit top-level union, cut into objects that never overlap.
27
+ //
28
+ // Top level in OpenSCAD is an implicit union, so `cube(100); cube(100,
29
+ // center=true);` is ONE solid -- writing the bodies as they arrive put both
30
+ // cubes in the file separately, overlapping, with their interior faces
31
+ // intact. Three rules, in order:
32
+ //
33
+ // 1. Union, never concatenate. Concatenating is only right while the
34
+ // bodies are disjoint; where two touch, each writes its own copy of
35
+ // the shared face and the result is non-manifold.
36
+ // 2. One object per colour, and no two objects share volume. Where
37
+ // differently-coloured solids overlap the LATER one owns the shared
38
+ // volume and the earlier is notched around it -- painter's order, so
39
+ // `color("red") body(); color("blue") detail();` leaves the detail
40
+ // whole. Only the invisible interior is affected: the visible surface
41
+ // is identical either way.
42
+ // 3. One object per connected component.
43
+ //
44
+ // A body Manifold rejected (an open shell is not a solid) can take part in
45
+ // none of that: it keeps its own triangles and its own object, and its
46
+ // 1-based index is appended to `openParts` for the caller to warn about.
47
+ std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& bodies,
48
+ std::vector<int>* openParts = nullptr);
49
+
50
+ // Writes a binary STL: composes every body's mesh into one solid (bodies
51
+ // with no `.body` -- 2D-only sections -- or an empty Manifold are
52
+ // skipped), per-triangle normals computed from vertex winding. Mirrors
53
+ // export.py's write_stl exactly (80-byte zero header, uint32 LE triangle
54
+ // count, 50 bytes/triangle: 3x float32 normal, 3x3 float32 vertices,
55
+ // uint16 attr=0). Throws std::runtime_error if there's no 3D geometry to
56
+ // export, or if the file can't be opened for writing.
57
+ //
58
+ // 3MF and format-from-extension dispatch land in Phase 5 per the plan's
59
+ // phased build order.
60
+ // One message per body that is not a closed manifold solid, ready to print.
61
+ // Empty when everything is sound.
62
+ //
63
+ // Returned rather than logged so each front end can surface it its own way,
64
+ // and so export.cpp needs no logging dependency. Nothing here refuses to
65
+ // write: a deliberately open surface is a legitimate thing to export, and
66
+ // silently blocking a save would be worse than an honest warning.
67
+ std::vector<std::string> checkExportBodies(const std::vector<ColoredBody>& bodies);
68
+
69
+ void writeStl(const std::string& path, const std::vector<ColoredBody>& bodies);
70
+
71
+ // OpenSCAD-compatible ASCII STL -- "solid OpenSCAD_Model" / one "facet
72
+ // normal .. outer loop .. vertex x3 .. endloop endfacet" per triangle /
73
+ // "endsolid". Format confirmed against real OpenSCAD's own -o out.stl.
74
+ void writeStlAscii(const std::string& path, const std::vector<ColoredBody>& bodies);
75
+
76
+ // Wavefront OBJ: one `o` group per object, `usemtl` naming a material in a
77
+ // companion .mtl written alongside (so an OBJ export produces TWO files).
78
+ // A multi-coloured surface becomes runs of faces with a `usemtl` between
79
+ // them, in triangle order -- the only per-face colour OBJ has.
80
+ void writeObj(const std::string& path, const std::vector<ExportObject>& objects);
81
+
82
+ // Binary little-endian PLY, one flat mesh with per-vertex colour. PLY has
83
+ // no object concept, so the objects are concatenated; an object carrying
84
+ // per-triangle colour is unwelded (three vertices per triangle), since a
85
+ // vertex shared by two differently-coloured triangles has no single answer.
86
+ void writePly(const std::string& path, const std::vector<ExportObject>& objects);
87
+
88
+ // VRML97 ("#VRML V2.0 utf8"), one Shape per object. Per-face colour rides
89
+ // on a Color node with `colorPerVertex FALSE`. Neither this nor X3D can
90
+ // carry per-triangle alpha, so the object's base alpha applies to the whole
91
+ // shape through Material.transparency (which is 1 - alpha).
92
+ void writeVrml(const std::string& path, const std::vector<ExportObject>& objects);
93
+
94
+ // X3D 3.3, Interchange profile -- the XML encoding of what writeVrml emits,
95
+ // node for node. Interchange is the accurate claim: per Annex B it is
96
+ // Geometry3D level 2 (IndexedFaceSet), Rendering level 3 (Coordinate,
97
+ // Color) and Shape level 1 (Appearance, Material), exactly the nodes used.
98
+ void writeX3d(const std::string& path, const std::vector<ExportObject>& objects);
99
+
100
+ // OFF (Object File Format): header "OFF", "$verts $tris 0", vertex lines,
101
+ // then "3 i j k" per triangle (0-indexed, count-prefixed). Mirrors
102
+ // export.py's write_off.
103
+ void writeOff(const std::string& path, const std::vector<ColoredBody>& bodies);
104
+
105
+ // 3MF: one mesh object + a base-color colorgroup per body (skipping empty
106
+ // bodies), written as a DEFLATE-compressed ZIP (writeDeflateZip, see
107
+ // zip_stored.hpp) -- the XML is highly compressible, so storing it would
108
+ // make the file several times larger for nothing. An entry that does not
109
+ // actually shrink is stored raw, as any ZIP writer would.
110
+ // Mirrors export.py's write_3mf's XML shape exactly (core + material
111
+ // namespaces, %.6g vertex formatting); throws std::runtime_error if there's
112
+ // no geometry to export.
113
+ void writeThreeMf(const std::string& path, const std::vector<ExportObject>& objects);
114
+
115
+ // -- one entry point ------------------------------------------------------
116
+
117
+ struct ExportOptions {
118
+ // Empty means "decide from the path's extension".
119
+ std::string format;
120
+ // .stl only; binary otherwise.
121
+ bool asciiStl = false;
122
+ // Remove zero-area faces before writing the single-mesh formats. They
123
+ // break no topology, but slicers commonly discard them and are then
124
+ // left with the holes their removal opens.
125
+ bool stripSlivers = true;
126
+ };
127
+
128
+ // Writes `bodies` to `path`, choosing the writer from the extension (or
129
+ // opts.format) and applying the same repair/verification policy the GUI
130
+ // used to apply itself. Returns the warnings to surface -- open shells,
131
+ // mesh problems, sliver removal -- rather than logging them, so each front
132
+ // end can present them its own way.
133
+ //
134
+ // Nothing here refuses to write: a deliberately open surface is a
135
+ // legitimate export, and blocking a save the user asked for would be worse
136
+ // than saying so. Throws std::runtime_error only when there is no geometry
137
+ // at all, the format is unknown, or the file cannot be opened.
138
+ std::vector<std::string> exportModel(const std::string& path, const std::vector<ColoredBody>& bodies,
139
+ const ExportOptions& opts = {});
140
+
141
+ // The extensions exportModel understands, lower-case and dot-prefixed.
142
+ const std::vector<std::string>& exportExtensions();
143
+
144
+ } // namespace oscadeval
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.29.3"
7
+ version = "0.31.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -19,6 +19,7 @@ __all__ = [
19
19
  "Evaluator", "ColoredBody", "EvalError", "ParseError", "OscObject", "parse", "to_renderable_bodies",
20
20
  "ManifoldCache", "CallSiteProfile", "ProfileResult", "format_csg_tree", "bodies_from_dicts",
21
21
  "FastContinueSignal", "parse_ast", "parse_ast_string", "check_mesh", "strip_slivers",
22
+ "export_model", "export_extensions",
22
23
  ]
23
24
 
24
25
 
@@ -288,6 +289,36 @@ def strip_slivers(verts, tris):
288
289
  return _ext.strip_slivers([float(v) for v in verts], [int(t) for t in tris])
289
290
 
290
291
 
292
+ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
293
+ strip_slivers: bool = True) -> list:
294
+ """Write `geometry` to `path`. Returns the warnings to surface.
295
+
296
+ `geometry` is the handle an Evaluator stashes on itself as
297
+ `.geometry` -- the evaluated bodies, still on the C++ side. Export has
298
+ to do real CSG (the implicit top-level union, the per-colour volume
299
+ claim, the connected-component split), and going through the flattened
300
+ arrays the renderer gets would mean rebuilding every Manifold first:
301
+ ~146ms on a 224k-triangle model, and Manifold's own provenance lost
302
+ along the way.
303
+
304
+ Format comes from the extension unless `format` overrides it. Warnings
305
+ -- open shells, mesh problems, slivers removed -- are returned rather
306
+ than logged so each front end can present them its own way. Nothing
307
+ here refuses to write: a deliberately open surface is a legitimate
308
+ export. Raises EvalError when there is no geometry, the format is
309
+ unknown, or the file cannot be opened.
310
+ """
311
+ try:
312
+ return list(_ext.export_model(path, geometry, format, ascii_stl, strip_slivers))
313
+ except Exception as e:
314
+ raise EvalError(str(e)) from e
315
+
316
+
317
+ def export_extensions() -> list:
318
+ """The file extensions export_model understands, dot-prefixed."""
319
+ return [".3mf", ".stl", ".obj", ".off", ".ply", ".wrl", ".x3d"]
320
+
321
+
291
322
  def check_mesh(verts, tris) -> dict:
292
323
  """Diagnose a triangle mesh against the manifoldness conditions.
293
324
 
@@ -448,9 +479,21 @@ class Evaluator:
448
479
  self._manifold_cache, self._return_hook, self._fast_continue_signal)
449
480
  self.csg_tree = []
450
481
  self.profile_result = None
482
+ # The debugger path has no geometry handle: debug_evaluate
483
+ # returns bodies for display only, and a paused session is
484
+ # not something to export from.
485
+ self.geometry = None
451
486
  else:
452
- body_dicts, echoes, id_spans, csg_tree, profile_result, dyn, dyn_explicit = _ext.evaluate(
487
+ (body_dicts, echoes, id_spans, csg_tree, profile_result, dyn,
488
+ dyn_explicit, geometry) = _ext.evaluate(
453
489
  source_path, vp, self._manifold_cache, self._profile)
490
+ # The evaluated bodies, still on the C++ side. Stashed like
491
+ # csg_tree/profile_result rather than returned, so
492
+ # evaluate()'s own 2-tuple result is unchanged -- callers
493
+ # that only render never need to know this exists. Hand it
494
+ # to export_model(); see its docstring for why export does
495
+ # not just rebuild from the arrays the renderer gets.
496
+ self.geometry = geometry
454
497
  if self._echo_fn:
455
498
  for line in echoes:
456
499
  self._echo_fn(line)
@@ -1,5 +1,6 @@
1
1
  #include "openscad_cpp_evaluator/function_builtins.hpp"
2
2
 
3
+ #include "openscad_cpp_evaluator/dispatch.hpp"
3
4
  #include "openscad_cpp_evaluator/evaluator.hpp"
4
5
  #include "openscad_cpp_evaluator/segments.hpp"
5
6
  #include "openscad_cpp_evaluator/text_metrics.hpp"
@@ -509,6 +510,18 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
509
510
  // elsewhere before reaching here) -- mirrors the old chain's fallthrough.
510
511
  if (idIt == ids.end()) return Value{};
511
512
 
513
+ // Only textmetrics/fontmetrics have an entry -- every other builtin
514
+ // function reads its arguments positionally upstream and warns about
515
+ // nothing. See builtinParamNames (registry.cpp).
516
+ if (const std::vector<std::string>* declared = builtinParamNames(name)) {
517
+ for (const auto& [argName, _] : args.named) {
518
+ if (!isConfigVariable(argName) &&
519
+ std::find(declared->begin(), declared->end(), argName) == declared->end()) {
520
+ warnUnexpectedNamedArg(ev, argName, &node.position());
521
+ }
522
+ }
523
+ }
524
+
512
525
  if (const auto arityIt = scalarNumericArity().find(name); arityIt != scalarNumericArity().end()) {
513
526
  const std::vector<Value> positional = allPositional(args);
514
527
  if (positional.size() < arityIt->second) return Value{};
@@ -0,0 +1,142 @@
1
+ #include "builtins.hpp"
2
+
3
+ #include "openscad_cpp_evaluator/dispatch.hpp"
4
+ #include "openscad_cpp_evaluator/eval_error.hpp"
5
+
6
+ namespace oscadeval {
7
+
8
+ const std::unordered_map<std::string_view, ResolveFn>& resolveDispatch() {
9
+ static const std::unordered_map<std::string_view, ResolveFn> table = {
10
+ {"cube", &resolveCube},
11
+ {"sphere", &resolveSphere},
12
+ {"cylinder", &resolveCylinder},
13
+ {"polyhedron", &resolvePolyhedron},
14
+ {"circle", &resolve2d},
15
+ {"square", &resolve2d},
16
+ {"polygon", &resolve2d},
17
+ {"translate", &resolveTransform},
18
+ {"rotate", &resolveTransform},
19
+ {"scale", &resolveTransform},
20
+ {"mirror", &resolveTransform},
21
+ {"multmatrix", &resolveTransform},
22
+ {"resize", &resolveTransform},
23
+ {"color", &resolveColor},
24
+ {"union", &resolveCsg},
25
+ {"difference", &resolveCsg},
26
+ {"intersection", &resolveCsg},
27
+ {"children", &resolveChildren},
28
+ {"render", &resolveRender},
29
+ {"breakpoint", &resolveBreakpoint},
30
+ {"import", &resolveImport},
31
+ {"hull", &resolveHull},
32
+ {"minkowski", &resolveMinkowski},
33
+ {"linear_extrude", &resolveLinearExtrude},
34
+ {"rotate_extrude", &resolveRotateExtrude},
35
+ {"projection", &resolveProjection},
36
+ {"roof", &resolveRoof},
37
+ {"offset", &resolveOffset},
38
+ {"surface", &resolveSurface},
39
+ {"text", &resolveText},
40
+ };
41
+ return table;
42
+ }
43
+
44
+ const std::unordered_map<std::string_view, GenerateFn>& generateDispatch() {
45
+ static const std::unordered_map<std::string_view, GenerateFn> table = {
46
+ {"cube", &generateCube},
47
+ {"sphere", &generateSphere},
48
+ {"cylinder", &generateCylinder},
49
+ {"polyhedron", &generatePolyhedron},
50
+ {"circle", &generate2d},
51
+ {"square", &generate2d},
52
+ {"polygon", &generate2d},
53
+ {"translate", &generateTransform},
54
+ {"rotate", &generateTransform},
55
+ {"scale", &generateTransform},
56
+ {"mirror", &generateTransform},
57
+ {"multmatrix", &generateTransform},
58
+ {"resize", &generateTransform},
59
+ {"color", &generateColor},
60
+ {"union", &generateCsg},
61
+ {"difference", &generateCsg},
62
+ {"intersection", &generateCsg},
63
+ {"highlight", &generateHighlight},
64
+ {"background", &generateBackground},
65
+ {"show_only", &generateShowOnly},
66
+ {"children", &generateChildren},
67
+ {"intersection_for", &generateIntersectionFor},
68
+ {"import", &generateImport},
69
+ {"hull", &generateHull},
70
+ {"minkowski", &generateMinkowski},
71
+ {"linear_extrude", &generateLinearExtrude},
72
+ {"rotate_extrude", &generateRotateExtrude},
73
+ {"projection", &generateProjection},
74
+ {"roof", &generateRoof},
75
+ {"offset", &generateOffset},
76
+ {"surface", &generateSurface},
77
+ {"text", &generateText},
78
+ };
79
+ return table;
80
+ }
81
+
82
+ const std::vector<std::string>* builtinParamNames(const std::string& name) {
83
+ // Deliberately absent: the builtin *functions* other than the three
84
+ // below. Real OpenSCAD's builtin functions read their arguments
85
+ // positionally without going through Parameters::parse, so `sin(bogus=30)`
86
+ // warns about nothing upstream -- verified against 2022.08.22 -- and
87
+ // warning here would be a divergence, not a fix.
88
+ static const std::unordered_map<std::string, std::vector<std::string>> table = {
89
+ // -- builtin modules ---------------------------------------------
90
+ {"cube", {"size", "center"}},
91
+ {"sphere", {"r", "d"}},
92
+ {"cylinder", {"h", "r1", "r2", "center", "r", "d", "d1", "d2"}},
93
+ {"polyhedron", {"points", "faces", "convexity", "triangles"}},
94
+ {"square", {"size", "center"}},
95
+ {"circle", {"r", "d"}},
96
+ {"polygon", {"points", "paths", "convexity"}},
97
+ {"translate", {"v"}},
98
+ {"rotate", {"a", "v"}},
99
+ {"scale", {"v"}},
100
+ {"mirror", {"v"}},
101
+ {"multmatrix", {"m"}},
102
+ {"resize", {"newsize", "auto", "convexity"}},
103
+ {"color", {"c", "alpha"}},
104
+ {"union", {}},
105
+ {"difference", {}},
106
+ {"intersection", {}},
107
+ {"hull", {}},
108
+ {"minkowski", {"convexity"}},
109
+ {"children", {"index"}},
110
+ {"render", {"convexity"}},
111
+ // "repair" is this port's own addition, not an upstream parameter.
112
+ {"import",
113
+ {"file", "layer", "convexity", "origin", "scale", "width", "height", "filename", "layername", "center", "dpi",
114
+ "id", "repair"}},
115
+ {"linear_extrude", {"height", "v", "scale", "center", "twist", "slices", "segments", "convexity"}},
116
+ {"rotate_extrude", {"angle", "start", "convexity"}},
117
+ {"projection", {"cut", "convexity"}},
118
+ {"roof", {"method", "convexity"}},
119
+ {"offset", {"r", "delta", "chamfer"}},
120
+ {"surface", {"file", "center", "convexity", "invert"}},
121
+ {"text", {"text", "size", "font", "direction", "language", "script", "halign", "valign", "spacing"}},
122
+ // breakpoint() is this port's own debugger extension, no upstream
123
+ // equivalent to mirror.
124
+ {"breakpoint", {"condition"}},
125
+
126
+ // -- the three builtin FUNCTIONS that do use Parameters::parse ----
127
+ {"textmetrics", {"text", "size", "font", "direction", "language", "script", "halign", "valign", "spacing"}},
128
+ {"fontmetrics", {"size", "font"}},
129
+ };
130
+ auto it = table.find(name);
131
+ return it == table.end() ? nullptr : &it->second;
132
+ }
133
+
134
+ void warnUnexpectedBuiltinArgs(Evaluator& ev, const oscad::ASTNode& callNode) {
135
+ if (callNode.kind() != oscad::NodeKind::ModularCall) return;
136
+ const auto& call = static_cast<const oscad::ModularCall&>(callNode);
137
+ if (const std::vector<std::string>* declared = builtinParamNames(call.name->name)) {
138
+ warnUnexpectedArgs(ev, *declared, call.arguments);
139
+ }
140
+ }
141
+
142
+ } // namespace oscadeval