openscad-cpp-evaluator 0.13.0__tar.gz → 0.13.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/bytecode.hpp +125 -17
  3. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +25 -0
  4. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/evaluator.hpp +50 -17
  5. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/builtins.hpp +16 -0
  7. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/color.cpp +10 -6
  8. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/transforms.cpp +7 -3
  9. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/bytecode_compiler.cpp +102 -9
  10. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/bytecode_vm.cpp +126 -5
  11. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/user_calls.cpp +8 -0
  12. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/CMakeLists.txt +13 -0
  13. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_bytecode_compiler.cpp +74 -13
  14. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_debug_hooks.cpp +47 -0
  15. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_tail_calls.cpp +2 -2
  16. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tools/cli/CMakeLists.txt +9 -0
  17. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/.github/workflows/ci.yml +0 -0
  18. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/.github/workflows/wheels.yml +0 -0
  19. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/.gitignore +0 -0
  20. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/.gitmodules +0 -0
  21. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/CLAUDE.md +0 -0
  22. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/CMakeLists.txt +0 -0
  23. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/LICENSE +0 -0
  24. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/README.md +0 -0
  25. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/bindings/CMakeLists.txt +0 -0
  26. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/bindings/module.cpp +0 -0
  27. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/cmake/embed_font.cmake +0 -0
  28. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/examples/CMakeLists.txt +0 -0
  29. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/examples/eval_perf_benchmark.cpp +0 -0
  30. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/examples/manifold_cache_reuse.cpp +0 -0
  31. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/examples/minimal_debugger.cpp +0 -0
  32. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  33. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/.gitignore +0 -0
  34. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  35. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  36. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/README.md +0 -0
  37. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  38. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  39. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  40. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  41. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  42. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  43. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  44. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  45. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  46. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  47. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  48. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  49. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  50. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  51. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  52. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  53. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
  54. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  55. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  56. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  57. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  58. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  59. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  60. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  61. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  62. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  63. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  64. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  65. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  66. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  67. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  68. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  69. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  70. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
  71. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  72. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  73. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  74. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  75. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  76. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  77. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  78. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  79. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  80. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  81. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  82. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  83. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  84. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  85. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  86. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  87. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  88. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  89. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  90. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  91. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  92. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  93. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  94. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  95. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  96. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  97. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  98. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  99. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  100. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  101. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  102. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  103. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  104. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  105. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  106. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  107. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  108. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  109. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  110. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  111. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
  112. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  113. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  114. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  115. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  116. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  117. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  118. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  119. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  120. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  121. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
  122. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  123. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  124. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
  125. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  126. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/python/openscad_cpp_evaluator/__init__.py +0 -0
  127. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/resources/fonts/LICENSE +0 -0
  128. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  129. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/CMakeLists.txt +0 -0
  130. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/booleans.cpp +0 -0
  131. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/call_args.cpp +0 -0
  132. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/control.cpp +0 -0
  133. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/extrude.cpp +0 -0
  134. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/function_builtins.cpp +0 -0
  135. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/import.cpp +0 -0
  136. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/modifiers.cpp +0 -0
  137. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/primitives_2d.cpp +0 -0
  138. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/primitives_3d.cpp +0 -0
  139. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/registry.cpp +0 -0
  140. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/roof.cpp +0 -0
  141. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/segments.cpp +0 -0
  142. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/surface.cpp +0 -0
  143. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/text.cpp +0 -0
  144. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/builtins/topology.cpp +0 -0
  145. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/colored_body.cpp +0 -0
  146. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/csg_generate.cpp +0 -0
  147. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/csg_resolve.cpp +0 -0
  148. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/css_colors.cpp +0 -0
  149. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/debug/debug_repl.cpp +0 -0
  150. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/debug_profile.cpp +0 -0
  151. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/eval_context.cpp +0 -0
  152. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/eval_error.cpp +0 -0
  153. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/eval_use.cpp +0 -0
  154. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/export.cpp +0 -0
  155. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/expr_eval.cpp +0 -0
  156. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/import/dxf_import.cpp +0 -0
  157. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/import/mesh_import.cpp +0 -0
  158. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/import/surface_load.cpp +0 -0
  159. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/import/svg_import.cpp +0 -0
  160. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/manifold_cache.cpp +0 -0
  161. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/stmt_eval.cpp +0 -0
  162. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/text/stb_font_provider.cpp +0 -0
  163. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/text/text_metrics.cpp +0 -0
  164. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/value.cpp +0 -0
  165. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/src/zip_stored.cpp +0 -0
  166. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_booleans.cpp +0 -0
  167. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_cli.cpp +0 -0
  168. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_control_flow.cpp +0 -0
  169. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_csg_tree.cpp +0 -0
  170. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_dxf_svg_import.cpp +0 -0
  171. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_eval_context.cpp +0 -0
  172. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_export.cpp +0 -0
  173. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_expr_eval.cpp +0 -0
  174. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_extrude_roof.cpp +0 -0
  175. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_function_builtins.cpp +0 -0
  176. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_helpers.hpp +0 -0
  177. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_import_export.cpp +0 -0
  178. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_manifold_cache.cpp +0 -0
  179. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_multi_color_merge.cpp +0 -0
  180. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_primitives.cpp +0 -0
  181. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_profiling.cpp +0 -0
  182. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_python_bindings.py +0 -0
  183. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_scope_trail.cpp +0 -0
  184. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_scoping.cpp +0 -0
  185. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_surface.cpp +0 -0
  186. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_text.cpp +0 -0
  187. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_transforms.cpp +0 -0
  188. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_use.cpp +0 -0
  189. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_value.cpp +0 -0
  190. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_viewport_params.cpp +0 -0
  191. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tests/test_zip_stored.cpp +0 -0
  192. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tools/cli/cli_lib.cpp +0 -0
  193. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tools/cli/cli_lib.hpp +0 -0
  194. {openscad_cpp_evaluator-0.13.0 → openscad_cpp_evaluator-0.13.2}/tools/cli/main.cpp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.13.0
