openscad-cpp-evaluator 1.6.1__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.1 → openscad_cpp_evaluator-1.7.0}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode.hpp +35 -0
  3. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/function_builtins.hpp +27 -0
  4. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/pyproject.toml +1 -1
  5. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/function_builtins.cpp +16 -12
  6. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/bytecode_compiler.cpp +48 -0
  7. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/bytecode_vm.cpp +123 -22
  8. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/mesh_check.cpp +92 -19
  9. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_bytecode_compiler.cpp +65 -0
  10. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_mesh_check.cpp +13 -0
  11. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/.github/workflows/ci.yml +0 -0
  12. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/.github/workflows/wheels.yml +0 -0
  13. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/.gitignore +0 -0
  14. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/.gitmodules +0 -0
  15. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/CLAUDE.md +0 -0
  16. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/CMakeLists.txt +0 -0
  17. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/LICENSE +0 -0
  18. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/README.md +0 -0
  19. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/bindings/CMakeLists.txt +0 -0
  20. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/bindings/ast_to_py.cpp +0 -0
  21. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/bindings/module.cpp +0 -0
  22. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/cmake/embed_font.cmake +0 -0
  23. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/examples/CMakeLists.txt +0 -0
  24. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/examples/eval_perf_benchmark.cpp +0 -0
  25. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/examples/manifold_cache_reuse.cpp +0 -0
  26. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/examples/minimal_debugger.cpp +0 -0
  27. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  28. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/.gitignore +0 -0
  29. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  30. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  31. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/README.md +0 -0
  32. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  33. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  34. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  35. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  36. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  37. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  38. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  39. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  40. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  41. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  42. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  43. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  44. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  45. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  46. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  47. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  48. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  49. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  50. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  51. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  52. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  53. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  54. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  55. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  56. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  57. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  58. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  59. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  60. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  61. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  62. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  63. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  64. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  65. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  66. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  67. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  68. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  69. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  70. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  71. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  72. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  73. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  74. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  75. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  76. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  77. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  78. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  79. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  80. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  81. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  82. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  83. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  84. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  85. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  86. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  87. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  88. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  89. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  90. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  91. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  92. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  93. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  94. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  95. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  96. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  97. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  98. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  99. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  100. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  101. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  102. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  103. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  104. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  105. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  106. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  107. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  108. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  109. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  110. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  111. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  112. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  113. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  114. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  115. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  116. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  117. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  118. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  119. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  120. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  121. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  122. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  123. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  124. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  125. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  126. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  127. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  128. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  129. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/resources/fonts/LICENSE +0 -0
  130. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  131. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/CMakeLists.txt +0 -0
  132. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/booleans.cpp +0 -0
  133. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/builtins.hpp +0 -0
  134. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/call_args.cpp +0 -0
  135. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/color.cpp +0 -0
  136. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/control.cpp +0 -0
  137. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/dxf_dim.cpp +0 -0
  138. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/extrude.cpp +0 -0
  139. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/import.cpp +0 -0
  140. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/modifiers.cpp +0 -0
  141. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/primitives_2d.cpp +0 -0
  142. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/primitives_3d.cpp +0 -0
  143. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/registry.cpp +0 -0
  144. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/roof.cpp +0 -0
  145. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/segments.cpp +0 -0
  146. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/surface.cpp +0 -0
  147. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/text.cpp +0 -0
  148. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/topology.cpp +0 -0
  149. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/builtins/transforms.cpp +0 -0
  150. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/colored_body.cpp +0 -0
  151. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/csg_generate.cpp +0 -0
  152. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/csg_resolve.cpp +0 -0
  153. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/css_colors.cpp +0 -0
  154. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/debug/debug_repl.cpp +0 -0
  155. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/debug_profile.cpp +0 -0
  156. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/eval_context.cpp +0 -0
  157. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/eval_error.cpp +0 -0
  158. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/eval_use.cpp +0 -0
  159. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/export.cpp +0 -0
  160. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/expr_eval.cpp +0 -0
  161. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/format_closure.cpp +0 -0
  162. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/import/dxf_import.cpp +0 -0
  163. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/import/mesh_import.cpp +0 -0
  164. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/import/surface_load.cpp +0 -0
  165. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/import/svg_import.cpp +0 -0
  166. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/manifold_cache.cpp +0 -0
  167. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/measure_geometry.cpp +0 -0
  168. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/stmt_eval.cpp +0 -0
  169. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/text/font_match.cpp +0 -0
  170. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/text/freetype_font_provider.cpp +0 -0
  171. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/text/text_metrics.cpp +0 -0
  172. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/user_calls.cpp +0 -0
  173. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/utf8.cpp +0 -0
  174. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/value.cpp +0 -0
  175. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/src/zip_stored.cpp +0 -0
  176. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/CMakeLists.txt +0 -0
  177. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_booleans.cpp +0 -0
  178. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_children_separate.cpp +0 -0
  179. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_cli.cpp +0 -0
  180. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_control_flow.cpp +0 -0
  181. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_csg_tree.cpp +0 -0
  182. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_debug_hooks.cpp +0 -0
  183. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_dxf_svg_import.cpp +0 -0
  184. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_eval_context.cpp +0 -0
  185. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_export.cpp +0 -0
  186. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_expr_eval.cpp +0 -0
  187. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_extrude_roof.cpp +0 -0
  188. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_feature_detection.cpp +0 -0
  189. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_function_builtins.cpp +0 -0
  190. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_helpers.hpp +0 -0
  191. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_import_export.cpp +0 -0
  192. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_include_cache.cpp +0 -0
  193. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_manifold_cache.cpp +0 -0
  194. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_multi_color_merge.cpp +0 -0
  195. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_primitives.cpp +0 -0
  196. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_profiling.cpp +0 -0
  197. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_python_bindings.py +0 -0
  198. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_render_expr.cpp +0 -0
  199. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_scope_trail.cpp +0 -0
  200. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_scoping.cpp +0 -0
  201. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_surface.cpp +0 -0
  202. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_tail_calls.cpp +0 -0
  203. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_text.cpp +0 -0
  204. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_transforms.cpp +0 -0
  205. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_unexpected_args.cpp +0 -0
  206. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_use.cpp +0 -0
  207. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_value.cpp +0 -0
  208. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_viewport_params.cpp +0 -0
  209. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tests/test_zip_stored.cpp +0 -0
  210. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tools/cli/CMakeLists.txt +0 -0
  211. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tools/cli/cli_lib.cpp +0 -0
  212. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tools/cli/cli_lib.hpp +0 -0
  213. {openscad_cpp_evaluator-1.6.1 → openscad_cpp_evaluator-1.7.0}/tools/cli/main.cpp +0 -0
  214. {openscad_cpp_evaluator-1.6.1 → 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.1
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 --
@@ -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.1"
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
@@ -49,8 +49,12 @@ CallArgs& buildCallArgs(const CompiledChunk::CallSite& site, Value* args, size_t
49
49
  // LIST is `paramNames` (in declared order -- a FunctionDeclaration's
50
50
  // parameters or a FunctionLiteral's). Shared by CallFn/CallFnTail (a
51
51
  // site.decl callee) and CallDynamic/CallDynamicTail (a closure callee).
52
+ // `emitWarnings=false` is for the one caller that has already emitted them
53
+ // through warnPlannedArgs and only needs the binding -- see Op::CallFnTail's
54
+ // no-hop fallback.
52
55
  BoundArgs buildBoundArgs(Evaluator& ev, const CompiledChunk::CallSite& site, Value* args, size_t argCount,
53
- const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& paramNames) {
56
+ const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& paramNames,
57
+ bool emitWarnings = true) {
54
58
  BoundArgs bound;
55
59
  bound.reserve(argCount);
56
60
  size_t positionalIdx = 0;
@@ -59,14 +63,14 @@ BoundArgs buildBoundArgs(Evaluator& ev, const CompiledChunk::CallSite& site, Val
59
63
  for (size_t i = 0; i < argCount; ++i) {
60
64
  if (site.argNames[i]) {
61
65
  const std::string& name = *site.argNames[i];
62
- if (!isConfigVariable(name) && !declaresParam(paramNames, name)) {
66
+ if (emitWarnings && !isConfigVariable(name) && !declaresParam(paramNames, name)) {
63
67
  warnUnexpectedNamedArg(ev, name, pos);
64
68
  }
65
69
  bound.set(name, std::move(args[i]));
66
70
  } else {
67
71
  if (positionalIdx < nparams) {
68
72
  bound.set(paramNames[positionalIdx]->name->name, std::move(args[i]));
69
- } else if (positionalIdx == nparams) {
73
+ } else if (emitWarnings && positionalIdx == nparams) {
70
74
  warnTooManyPositionalArgs(ev, pos);
71
75
  }
72
76
  ++positionalIdx;
@@ -108,6 +112,60 @@ void bindBoundArgsIntoFrame(const CompiledChunk& chunk, const BoundArgs& bound,
108
112
  }
109
113
  }
110
114
 
115
+ // Where a pushed frame's arguments come from: a call site's compile-time plan
116
+ // over the caller's own live operand stack (the hot path), or an
117
+ // already-name-matched BoundArgs (closures and dynamic callees, which have no
118
+ // compile-time parameter list to plan against).
119
+ struct FrameArgs {
120
+ const CompiledChunk::CallSite* site = nullptr;
121
+ Value* args = nullptr;
122
+ size_t argCount = 0;
123
+ const BoundArgs* bound = nullptr;
124
+ };
125
+
126
+ // The compile-time counterpart of bindBoundArgsIntoFrame: binds a call's
127
+ // arguments straight from the caller's operand stack into the callee frame,
128
+ // using the plan its call site worked out once (CallSite::argBinds). No name
129
+ // is compared and no BoundArgs is built, and each argument is MOVED into its
130
+ // slot rather than moved into a BoundArgs and copied back out. `args` must
131
+ // still be live -- the caller truncates its stack only after this returns.
132
+ // The argument diagnostics of a planned call, split out of the binder below
133
+ // because WHEN they fire is observable: their "TRACE: called by ..." line
134
+ // names whatever is on top of the call stack, and a tail hop has already
135
+ // replaced that with the CALLEE by the time it binds. buildBoundArgs warned
136
+ // before any of that happened, so this must too -- caught by
137
+ // UnexpectedArgs.NestedUserFunctionCallStillWarns, which compares the VM
138
+ // against the interpreter.
139
+ void warnPlannedArgs(Evaluator& ev, const CompiledChunk::CallSite& site, size_t argCount) {
140
+ const oscad::Position* pos = site.callNode ? &site.callNode->position() : nullptr;
141
+ for (size_t i = 0; i < argCount; ++i) {
142
+ const CompiledChunk::CallSite::ArgBind& b = site.argBinds[i];
143
+ if (b.warnUnexpectedNamed) warnUnexpectedNamedArg(ev, *site.argNames[i], pos);
144
+ if (b.warnTooManyPositional) warnTooManyPositionalArgs(ev, pos);
145
+ }
146
+ }
147
+
148
+ void bindPlannedArgsIntoFrame(const CompiledChunk& chunk, const CompiledChunk::CallSite& site, Value* args,
149
+ size_t argCount, VmFrame& frame) {
150
+ EvalContext& ctx = frame.ctxChain.back();
151
+ for (size_t i = 0; i < argCount; ++i) {
152
+ const CompiledChunk::CallSite::ArgBind& b = site.argBinds[i];
153
+ if (b.paramIndex >= 0) {
154
+ const CompiledChunk::Param& p = chunk.params[static_cast<size_t>(b.paramIndex)];
155
+ if (p.isDyn) {
156
+ ctx.dyn->set(p.name, std::move(args[i]));
157
+ } else {
158
+ frame.slots[static_cast<size_t>(p.slot)] = std::move(args[i]);
159
+ }
160
+ frame.bound[static_cast<size_t>(b.paramIndex)] = true;
161
+ } else if (b.toDyn) {
162
+ ctx.dyn->set(*site.argNames[i], std::move(args[i]));
163
+ }
164
+ // else: an undeclared plain name, or a positional past the end --
165
+ // dropped, exactly as the name-matching path drops it.
166
+ }
167
+ }
168
+
111
169
  // Same, but for a call site whose arguments are still raw AST (evaluated
112
170
  // here against `callerCtx`) -- only ever used by runCompiledFunction's own
113
171
  // entry point (a top-level call with raw AST arguments, mirroring
@@ -249,7 +307,7 @@ void pushBareFrame(Evaluator& ev, const CompiledChunk& chunk, const std::vector<
249
307
  // own parameters exactly (a FunctionDeclaration's decl/*decl.expr, or a
250
308
  // FunctionLiteral's funcNode/*funcNode.body).
251
309
  void pushBracketedCallFrame(Evaluator& ev, const CompiledChunk& chunk, const oscad::ASTNode& declNode,
252
- const oscad::Expression& bodyExpr, const std::string& name, BoundArgs bound,
310
+ const oscad::Expression& bodyExpr, const std::string& name, const FrameArgs& fargs,
253
311
  EvalContext& callerCtx, const oscad::Scope* fnScope,
254
312
  const std::shared_ptr<TrailView<Value>>& capturedLet, const oscad::Position* callPos) {
255
313
  if (ev.vmCallStack_.size() >= Evaluator::kMaxVmCallStackDepth) {
@@ -274,7 +332,11 @@ void pushBracketedCallFrame(Evaluator& ev, const CompiledChunk& chunk, const osc
274
332
  frame->tailHopGuard = 0;
275
333
  frame->logicalName = name;
276
334
  frame->hopEligible = true; // just pushed a fresh, correctly-named callStack_ entry
277
- bindBoundArgsIntoFrame(chunk, bound, *frame);
335
+ if (fargs.site) {
336
+ bindPlannedArgsIntoFrame(chunk, *fargs.site, fargs.args, fargs.argCount, *frame);
337
+ } else {
338
+ bindBoundArgsIntoFrame(chunk, *fargs.bound, *frame);
339
+ }
278
340
  applyCompiledDefaultsToFrame(ev, chunk, *frame);
279
341
 
280
342
  // enterUserCall's own bodyCtx must point at frame->ctxChain's OWN
@@ -802,7 +864,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
802
864
  f.stack.resize(argBase);
803
865
  f.stack.push_back(importAsValue(ev, callArgs, *site.callNode));
804
866
  ++f.pc;
805
- } else if (site.isBuiltin && site.calleeName == "object") {
867
+ } else if (site.isObjectBuiltin) {
806
868
  std::vector<std::pair<std::optional<std::string>, Value>> pairs;
807
869
  pairs.reserve(argCount);
808
870
  for (size_t i = 0; i < argCount; ++i) pairs.emplace_back(site.argNames[i], std::move(args[i]));
@@ -812,24 +874,39 @@ Value driveVm(Evaluator& ev, size_t floor) {
812
874
  } else if (site.isBuiltin) {
813
875
  CallArgs& callArgs = buildCallArgs(site, args, argCount, f.argScratch);
814
876
  f.stack.resize(argBase);
815
- f.stack.push_back(evalBuiltinFunction(ev, site.calleeName, callArgs, *site.callNode));
877
+ f.stack.push_back(evalBuiltinFunctionResolved(ev, site.builtinId, site.declaredParams,
878
+ site.calleeName, callArgs, *site.callNode));
816
879
  ++f.pc;
817
880
  } else {
818
- BoundArgs bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
819
- f.stack.resize(argBase);
820
881
  const CompiledChunk* calleeChunk = ev.useBytecodeVm() ? ev.lookupOrCompileChunk(*site.decl) : nullptr;
821
- if (calleeChunk) {
882
+ if (calleeChunk && site.hasArgPlan) {
883
+ warnPlannedArgs(ev, site, argCount);
884
+ // The hot path: bind straight off this frame's own
885
+ // stack using the site's compile-time plan, then
886
+ // truncate. Truncating FIRST would destroy the very
887
+ // values being bound.
822
888
  const oscad::Scope* fnScope = ctx.scopeOf(*site.decl) ? ctx.scopeOf(*site.decl) : ctx.scope;
823
889
  pushBracketedCallFrame(ev, *calleeChunk, *site.decl, *site.decl->expr, site.calleeName,
824
- std::move(bound), ctx, fnScope, nullptr, &site.callNode->position());
890
+ FrameArgs{&site, args, argCount, nullptr}, ctx, fnScope, nullptr,
891
+ &site.callNode->position());
892
+ f.stack.resize(argBase);
825
893
  // f.pc deliberately NOT advanced -- resumes when the
826
894
  // pushed frame completes (see driveVm's own
827
895
  // completion branch, above).
828
896
  } else {
829
- Value result = ev.evalUserFunctionFromBound(site.calleeName, *site.decl, std::move(bound), ctx,
830
- &site.callNode->position());
831
- f.stack.push_back(std::move(result));
832
- ++f.pc;
897
+ BoundArgs bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
898
+ f.stack.resize(argBase);
899
+ if (calleeChunk) {
900
+ const oscad::Scope* fnScope = ctx.scopeOf(*site.decl) ? ctx.scopeOf(*site.decl) : ctx.scope;
901
+ pushBracketedCallFrame(ev, *calleeChunk, *site.decl, *site.decl->expr, site.calleeName,
902
+ FrameArgs{nullptr, nullptr, 0, &bound}, ctx, fnScope, nullptr,
903
+ &site.callNode->position());
904
+ } else {
905
+ Value result = ev.evalUserFunctionFromBound(site.calleeName, *site.decl, std::move(bound),
906
+ ctx, &site.callNode->position());
907
+ f.stack.push_back(std::move(result));
908
+ ++f.pc;
909
+ }
833
910
  }
834
911
  }
835
912
  break;
@@ -849,7 +926,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
849
926
  if (calleeChunk) {
850
927
  const oscad::Scope* fnScope = ctx.scopeOf(funcNode) ? ctx.scopeOf(funcNode) : ctx.scope;
851
928
  pushBracketedCallFrame(ev, *calleeChunk, funcNode, *funcNode.body, "<function literal>",
852
- std::move(bound), ctx, fnScope, capturedLetTrail(closure), ins.pos);
929
+ FrameArgs{nullptr, nullptr, 0, &bound}, ctx, fnScope, capturedLetTrail(closure), ins.pos);
853
930
  } else {
854
931
  Value result = ev.evalFunctionLiteralFromBound(closure, std::move(bound), ctx, ins.pos);
855
932
  f.stack.push_back(std::move(result));
@@ -868,8 +945,17 @@ Value driveVm(Evaluator& ev, size_t floor) {
868
945
  const size_t argCount = static_cast<size_t>(ins.b);
869
946
  const size_t argBase = f.stack.size() - argCount;
870
947
  Value* args = f.stack.data() + argBase; // into f.stack; truncated below once consumed
871
- BoundArgs bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
872
- f.stack.resize(argBase);
948
+ // A planned site defers both of these: the arguments have
949
+ // to stay live on this frame's own stack until they are
950
+ // bound, and a tail HOP binds into this very frame.
951
+ const bool planned = site.hasArgPlan;
952
+ BoundArgs bound;
953
+ if (planned) {
954
+ warnPlannedArgs(ev, site, argCount); // before recordTailCallHop; see warnPlannedArgs
955
+ } else {
956
+ bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
957
+ f.stack.resize(argBase);
958
+ }
873
959
  // Tail-hop-in-place requires f.hopEligible -- a frame
874
960
  // that's call-boundary-free (statement expression,
875
961
  // assignment block, parameter default) has no
@@ -898,22 +984,37 @@ Value driveVm(Evaluator& ev, size_t floor) {
898
984
  f.setCode(calleeChunk->bodyCode);
899
985
  f.pc = 0;
900
986
  f.slots.assign(static_cast<size_t>(calleeChunk->numSlots), Value{});
901
- f.stack.clear();
902
987
  f.bound.assign(calleeChunk->params.size(), false);
903
988
  f.accumStack.clear();
904
989
  f.iterLists.assign(static_cast<size_t>(calleeChunk->numIterLists), IterList{});
905
990
  f.ctxChain.push_back(std::move(*hopCtx));
906
- bindBoundArgsIntoFrame(*calleeChunk, bound, f);
991
+ // The stack is cleared AFTER binding on the planned
992
+ // path: a hop rebinds this same frame, and `args`
993
+ // still points into the stack it would have wiped.
994
+ if (planned) {
995
+ bindPlannedArgsIntoFrame(*calleeChunk, site, args, argCount, f);
996
+ f.stack.clear();
997
+ } else {
998
+ f.stack.clear();
999
+ bindBoundArgsIntoFrame(*calleeChunk, bound, f);
1000
+ }
907
1001
  applyCompiledDefaultsToFrame(ev, *calleeChunk, f);
908
1002
  // continue via the outer while -- re-fetches this
909
1003
  // same (now-mutated) frame from its new pc=0.
910
1004
  } else {
1005
+ if (planned) { // no hop after all -- fall back to name matching
1006
+ // warnPlannedArgs already emitted these above.
1007
+ bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters,
1008
+ /*emitWarnings=*/false);
1009
+ f.stack.resize(argBase);
1010
+ }
911
1011
  const CompiledChunk* fallbackChunk =
912
1012
  ev.useBytecodeVm() ? ev.lookupOrCompileChunk(*site.decl) : nullptr;
913
1013
  if (fallbackChunk) {
914
1014
  const oscad::Scope* fnScope = ctx.scopeOf(*site.decl) ? ctx.scopeOf(*site.decl) : ctx.scope;
915
1015
  pushBracketedCallFrame(ev, *fallbackChunk, *site.decl, *site.decl->expr, site.calleeName,
916
- std::move(bound), ctx, fnScope, nullptr, &site.callNode->position());
1016
+ FrameArgs{nullptr, nullptr, 0, &bound}, ctx, fnScope, nullptr,
1017
+ &site.callNode->position());
917
1018
  } else {
918
1019
  Value result = ev.evalUserFunctionFromBound(site.calleeName, *site.decl, std::move(bound), ctx,
919
1020
  &site.callNode->position());
@@ -960,7 +1061,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
960
1061
  if (fallbackChunk) {
961
1062
  const oscad::Scope* fnScope = ctx.scopeOf(funcNode) ? ctx.scopeOf(funcNode) : ctx.scope;
962
1063
  pushBracketedCallFrame(ev, *fallbackChunk, funcNode, *funcNode.body, "<function literal>",
963
- std::move(bound), ctx, fnScope, capturedLetTrail(closure), ins.pos);
1064
+ FrameArgs{nullptr, nullptr, 0, &bound}, ctx, fnScope, capturedLetTrail(closure), ins.pos);
964
1065
  } else {
965
1066
  Value result = ev.evalFunctionLiteralFromBound(closure, std::move(bound), ctx, ins.pos);
966
1067
  f.stack.push_back(std::move(result));