openscad-cpp-evaluator 0.29.2__tar.gz → 0.30.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 (201) hide show
  1. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/CLAUDE.md +23 -1
  2. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/PKG-INFO +1 -1
  3. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/dispatch.hpp +19 -0
  4. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/eval_error.hpp +35 -0
  5. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/function_builtins.cpp +13 -0
  7. openscad_cpp_evaluator-0.30.0/src/builtins/registry.cpp +142 -0
  8. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/bytecode_vm.cpp +20 -6
  9. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/csg_resolve.cpp +1 -0
  10. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/eval_error.cpp +37 -0
  11. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/user_calls.cpp +8 -1
  12. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/CMakeLists.txt +1 -0
  13. openscad_cpp_evaluator-0.30.0/tests/test_unexpected_args.cpp +151 -0
  14. openscad_cpp_evaluator-0.29.2/src/builtins/registry.cpp +0 -81
  15. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/.github/workflows/ci.yml +0 -0
  16. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/.github/workflows/wheels.yml +0 -0
  17. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/.gitignore +0 -0
  18. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/.gitmodules +0 -0
  19. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/CMakeLists.txt +0 -0
  20. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/LICENSE +0 -0
  21. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/README.md +0 -0
  22. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/bindings/CMakeLists.txt +0 -0
  23. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/bindings/ast_to_py.cpp +0 -0
  24. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/bindings/module.cpp +0 -0
  25. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/cmake/embed_font.cmake +0 -0
  26. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/examples/CMakeLists.txt +0 -0
  27. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/examples/eval_perf_benchmark.cpp +0 -0
  28. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/examples/manifold_cache_reuse.cpp +0 -0
  29. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/examples/minimal_debugger.cpp +0 -0
  30. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  31. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/.gitignore +0 -0
  32. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  33. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  34. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/README.md +0 -0
  35. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  36. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  37. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  38. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  39. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  40. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  41. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  42. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  43. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  44. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  45. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  46. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  47. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  48. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  49. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  50. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  51. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  52. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  53. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  54. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  55. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  56. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  57. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  58. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  59. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  60. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  61. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  62. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  63. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  64. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  65. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  66. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  67. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  68. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  69. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  70. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  71. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  72. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  73. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  74. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  75. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  76. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  77. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  78. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  79. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  80. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  81. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  82. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  83. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  84. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  85. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  86. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  87. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  88. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  89. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  90. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  91. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  92. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  93. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  94. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  95. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  96. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  97. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  98. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  99. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  100. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  101. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  102. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  103. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  104. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  105. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  106. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  107. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  108. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  109. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  110. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  111. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  112. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  113. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  114. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  115. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  116. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  117. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  118. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  119. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  120. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  121. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
  122. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  123. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  124. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  125. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  126. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  127. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/resources/fonts/LICENSE +0 -0
  128. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  129. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/CMakeLists.txt +0 -0
  130. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/booleans.cpp +0 -0
  131. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/builtins.hpp +0 -0
  132. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/call_args.cpp +0 -0
  133. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/color.cpp +0 -0
  134. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/control.cpp +0 -0
  135. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/extrude.cpp +0 -0
  136. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/import.cpp +0 -0
  137. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/modifiers.cpp +0 -0
  138. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/primitives_2d.cpp +0 -0
  139. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/primitives_3d.cpp +0 -0
  140. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/roof.cpp +0 -0
  141. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/segments.cpp +0 -0
  142. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/surface.cpp +0 -0
  143. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/text.cpp +0 -0
  144. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/topology.cpp +0 -0
  145. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/builtins/transforms.cpp +0 -0
  146. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/bytecode_compiler.cpp +0 -0
  147. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/colored_body.cpp +0 -0
  148. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/csg_generate.cpp +0 -0
  149. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/css_colors.cpp +0 -0
  150. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/debug/debug_repl.cpp +0 -0
  151. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/debug_profile.cpp +0 -0
  152. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/eval_context.cpp +0 -0
  153. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/eval_use.cpp +0 -0
  154. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/export.cpp +0 -0
  155. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/expr_eval.cpp +0 -0
  156. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/import/dxf_import.cpp +0 -0
  157. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/import/mesh_import.cpp +0 -0
  158. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/import/surface_load.cpp +0 -0
  159. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/import/svg_import.cpp +0 -0
  160. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/manifold_cache.cpp +0 -0
  161. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/mesh_check.cpp +0 -0
  162. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/stmt_eval.cpp +0 -0
  163. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/text/stb_font_provider.cpp +0 -0
  164. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/text/text_metrics.cpp +0 -0
  165. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/value.cpp +0 -0
  166. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/src/zip_stored.cpp +0 -0
  167. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_booleans.cpp +0 -0
  168. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_bytecode_compiler.cpp +0 -0
  169. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_cli.cpp +0 -0
  170. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_control_flow.cpp +0 -0
  171. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_csg_tree.cpp +0 -0
  172. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_debug_hooks.cpp +0 -0
  173. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_dxf_svg_import.cpp +0 -0
  174. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_eval_context.cpp +0 -0
  175. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_export.cpp +0 -0
  176. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_expr_eval.cpp +0 -0
  177. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_extrude_roof.cpp +0 -0
  178. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_function_builtins.cpp +0 -0
  179. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_helpers.hpp +0 -0
  180. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_import_export.cpp +0 -0
  181. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_manifold_cache.cpp +0 -0
  182. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_mesh_check.cpp +0 -0
  183. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_multi_color_merge.cpp +0 -0
  184. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_primitives.cpp +0 -0
  185. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_profiling.cpp +0 -0
  186. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_python_bindings.py +0 -0
  187. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_scope_trail.cpp +0 -0
  188. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_scoping.cpp +0 -0
  189. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_surface.cpp +0 -0
  190. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_tail_calls.cpp +0 -0
  191. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_text.cpp +0 -0
  192. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_transforms.cpp +0 -0
  193. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_use.cpp +0 -0
  194. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_value.cpp +0 -0
  195. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_viewport_params.cpp +0 -0
  196. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tests/test_zip_stored.cpp +0 -0
  197. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tools/cli/CMakeLists.txt +0 -0
  198. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tools/cli/cli_lib.cpp +0 -0
  199. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tools/cli/cli_lib.hpp +0 -0
  200. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/tools/cli/main.cpp +0 -0
  201. {openscad_cpp_evaluator-0.29.2 → openscad_cpp_evaluator-0.30.0}/uv.lock +0 -0
