openscad-cpp-evaluator 1.6.0__tar.gz → 1.7.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 (214) hide show
  1. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode.hpp +35 -0
  3. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/function_builtins.hpp +27 -0
  4. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/scope_trail.hpp +104 -34
  5. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/function_builtins.cpp +16 -12
  7. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/bytecode_compiler.cpp +48 -0
  8. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/bytecode_vm.cpp +123 -22
  9. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/eval_context.cpp +17 -3
  10. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/mesh_check.cpp +92 -19
  11. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_bytecode_compiler.cpp +65 -0
  12. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_mesh_check.cpp +13 -0
  13. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/.github/workflows/ci.yml +0 -0
  14. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/.github/workflows/wheels.yml +0 -0
  15. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/.gitignore +0 -0
  16. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/.gitmodules +0 -0
  17. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/CLAUDE.md +0 -0
  18. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/CMakeLists.txt +0 -0
  19. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/LICENSE +0 -0
  20. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/README.md +0 -0
  21. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/bindings/CMakeLists.txt +0 -0
  22. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/bindings/ast_to_py.cpp +0 -0
  23. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/bindings/module.cpp +0 -0
  24. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/cmake/embed_font.cmake +0 -0
  25. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/examples/CMakeLists.txt +0 -0
  26. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/examples/eval_perf_benchmark.cpp +0 -0
  27. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/examples/manifold_cache_reuse.cpp +0 -0
  28. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/examples/minimal_debugger.cpp +0 -0
  29. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  30. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/.gitignore +0 -0
  31. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  32. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  33. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/README.md +0 -0
  34. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  35. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  36. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  37. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  38. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  39. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  40. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  41. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  42. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  43. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  44. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  45. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  46. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  47. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  48. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  49. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  50. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  51. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  52. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  53. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  54. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  55. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  56. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  57. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  58. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  59. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  60. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  61. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  62. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  63. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  64. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  65. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  66. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  67. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  68. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  69. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  70. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  71. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  72. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  73. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  74. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  75. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  76. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  77. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  78. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  79. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  80. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  81. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  82. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  83. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  84. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  85. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  86. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  87. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  88. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  89. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  90. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  91. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  92. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  93. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  94. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  95. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  96. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  97. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  98. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  99. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  100. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  101. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  102. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  103. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  104. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  105. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  106. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  107. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  108. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  109. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  110. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  111. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  112. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  113. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  114. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  115. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  116. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  117. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  118. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  119. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  120. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  121. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  122. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  123. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  124. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  125. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  126. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  127. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  128. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  129. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  130. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/resources/fonts/LICENSE +0 -0
  131. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  132. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/CMakeLists.txt +0 -0
  133. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/booleans.cpp +0 -0
  134. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/builtins.hpp +0 -0
  135. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/call_args.cpp +0 -0
  136. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/color.cpp +0 -0
  137. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/control.cpp +0 -0
  138. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/dxf_dim.cpp +0 -0
  139. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/extrude.cpp +0 -0
  140. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/import.cpp +0 -0
  141. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/modifiers.cpp +0 -0
  142. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/primitives_2d.cpp +0 -0
  143. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/primitives_3d.cpp +0 -0
  144. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/registry.cpp +0 -0
  145. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/roof.cpp +0 -0
  146. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/segments.cpp +0 -0
  147. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/surface.cpp +0 -0
  148. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/text.cpp +0 -0
  149. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/topology.cpp +0 -0
  150. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/builtins/transforms.cpp +0 -0
  151. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/colored_body.cpp +0 -0
  152. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/csg_generate.cpp +0 -0
  153. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/csg_resolve.cpp +0 -0
  154. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/css_colors.cpp +0 -0
  155. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/debug/debug_repl.cpp +0 -0
  156. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/debug_profile.cpp +0 -0
  157. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/eval_error.cpp +0 -0
  158. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/eval_use.cpp +0 -0
  159. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/export.cpp +0 -0
  160. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/expr_eval.cpp +0 -0
  161. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/format_closure.cpp +0 -0
  162. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/import/dxf_import.cpp +0 -0
  163. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/import/mesh_import.cpp +0 -0
  164. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/import/surface_load.cpp +0 -0
  165. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/import/svg_import.cpp +0 -0
  166. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/manifold_cache.cpp +0 -0
  167. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/measure_geometry.cpp +0 -0
  168. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/stmt_eval.cpp +0 -0
  169. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/text/font_match.cpp +0 -0
  170. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/text/freetype_font_provider.cpp +0 -0
  171. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/text/text_metrics.cpp +0 -0
  172. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/user_calls.cpp +0 -0
  173. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/utf8.cpp +0 -0
  174. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/value.cpp +0 -0
  175. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/src/zip_stored.cpp +0 -0
  176. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/CMakeLists.txt +0 -0
  177. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_booleans.cpp +0 -0
  178. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_children_separate.cpp +0 -0
  179. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_cli.cpp +0 -0
  180. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_control_flow.cpp +0 -0
  181. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_csg_tree.cpp +0 -0
  182. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_debug_hooks.cpp +0 -0
  183. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_dxf_svg_import.cpp +0 -0
  184. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_eval_context.cpp +0 -0
  185. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_export.cpp +0 -0
  186. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_expr_eval.cpp +0 -0
  187. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_extrude_roof.cpp +0 -0
  188. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_feature_detection.cpp +0 -0
  189. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_function_builtins.cpp +0 -0
  190. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_helpers.hpp +0 -0
  191. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_import_export.cpp +0 -0
  192. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_include_cache.cpp +0 -0
  193. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_manifold_cache.cpp +0 -0
  194. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_multi_color_merge.cpp +0 -0
  195. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_primitives.cpp +0 -0
  196. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_profiling.cpp +0 -0
  197. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_python_bindings.py +0 -0
  198. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_render_expr.cpp +0 -0
  199. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_scope_trail.cpp +0 -0
  200. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_scoping.cpp +0 -0
  201. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_surface.cpp +0 -0
  202. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_tail_calls.cpp +0 -0
  203. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_text.cpp +0 -0
  204. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_transforms.cpp +0 -0
  205. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_unexpected_args.cpp +0 -0
  206. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_use.cpp +0 -0
  207. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_value.cpp +0 -0
  208. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_viewport_params.cpp +0 -0
  209. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tests/test_zip_stored.cpp +0 -0
  210. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tools/cli/CMakeLists.txt +0 -0
  211. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tools/cli/cli_lib.cpp +0 -0
  212. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tools/cli/cli_lib.hpp +0 -0
  213. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/tools/cli/main.cpp +0 -0
  214. {openscad_cpp_evaluator-1.6.0 → openscad_cpp_evaluator-1.7.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -1,5 +1,6 @@
1
1
  #pragma once
2
2
 
3
+ #include "openscad_cpp_evaluator/function_builtins.hpp"
3
4
  #include "openscad_cpp_evaluator/value.hpp"
4
5
 
5
6
  #include "openscad_cpp_parser/ast/ast_node.hpp"
@@ -787,6 +788,40 @@ struct CompiledChunk {
787
788
  const oscad::FunctionDeclaration* decl = nullptr;
788
789
  std::vector<std::optional<std::string>> argNames;
789
790
  const oscad::ASTNode* callNode = nullptr;
791
+ // Everything below is `calleeName` already looked up, once, here at
792
+ // compile time. The VM used to redo all three on EVERY builtin call:
793
+ // two std::string hashes into static tables plus a string compare
794
+ // against "object", for answers that cannot change once this site is
795
+ // compiled. `declaredParams` points into a function-local static
796
+ // table with process lifetime, so holding the pointer is safe.
797
+ BuiltinFnId builtinId = BuiltinFnId::None;
798
+ const std::vector<std::string>* declaredParams = nullptr;
799
+ bool isObjectBuiltin = false;
800
+
801
+ // Where each argument of this call goes, worked out once at compile
802
+ // time against `decl`'s parameter list -- see ArgBind. Only filled in
803
+ // for a static user-function callee (`decl` set); a builtin, an
804
+ // import or a dynamic/closure callee has no compile-time parameter
805
+ // list to match against and keeps the name-matching path.
806
+ //
807
+ // The names on both sides of that matching are fixed the moment this
808
+ // site is compiled, but the VM was redoing it on every call, twice:
809
+ // buildBoundArgs linear-scanned a name-keyed BoundArgs (copying each
810
+ // name into it), then bindBoundArgsIntoFrame linear-scanned it again
811
+ // for every parameter, then a third nested loop compared every bound
812
+ // name against every parameter name. A two-argument call did roughly
813
+ // ten std::string comparisons and two string copies to reach an
814
+ // answer that was already known. Binding straight into the frame's
815
+ // slots also MOVES each argument instead of moving it into BoundArgs
816
+ // and copying it back out.
817
+ struct ArgBind {
818
+ int paramIndex = -1; // >=0: this argument binds that parameter
819
+ bool toDyn = false; // instead bind by name into ctx.dyn ($-named, undeclared)
820
+ bool warnUnexpectedNamed = false;
821
+ bool warnTooManyPositional = false;
822
+ };
823
+ std::vector<ArgBind> argBinds;
824
+ bool hasArgPlan = false; // argBinds is authoritative (it is empty for a zero-argument call too)
790
825
  };
791
826
 
792
827
  // An upvalue read (see Op::LoadUpvalue): `targetDecl` is the enclosing
@@ -26,8 +26,35 @@ bool isBuiltinFunctionName(const std::string& name);
26
26
  // accept $-prefixed named-argument overrides). Mirrors the reference's
27
27
  // _math_fns dispatch table plus the textmetrics()/fontmetrics() special
28
28
  // cases (implemented on top of FontProvider, text_metrics.hpp).
29
+ // One id per name evalBuiltinFunction handles (NOT the same list as
30
+ // isBuiltinFunctionName -- "object" is deliberately absent, since it is
31
+ // special-cased to builtinObject() before this function is reached). Public
32
+ // so a CALL SITE can resolve its callee once, at compile time
33
+ // (CompiledChunk::CallSite::builtinId), instead of hashing the name string
34
+ // on every single call.
35
+ enum class BuiltinFnId {
36
+ None, // not a name evalBuiltinFunction handles
37
+ TextMetrics, FontMetrics, Abs, Sign, Ceil, Floor, Round, Sqrt, Ln, Log, Exp, Sin, Cos, Tan,
38
+ Asin, Acos, Atan, Atan2, Max, Min, Pow, Norm, Cross, Rands, Concat, Len, Str, Chr, Ord,
39
+ IsUndef, IsNum, IsBool, IsString, IsList, IsFunction, IsObject, Search, Lookup, HasKey,
40
+ Version, VersionNum, ParentModule, DxfDim, DxfCross, SupportedFeature, LinearSolve,
41
+ };
42
+
43
+ // `name` -> its id, or None. The one place that hashes the name; everything
44
+ // on a hot path should call this once at compile time and keep the answer.
45
+ BuiltinFnId builtinFnIdFor(const std::string& name);
46
+
29
47
  Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs& args, const oscad::ASTNode& node);
