openscad-cpp-evaluator 1.33.0__tar.gz → 1.35.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 (227) hide show
  1. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/.github/workflows/ci.yml +14 -1
  2. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/.github/workflows/wheels.yml +9 -1
  3. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/CLAUDE.md +12 -1
  4. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/CMakeLists.txt +9 -0
  5. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/PKG-INFO +1 -1
  6. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/bindings/module.cpp +4 -3
  7. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/mesh_import.hpp +9 -0
  8. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/value.hpp +63 -4
  9. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/pyproject.toml +1 -1
  10. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/CMakeLists.txt +1 -0
  11. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/booleans.cpp +1 -1
  12. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/function_builtins.cpp +15 -8
  13. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/import.cpp +18 -4
  14. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/primitives_3d.cpp +1 -1
  15. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/expr_eval.cpp +1 -1
  16. openscad_cpp_evaluator-1.35.0/src/import/scene_import.cpp +714 -0
  17. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/import/svg_import.cpp +8 -0
  18. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/value.cpp +44 -10
  19. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/CMakeLists.txt +16 -0
  20. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_dxf_svg_import.cpp +44 -0
  21. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_function_builtins.cpp +9 -9
  22. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_import_export.cpp +158 -0
  23. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_value.cpp +68 -0
  24. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/uv.lock +1 -1
  25. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/.gitignore +0 -0
  26. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/.gitmodules +0 -0
  27. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/LICENSE +0 -0
  28. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/README.md +0 -0
  29. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/bindings/CMakeLists.txt +0 -0
  30. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/bindings/ast_to_py.cpp +0 -0
  31. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/cmake/embed_font.cmake +0 -0
  32. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/examples/CMakeLists.txt +0 -0
  33. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/examples/eval_perf_benchmark.cpp +0 -0
  34. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/examples/manifold_cache_reuse.cpp +0 -0
  35. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/examples/minimal_debugger.cpp +0 -0
  36. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  37. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/.gitignore +0 -0
  38. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  39. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  40. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/README.md +0 -0
  41. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  42. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  43. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  44. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  45. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  46. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  47. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  48. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  49. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  50. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  51. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  52. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  53. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  54. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  55. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  56. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  57. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  58. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  59. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  60. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  61. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  62. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  63. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  64. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  65. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  66. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  67. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  68. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  69. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  70. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  71. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  72. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  73. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  74. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  75. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  76. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  77. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  78. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  79. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  80. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  81. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  82. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  83. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  84. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  85. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  86. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  87. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  88. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  89. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  90. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  91. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  92. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  93. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  94. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  95. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  96. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  97. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  98. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  99. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  100. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  101. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  102. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  103. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  104. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  105. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  106. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  107. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  108. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  109. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  110. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  111. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  112. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  113. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  114. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  115. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  116. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  117. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  118. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  119. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  120. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  121. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  122. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  123. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  124. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  125. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  126. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  127. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  128. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  129. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  130. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  131. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  132. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  133. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  134. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  135. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  136. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  137. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  138. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  139. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  140. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  141. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  142. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/resources/fonts/LICENSE +0 -0
  143. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  144. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  145. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  146. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  147. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/builtins.hpp +0 -0
  148. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/call_args.cpp +0 -0
  149. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/color.cpp +0 -0
  150. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/control.cpp +0 -0
  151. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/dxf_dim.cpp +0 -0
  152. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/extrude.cpp +0 -0
  153. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/modifiers.cpp +0 -0
  154. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/primitives_2d.cpp +0 -0
  155. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/registry.cpp +0 -0
  156. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/roof.cpp +0 -0
  157. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/segments.cpp +0 -0
  158. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/surface.cpp +0 -0
  159. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/text.cpp +0 -0
  160. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/topology.cpp +0 -0
  161. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/builtins/transforms.cpp +0 -0
  162. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/bytecode_compiler.cpp +0 -0
  163. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/bytecode_vm.cpp +0 -0
  164. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/colored_body.cpp +0 -0
  165. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/coverage.cpp +0 -0
  166. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/csg_generate.cpp +0 -0
  167. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/csg_resolve.cpp +0 -0
  168. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/css_colors.cpp +0 -0
  169. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/debug/debug_repl.cpp +0 -0
  170. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/debug_profile.cpp +0 -0
  171. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/eval_context.cpp +0 -0
  172. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/eval_error.cpp +0 -0
  173. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/eval_use.cpp +0 -0
  174. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/export.cpp +0 -0
  175. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/format_closure.cpp +0 -0
  176. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/import/dxf_import.cpp +0 -0
  177. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/import/mesh_import.cpp +0 -0
  178. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/import/surface_load.cpp +0 -0
  179. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/manifold_cache.cpp +0 -0
  180. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/measure_geometry.cpp +0 -0
  181. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/mesh_check.cpp +0 -0
  182. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/stmt_eval.cpp +0 -0
  183. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/text/font_match.cpp +0 -0
  184. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/text/freetype_font_provider.cpp +0 -0
  185. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/text/text_metrics.cpp +0 -0
  186. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/user_calls.cpp +0 -0
  187. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/utf8.cpp +0 -0
  188. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/xkcd_colors.cpp +0 -0
  189. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/xkcd_colors.hpp +0 -0
  190. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/src/zip_stored.cpp +0 -0
  191. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_booleans.cpp +0 -0
  192. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_bytecode_compiler.cpp +0 -0
  193. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_children_separate.cpp +0 -0
  194. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_cli.cpp +0 -0
  195. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_control_flow.cpp +0 -0
  196. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_coverage.cpp +0 -0
  197. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_csg_tree.cpp +0 -0
  198. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_debug_hooks.cpp +0 -0
  199. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_discretizer.cpp +0 -0
  200. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_eval_context.cpp +0 -0
  201. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_export.cpp +0 -0
  202. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_expr_eval.cpp +0 -0
  203. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_extrude_roof.cpp +0 -0
  204. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_feature_detection.cpp +0 -0
  205. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_helpers.hpp +0 -0
  206. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_include_cache.cpp +0 -0
  207. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_manifold_cache.cpp +0 -0
  208. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_mesh_check.cpp +0 -0
  209. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_multi_color_merge.cpp +0 -0
  210. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_primitives.cpp +0 -0
  211. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_profiling.cpp +0 -0
  212. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_python_bindings.py +0 -0
  213. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_render_expr.cpp +0 -0
  214. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_scope_trail.cpp +0 -0
  215. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_scoping.cpp +0 -0
  216. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_surface.cpp +0 -0
  217. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_tail_calls.cpp +0 -0
  218. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_text.cpp +0 -0
  219. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_transforms.cpp +0 -0
  220. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_unexpected_args.cpp +0 -0
  221. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_use.cpp +0 -0
  222. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_viewport_params.cpp +0 -0
  223. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tests/test_zip_stored.cpp +0 -0
  224. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tools/cli/CMakeLists.txt +0 -0
  225. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tools/cli/cli_lib.cpp +0 -0
  226. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tools/cli/cli_lib.hpp +0 -0
  227. {openscad_cpp_evaluator-1.33.0 → openscad_cpp_evaluator-1.35.0}/tools/cli/main.cpp +0 -0