3
+ Version: 0.13.2
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -260,26 +260,101 @@ enum class Op {
260
260
  // which splice is unconditional).
261
261
  CallModule,
262
262
 
263
- // A single "native passthrough" statement -- a modifier wrapper,
264
- // intersection_for, children(), a builtin module call, or a user-
265
- // module call that didn't resolve at compile time (shadowed, forward-
266
- // declared, or otherwise not statically known) -- anything
267
- // compileStatementList doesn't give its own real bytecode. (Assignment/
268
- // ModularEcho/ModularAssert/ModularLet used to fall here too; they now
269
- // have their own real bytecode -- Op::StoreModuleVar/Op::Echo/
270
- // Op::AssertStatement/Op::OpenLetScope+StoreLetVar -- purely a
271
- // throughput change, since none of these were ever the recursion-depth
272
- // risk this compiler targets.)
263
+ // -- Builtin-wrap compilation (closes the "NativeStatement gap" for ----
264
+ // -- translate/rotate/scale/mirror/multmatrix/resize/color/#/%/!) ------
265
+ // A builtin-with-children statement that isn't a "call" the way
266
+ // Op::CallModule's target is (no callStack_/profiling participation,
267
+ // no named scope with upvalue semantics -- see CompiledChunk::
268
+ // BuiltinWrapSite's own doc comment for the full "why this doesn't
269
+ // need vmCallStack_/pushBracketedModuleFrame-style bracketing"
270
+ // reasoning) -- so unlike Op::CallModule, its children compile INLINE
271
+ // into the SAME instruction stream (via compileStatementList, exactly
272
+ // like Op::OpenLetScope's own body does for ModularLet) rather than
273
+ // becoming a separate chunk. Exists because falling through to
274
+ // Op::NativeStatement here was a REAL, proven Windows/MSVC crash risk
275
+ // for a recursive translate()/multmatrix()-wrapped module chain (see
276
+ // this project's own session notes: BOSL2's attachable() machinery
277
+ // needs native reentry depth ~55, past the empirically-proven-unsafe
278
+ // Windows ceiling for that reentry mechanism -- no depth-guard tuning
279
+ // could satisfy both "the real script works" and "Windows doesn't
280
+ // crash", only eliminating the native reentry itself could).
281
+ //
282
+ // a = index into CompiledChunk::builtinWrapSites. Runtime handler:
283
+ // captures ev.randsCallCount() BEFORE any argument resolution
284
+ // (mirrors Evaluator::buildTreeNode's own ordering exactly -- doing
285
+ // this AFTER would silently drop uncacheable/ManifoldCache taint
286
+ // tracking for a rands() call embedded in the wrapper's own
287
+ // arguments), computes this site's own params (and, for Transform/
288
+ // Color kinds, a possibly-$-scoped child EvalContext, pushed onto
289
+ // f.ctxChain unconditionally -- Modifier kind needs neither params
290
+ // nor a ctx push), pushes a fresh ev.treeStack_ frame, and stashes
291
+ // {params, randsBefore, siteIdx} onto VmFrame::builtinWrapStack (a
292
+ // real per-frame LIFO stack, not a single slot: Push/PopBuiltinWrap
293
+ // pairs can nest or sequence within one frame's own instruction
294
+ // stream, e.g. `translate(a) translate(b) recur();`). The compiler
295
+ // always emits a plain Op::CheckDebugStatement immediately before
296
+ // this (see emitBuiltinWrap, bytecode_compiler.cpp), mirroring
297
+ // ModularEcho/ModularAssert's own pattern -- NOT skipped the way
298
+ // Op::CallModule's own call site skips one: this is a genuine
299
+ // statement doing real work here, unlike a module call (which
300
+ // transfers control to a declaration whose OWN body statements each
301
+ // get their own check instead).
302
+ PushBuiltinWrap,
303
+
304
+ // Closes the matching Op::PushBuiltinWrap bracket: pops
305
+ // VmFrame::builtinWrapStack's own top entry FIRST (before anything
306
+ // that can itself throw, e.g. Evaluator::setTreeDepthOrThrow below --
307
+ // so the exception-teardown path's own pending count is already
308
+ // correct if THIS throws), pops the ctx push Push made (Transform/
309
+ // Color kinds only), pops ev.treeStack_ to retrieve the children this
310
+ // bracket's own body produced, and builds the tagged CSGNode exactly
311
+ // like Evaluator::buildTreeNode's own post-resolveBody() half does
312
+ // (kind/node/isBuiltin=true/children/params/uncacheable/
313
+ // setTreeDepthOrThrow), pushing it onto the new top of treeStack_. a
314
+ // = index into CompiledChunk::builtinWrapSites (same site Push used).
315
+ //
316
+ // teardownVmCallStackDownTo's own exception path (bytecode_vm.cpp)
317
+ // pops frame->builtinWrapStack.size() additional treeStack_ entries
318
+ // per torn-down frame, on top of its existing ownsModuleSplice-gated
319
+ // pop -- required because an exception can leave N of these brackets
320
+ // open in one frame, unlike the "at most one Op::CallModule splice
321
+ // per frame" shape that gated pop was originally sized for. See
322
+ // releaseVmFrame's own doc comment (user_calls.cpp) for a real,
323
+ // previously-ASan-caught bug from exactly this class of mismatched-
324
+ // bookkeeping-vs-treeStack_-depth mistake (a 1-bit version of the
325
+ // same seam, now a counter).
326
+ PopBuiltinWrap,
327
+
328
+ // A single "native passthrough" statement -- intersection_for,
329
+ // children(), union/difference/intersection and every other builtin
330
+ // module call NOT covered by Op::PushBuiltinWrap (see that op's own
331
+ // doc comment for exactly which builtins ARE covered), the `*`
332
+ // modifier's own no-op case, or a user-module call that didn't
333
+ // resolve at compile time (shadowed, forward-declared, or otherwise
334
+ // not statically known) -- anything compileStatementList doesn't give
335
+ // its own real bytecode. (Assignment/ModularEcho/ModularAssert/
336
+ // ModularLet used to fall here too; they now have their own real
337
+ // bytecode -- Op::StoreModuleVar/Op::Echo/Op::AssertStatement/
338
+ // Op::OpenLetScope+StoreLetVar -- purely a throughput change, since
339
+ // none of these were ever the recursion-depth risk this compiler
340
+ // targets. `#`/`%`/`!` modifiers and translate/rotate/scale/mirror/
341
+ // multmatrix/resize/color used to fall here too, for the SAME
342
+ // throughput reasoning -- WRONG in that one specific case: a
343
+ // recursive module call wrapped in one of these is exactly the
344
+ // pattern that made this op's own native reentry a genuine Windows
345
+ // crash risk in practice, not just a missed optimization. See
346
+ // Op::PushBuiltinWrap's own doc comment for the real story and the
347
+ // fix.)
273
348
  // a = index into CompiledChunk::nativeStatements. Runtime just does
274
349
  // what Evaluator::evalChildren's own per-statement loop already does
275
350
  // for one node: derive childCtx via ctx.withScope(...), checkDebug,
276
- // evalStatement. These are "leaf-shaped" in the sense the Stage 2 plan
277
- // means it: whatever native recursion they make (a builtin's own
278
- // resolve function walking ITS children, etc.) is bounded by ordinary
279
- // script structure, not by how deep a recursive module chain goes --
280
- // that risk is fully covered by CallModule/ForIterNext/the Jump-based
281
- // if/for control flow instead, regardless of how many of THESE sit
282
- // alongside them in the same body.
351
+ // evalStatement. These are still "leaf-shaped" for what's left here
352
+ // after Op::PushBuiltinWrap peeled off the proven-risky subset: real
353
+ // recursion safety for a recursive module chain is covered by
354
+ // CallModule/PushBuiltinWrap/ForIterNext/the Jump-based if/for control
355
+ // flow, not by how many of THESE sit alongside them in the same body
356
+ // -- true again now that the one construct that violated it
357
+ // (translate()-wrapped recursion) has its own real bytecode instead.
283
358
  NativeStatement,
284
359
 
285
360
  // If/if-else's own condition, evaluated NATIVELY (Evaluator::
@@ -583,6 +658,38 @@ struct CompiledChunk {
583
658
  std::string calleeName;
584
659
  };
585
660
 
661
+ // One Op::PushBuiltinWrap/PopBuiltinWrap site pair -- a builtin-with-
662
+ // children statement recognized at COMPILE time as one of the small,
663
+ // closed set this covers (see Op::PushBuiltinWrap's own doc comment
664
+ // for the full list and the Windows-crash rationale). Unlike
665
+ // ModuleCallSite, this is NOT "a call" -- see this struct's own `kind`
666
+ // discriminator and Evaluator::evalModularCall/buildTreeNode/
667
+ // evalModifier (csg_resolve.cpp): builtins never touch callStack_ or
668
+ // fire profileEnter/profileExit, native or compiled, so there's no
669
+ // enterUserCall-style bracketing to represent here, just enough to
670
+ // replay the native param-resolution step and rebuild the tagged
671
+ // CSGNode at Pop time.
672
+ //
673
+ // `node`'s concrete type depends on `kind`: Transform/Color sites are
674
+ // genuine `ModularCall`s (down-cast to read `.name`/`.arguments`/
675
+ // `.children`); Modifier sites are the wrapper node itself
676
+ // (`ModularModifierHighlight`/`Background`/`ShowOnly` -- `!`/`#`/`%`;
677
+ // `*`/Disable never reaches here, its child never evaluates at all,
678
+ // so it stays Op::NativeStatement's no-op-shaped native path), which
679
+ // does NOT derive from ModularCall (it derives from
680
+ // ModuleInstantiation directly and carries a single `child`) -- read
681
+ // via its own concrete type when kind == Modifier, never as a
682
+ // ModularCall. Stored as the generic `ASTNode*` here (not a tagged
683
+ // union of concrete pointers) because that's all Op::PopBuiltinWrap
684
+ // itself ever needs `node` for: the resulting CSGNode's own
685
+ // `node`/error-position field.
686
+ struct BuiltinWrapSite {
687
+ enum class Kind { Transform, Color, Modifier };
688
+ Kind kind;
689
+ std::string tagName; // "translate"/"rotate"/.../"color"/"highlight"/"background"/"show_only"
690
+ const oscad::ASTNode* node = nullptr;
691
+ };
692
+
586
693
  // One Op::AssertStatement site -- see that op's own doc comment for
587
694
  // the full contract. `conditionArgIndex`/`messageArgIndex` are indices
588
695
  // into the site's own argCount-sized popped-argument array (source
@@ -644,6 +751,7 @@ struct CompiledChunk {
644
751
  // NativeCondJumpIfFalse/NativeCheckDebugExprLevel/NativeIterMaterialize's
645
752
  // own doc comments, above) -- always empty for a function chunk.
646
753
  std::vector<ModuleCallSite> moduleCallSites;
754
+ std::vector<BuiltinWrapSite> builtinWrapSites;
647
755
  std::vector<AssertSite> assertSites;
648
756
  std::vector<const oscad::Expression*> nativeExprs;
649
757
  std::vector<const oscad::ASTNode*> nativeStatements;
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include "openscad_cpp_evaluator/bound_args.hpp"
4
4
  #include "openscad_cpp_evaluator/bytecode.hpp"
5
+ #include "openscad_cpp_evaluator/csg_node.hpp"
5
6
  #include "openscad_cpp_evaluator/eval_context.hpp"
6
7
  #include "openscad_cpp_evaluator/value.hpp"
7
8
 
@@ -16,6 +17,19 @@ namespace oscadeval {
16
17
 
17
18
  class Evaluator;
18
19
 
20
+ // One still-open Op::PushBuiltinWrap bracket's own state, needed again by
21
+ // its matching Op::PopBuiltinWrap -- see that op's own doc comment
22
+ // (bytecode.hpp) for the full contract. Lives in the header for the same
23
+ // reason IterList does, just above: it travels with a VmFrame (VmFrame::
24
+ // builtinWrapStack, below), not a free-standing local, since Push/
25
+ // PopBuiltinWrap pairs can nest or sequence within one frame's own
26
+ // instruction stream.
27
+ struct PendingBuiltinWrap {
28
+ CSGParams params;
29
+ std::uint64_t randsBefore = 0;
30
+ int siteIdx = -1;
31
+ };
32
+
19
33
  // One ListCompFor/statement-for assignment's own materialized iteration
20
34
  // state -- see Op::IterMaterialize/IterReset/IterNext's own doc comments
21
35
  // (bytecode.hpp). Lives in the header (not bytecode_vm.cpp's own anonymous
@@ -102,6 +116,17 @@ struct VmFrame {
102
116
  std::vector<std::vector<Value>> accumStack;
103
117
  std::vector<IterList> iterLists;
104
118
  std::vector<EvalContext> ctxChain;
119
+ // Still-open Op::PushBuiltinWrap brackets, LIFO, scoped to THIS frame's
120
+ // own instruction stream -- mirrors accumStack/iterLists' own role for
121
+ // their respective bracket pairs. Normal execution always drains this
122
+ // back to empty (every Push has a compile-time-matched Pop); only the
123
+ // exception-teardown path (teardownVmCallStackDownTo, bytecode_vm.cpp)
124
+ // needs to know its size, to pop the matching number of extra
125
+ // treeStack_ entries for a frame torn down mid-bracket. Not explicitly
126
+ // cleared in releaseVmFrame, same as accumStack/ctxChain -- the
127
+ // existing invariant ("whoever pops this frame drains its own open
128
+ // brackets first") already covers it.
129
+ std::vector<PendingBuiltinWrap> builtinWrapStack;
105
130
  // The ORIGINAL callee name at push time, used by
106
131
  // Evaluator::exitUserCallSuccess's own returnHook call when this frame
107
132
  // carries a bracket -- deliberately NOT updated by a later tail hop
@@ -559,18 +559,25 @@ private:
559
559
  void buildTreeNode(const std::string& kind, const oscad::ASTNode& node,
560
560
  const std::function<CSGParams()>& resolveBody);
561
561
 
562
+ // -- User function/module calls (Phase 4) --------------------------
563
+
564
+ public:
562
565
  // Sets node.treeDepth from its own (already-finalized) `children`,
563
566
  // throwing (kMaxCsgTreeDepth's own doc comment, above, for why) if
564
567
  // it's now too deep. Called by every csg_resolve.cpp site that
565
568
  // finalizes a CSGNode's own `children` -- buildTreeNode,
566
569
  // evalModularCall's non-splice tail, spliceModuleChildren's
567
570
  // union-wrap branch -- right after assigning `children`, before the
568
- // node is ever linked into anything a caller could see.
571
+ // node is ever linked into anything a caller could see. Public (not
572
+ // alongside buildTreeNode/evalModularCall, just above, which stay
573
+ // private member functions): Op::PopBuiltinWrap's own runtime handler
574
+ // (bytecode_vm.cpp, a free function, same "needs direct access, no
575
+ // friend declaration in play" reasoning as treeStack_/randsCallCount()
576
+ // above) calls this directly, replicating buildTreeNode's own
577
+ // post-resolveBody() half rather than going through it (the "body"
578
+ // there already ran as bytecode, not a callback buildTreeNode could
579
+ // invoke).
569
580
  void setTreeDepthOrThrow(CSGNode& node, const oscad::ASTNode& errNode);
570
-
571
- // -- User function/module calls (Phase 4) --------------------------
572
-
573
- public:
574
581
  // Picks between an isolated call scope (callCtx()) and a closure-
575
582
  // capturing one (childCtx()) for entering `decl`'s body: walks the
576
583
  // live call stack, and if `decl`'s own declaration span is *strictly*
@@ -1351,18 +1358,44 @@ public:
1351
1358
  // doubled to 100 for headroom -- that immediately segfaulted on
1352
1359
  // Windows CI (ModuleBodyCompiles.
1353
1360
  // NativeReentrantRecursionHitsAControlledErrorInsteadOfCrashing, its
1354
- // own guard-safety regression test). Backed off to 50 -- STILL
1355
- // segfaulted there. Confirms this chain's real per-level native-frame
1356
- // cost is heavier than kMaxUserCallDepth's own (which needed the SAME
1357
- // kind of comedown, an initial 50 down to 30, for a shallower chain),
1358
- // and that Windows' real safe ceiling for THIS chain sits somewhere
1359
- // below 50, above the already-Windows-verified-safe 30 (confirmed
1360
- // safe by PR #60's own successful merge, before this value ever
1361
- // changed). Currently at 40 -- ALSO still functionally sufficient
1362
- // (all 3 real scripts still render locally at this value) -- bisecting
1363
- // downward toward Windows' actual ceiling via successive CI runs, one
1364
- // step at a time; if 40 itself is still unsafe there, keep coming
1365
- // down. Do not raise this value again based on local (macOS/Linux)
1361
+ // own guard-safety regression test at the time -- since renamed/
1362
+ // repurposed, see Op::PushBuiltinWrap below). Backed off to 50 --
1363
+ // STILL segfaulted there. Confirms this chain's real per-level
1364
+ // native-frame cost is heavier than kMaxUserCallDepth's own (which
1365
+ // needed the SAME kind of comedown, an initial 50 down to 30, for a
1366
+ // shallower chain), and that Windows' real safe ceiling for THIS
1367
+ // chain sits somewhere below 50, above the already-Windows-verified-
1368
+ // safe 30 (confirmed safe by PR #60's own successful merge, before
1369
+ // this value ever changed). Landed at 40.
1370
+ //
1371
+ // A real stack-margin check (nativeStackMarginLow(), since removed --
1372
+ // see git history for `native_stack.hpp`/`.cpp` if the exact mechanism
1373
+ // is ever needed again) was tried as a REPLACEMENT for this fixed
1374
+ // count, specifically because BOSL2's attachable() machinery
1375
+ // (Anklet.scad) needed native reentry depth 55, past this ceiling --
1376
+ // and confirmed working for that: Anklet.scad rendered successfully
1377
+ // with an unmodified build. But the margin-based check was THEN
1378
+ // confirmed, via two separate real Windows CI runs, to segfault for a
1379
+ // DIFFERENT deep native-reentry chain (union()-wrapped recursion)
1380
+ // regardless of total thread stack size (an 8 MiB Windows stack,
1381
+ // matching macOS's own default byte-for-byte, still crashed at the
1382
+ // same depth) -- i.e. this fixed count, not the margin check, is the
1383
+ // mechanism actually proven safe on Windows for genuine deep native
1384
+ // reentry; the margin check is not a safe general replacement for it.
1385
+ //
1386
+ // The REAL fix for Anklet.scad turned out to be architectural, not a
1387
+ // better safety-check mechanism: Op::PushBuiltinWrap/PopBuiltinWrap
1388
+ // (bytecode.hpp/bytecode_compiler.cpp/bytecode_vm.cpp) eliminates
1389
+ // native reentry ENTIRELY for the specific pattern that needed depth
1390
+ // 55 (translate/rotate/scale/mirror/multmatrix/resize/color/#/%/!-
1391
+ // wrapped recursion) by compiling it to run on the heap-based
1392
+ // vmCallStack_ instead of falling to Op::NativeStatement -- so this
1393
+ // guard no longer needs to accommodate that case at all. What's left
1394
+ // uncovered (union/difference/intersection-wrapped recursion, other
1395
+ // builtins, fully interpreted-mode scripts) is genuinely "leaf-shaped"
1396
+ // again in the sense Stage 2's original design assumed, comfortably
1397
+ // within this fixed, Windows-proven-safe ceiling for any realistic
1398
+ // script. Do not raise this value again based on local (macOS/Linux)
1366
1399
  // testing alone -- only a real Windows CI pass is evidence of safety
1367
1400
  // here. Deliberately its own named constant (not a reuse of
1368
1401
  // kMaxUserCallDepth) so the two can be recalibrated independently.
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.13.0"
7
+ version = "0.13.2"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -38,13 +38,29 @@ CSGParams resolve2d(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
38
38
  std::vector<ColoredBody> generate2d(Evaluator& ev, const CSGParams& params,
39
39
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
40
40
 
41
+ // Shared return shape for computeTransformParams/computeColorParams,
42
+ // below -- the "resolve args, build params, compute a possibly-$-scoped
43
+ // child ctx" half of resolveTransform/resolveColor, split out so
44
+ // Op::PushBuiltinWrap's own runtime handler (bytecode_vm.cpp) can call it
45
+ // directly instead of going through the full resolve function (whose
46
+ // OTHER half, `ev.evalChildren(...)`, is exactly the native reentry this
47
+ // split exists to avoid). `ctx` is the input ctx unchanged unless this
48
+ // builtin's own resolution opened a new one (mirrors ResolvedCallArgs's
49
+ // own `ctx` field, call_args.hpp).
50
+ struct BuiltinWrapParams {
51
+ CSGParams params;
52
+ EvalContext ctx;
53
+ };
54
+
41
55
  // translate/rotate/scale/mirror/multmatrix/resize share one resolve/
42
56
  // generate pair (2D/3D dispatch happens per-body at generate time).
57
+ BuiltinWrapParams computeTransformParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
43
58
  CSGParams resolveTransform(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
44
59
  std::vector<ColoredBody> generateTransform(Evaluator& ev, const CSGParams& params,
45
60
  const std::vector<std::unique_ptr<CSGNode>>& children,
46
61
  const oscad::ASTNode& node);
47
62
 
63
+ BuiltinWrapParams computeColorParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
48
64
  CSGParams resolveColor(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
49
65
  std::vector<ColoredBody> generateColor(Evaluator& ev, const CSGParams& params,
50
66
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
@@ -12,7 +12,7 @@ namespace oscadeval {
12
12
  // case). Sets the color on ctx for every descendant statement. Mirrors
13
13
  // _resolve_color/_generate_color.
14
14
 
15
- CSGParams resolveColor(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
15
+ BuiltinWrapParams computeColorParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
16
16
  auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
17
17
  const Value defaultC =
18
18
  Value{std::make_shared<const ValueList>(ValueList{{Value{1.0}, Value{1.0}, Value{1.0}, Value{1.0}}})};
@@ -33,15 +33,19 @@ CSGParams resolveColor(Evaluator& ev, const oscad::ModularCall& node, EvalContex
33
33
  }
34
34
 
35
35
  EvalContext childCtx = effCtx.childCtx(nullptr, std::optional<std::array<double, 4>>(rgba));
36
+ CSGParams params;
37
+ params["rgba"] = colorToValue(rgba);
38
+ return BuiltinWrapParams{std::move(params), std::move(childCtx)};
39
+ }
40
+
41
+ CSGParams resolveColor(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
42
+ BuiltinWrapParams result = computeColorParams(ev, node, ctx);
36
43
  // Evaluated for the side effect of building the children's own CSGNodes
37
44
  // under the color-tagged context -- the returned bodies themselves are
38
45
  // unused here; generate reads them back via each child's own .bodies
39
46
  // and stamps `rgba` onto all of them. Mirrors _resolve_color.
40
- ev.evalChildren(node.children, childCtx);
41
-
42
- CSGParams params;
43
- params["rgba"] = colorToValue(rgba);
44
- return params;
47
+ ev.evalChildren(node.children, result.ctx);
48
+ return std::move(result.params);
45
49
  }
46
50
 
47
51
  std::vector<ColoredBody> generateColor(Evaluator&, const CSGParams& params,
@@ -164,7 +164,7 @@ manifold::CrossSection applyTransform2d(const std::string& name, const CallArgs&
164
164
 
165
165
  } // namespace
166
166
 
167
- CSGParams resolveTransform(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
167
+ BuiltinWrapParams computeTransformParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
168
168
  const std::string& name = node.name->name;
169
169
  auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
170
170
 
@@ -176,9 +176,13 @@ CSGParams resolveTransform(Evaluator& ev, const oscad::ModularCall& node, EvalCo
176
176
  // getArg() again in applyTransform2d/3d below, instead of resolving
177
177
  // e.g. "v"/"a" to a concrete vec3/vec2 here.
178
178
  params["args"] = callArgsToValue(args);
179
+ return BuiltinWrapParams{std::move(params), std::move(effCtx)};
180
+ }
179
181
 
180
- ev.evalChildren(node.children, effCtx);
181
- return params;
182
+ CSGParams resolveTransform(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
183
+ BuiltinWrapParams result = computeTransformParams(ev, node, ctx);
184
+ ev.evalChildren(node.children, result.ctx);
185
+ return std::move(result.params);
182
186
  }
183
187
 
184
188
  std::vector<ColoredBody> generateTransform(Evaluator&, const CSGParams& params,
@@ -1,8 +1,11 @@
1
1
  #include "openscad_cpp_evaluator/bytecode_compiler.hpp"
2
2
 
3
3
  #include "openscad_cpp_evaluator/call_args.hpp"
4
+ #include "openscad_cpp_evaluator/dispatch.hpp"
4
5
  #include "openscad_cpp_evaluator/function_builtins.hpp"
5
6
 
7
+ #include "builtins/builtins.hpp"
8
+
6
9
  #include "openscad_cpp_parser/ast/declarations.hpp"
7
10
  #include "openscad_cpp_parser/ast/expression.hpp"
8
11
  #include "openscad_cpp_parser/ast/module_instantiation.hpp"
@@ -1163,6 +1166,42 @@ public:
1163
1166
  out.push_back({Op::CloseExprScope, 0, 0, nullptr});
1164
1167
  }
1165
1168
 
1169
+ // Shared by ModularCall's Transform/Color-kind branch and the 3 real
1170
+ // modifier cases (ModularModifierHighlight/Background/ShowOnly),
1171
+ // below -- emits one Op::PushBuiltinWrap/PopBuiltinWrap bracket around
1172
+ // `children` compiled inline (exactly like ModularLet's own body
1173
+ // does, via this same compileStatementList recursion). See
1174
+ // Op::PushBuiltinWrap's own doc comment (bytecode.hpp) for the full
1175
+ // design and why this specific set doesn't fall to Op::NativeStatement
1176
+ // like other builtins-with-children still do.
1177
+ //
1178
+ // Op::CheckDebugStatement emitted first, mirroring ModularEcho/
1179
+ // ModularAssert's own pattern (both above) -- NOT Op::CallModule's own
1180
+ // lack of one: that omission is specific to a resolved USER MODULE
1181
+ // call, whose own body statements each get their own check instead
1182
+ // (mirrors evalUserModule's "no body-entry checkDebug of its own",
1183
+ // evaluator.hpp). A builtin wrap statement isn't "control transferring
1184
+ // to a declaration" the way a module call is -- it's a plain statement
1185
+ // representing real work happening HERE, exactly like echo/assert/
1186
+ // assignment, which is why those get their own checkpoint. Confirmed
1187
+ // for real: DebugHooks.FastContinueNotHookSkippableStillFiresEvery-
1188
+ // Checkpoint (a translate()-wrapped script) caught the miscount when
1189
+ // this was first omitted by analogy to Op::CallModule.
1190
+ void emitBuiltinWrap(CompiledChunk::BuiltinWrapSite::Kind kind, const std::string& tagName,
1191
+ const oscad::ASTNode& wrapperNode, const std::vector<const oscad::ASTNode*>& children,
1192
+ std::vector<Instruction>& out) {
1193
+ out.push_back({Op::CheckDebugStatement, internNativeStatement(&wrapperNode), 0, nullptr});
1194
+ CompiledChunk::BuiltinWrapSite site;
1195
+ site.kind = kind;
1196
+ site.tagName = tagName;
1197
+ site.node = &wrapperNode;
1198
+ chunk_.builtinWrapSites.push_back(std::move(site));
1199
+ const int idx = static_cast<int>(chunk_.builtinWrapSites.size()) - 1;
1200
+ out.push_back({Op::PushBuiltinWrap, idx, 0, &wrapperNode.position()});
1201
+ compileStatementList(children, out);
1202
+ out.push_back({Op::PopBuiltinWrap, idx, 0, &wrapperNode.position()});
1203
+ }
1204
+
1166
1205
  void compileOneStatement(const oscad::ASTNode& stmt, std::vector<Instruction>& out) {
1167
1206
  using oscad::NodeKind;
1168
1207
  trackSpan(stmt);
@@ -1350,14 +1389,61 @@ public:
1350
1389
  {Op::CallModule, static_cast<int>(chunk_.moduleCallSites.size()) - 1, 0, &call.position()});
1351
1390
  return;
1352
1391
  }
1353
- // Builtin, children(), or a name that didn't resolve to a
1354
- // user module statically -- native passthrough, exactly
1355
- // like echo/assert/etc. below. Never the recursion-depth
1356
- // risk this compiler targets (see NativeStatement's own
1357
- // doc comment, bytecode.hpp).
1392
+ // A user module never shadows a builtin transform/color
1393
+ // name in a way that reaches here -- the `resolved` check
1394
+ // above already ruled that out (isBuiltin per
1395
+ // evalModularCall's own comment). So a name found in
1396
+ // resolveDispatch() here is unambiguously the real C++
1397
+ // builtin. Detected by FUNCTION-POINTER identity against
1398
+ // &resolveTransform/&resolveColor, not a second,
1399
+ // independently-maintained name list -- stays in sync
1400
+ // with registry.cpp automatically if a 7th transform name
1401
+ // is ever added there. See Op::PushBuiltinWrap's own doc
1402
+ // comment (bytecode.hpp) for why this specific subset
1403
+ // gets real bytecode instead of falling to
1404
+ // Op::NativeStatement below like every other builtin
1405
+ // still does.
1406
+ const auto& dispatch = resolveDispatch();
1407
+ auto dispatchIt = dispatch.find(call.name->name);
1408
+ std::optional<CompiledChunk::BuiltinWrapSite::Kind> wrapKind;
1409
+ if (dispatchIt != dispatch.end()) {
1410
+ if (dispatchIt->second == &resolveTransform) {
1411
+ wrapKind = CompiledChunk::BuiltinWrapSite::Kind::Transform;
1412
+ } else if (dispatchIt->second == &resolveColor) {
1413
+ wrapKind = CompiledChunk::BuiltinWrapSite::Kind::Color;
1414
+ }
1415
+ }
1416
+ if (wrapKind) {
1417
+ std::vector<const oscad::ASTNode*> children;
1418
+ children.reserve(call.children.size());
1419
+ for (const auto& c : call.children) children.push_back(c.get());
1420
+ emitBuiltinWrap(*wrapKind, call.name->name, call, children, out);
1421
+ return;
1422
+ }
1423
+ // Every other builtin, children(), or a name that didn't
1424
+ // resolve to a user module statically -- native
1425
+ // passthrough, exactly like echo/assert/etc. below. Never
1426
+ // the recursion-depth risk this compiler targets for
1427
+ // THESE (see NativeStatement's own doc comment,
1428
+ // bytecode.hpp).
1358
1429
  out.push_back({Op::NativeStatement, internNativeStatement(&stmt), 0, &stmt.position()});
1359
1430
  return;
1360
1431
  }
1432
+ case NodeKind::ModularModifierHighlight: {
1433
+ auto& n = static_cast<const oscad::ModularModifierHighlight&>(stmt);
1434
+ emitBuiltinWrap(CompiledChunk::BuiltinWrapSite::Kind::Modifier, "highlight", n, {n.child.get()}, out);
1435
+ return;
1436
+ }
1437
+ case NodeKind::ModularModifierBackground: {
1438
+ auto& n = static_cast<const oscad::ModularModifierBackground&>(stmt);
1439
+ emitBuiltinWrap(CompiledChunk::BuiltinWrapSite::Kind::Modifier, "background", n, {n.child.get()}, out);
1440
+ return;
1441
+ }
1442
+ case NodeKind::ModularModifierShowOnly: {
1443
+ auto& n = static_cast<const oscad::ModularModifierShowOnly&>(stmt);
1444
+ emitBuiltinWrap(CompiledChunk::BuiltinWrapSite::Kind::Modifier, "show_only", n, {n.child.get()}, out);
1445
+ return;
1446
+ }
1361
1447
  case NodeKind::ModularIf: {
1362
1448
  auto& n = static_cast<const oscad::ModularIf&>(stmt);
1363
1449
  const int jumpFalseIdx = static_cast<int>(out.size());
@@ -1389,10 +1475,17 @@ public:
1389
1475
  return;
1390
1476
  }
1391
1477
  default:
1392
- // modifiers/intersection_for -- deliberately native (see
1393
- // this section's own header comment above); echo/assert/
1394
- // assignment/let-block now have their own real bytecode
1395
- // cases, above.
1478
+ // ModularModifierDisable (`*`) -- deliberately native: its
1479
+ // child never evaluates at all (see evalStatement's own
1480
+ // ModularModifierDisable case, stmt_eval.cpp), so there's
1481
+ // no recursion to eliminate here in the first place.
1482
+ // intersection_for -- deliberately native (bespoke
1483
+ // per-statement grouping, same reasoning as union/
1484
+ // difference/intersection; not covered by
1485
+ // Op::PushBuiltinWrap, see that op's own doc comment).
1486
+ // `#`/`%`/`!` and translate/rotate/scale/mirror/multmatrix/
1487
+ // resize/color have their own real bytecode cases now,
1488
+ // above; echo/assert/assignment/let-block already did.
1396
1489
  out.push_back({Op::NativeStatement, internNativeStatement(&stmt), 0, &stmt.position()});
1397
1490
  return;
1398
1491
  }