30
48
 
49
+ // The same dispatch with both of its name lookups already done: `id` from
50
+ // builtinFnIdFor and `declaredParams` from builtinParamNames (dispatch.hpp),
51
+ // which for all but a couple of builtins is null. `name` survives only
52
+ // because diagnostics quote it. The string-taking overload above is just
53
+ // this one with the two lookups performed first, and remains the entry point
54
+ // for the AST interpreter, where there is no call site to cache them on.
55
+ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vector<std::string>* declaredParams,
56
+ const std::string& name, const CallArgs& args, const oscad::ASTNode& node);
57
+
31
58
  // object(a=1, b=2, ...) -- an ordered string-keyed map merging positional
32
59
  // (an existing object's entries, or a list of [key,value] pairs) and named
33
60
  // arguments, later arguments winning over earlier ones for the same key --
@@ -12,37 +12,101 @@
12
12
 
13
13
  namespace oscadeval {
14
14
 
15
- // A "binding trail" (the classic Prolog/WAM undo-log pattern): each
16
- // variable name owns a stack of (value, level) entries. Setting a name
17
- // pushes; entering a new scope opens a fresh `level`; exiting a scope pops
18
- // every entry tagged with that level, in O(bindings actually made at that
19
- // level) rather than O(whole-map-size) -- replacing EvalContext's previous
20
- // copy-the-whole-map-on-every-derivation design. Safe here specifically
21
- // because this codebase has no escaping closures: a FunctionLiteral value
22
- // is a bare AST pointer with no captured environment, and callCtxFor()
23
- // re-derives every call's context from the LIVE call stack -- nothing ever
24
- // reads a binding after the scope that pushed it has already exited.
15
+ // Recycles the blocks that TrailView/IndexedTrailView's own shared_ptrs are
16
+ // made of. Deriving one EvalContext opens three trail levels -- dyn, let_,
17
+ // dynPositions -- and each was a fresh make_shared: ~2M allocations in one
18
+ // Anklet.scad render, all of them the same size, almost all of them freed in
19
+ // reverse order a few microseconds later. This hands the same block straight
20
+ // back out.
25
21
  //
26
- // Visibility is by TRUE ANCESTRY, not by level-number comparison: each
27
- // level records its own PARENT level (the level that was current when it
28
- // was opened, or 0 -- meaning "no parent" -- for an isolating derivation,
29
- // see TrailView::openChild). A view at level L can see an entry pushed at
30
- // level E iff E appears on L's own parent chain (L, parent(L), parent(
31
- // parent(L)), ... down to 0). This was NOT the original design here: an
32
- // earlier version used a single numeric "ceiling" (visible iff E <= L),
33
- // which is necessary but not sufficient -- it incorrectly treated any
34
- // chronologically-earlier-but-still-open level as an ancestor, even an
35
- // unrelated sibling/isolated scope that happens to still be on the call
36
- // stack. Caught on a real script (BOSL2's attachable()/trapezoid(), which
37
- // deep-forwards children() through several more calls while attachable()
38
- // itself -- an ISOLATED scope with its own same-named "path"/"h"
39
- // parameters, still open throughout -- sits on the stack): the ceiling-
40
- // only check found attachable()'s own unbound "path"/"h" (undef) instead
41
- // of trapezoid()'s real ones, since level-number order alone can't tell
42
- // "ancestor" from "unrelated open branch." Parent-chain walking fixes this
43
- // by construction. See eval_context.hpp for how each derivation method
44
- // picks its own level and (via `isolate`) whether the parent chain
45
- // continues to the caller or terminates there.
22
+ // It changes WHERE the memory comes from and nothing else: no lifetime, no
23
+ // visibility, no popLevel timing. That is the whole point -- the trail's
24
+ // escaping-closure rules are the most delicate thing in this file, and an
25
+ // allocator cannot get them wrong.
26
+ //
27
+ // One size class, because there is exactly one: every block is the control
28
+ // block plus one view object. Anything else falls through to the global
29
+ // allocator rather than being kept.
30
+ //
31
+ // Worth ~1% of an Anklet.scad render, for 2M allocations removed -- a modest
32
+ // return, and deliberately recorded here as such: macOS's own small-object
33
+ // allocator is already a free list, so swapping it for another one only pays
34
+ // for the bookkeeping either side of it. Removing an allocation that also
35
+ // removed real work (a vector's worth of Value moves, say) has paid far
36
+ // better everywhere it has been tried in this codebase.
37
+ class ViewBlockPool {
38
+ public:
39
+ ViewBlockPool() { free_.reserve(kMaxKept); }
40
+ ~ViewBlockPool() {
41
+ for (void* p : free_) ::operator delete(p);
42
+ }
43
+ ViewBlockPool(const ViewBlockPool&) = delete;
44
+ ViewBlockPool& operator=(const ViewBlockPool&) = delete;
45
+
46
+ void* take(std::size_t bytes) {
47
+ if (bytes == blockSize_ && !free_.empty()) {
48
+ void* p = free_.back();
49
+ free_.pop_back();
50
+ return p;
51
+ }
52
+ if (blockSize_ == 0) blockSize_ = bytes;
53
+ return ::operator new(bytes);
54
+ }
55
+ // noexcept is safe: free_ was reserved to kMaxKept up front and is never
56
+ // pushed past it, so this push_back cannot reallocate and cannot throw.
57
+ void give(void* p, std::size_t bytes) noexcept {
58
+ if (bytes != blockSize_ || free_.size() >= kMaxKept) {
59
+ ::operator delete(p);
60
+ return;
61
+ }
62
+ free_.push_back(p);
63
+ }
64
+
65
+ private:
66
+ static constexpr std::size_t kMaxKept = 512;
67
+ std::size_t blockSize_ = 0;
68
+ std::vector<void*> free_;
69
+ };
70
+
71
+ // A STATELESS allocator over one pool per view type (each type has exactly
72
+ // one block size, so each gets its own single-size-class pool). Stateless
73
+ // matters twice over: std::allocate_shared stores a copy of the allocator
74
+ // inside the very block it allocated, so a stateful one both grows every
75
+ // block and -- if it held a shared_ptr to keep the pool alive past the last
76
+ // view, which a pool owned by the storage would need -- pays an atomic
77
+ // refcount pair per allocation. That version was measured, and it was SLOWER
78
+ // than not pooling at all.
79
+ //
80
+ // thread_local, so no locking and no cross-thread sharing, and it outlives
81
+ // every view on its thread, which is what makes "keep the pool alive for the
82
+ // final deallocate" a non-problem rather than a lifetime puzzle.
83
+ template <typename T>
84
+ class ViewBlockAllocator {
85
+ public:
86
+ using value_type = T;
87
+ ViewBlockAllocator() = default;
88
+ template <typename U>
89
+ ViewBlockAllocator(const ViewBlockAllocator<U>&) {}
90
+
91
+ T* allocate(std::size_t n) { return static_cast<T*>(pool().take(n * sizeof(T))); }
92
+ void deallocate(T* p, std::size_t n) noexcept { pool().give(p, n * sizeof(T)); }
93
+
94
+ template <typename U>
95
+ bool operator==(const ViewBlockAllocator<U>&) const noexcept {
96
+ return true;
97
+ }
98
+ template <typename U>
99
+ bool operator!=(const ViewBlockAllocator<U>&) const noexcept {
100
+ return false;
101
+ }
102
+
103
+ private:
104
+ static ViewBlockPool& pool() {
105
+ static thread_local ViewBlockPool p;
106
+ return p;
107
+ }
108
+ };
109
+
46
110
  template <typename T>
47
111
  class ScopeTrailStorage {
48
112
  public:
@@ -207,6 +271,7 @@ private:
207
271
  // depends on level numbers being globally monotonic.
208
272
  std::vector<int> parent_{0};
209
273
  int nextLevel_ = 0;
274
+
210
275
  };
211
276
 
212
277
  // Per-EvalContext handle onto a shared ScopeTrailStorage<T>: this view's
@@ -235,7 +300,8 @@ public:
235
300
  static std::shared_ptr<TrailView<T>> makeRoot() {
236
301
  auto storage = std::make_shared<ScopeTrailStorage<T>>();
237
302
  int level = storage->openLevel(0);
238
- return std::make_shared<TrailView<T>>(storage, level);
303
+ return std::allocate_shared<TrailView<T>>(ViewBlockAllocator<TrailView<T>>(), storage,
304
+ level);
239
305
  }
240
306
 
241
307
  // Open a fresh level for writes. `isolate=true` terminates the new
@@ -272,7 +338,8 @@ public:
272
338
  // changes what happens when something holds an EXTRA reference.
273
339
  std::shared_ptr<TrailView<T>> openChild(bool isolate) const {
274
340
  int level = storage_->openLevel(isolate ? 0 : level_);
275
- auto child = std::make_shared<TrailView<T>>(storage_, level);
341
+ auto child = std::allocate_shared<TrailView<T>>(ViewBlockAllocator<TrailView<T>>(),
342
+ storage_, level);
276
343
  if (!isolate) child->parentView_ = this->shared_from_this();
277
344
  return child;
278
345
  }
@@ -462,6 +529,7 @@ private:
462
529
  std::unordered_map<int, std::vector<int>> dirty_;
463
530
  std::vector<int> parent_{0}; // see ScopeTrailStorage::parent_
464
531
  int nextLevel_ = 0;
532
+
465
533
  };