@@ -50,8 +50,21 @@ jobs:
50
50
  # Linux/macOS use (CMAKE_BUILD_TYPE already picked the config), but
51
51
  # required on Windows's default multi-config Visual Studio
52
52
  # generator, which ignores CMAKE_BUILD_TYPE entirely.
53
+ # A bounded job count on the Unix runners. A bare `-j` becomes `make -j`,
54
+ # which starts EVERY compile at once; on macos-latest (3 vCPU, 7 GB) a
55
+ # pile of template-heavy translation units that size ran the build at
56
+ # 852-2000 s against Linux's ~300 s. Windows keeps the bare -j: MSBuild
57
+ # reads it as "use the cores", which is already bounded.
53
58
  - name: Build
54
- run: cmake --build build --config Release -j
59
+ shell: bash
60
+ run: |
61
+ case "$RUNNER_OS" in
62
+ macOS) JOBS=$(sysctl -n hw.ncpu) ;;
63
+ Linux) JOBS=$(nproc) ;;
64
+ *) JOBS= ;;
65
+ esac
66
+ echo "building with -j ${JOBS:-<unbounded: MSBuild>}"
67
+ cmake --build build --config Release -j $JOBS
55
68
 
56
69
  # Bytecode VM on (the default as of the Phase 5 rollout decision --