@@ -424,7 +424,29 @@ grep for `ponytail:`.
424
424
  give sibling statements in the same block correct assignment visibility (see the header comment
425
425
  before reworking this; it's not an arbitrary choice).
426
426
  - `include/openscad_cpp_evaluator/eval_error.hpp`, `src/eval_error.cpp` — `EvalError` and the
427
- exact ERROR/TRACE string formatting real OpenSCAD produces.
427
+ exact ERROR/TRACE string formatting real OpenSCAD produces. Also the **unexpected-argument
428
+ warnings** (`warnUnexpectedNamedArg`/`warnTooManyPositionalArgs`/`warnUnexpectedArgs`), the port
429
+ of real OpenSCAD's `Parameters.cc` `parse_without_defaults`: `variable X not specified as
430
+ parameter` for a named argument the callee doesn't declare, and `Too many unnamed arguments
431
+ supplied` once per call for positional arguments past the last parameter. `$`-prefixed names
432
+ other than `$children` are exempt (`isConfigVariable`, mirroring
433
+ `ContextFrame::is_config_variable` — a `$`-name is a dynamic-scope override, never a parameter).
434
+ The check has to be repeated at **every** argument-binding path, since there are five and none of
435
+ them share a choke point: `bindArgs` (interpreter, `user_calls.cpp`),
436
+ `buildBoundArgs`/`bindAstArgsIntoFrame` (bytecode VM, `bytecode_vm.cpp`), `evalModularCall`
437
+ (builtin modules, `csg_resolve.cpp`) and the VM's own `Op::PushBuiltinWrap`/`Op::PushCsgWrap`
438
+ handlers — the transform/color/hull/minkowski/render/extrude/projection/offset/roof/CSG family
439
+ bypasses `evalModularCall` entirely once compiled, which is exactly the gap
440
+ `tests/test_unexpected_args.cpp` runs every case twice (VM off and on) to catch. Builtin
441
+ parameter names live in `builtinParamNames` (`registry.cpp`): each list is the union of real
442
+ OpenSCAD's own `Parameters::parse` declaration and any extra name this port reads via `getArg`,
443
+ so the port never warns about an argument it goes on to honour — **add to it whenever a builtin
444
+ gains a parameter**, or that parameter starts warning. Builtin *functions* deliberately have no
445
+ entries beyond `textmetrics`/`fontmetrics`: upstream reads their arguments positionally without
446
+ `Parameters::parse`, so `sin(bogus=30)` warns about nothing there (verified against 2022.08.22)
447
+ and warning here would be a divergence. Not ported: the reference's `argument X supplied more
448
+ than once` / `argument X overrides positional argument`, separate conditions this port's simpler
449
+ positional-matching rule doesn't track.
428
450
  - `include/openscad_cpp_evaluator/evaluator.hpp`, `src/expr_eval.cpp`, `src/stmt_eval.cpp`,
429
451
  `src/user_calls.cpp` — the `Evaluator` class. Expression/statement dispatch is a `switch` on
430
452
  `NodeKind` (matches `openscad_cpp_parser`'s own dispatch convention, not a visitor).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.29.2
3
+ Version: 0.30.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -54,6 +54,25 @@ using GenerateFn = std::vector<ColoredBody> (*)(Evaluator&, const CSGParams&, co
54
54
  const std::unordered_map<std::string_view, ResolveFn>& resolveDispatch();
55
55
  const std::unordered_map<std::string_view, GenerateFn>& generateDispatch();
56
56
 
57
+ // Every parameter name a builtin accepts, for the unexpected-argument
58
+ // warning (see eval_error.hpp). Returns nullptr for a name with no entry,
59
+ // which suppresses the check rather than warning about everything.
60
+ //
61
+ // Each list is the UNION of real OpenSCAD's own Parameters::parse
62
+ // declaration for that builtin (2022.08.22 -- the authority on what warns
63
+ // upstream) and any extra name this port itself reads via getArg, so this
64
+ // port never warns about an argument it goes on to honour.
65
+ const std::vector<std::string>* builtinParamNames(const std::string& name);
66
+
67
+ // builtinParamNames + warnUnexpectedArgs for one builtin module call. Must
68
+ // be invoked from EVERY path a builtin call can take: evalModularCall
69
+ // (interpreter, and Op::NativeStatement) plus the bytecode VM's own
70
+ // Op::PushBuiltinWrap/Op::PushCsgWrap handlers, which bypass
71
+ // evalModularCall entirely for the transform/color/hull/extrude/CSG family.
72
+ // Silently does nothing for a node that isn't a ModularCall (a `#`/`%`/`!`
73
+ // modifier shares BuiltinWrapSite but carries no arguments).
74
+ void warnUnexpectedBuiltinArgs(Evaluator& ev, const oscad::ASTNode& callNode);
75
+
57
76
  // Concatenates every top-level node's already-generated `.bodies` (does NOT
58
77
  // recurse into `.children` -- a parent's `.bodies` is already the fully
59
78
  // combined result of its children). Mirrors the reference's
@@ -2,12 +2,15 @@
2
2
 
3
3
  #include "openscad_cpp_parser/position.hpp"
4
4
 
5
+ #include <memory>
5
6
  #include <stdexcept>
6
7
  #include <string>
7
8
  #include <vector>
8
9
 
9
10
  namespace oscad {
10
11
  class ASTNode;
12
+ class Argument;
13
+ class ParameterDeclaration;
11
14
  } // namespace oscad
12
15
 
13
16
  namespace oscadeval {
@@ -129,4 +132,36 @@ std::string formatError(const std::string& msg, const oscad::Position* nodePosit
129
132
  std::string formatWarning(const std::string& msg, const oscad::Position* nodePosition,
130
133
  const std::vector<CallStackFrame>& callStack);
131
134
 
135
+ // -- Unexpected-argument warnings -----------------------------------------
136
+ //
137
+ // Real OpenSCAD (Parameters.cc's parse_without_defaults) warns for a named
138
+ // argument the callee doesn't declare, and once per call for positional
139
+ // arguments past the last parameter. Both are silently dropped otherwise,
140
+ // which makes a typo'd argument name invisible -- the call still runs, the
141
+ // parameter just keeps its default. Wording is verbatim from the reference
142
+ // (2022.08.22, which quotes neither name nor message).
143
+ //
144
+ // NOT covered here (separate reference warnings, separate conditions):
145
+ // "argument X supplied more than once" and "argument X overrides positional
146
+ // argument".
147
+ class Evaluator;
148
+
149
+ // ContextFrame::is_config_variable: a $-prefixed name other than $children
150
+ // is a dynamic-scope override, never a declared parameter, so it is exempt.
151
+ bool isConfigVariable(const std::string& name);
152
+
153
+ // Linear scan -- ponytail: parameter lists are single-digit in practice, so
154
+ // a per-call set/map would cost more than it saves.
155
+ bool declaresParam(const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params, const std::string& name);
156
+
157
+ void warnUnexpectedNamedArg(Evaluator& ev, const std::string& name, const oscad::Position* pos);
158
+ void warnTooManyPositionalArgs(Evaluator& ev, const oscad::Position* pos);
159
+
160
+ // Both warnings at once for a callee whose parameter names are a fixed list
161
+ // rather than a declaration -- i.e. a builtin (see builtinParamNames,
162
+ // dispatch.hpp). Reports against each argument's own position, which is the
163
+ // call's own line in every case that isn't a multi-line argument list.
164
+ void warnUnexpectedArgs(Evaluator& ev, const std::vector<std::string>& params,
165
+ const std::vector<std::unique_ptr<oscad::Argument>>& arguments);
166
+
132
167
  } // namespace oscadeval
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.29.2"
7
+ version = "0.30.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1,5 +1,6 @@
1
1
  #include "openscad_cpp_evaluator/function_builtins.hpp"
2
2
 
3
+ #include "openscad_cpp_evaluator/dispatch.hpp"
3
4
  #include "openscad_cpp_evaluator/evaluator.hpp"
4
5
  #include "openscad_cpp_evaluator/segments.hpp"
5
6
  #include "openscad_cpp_evaluator/text_metrics.hpp"
@@ -509,6 +510,18 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
509
510
  // elsewhere before reaching here) -- mirrors the old chain's fallthrough.
510
511
  if (idIt == ids.end()) return Value{};
511
512
 
513
+ // Only textmetrics/fontmetrics have an entry -- every other builtin
514
+ // function reads its arguments positionally upstream and warns about
515
+ // nothing. See builtinParamNames (registry.cpp).
516
+ if (const std::vector<std::string>* declared = builtinParamNames(name)) {
517
+ for (const auto& [argName, _] : args.named) {
518
+ if (!isConfigVariable(argName) &&
519
+ std::find(declared->begin(), declared->end(), argName) == declared->end()) {
520
+ warnUnexpectedNamedArg(ev, argName, &node.position());
521
+ }
522
+ }
523
+ }
524
+
512
525
  if (const auto arityIt = scalarNumericArity().find(name); arityIt != scalarNumericArity().end()) {
513
526
  const std::vector<Value> positional = allPositional(args);
514
527
  if (positional.size() < arityIt->second) return Value{};
@@ -0,0 +1,142 @@
1
+ #include "builtins.hpp"
2
+
3
+ #include "openscad_cpp_evaluator/dispatch.hpp"
4
+ #include "openscad_cpp_evaluator/eval_error.hpp"
5
+
6
+ namespace oscadeval {
7
+
8
+ const std::unordered_map<std::string_view, ResolveFn>& resolveDispatch() {
9
+ static const std::unordered_map<std::string_view, ResolveFn> table = {
10
+ {"cube", &resolveCube},
11
+ {"sphere", &resolveSphere},
12
+ {"cylinder", &resolveCylinder},
13
+ {"polyhedron", &resolvePolyhedron},
14
+ {"circle", &resolve2d},
15
+ {"square", &resolve2d},
16
+ {"polygon", &resolve2d},
17
+ {"translate", &resolveTransform},
18
+ {"rotate", &resolveTransform},
19
+ {"scale", &resolveTransform},
20
+ {"mirror", &resolveTransform},
21
+ {"multmatrix", &resolveTransform},
22
+ {"resize", &resolveTransform},
23
+ {"color", &resolveColor},
24
+ {"union", &resolveCsg},
25
+ {"difference", &resolveCsg},
26
+ {"intersection", &resolveCsg},
27
+ {"children", &resolveChildren},
28
+ {"render", &resolveRender},
29
+ {"breakpoint", &resolveBreakpoint},
30
+ {"import", &resolveImport},
31
+ {"hull", &resolveHull},
32
+ {"minkowski", &resolveMinkowski},
33
+ {"linear_extrude", &resolveLinearExtrude},
34
+ {"rotate_extrude", &resolveRotateExtrude},
35
+ {"projection", &resolveProjection},
36
+ {"roof", &resolveRoof},
37
+ {"offset", &resolveOffset},
38
+ {"surface", &resolveSurface},
39
+ {"text", &resolveText},
40
+ };
41
+ return table;
42
+ }
43
+
44
+ const std::unordered_map<std::string_view, GenerateFn>& generateDispatch() {
45
+ static const std::unordered_map<std::string_view, GenerateFn> table = {
46
+ {"cube", &generateCube},
47
+ {"sphere", &generateSphere},
48
+ {"cylinder", &generateCylinder},
49
+ {"polyhedron", &generatePolyhedron},
50
+ {"circle", &generate2d},
51
+ {"square", &generate2d},
52
+ {"polygon", &generate2d},
53
+ {"translate", &generateTransform},
54
+ {"rotate", &generateTransform},
55
+ {"scale", &generateTransform},
56
+ {"mirror", &generateTransform},
57
+ {"multmatrix", &generateTransform},
58
+ {"resize", &generateTransform},
59
+ {"color", &generateColor},
60
+ {"union", &generateCsg},
61
+ {"difference", &generateCsg},
62
+ {"intersection", &generateCsg},
63
+ {"highlight", &generateHighlight},
64
+ {"background", &generateBackground},
65
+ {"show_only", &generateShowOnly},
66
+ {"children", &generateChildren},
67
+ {"intersection_for", &generateIntersectionFor},
68
+ {"import", &generateImport},
69
+ {"hull", &generateHull},
70
+ {"minkowski", &generateMinkowski},
71
+ {"linear_extrude", &generateLinearExtrude},
72
+ {"rotate_extrude", &generateRotateExtrude},
73
+ {"projection", &generateProjection},
74
+ {"roof", &generateRoof},
75
+ {"offset", &generateOffset},
76
+ {"surface", &generateSurface},
77
+ {"text", &generateText},
78
+ };
79
+ return table;
80
+ }
81
+
82
+ const std::vector<std::string>* builtinParamNames(const std::string& name) {
83
+ // Deliberately absent: the builtin *functions* other than the three
84
+ // below. Real OpenSCAD's builtin functions read their arguments
85
+ // positionally without going through Parameters::parse, so `sin(bogus=30)`
86
+ // warns about nothing upstream -- verified against 2022.08.22 -- and
87
+ // warning here would be a divergence, not a fix.
88
+ static const std::unordered_map<std::string, std::vector<std::string>> table = {
89
+ // -- builtin modules ---------------------------------------------
90
+ {"cube", {"size", "center"}},
91
+ {"sphere", {"r", "d"}},
92
+ {"cylinder", {"h", "r1", "r2", "center", "r", "d", "d1", "d2"}},
93
+ {"polyhedron", {"points", "faces", "convexity", "triangles"}},
94
+ {"square", {"size", "center"}},
95
+ {"circle", {"r", "d"}},
96
+ {"polygon", {"points", "paths", "convexity"}},
97
+ {"translate", {"v"}},
98
+ {"rotate", {"a", "v"}},
99
+ {"scale", {"v"}},
100
+ {"mirror", {"v"}},
101
+ {"multmatrix", {"m"}},
102
+ {"resize", {"newsize", "auto", "convexity"}},
103
+ {"color", {"c", "alpha"}},
104
+ {"union", {}},
105
+ {"difference", {}},
106
+ {"intersection", {}},
107
+ {"hull", {}},
108
+ {"minkowski", {"convexity"}},
109
+ {"children", {"index"}},
110
+ {"render", {"convexity"}},
111
+ // "repair" is this port's own addition, not an upstream parameter.
112
+ {"import",
113
+ {"file", "layer", "convexity", "origin", "scale", "width", "height", "filename", "layername", "center", "dpi",
114
+ "id", "repair"}},
115
+ {"linear_extrude", {"height", "v", "scale", "center", "twist", "slices", "segments", "convexity"}},
116
+ {"rotate_extrude", {"angle", "start", "convexity"}},
117
+ {"projection", {"cut", "convexity"}},
118
+ {"roof", {"method", "convexity"}},
119
+ {"offset", {"r", "delta", "chamfer"}},
120
+ {"surface", {"file", "center", "convexity", "invert"}},
121
+ {"text", {"text", "size", "font", "direction", "language", "script", "halign", "valign", "spacing"}},
122
+ // breakpoint() is this port's own debugger extension, no upstream
123
+ // equivalent to mirror.
124
+ {"breakpoint", {"condition"}},
125
+
126
+ // -- the three builtin FUNCTIONS that do use Parameters::parse ----
127
+ {"textmetrics", {"text", "size", "font", "direction", "language", "script", "halign", "valign", "spacing"}},
128
+ {"fontmetrics", {"size", "font"}},
129
+ };
130
+ auto it = table.find(name);
131
+ return it == table.end() ? nullptr : &it->second;
132
+ }
133
+
134
+ void warnUnexpectedBuiltinArgs(Evaluator& ev, const oscad::ASTNode& callNode) {
135
+ if (callNode.kind() != oscad::NodeKind::ModularCall) return;
136
+ const auto& call = static_cast<const oscad::ModularCall&>(callNode);
137
+ if (const std::vector<std::string>* declared = builtinParamNames(call.name->name)) {
138
+ warnUnexpectedArgs(ev, *declared, call.arguments);
139
+ }
140
+ }
141
+
142
+ } // namespace oscadeval
@@ -40,18 +40,25 @@ CallArgs buildCallArgs(const CompiledChunk::CallSite& site, std::vector<Value>&
40
40
  // LIST is `paramNames` (in declared order -- a FunctionDeclaration's
41
41
  // parameters or a FunctionLiteral's). Shared by CallFn/CallFnTail (a
42
42
  // site.decl callee) and CallDynamic/CallDynamicTail (a closure callee).
43
- BoundArgs buildBoundArgs(const CompiledChunk::CallSite& site, std::vector<Value>& args, size_t argCount,
43
+ BoundArgs buildBoundArgs(Evaluator& ev, const CompiledChunk::CallSite& site, std::vector<Value>& args, size_t argCount,
44
44
  const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& paramNames) {
45
45
  BoundArgs bound;
46
46
  bound.reserve(argCount);
47
47
  size_t positionalIdx = 0;
48
48
  const size_t nparams = paramNames.size();
49
+ const oscad::Position* pos = site.callNode ? &site.callNode->position() : nullptr;
49
50
  for (size_t i = 0; i < argCount; ++i) {
50
51
  if (site.argNames[i]) {
51
- bound.set(*site.argNames[i], std::move(args[i]));
52
+ const std::string& name = *site.argNames[i];
53
+ if (!isConfigVariable(name) && !declaresParam(paramNames, name)) {
54
+ warnUnexpectedNamedArg(ev, name, pos);
55
+ }
56
+ bound.set(name, std::move(args[i]));
52
57
  } else {
53
58
  if (positionalIdx < nparams) {
54
59
  bound.set(paramNames[positionalIdx]->name->name, std::move(args[i]));
60
+ } else if (positionalIdx == nparams) {
61
+ warnTooManyPositionalArgs(ev, pos);
55
62
  }
56
63
  ++positionalIdx;
57
64
  }
@@ -126,6 +133,9 @@ void bindAstArgsIntoFrame(Evaluator& ev, const CompiledChunk& chunk,
126
133
  if (!matched && !name.empty() && name[0] == '$') {
127
134
  ctx.dyn->set(name, v);
128
135
  }
136
+ if (!matched && !isConfigVariable(name)) {
137
+ warnUnexpectedNamedArg(ev, name, &argPtr->position());
138
+ }
129
139
  } else {
130
140
  auto& a = static_cast<const oscad::PositionalArgument&>(*argPtr);
131
141
  Value v = ev.evalExpr(*a.expr, callerCtx);
@@ -137,6 +147,8 @@ void bindAstArgsIntoFrame(Evaluator& ev, const CompiledChunk& chunk,
137
147
  frame.slots[static_cast<size_t>(p.slot)] = std::move(v);
138
148
  }
139
149
  frame.bound[positionalIdx] = true;
150
+ } else if (positionalIdx == nparams) {
151
+ warnTooManyPositionalArgs(ev, &argPtr->position());
140
152
  }
141
153
  ++positionalIdx;
142
154
  }
@@ -770,7 +782,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
770
782
  f.stack.push_back(evalBuiltinFunction(ev, site.calleeName, callArgs, *site.callNode));
771
783
  ++f.pc;
772
784
  } else {
773
- BoundArgs bound = buildBoundArgs(site, args, argCount, site.decl->parameters);
785
+ BoundArgs bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
774
786
  const CompiledChunk* calleeChunk = ev.useBytecodeVm() ? ev.lookupOrCompileChunk(*site.decl) : nullptr;
775
787
  if (calleeChunk) {
776
788
  const oscad::Scope* fnScope = site.decl->scope() ? site.decl->scope() : ctx.scope;
@@ -801,7 +813,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
801
813
  if (const auto* closurePtr = std::get_if<ClosurePtr>(&callee); closurePtr && *closurePtr) {
802
814
  const Closure& closure = **closurePtr;
803
815
  const oscad::FunctionLiteral& funcNode = *closure.node;
804
- BoundArgs bound = buildBoundArgs(site, args, argCount, funcNode.parameters);
816
+ BoundArgs bound = buildBoundArgs(ev, site, args, argCount, funcNode.parameters);
805
817
  const CompiledChunk* calleeChunk = ev.useBytecodeVm() ? ev.lookupCompiledLiteralChunk(funcNode) : nullptr;
806
818
  if (calleeChunk) {
807
819
  const oscad::Scope* fnScope = funcNode.scope() ? funcNode.scope() : ctx.scope;
@@ -827,7 +839,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
827
839
  args[argCount - 1 - i] = std::move(f.stack.back());
828
840
  f.stack.pop_back();
829
841
  }
830
- BoundArgs bound = buildBoundArgs(site, args, argCount, site.decl->parameters);
842
+ BoundArgs bound = buildBoundArgs(ev, site, args, argCount, site.decl->parameters);
831
843
  // Tail-hop-in-place requires f.hopEligible -- a frame
832
844
  // that's call-boundary-free (statement expression,
833
845
  // assignment block, parameter default) has no
@@ -894,7 +906,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
894
906
  if (const auto* closurePtr = std::get_if<ClosurePtr>(&callee); closurePtr && *closurePtr) {
895
907
  const Closure& closure = **closurePtr;
896
908
  const oscad::FunctionLiteral& funcNode = *closure.node;
897
- BoundArgs bound = buildBoundArgs(site, args, argCount, funcNode.parameters);
909
+ BoundArgs bound = buildBoundArgs(ev, site, args, argCount, funcNode.parameters);
898
910
  const bool thisFrameBracketed = f.hopEligible;
899
911
  std::optional<EvalContext> hopCtx = thisFrameBracketed
900
912
  ? ev.isolatedCallCtxFor(funcNode, ctx, capturedLetTrail(closure))
@@ -1055,6 +1067,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
1055
1067
  // uncacheable/ManifoldCache taint tracking for a
1056
1068
  // rands() call embedded in the wrapper's own args).
1057
1069
  const std::uint64_t randsBefore = ev.randsCallCount();
1070
+ warnUnexpectedBuiltinArgs(ev, *site.node);
1058
1071
  CSGParams params;
1059
1072
  CallArgs deferredArgs; // Roof only -- see PendingBuiltinWrap's own doc comment
1060
1073
  switch (site.kind) {
@@ -1183,6 +1196,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
1183
1196
  // rands-in-args taint reasoning as Op::PushBuiltinWrap.
1184
1197
  const std::uint64_t randsBefore = ev.randsCallCount();
1185
1198
  if (site.hasArgs) {
1199
+ warnUnexpectedBuiltinArgs(ev, *site.node);
1186
1200
  // union/difference/intersection take no positional
1187
1201
  // arguments in real OpenSCAD -- `args` is discarded,
1188
1202
  // exactly mirroring resolveCsg's own `(void)args;`
@@ -94,6 +94,7 @@ void Evaluator::evalModularCall(const oscad::ModularCall& node, EvalContext& ctx
94
94
  CSGParams params;
95
95
  try {
96
96
  if (hasResolveFn) {
97
+ warnUnexpectedBuiltinArgs(*this, node);
97
98
  params = it->second(*this, node, ctx);
98
99
  } else if (!isBuiltin) {
99
100
  evalUserModule(static_cast<const oscad::ModuleDeclaration&>(*userModuleDecl), node, ctx);
@@ -2,6 +2,8 @@
2
2
 
3
3
  #include "openscad_cpp_evaluator/evaluator.hpp"
4
4
 
5
+ #include <algorithm>
6
+
5
7
  namespace oscadeval {
6
8
 
7
9
  void Evaluator::error(const std::string& msg, const oscad::ASTNode& node, const std::string& innermostFrame) {
@@ -122,4 +124,39 @@ std::string formatWarning(const std::string& msg, const oscad::Position* nodePos
122
124
  return full;
123
125
  }
124
126
 
127
+ bool isConfigVariable(const std::string& name) {
128
+ return !name.empty() && name[0] == '$' && name != "$children";
129
+ }
130
+
131
+ bool declaresParam(const std::vector<std::unique_ptr<oscad::ParameterDeclaration>>& params, const std::string& name) {
132
+ for (const auto& p : params) {
133
+ if (p->name->name == name) return true;
134
+ }
135
+ return false;
136
+ }
137
+
138
+ void warnUnexpectedNamedArg(Evaluator& ev, const std::string& name, const oscad::Position* pos) {
139
+ ev.warn("variable " + name + " not specified as parameter", pos);
140
+ }
141
+
142
+ void warnTooManyPositionalArgs(Evaluator& ev, const oscad::Position* pos) {
143
+ ev.warn("Too many unnamed arguments supplied", pos);
144
+ }
145
+
146
+ void warnUnexpectedArgs(Evaluator& ev, const std::vector<std::string>& params,
147
+ const std::vector<std::unique_ptr<oscad::Argument>>& arguments) {
148
+ size_t positionalIdx = 0;
149
+ for (const auto& argPtr : arguments) {
150
+ if (argPtr->kind() == oscad::NodeKind::NamedArgument) {
151
+ const std::string& name = static_cast<const oscad::NamedArgument&>(*argPtr).name->name;
152
+ if (!isConfigVariable(name) &&
153
+ std::find(params.begin(), params.end(), name) == params.end()) {
154
+ warnUnexpectedNamedArg(ev, name, &argPtr->position());
155
+ }
156
+ } else if (positionalIdx++ == params.size()) {
157
+ warnTooManyPositionalArgs(ev, &argPtr->position());
158
+ }
159
+ }
160
+ }
161
+
125
162
  } // namespace oscadeval
@@ -191,11 +191,18 @@ BoundArgs Evaluator::bindArgs(const std::vector<std::unique_ptr<oscad::Parameter
191
191
  for (const auto& argPtr : arguments) {
192
192
  if (argPtr->kind() == oscad::NodeKind::NamedArgument) {
193
193
  auto& a = static_cast<const oscad::NamedArgument&>(*argPtr);
194
- result.set(a.name->name, evalExprMaybeCompiled(*a.expr, ctx));
194
+ const std::string& name = a.name->name;
195
+ if (!isConfigVariable(name) && !declaresParam(params, name)) {
196
+ warnUnexpectedNamedArg(*this, name, &argPtr->position());
197
+ }
198
+ result.set(name, evalExprMaybeCompiled(*a.expr, ctx));
195
199
  } else {
196
200
  auto& a = static_cast<const oscad::PositionalArgument&>(*argPtr);
197
201
  if (positionalIdx < nparams) {
198
202
  result.set(params[positionalIdx]->name->name, evalExprMaybeCompiled(*a.expr, ctx));
203
+ } else if (positionalIdx == nparams) {
204
+ // Once per call, like the reference's warned_for_extra_arguments.
205
+ warnTooManyPositionalArgs(*this, &argPtr->position());
199
206
  }
200
207
  ++positionalIdx;
201
208
  }
@@ -35,6 +35,7 @@ add_executable(oscad_eval_tests
35
35
  test_debug_hooks.cpp
36
36
  test_multi_color_merge.cpp
37
37
  test_viewport_params.cpp
38
+ test_unexpected_args.cpp
38
39
  test_cli.cpp
39
40
  )
40
41
  target_link_libraries(oscad_eval_tests PRIVATE openscad_cpp_evaluator oscad_cli_lib GTest::gtest_main)
@@ -0,0 +1,151 @@
1
+ #include "openscad_cpp_evaluator/evaluator.hpp"
2
+
3
+ #include "test_helpers.hpp"
4
+
5
+ #include <gtest/gtest.h>
6
+
7
+ // Real OpenSCAD (Parameters.cc's parse_without_defaults) warns for a named
8
+ // argument the callee doesn't declare, and once per call for positional
9
+ // arguments past the last parameter. Every expectation below was checked
10
+ // against a real OpenSCAD 2022.08.22 run of the same script -- same message
11
+ // text, same set of calls warned about.
12
+ //
13
+ // Every case runs twice, VM off and VM on: user calls bind through
14
+ // bindArgs (interpreter) or buildBoundArgs/bindAstArgsIntoFrame (VM), and
15
+ // the transform/color/hull/extrude/CSG builtins bypass evalModularCall
16
+ // entirely once compiled (Op::PushBuiltinWrap/Op::PushCsgWrap). Any of those
17
+ // paths missing the check is exactly the bug this file exists to catch.
18
+ using namespace oscadeval;
19
+ using namespace oscadeval::test;
20
+
21
+ namespace {
22
+
23
+ class ScopedVm {
24
+ public:
25
+ explicit ScopedVm(bool enabled) { Evaluator::setBytecodeVmEnabledForTesting(enabled); }
26
+ ~ScopedVm() { Evaluator::setBytecodeVmEnabledForTesting(std::nullopt); }
27
+ };
28
+
29
+ std::vector<std::string> warningsFor(const std::string& code) {
30
+ std::vector<std::string> out;
31
+ Evaluated e = evalSrc(code, [&](const std::string& msg) {
32
+ if (msg.rfind("WARNING: ", 0) == 0) out.push_back(msg);
33
+ });
34
+ (void)e;
35
+ return out;
36
+ }
37
+
38
+ // Every warning line, both VM settings, asserted to be identical between
39
+ // them -- the two binding paths must not disagree about what is unexpected.
40
+ std::vector<std::string> warningsBothPaths(const std::string& code) {
41
+ std::vector<std::string> interpreted;
42
+ {
43
+ ScopedVm vm(false);
44
+ interpreted = warningsFor(code);
45
+ }
46
+ std::vector<std::string> compiled;
47
+ {
48
+ ScopedVm vm(true);
49
+ compiled = warningsFor(code);
50
+ }
51
+ EXPECT_EQ(interpreted, compiled) << "VM-on and VM-off disagree for: " << code;
52
+ return interpreted;
53
+ }
54
+
55
+ // True if some warning contains `needle`.
56
+ bool has(const std::vector<std::string>& warnings, const std::string& needle) {
57
+ for (const std::string& w : warnings) {
58
+ if (w.find(needle) != std::string::npos) return true;
59
+ }
60
+ return false;
61
+ }
62
+
63
+ } // namespace
64
+
65
+ TEST(UnexpectedArgs, UserModuleNamedArgNotAParameter) {
66
+ auto w = warningsBothPaths("module m(a=1) { } m(a=2, b=3);");
67
+ ASSERT_EQ(w.size(), 1u);
68
+ EXPECT_NE(w[0].find("WARNING: variable b not specified as parameter"), std::string::npos);
69
+ }
70
+
71
+ TEST(UnexpectedArgs, UserFunctionNamedArgNotAParameter) {
72
+ auto w = warningsBothPaths("function f(x=1) = x; echo(f(x=2, y=3));");
73
+ ASSERT_EQ(w.size(), 1u);
74
+ EXPECT_NE(w[0].find("WARNING: variable y not specified as parameter"), std::string::npos);
75
+ }
76
+
77
+ // A call from inside another function is the case the bytecode VM's own
78
+ // Op::CallFn path (buildBoundArgs) handles, distinct from the top-level
79
+ // entry (bindAstArgsIntoFrame).
80
+ TEST(UnexpectedArgs, NestedUserFunctionCallStillWarns) {
81
+ auto w = warningsBothPaths("function inner(n=1) = n; function outer(k) = inner(n=k, bogus=1); echo(outer(2));");
82
+ ASSERT_EQ(w.size(), 1u);
83
+ EXPECT_NE(w[0].find("WARNING: variable bogus not specified as parameter"), std::string::npos);
84
+ }
85
+
86
+ TEST(UnexpectedArgs, FunctionLiteralWarnsToo) {
87
+ auto w = warningsBothPaths("g = function(p) p * 2; echo(g(3, extra=9));");
88
+ ASSERT_EQ(w.size(), 1u);
89
+ EXPECT_NE(w[0].find("WARNING: variable extra not specified as parameter"), std::string::npos);
90
+ }
91
+
92
+ TEST(UnexpectedArgs, TooManyPositionalArgsWarnsExactlyOnce) {
93
+ // One warning for the whole call, however many extra arguments -- the
94
+ // reference's own warned_for_extra_arguments latch.
95
+ auto w = warningsBothPaths("module m(a) { } m(1, 2, 3);");
96
+ ASSERT_EQ(w.size(), 1u);
97
+ EXPECT_NE(w[0].find("WARNING: Too many unnamed arguments supplied"), std::string::npos);
98
+ }
99
+
100
+ TEST(UnexpectedArgs, DollarVariablesAreNeverUnexpected) {
101
+ // ContextFrame::is_config_variable: a $-name is a dynamic-scope
102
+ // override, not a parameter, so passing one to anything is fine.
103
+ EXPECT_TRUE(warningsBothPaths("module m(a=1) { } m(a=2, $custom=3, $fn=8);").empty());
104
+ EXPECT_TRUE(warningsBothPaths("function f(x=1) = x; echo(f(x=2, $custom=3));").empty());
105
+ EXPECT_TRUE(warningsBothPaths("sphere(r=1, $fn=8);").empty());
106
+ }
107
+
108
+ TEST(UnexpectedArgs, DeclaredParametersNeverWarn) {
109
+ EXPECT_TRUE(warningsBothPaths("module m(a, b=2) { } m(1, b=3);").empty());
110
+ EXPECT_TRUE(warningsBothPaths("cylinder(h=2, r1=1, r2=0, center=true);").empty());
111
+ EXPECT_TRUE(warningsBothPaths("linear_extrude(height=1, twist=10, convexity=2) square(1);").empty());
112
+ }
113
+
114
+ TEST(UnexpectedArgs, BuiltinPrimitiveWarns) {
115
+ auto w = warningsBothPaths("cube(size=2, bogus=9);");
116
+ ASSERT_EQ(w.size(), 1u);
117
+ EXPECT_NE(w[0].find("WARNING: variable bogus not specified as parameter"), std::string::npos);
118
+ }
119
+
120
+ // The transform/color/hull/CSG family never reaches evalModularCall once
121
+ // the bytecode compiler turns it into Op::PushBuiltinWrap/Op::PushCsgWrap
122
+ // -- the whole point of running these VM-on as well.
123
+ TEST(UnexpectedArgs, BuiltinsWithChildrenWarnOnBothPaths) {
124
+ EXPECT_TRUE(has(warningsBothPaths("translate([1,0,0], junk=1) cube(1);"), "variable junk"));
125
+ EXPECT_TRUE(has(warningsBothPaths("color(\"red\", junk=1) cube(1);"), "variable junk"));
126
+ EXPECT_TRUE(has(warningsBothPaths("hull(junk=1) cube(1);"), "variable junk"));
127
+ EXPECT_TRUE(has(warningsBothPaths("union(junk=1) cube(1);"), "variable junk"));
128
+ EXPECT_TRUE(has(warningsBothPaths("difference(junk=1) { cube(1); }"), "variable junk"));
129
+ EXPECT_TRUE(has(warningsBothPaths("offset(r=1, junk=1) square(1);"), "variable junk"));
130
+ }
131
+
132
+ // The `#`/`%`/`!` modifiers share BuiltinWrapSite with the transforms but
133
+ // carry no argument list at all -- must not trip the ModularCall cast.
134
+ TEST(UnexpectedArgs, ModifiersAreNotCalls) {
135
+ EXPECT_TRUE(warningsBothPaths("#translate([1,0,0]) cube(1);").empty());
136
+ EXPECT_TRUE(warningsBothPaths("%cube(1);").empty());
137
+ }
138
+
139
+ // Real OpenSCAD's builtin FUNCTIONS read their arguments positionally
140
+ // without Parameters::parse, so they warn about nothing -- verified against
141
+ // 2022.08.22, where both `sin(x=30)` and `sin(bogus=30)` return 0.5 in
142
+ // silence. textmetrics/fontmetrics are the exceptions that do parse.
143
+ TEST(UnexpectedArgs, BuiltinFunctionsDoNotWarn) {
144
+ EXPECT_TRUE(warningsBothPaths("echo(sin(bogus=30));").empty());
145
+ EXPECT_TRUE(warningsBothPaths("echo(len(bogus=[1,2]));").empty());
146
+ }
147
+
148
+ TEST(UnexpectedArgs, TextMetricsWarns) {
149
+ auto w = warningsBothPaths("echo(textmetrics(text=\"hi\", size=5, nope=1));");
150
+ EXPECT_TRUE(has(w, "variable nope not specified as parameter"));
151
+ }