466
534
 
467
535
  // Per-EvalContext handle onto a shared IndexedScopeTrailStorage<T> -- the
@@ -474,12 +542,14 @@ public:
474
542
  static std::shared_ptr<IndexedTrailView<T>> makeRoot(std::shared_ptr<DynNameIntern> intern) {
475
543
  auto storage = std::make_shared<IndexedScopeTrailStorage<T>>(std::move(intern));
476
544
  int level = storage->openLevel(0);
477
- return std::make_shared<IndexedTrailView<T>>(storage, level);
545
+ return std::allocate_shared<IndexedTrailView<T>>(
546
+ ViewBlockAllocator<IndexedTrailView<T>>(), storage, level);
478
547
  }
479
548
 
480
549
  std::shared_ptr<IndexedTrailView<T>> openChild(bool isolate) const {
481
550
  int level = storage_->openLevel(isolate ? 0 : level_);
482
- return std::make_shared<IndexedTrailView<T>>(storage_, level);
551
+ return std::allocate_shared<IndexedTrailView<T>>(
552
+ ViewBlockAllocator<IndexedTrailView<T>>(), storage_, level);
483
553
  }
484
554
 
485
555
  IndexedTrailView(std::shared_ptr<IndexedScopeTrailStorage<T>> storage, int level)
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.6.0"
7
+ version = "1.7.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1007,12 +1007,7 @@ namespace {
1007
1007
  // `if (name == "...")` string-compare chain; the switch below then