57
70
  # see evaluator.hpp's own bytecodeVmEnabled() comment) and off
@@ -38,8 +38,16 @@ jobs:
38
38
  name: macos-arm64
39
39
  - runner: macos-15-intel
40
40
  name: macos-x86_64
41
+ # Two Windows jobs, one per architecture, both on the x86_64 runner
42
+ # (ARM64 is cross-compiled; see CIBW_ARCHS_WINDOWS). As one job they
43
+ # built one after the other -- 7 min each, 14.5 min for the job,
44
+ # the slowest in the release -- when neither needs the other.
41
45
  - runner: windows-latest
42
46
  name: windows-x86_64
47
+ archs: AMD64
48
+ - runner: windows-latest
49
+ name: windows-arm64
50
+ archs: ARM64
43
51
  runs-on: ${{ matrix.runner }}
44
52
  steps:
45
53
  - uses: actions/checkout@v7
@@ -65,7 +73,7 @@ jobs:
65
73
  # ARM64 build at all, so building on an ARM runner would have to
66
74
  # emulate it. cibuildwheel skips CIBW_TEST_COMMAND for the
67
75
  # cross-compiled wheel, since an x86_64 host cannot run it.
68
- CIBW_ARCHS_WINDOWS: "AMD64 ARM64"
76
+ CIBW_ARCHS_WINDOWS: ${{ matrix.archs }}
69
77
  # delvewheel vendors the MSVC runtime into the wheel, but on an
70
78
  # x86_64 host it can only find the x86_64 copy -- repairing the
71
79
  # cross-built ARM64 wheel died with "Unable to find library:
@@ -1185,10 +1185,21 @@ grep for `ponytail:`.
1185
1185
  - `include/openscad_cpp_evaluator/mesh_import.hpp`, `src/import/mesh_import.cpp` — STL (ASCII +
1186
1186
  binary, exact-match vertex welding)/OBJ/OFF/3MF mesh loaders, returning plain `(verts, tris)` —
1187
1187
  no `Evaluator`/`Value` dependency, so these are reusable from both `import()` contexts below.
1188
+ - `src/import/scene_import.cpp` — AMF, X3D and VRML97 import, the three multi-object formats export
1189
+ writes that nothing could read back (current upstream OpenSCAD removed its AMF importer, so all
1190
+ three go beyond it). Geometry only, like the loaders above, but each format's scene structure is
1191
+ honoured: X3D/VRML `Transform`s nest and apply in full (`T·C·R·SR·S·SR⁻¹·C⁻¹`), `DEF`/`USE`
1192
+ resolves, `ccw FALSE` flips winding, `IndexedFaceSet` polygons fan-triangulate (a last polygon
1193
+ without `-1` counts), and X3D's `IndexedTriangleSet`/`TriangleSet` are read. X3D goes through a
1194
+ small real XML parser (comments, CDATA, DOCTYPE, entities); VRML through a tokenizer + generic
1195
+ node parser that steps over `PROTO`/`EXTERNPROTO`/`ROUTE` (VRML 1.0 is refused by name). AMF's
1196
+ `unit` scales to mm, and a zipped AMF (`PK` header) is read through `readStoredZipEntryBySuffix`.
1197
+ What is not a mesh — primitives (Box, Sphere, ...), `Inline`, AMF constellations — lands in
1198
+ `LoadedMesh::warnings`, which both `import()` faces emit as `import: '<file>': ...`.
1188
1199
  - `include/openscad_cpp_evaluator/import_builtin.hpp`, `include/openscad_cpp_evaluator/
1189
1200
  zip_stored.hpp` (+ `src/zip_stored.cpp`), `src/builtins/import.cpp` — `import()`'s two faces:
1190
1201
  `resolveImport`/`generateImport` (registered in `registry.cpp` like any other builtin *module* —
1191
- a geometry statement, STL/OBJ/OFF/3MF/DXF/SVG) and `importAsValue` (called directly from
1202
+ a geometry statement, STL/OBJ/OFF/3MF/AMF/X3D/VRML/DXF/SVG) and `importAsValue` (called directly from
1192
1203
  `user_calls.cpp`'s `evalFunctionCall`, special-cased *before* the `isBuiltinFunctionName` gate
1193
1204
  since `import` isn't in that table — returns a VNF `[[verts],[faces]]` for a mesh file, a Region
1194
1205
  `[[[x,y],...],...]` for DXF/SVG, or the JSON file's content as native values).
@@ -79,6 +79,15 @@ if(MSVC)
79
79
  # unconditionally (a POSIX extension our code already relies on), so no
80
80
  # equivalent is needed there.
81
81
  add_compile_definitions(_USE_MATH_DEFINES)
82
+ # /MP: compile a target's source files in parallel. MSBuild's own /m (what
83
+ # `cmake --build -j` passes) runs PROJECTS in parallel but each project's
84
+ # files one at a time, and nearly everything here is one big library, so a
85
+ # Windows build was close to serial (CI's Build step ~665 s against Linux's
86
+ # ~250). Visual Studio generators only: under Ninja every compiler call is
87
+ # already one file, and Ninja does the parallelism itself.
88
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
89
+ add_compile_options(/MP)
90
+ endif()
82
91
  endif()
83
92
 
84
93
  # The nanobind Python extension (bindings/) links the static evaluator lib
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.33.0
3
+ Version: 1.35.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -73,9 +73,10 @@ oscadeval::Value pyToValue(nb::handle v) {
73
73
  if (nb::isinstance<nb::int_>(v) || nb::isinstance<nb::float_>(v)) return oscadeval::Value{nb::cast<double>(v)};
74
74
  if (nb::isinstance<nb::str>(v)) return oscadeval::Value{nb::cast<std::string>(v)};
75
75
  if (nb::isinstance<nb::list>(v) || nb::isinstance<nb::tuple>(v)) {
76
- oscadeval::ValueList vl;
77
- for (nb::handle item : nb::borrow<nb::sequence>(v)) vl.items.push_back(pyToValue(item));
78
- return oscadeval::Value{oscadeval::ListPtr(std::make_shared<const oscadeval::ValueList>(std::move(vl)))};
76
+ std::vector<oscadeval::Value> items;
77
+ for (nb::handle item : nb::borrow<nb::sequence>(v)) items.push_back(pyToValue(item));
78
+ return oscadeval::Value{oscadeval::ListPtr(
79
+ std::make_shared<const oscadeval::ValueList>(oscadeval::ValueList{std::move(items)}))};
79
80
  }
80
81
  return oscadeval::Value{}; // monostate = undef
81
82
  }
@@ -13,6 +13,9 @@ namespace oscadeval {
13
13
  struct LoadedMesh {
14
14
  std::vector<std::array<double, 3>> verts;
15
15
  std::vector<std::array<int, 3>> tris;
16
+ // What the loader read but could not turn into mesh (X3D/VRML primitives,
17
+ // Inline, AMF constellations), for import() to warn about.
18
+ std::vector<std::string> warnings;
16
19
  };
17
20
 
18
21
  // Each throws std::runtime_error with a message suitable for wrapping into
@@ -23,5 +26,11 @@ LoadedMesh loadStl(const std::string& path);
23
26
  LoadedMesh loadObj(const std::string& path);
24
27
  LoadedMesh loadOff(const std::string& path);
25
28
  LoadedMesh loadThreeMf(const std::string& path);
29
+ // scene_import.cpp: the three multi-object formats export writes. AMF (plain
30
+ // or zipped, `unit` scaled to mm), X3D and VRML97 (Transforms applied,
31
+ // DEF/USE resolved, polygons fan-triangulated). Geometry only, like the rest.
32
+ LoadedMesh loadAmf(const std::string& path);
33
+ LoadedMesh loadX3d(const std::string& path);
34
+ LoadedMesh loadVrml(const std::string& path);
26
35
 
27
36
  } // namespace oscadeval
@@ -2,7 +2,9 @@
2
2
 
3
3
  #include "openscad_cpp_evaluator/osc_range.hpp"
4
4
 
5
+ #include <atomic>
5
6
  #include <functional>
7
+ #include <initializer_list>
6
8
  #include <memory>
7
9
  #include <optional>
8
10
  #include <string>
@@ -98,13 +100,70 @@ inline std::shared_ptr<TrailView<Value>> capturedLetTrail(const Closure& c) {
98
100
  return std::static_pointer_cast<TrailView<Value>>(c.capturedLet);
99
101
  }
100
102
 
101
- // Defined after Value so both can hold Value by value -- the standard
102
- // recursive-variant pattern (indirection through a forward-declared,
103
- // heap-allocated aggregate).
103
+ // A list's elements: a read-only view of the first `size()` elements of a
104
+ // buffer that other lists may share. Lists that are prefixes of one another
105
+ // share one buffer, which is what makes repeated appending cheap: `acc`
106
+ // and `concat(acc, [x])` are the same buffer, the second one element
107
+ // longer (listAppend). Defined after Value so both can hold Value by value
108
+ // -- the standard recursive-variant pattern.
109
+ //
110
+ // The buffer only ever grows within the capacity it was given, so element
111
+ // addresses never move while any view of it is alive, and an element, once
112
+ // written, is never changed. `used` is how far the longest view reaches;
113
+ // only a list ending exactly there may extend it, claiming the new slots
114
+ // with one compare-and-swap, so two lists sharing a prefix can never write
115
+ // the same slot (the loser copies).
116
+ struct ListBuffer {
117
+ std::vector<Value> v;
118
+ std::atomic<size_t> used;
119
+ // Set when this buffer came from appending: a list that was appended
120
+ // to once is likely to be again, so ITS copies grow geometrically,
121
+ // while a one-off concat's result is allocated at exactly its size.
122
+ bool fromAppend = false;
123
+ explicit ListBuffer(std::vector<Value>&& items) : v(std::move(items)), used(v.size()) {}
124
+ };
125
+
126
+ class ListItems {
127
+ public:
128
+ ListItems() = default;
129
+ ListItems(std::vector<Value>&& items) // NOLINT: implicit, as the old vector was
130
+ : buf_(std::make_shared<ListBuffer>(std::move(items))), n_(buf_->v.size()) {}
131
+ ListItems(const std::vector<Value>& items) : ListItems(std::vector<Value>(items)) {} // NOLINT
132
+ ListItems(std::initializer_list<Value> items) : ListItems(std::vector<Value>(items)) {}
133
+
134
+ size_t size() const { return n_; }
135
+ bool empty() const { return n_ == 0; }
136
+ const Value* data() const { return buf_ ? buf_->v.data() : nullptr; }
137
+ const Value* begin() const { return data(); }
138
+ const Value* end() const { return data() + n_; }
139
+ const Value& operator[](size_t i) const { return data()[i]; }
140
+ const Value& at(size_t i) const;
141
+ const Value& front() const { return data()[0]; }
142
+ const Value& back() const { return data()[n_ - 1]; }
143
+ // A copy as a plain vector, for the few callers that build on one.
144
+ // Explicit, so a copy is never made by accident binding a reference.
145
+ explicit operator std::vector<Value>() const { return std::vector<Value>(begin(), end()); }
146
+ std::vector<Value> toVector() const { return std::vector<Value>(begin(), end()); }
147
+
148
+ private:
149
+ ListItems(std::shared_ptr<ListBuffer> buf, size_t n) : buf_(std::move(buf)), n_(n) {}
150
+ std::shared_ptr<ListBuffer> buf_;
151
+ size_t n_ = 0;
152
+ friend ListPtr listAppend(const ListPtr& base, std::vector<Value>&& extra);
153
+ };
154
+
104
155
  struct ValueList {
105
- std::vector<Value> items;
156
+ ListItems items;
106
157
  };
107
158
 
159
+ // `base` followed by `extra`, sharing base's buffer whenever base is the
160
+ // longest list using it and the buffer has room: amortized O(|extra|)
161
+ // rather than O(|base| + |extra|), which is what turns the idiomatic
162
+ // tail-recursive accumulator, f(i, concat(acc, [x])), from quadratic into
163
+ // linear. Safe whatever else still holds `base`: base keeps seeing only
164
+ // its own elements.
165
+ ListPtr listAppend(const ListPtr& base, std::vector<Value>&& extra);
166
+
108
167
  // Insertion-ordered key/value pairs, not a map: object()'s iteration order
109
168
  // and `==` are order-sensitive (doc: openscad_evaluator/docs/evaluator.md,
110
169
  // the object() entry).
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.33.0"
7
+ version = "1.35.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -23,6 +23,7 @@ add_library(openscad_cpp_evaluator STATIC
23
23
  mesh_check.cpp
24
24
  zip_stored.cpp
25
25
  import/mesh_import.cpp
26
+ import/scene_import.cpp
26
27
  import/surface_load.cpp
27
28
  import/dxf_import.cpp
28
29
  import/svg_import.cpp
@@ -313,7 +313,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
313
313
  const std::string& op = std::get<std::string>(params.at("op"));
314
314
  const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
315
315
  const auto emptyIsAGroupIt = params.find("empty_is_a_group");
316
- const std::vector<Value>* emptyIsAGroup =
316
+ const ListItems* emptyIsAGroup =
317
317
  emptyIsAGroupIt == params.end()
318
318
  ? nullptr
319
319
  : &std::get<ListPtr>(emptyIsAGroupIt->second)->items;
@@ -616,11 +616,11 @@ Value builtinSearch(const CallArgs& args, Evaluator& ev, const oscad::Position*
616
616
  const unsigned numReturns = static_cast<unsigned>(static_cast<long long>(nrRaw));
617
617
  const unsigned indexCol = static_cast<unsigned>(static_cast<long long>(icRaw));
618
618
 
619
- static const std::vector<Value> kNoItems;
619
+ static const ListItems kNoItems;
620
620
  const ListPtr* tablePtr = std::get_if<ListPtr>(&tableArg);
621
- const std::vector<Value>& table = (tablePtr && *tablePtr) ? (*tablePtr)->items : kNoItems;
621
+ const ListItems& table = (tablePtr && *tablePtr) ? (*tablePtr)->items : kNoItems;
622
622
 
623
- const auto itemsOf = [](const Value& v) -> const std::vector<Value>& {
623
+ const auto itemsOf = [](const Value& v) -> const ListItems& {
624
624
  const ListPtr* l = std::get_if<ListPtr>(&v);
625
625
  return (l && *l) ? (*l)->items : kNoItems;
626
626
  };
@@ -629,7 +629,7 @@ Value builtinSearch(const CallArgs& args, Evaluator& ev, const oscad::Position*
629
629
  // only when the entry really is a long enough vector.
630
630
  const auto hits = [&](const Value& needle, const Value& entry) {
631
631
  if (indexCol == 0 && oscEqual(needle, entry)) return true;
632
- const std::vector<Value>& ev2 = itemsOf(entry);
632
+ const ListItems& ev2 = itemsOf(entry);
633
633
  return indexCol < ev2.size() && oscEqual(needle, ev2[indexCol]);
634
634
  };
635
635
  const auto num = [](size_t j) { return Value{static_cast<double>(j)}; };
@@ -682,7 +682,7 @@ Value builtinSearch(const CallArgs& args, Evaluator& ev, const oscad::Position*
682
682
  unsigned matchCount = 0;
683
683
  std::vector<Value> resultvec;
684
684
  for (size_t j = 0; j < table.size(); ++j) {
685
- const std::vector<Value>& entryVec = itemsOf(table[j]);
685
+ const ListItems& entryVec = itemsOf(table[j]);
686
686
  if (entryVec.size() <= indexCol) {
687
687
  ev.warn("Invalid entry in search vector at index " + std::to_string(j) +
688
688
  ", required number of values in the entry: " + std::to_string(indexCol + 1) +
@@ -1162,9 +1162,9 @@ bool checkMinMax(Evaluator& ev, const std::string& name, const CallArgs& args, c
1162
1162
  return false;
1163
1163
  }
1164
1164
  if (nPos == 1 && std::holds_alternative<ListPtr>(positionalAt(args, 0))) {
1165
- static const std::vector<Value> kEmptyItems;
1165
+ static const ListItems kEmptyItems;
1166
1166
  const ListPtr& l = std::get<ListPtr>(positionalAt(args, 0));
1167
- const std::vector<Value>& items = l ? l->items : kEmptyItems;
1167
+ const ListItems& items = l ? l->items : kEmptyItems;
1168
1168
  if (items.empty()) {
1169
1169
  warnArity(ev, name, "at least 1 vector element", 0, pos);
1170
1170
  return false;
@@ -1346,14 +1346,21 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
1346
1346
  toDoubleLenient(getArg(args, 2, "value_count", Value{})), getArg(args, 3, "seed", Value{}));
1347
1347
  }
1348
1348
  case BuiltinFnId::Concat: {
1349
+ // Everything after the first argument, appended to the first
1350
+ // when it is a list: listAppend extends its buffer in place when
1351
+ // it can, so an accumulator loop is linear, not quadratic.
1352
+ const size_t count = positionalCount(args);
1353
+ const ListPtr* first = count ? std::get_if<ListPtr>(&positionalAt(args, 0)) : nullptr;
1349
1354
  std::vector<Value> out;
1350
- for (const Value& a : allPositional(args)) {
1355
+ for (size_t i = (first && *first) ? 1 : 0; i < count; ++i) {
1356
+ const Value& a = positionalAt(args, i);
1351
1357
  if (const ListPtr* l = std::get_if<ListPtr>(&a); l && *l) {
1352
1358
  out.insert(out.end(), (*l)->items.begin(), (*l)->items.end());
1353
1359
  } else {
1354
1360
  out.push_back(a);
1355
1361
  }
1356
1362
  }
1363
+ if (first && *first) return Value{listAppend(*first, std::move(out))};
1357
1364
  return listOf(std::move(out));
1358
1365
  }
1359
1366
  case BuiltinFnId::Len: {
@@ -46,10 +46,16 @@ LoadedMesh loadMeshByExt(const std::string& path, const std::string& ext) {
46
46
  if (ext == ".stl") return loadStl(path);
47
47
  if (ext == ".obj") return loadObj(path);
48
48
  if (ext == ".off") return loadOff(path);
49
+ if (ext == ".amf") return loadAmf(path);
50
+ if (ext == ".x3d") return loadX3d(path);
51
+ if (ext == ".wrl") return loadVrml(path);
49
52
  return loadThreeMf(path);
50
53
  }
51
54
 
52
- bool isMeshExt(const std::string& ext) { return ext == ".stl" || ext == ".obj" || ext == ".off" || ext == ".3mf"; }
55
+ bool isMeshExt(const std::string& ext) {
56
+ return ext == ".stl" || ext == ".obj" || ext == ".off" || ext == ".3mf" || ext == ".amf" || ext == ".x3d" ||
57
+ ext == ".wrl";
58
+ }
53
59
 
54
60
 
55
61
  Value jsonToValue(const nlohmann::ordered_json& j) {
@@ -208,7 +214,10 @@ CSGParams resolveImport(Evaluator& ev, const oscad::ModularCall& node, EvalConte
208
214
  params["dxf"] = Value{ext == ".dxf"};
209
215
  return params;
210
216
  }
211
- if (ext == ".dxf" || ext == ".svg" || ext == ".pdf") {
217
+ // .pdf is not here: it used to be, handed to the SVG parser, which hung on
218
+ // a PDF's bytes. Nothing reads PDF (OpenSCAD does not either), so it takes
219
+ // the ordinary "unsupported file type" error below.
220
+ if (ext == ".dxf" || ext == ".svg") {
212
221
  std::vector<Contour2d> contours;
213
222
  bool filteredMiss = false;
214
223
  try {
@@ -257,6 +266,7 @@ CSGParams resolveImport(Evaluator& ev, const oscad::ModularCall& node, EvalConte
257
266
  } catch (const std::exception& e) {
258
267
  ev.error(std::string("import: ") + e.what(), node);
259
268
  }
269
+ for (const std::string& w : mesh.warnings) ev.warn("import: '" + path + "': " + w, &node.position());
260
270
  std::vector<Value> vertsFlat;
261
271
  vertsFlat.reserve(mesh.verts.size() * 3);
262
272
  for (const auto& v : mesh.verts) {
@@ -428,8 +438,12 @@ Value importAsValue(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& n
428
438
 
429
439
  try {
430
440
  if (ext == ".json") return loadJsonAsValue(path);
431
- if (isMeshExt(ext)) return meshToVnf(loadMeshByExt(path, ext));
432
- if (ext == ".dxf" || ext == ".svg" || ext == ".pdf") {
441
+ if (isMeshExt(ext)) {
442
+ const LoadedMesh mesh = loadMeshByExt(path, ext);
443
+ for (const std::string& w : mesh.warnings) ev.warn("import: '" + path + "': " + w, &node.position());
444
+ return meshToVnf(mesh);
445
+ }
446
+ if (ext == ".dxf" || ext == ".svg") {
433
447
  std::vector<Contour2d> contours;
434
448
  if (ext == ".dxf") {
435
449
  std::optional<std::string> layer;
@@ -133,7 +133,7 @@ CSGParams resolveCube(Evaluator& ev, const oscad::ModularCall& node, EvalContext
133
133
  } else if (l && *l && (*l)->items.size() == 3 &&
134
134
  std::all_of((*l)->items.begin(), (*l)->items.end(),
135
135
  [](const Value& v) { return std::holds_alternative<double>(v); })) {
136
- sizeVec = (*l)->items;
136
+ sizeVec = (*l)->items.toVector();
137
137
  } else if (!std::holds_alternative<std::monostate>(sizeArg)) {
138
138
  ev.warn("Unable to convert cube(size=" + fmtValue(sizeArg) +
139
139
  ", ...) parameter to a number or a vec3 of numbers",
@@ -42,7 +42,7 @@ std::optional<bool> valueLess(const Value& a, const Value& b) {
42
42
 
43
43
  const ListPtr& la = std::get<ListPtr>(a);
44
44
  const ListPtr& lb = std::get<ListPtr>(b);
45
- static const std::vector<Value> kEmpty;
45
+ static const ListItems kEmpty;
46
46
  const auto& ia = la ? la->items : kEmpty;
47
47
  const auto& ib = lb ? lb->items : kEmpty;
48
48
  const size_t n = std::min(ia.size(), ib.size());