1008
1008
  // compiles to a jump table instead of sequential comparisons. No branch's
1009
1009
  // logic changed, only how it's reached.
1010
- enum class BuiltinFnId {
1011
- TextMetrics, FontMetrics, Abs, Sign, Ceil, Floor, Round, Sqrt, Ln, Log, Exp, Sin, Cos, Tan,
1012
- Asin, Acos, Atan, Atan2, Max, Min, Pow, Norm, Cross, Rands, Concat, Len, Str, Chr, Ord,
1013
- IsUndef, IsNum, IsBool, IsString, IsList, IsFunction, IsObject, Search, Lookup, HasKey,
1014
- Version, VersionNum, ParentModule, DxfDim, DxfCross, SupportedFeature, LinearSolve,
1015
- };
1010
+ // BuiltinFnId itself now lives in function_builtins.hpp -- see builtinFnIdFor.
1016
1011
 
1017
1012
  // supported_feature("name") -> the level at which this build implements that
1018
1013
  // feature, or 0 for one it does not implement (and for a name it has never
@@ -1242,18 +1237,26 @@ bool checkBuiltinArgs(Evaluator& ev, const std::string& name, BuiltinFnId id, co
1242
1237
 
1243
1238
  } // namespace
1244
1239
 
1240
+ BuiltinFnId builtinFnIdFor(const std::string& name) {
1241
+ const auto& ids = builtinFnIds();
1242
+ const auto it = ids.find(name);
1243
+ return it == ids.end() ? BuiltinFnId::None : it->second;
1244
+ }
1245
+
1245
1246
  Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs& args, const oscad::ASTNode& node) {
1247
+ return evalBuiltinFunctionResolved(ev, builtinFnIdFor(name), builtinParamNames(name), name, args, node);
1248
+ }
1246
1249
 
1247
- const auto& ids = builtinFnIds();
1248
- const auto idIt = ids.find(name);
1250
+ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vector<std::string>* declaredParams,
1251
+ const std::string& name, const CallArgs& args, const oscad::ASTNode& node) {
1249
1252
  // Not one of the names this function handles (e.g. "object", routed
1250
1253
  // elsewhere before reaching here) -- mirrors the old chain's fallthrough.
1251
- if (idIt == ids.end()) return Value{};
1254
+ if (id == BuiltinFnId::None) return Value{};
1252
1255
 
1253
1256
  // Only textmetrics/fontmetrics have an entry -- every other builtin
1254
1257
  // function reads its arguments positionally upstream and warns about
1255
1258
  // nothing. See builtinParamNames (registry.cpp).
1256
- if (const std::vector<std::string>* declared = builtinParamNames(name)) {
1259
+ if (const std::vector<std::string>* declared = declaredParams) {
1257
1260
  for (const auto& [argName, _] : args.named) {
1258
1261
  if (!isConfigVariable(argName) &&
1259
1262
  std::find(declared->begin(), declared->end(), argName) == declared->end()) {
@@ -1265,9 +1268,10 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
1265
1268
  // Arity and argument types, with the reference's own two diagnostics.
1266
1269
  // This replaced a silent version of the same gate (scalarNumericArity /
1267
1270
  // numericOnlyNames), which returned undef without ever saying why.
1268
- if (!checkBuiltinArgs(ev, name, idIt->second, args, &node.position())) return Value{};
1271
+ if (!checkBuiltinArgs(ev, name, id, args, &node.position())) return Value{};
1269
1272
 
1270
- switch (idIt->second) {
1273
+ switch (id) {
1274
+ case BuiltinFnId::None: return Value{}; // unreachable: handled above
1271
1275
  case BuiltinFnId::TextMetrics: return builtinTextmetrics(ev, args);
1272
1276
  case BuiltinFnId::FontMetrics: return builtinFontmetrics(ev, args);
1273
1277
  case BuiltinFnId::Abs: return Value{std::fabs(toDoubleLenient(getArg(args, 0, "x", Value{})))};
@@ -20,6 +20,46 @@
20
20
  namespace oscadeval {
21
21
 
22
22
  namespace {
23
+ // Replays buildBoundArgs' own positional/named matching rule (bytecode_vm.cpp)
24
+ // against a parameter list known at compile time, recording the answer per
25
+ // argument instead of recomputing it per call. The rule, unchanged: a named
26
+ // argument binds the parameter of that name, warning when there is none and
27
+ // the name is not a $-config variable; a positional argument binds the
28
+ // parameter at its own positional index, warning once when it runs past the
29
+ // end; an undeclared $-name still reaches ctx.dyn; anything else is dropped.
30
+ // A later argument writing the same parameter still wins, because both bind
31
+ // the same slot in order.
32
+ void planCallSiteArgs(CompiledChunk::CallSite& site,
33
+ const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params) {
34
+ const size_t nparams = params.size();
35
+ size_t positionalIdx = 0;
36
+ site.argBinds.resize(site.argNames.size());
37
+ for (size_t i = 0; i < site.argNames.size(); ++i) {
38
+ CompiledChunk::CallSite::ArgBind& b = site.argBinds[i];
39
+ if (site.argNames[i]) {
40
+ const std::string& name = *site.argNames[i];
41
+ int found = -1;
42
+ for (size_t p = 0; p < nparams; ++p) {
43
+ if (params[p]->name->name == name) {
44
+ found = static_cast<int>(p);
45
+ break;
46
+ }
47
+ }
48
+ b.paramIndex = found;
49
+ b.warnUnexpectedNamed = (found < 0) && !isConfigVariable(name);
50
+ b.toDyn = (found < 0) && !name.empty() && name[0] == '$';
51
+ } else {
52
+ if (positionalIdx < nparams) {
53
+ b.paramIndex = static_cast<int>(positionalIdx);
54
+ } else if (positionalIdx == nparams) {
55
+ b.warnTooManyPositional = true;
56
+ }
57
+ ++positionalIdx;
58
+ }
59
+ }
60
+ site.hasArgPlan = true;
61
+ }
62
+
23
63
 
24
64
  // Thrown by compileExpr wherever it hits a construct this phase doesn't
25
65
  // compile yet -- tryCompileFunction catches it and returns nullopt (falls
@@ -601,6 +641,11 @@ public:
601
641
  // call-site interleaved order, not resolveArgs'
602
642
  // split positional/named CallArgs shape).
603
643
  site.isBuiltin = true;
644
+ // Resolve the callee here rather than per call; see
645
+ // CallSite's own doc comment (bytecode.hpp).
646
+ site.builtinId = builtinFnIdFor(calleeName);
647
+ site.declaredParams = builtinParamNames(calleeName);
648
+ site.isObjectBuiltin = (calleeName == "object");
604
649
  isStatic = true;
605
650
  }
606
651
  // Anything else stays dynamic: a function-literal value,
@@ -674,6 +719,9 @@ public:
674
719
  }
675
720
  }
676
721
  }
722
+ // Resolve every argument to its parameter now; see
723
+ // CallSite::argBinds (bytecode.hpp) for why.
724
+ if (site.decl) planCallSiteArgs(site, site.decl->parameters);
677
725
  int siteIdx = static_cast<int>(chunk_.callSites.size());
678
726
  chunk_.callSites.push_back(std::move(site));
679
727
  // Builtins and import() never trampoline (matching