openscad-cpp-evaluator 1.49.2__tar.gz → 1.49.3__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 (235) hide show
  1. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/bytecode.hpp +4 -0
  3. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/evaluator.hpp +16 -0
  4. openscad_cpp_evaluator-1.49.3/include/openscad_cpp_evaluator/reassign.hpp +61 -0
  5. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/bytecode_compiler.cpp +5 -1
  7. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/csg_resolve.cpp +1 -0
  8. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/eval_use.cpp +59 -3
  9. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/stmt_eval.cpp +32 -1
  10. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_scoping.cpp +17 -0
  11. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_use.cpp +31 -0
  12. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/uv.lock +1 -1
  13. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/.github/workflows/ci.yml +0 -0
  14. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/.github/workflows/wheels.yml +0 -0
  15. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/.gitignore +0 -0
  16. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/.gitmodules +0 -0
  17. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/CLAUDE.md +0 -0
  18. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/CMakeLists.txt +0 -0
  19. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/LICENSE +0 -0
  20. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/README.md +0 -0
  21. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/bindings/CMakeLists.txt +0 -0
  22. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/bindings/ast_to_py.cpp +0 -0
  23. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/bindings/module.cpp +0 -0
  24. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/cmake/embed_font.cmake +0 -0
  25. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/cmake/patch_manifold.cmake +0 -0
  26. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/examples/CMakeLists.txt +0 -0
  27. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/examples/eval_perf_benchmark.cpp +0 -0
  28. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/examples/manifold_cache_reuse.cpp +0 -0
  29. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/examples/minimal_debugger.cpp +0 -0
  30. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  31. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/.gitignore +0 -0
  32. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  33. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  34. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/LICENSE +0 -0
  35. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/README.md +0 -0
  36. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  37. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  38. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  39. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  40. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  41. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  42. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  43. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  44. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  45. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  46. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  47. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  48. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  49. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  50. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  51. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  52. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  53. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  54. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/api.cpp +0 -0
  55. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  56. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  57. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  58. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  59. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  60. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  61. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  62. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  63. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  64. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  65. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  66. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  67. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  68. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  69. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  70. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  71. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/position.cpp +0 -0
  72. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  73. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  74. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  75. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  76. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  77. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  78. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  79. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  80. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  81. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  82. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  83. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  84. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  85. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  86. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  87. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  88. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  89. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  90. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  91. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  92. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  93. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  94. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  95. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  96. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  97. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  98. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  99. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  100. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  101. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  102. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  103. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  104. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  105. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  106. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  107. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  108. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  109. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  110. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  111. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  112. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  113. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  114. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  115. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  116. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  117. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  118. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/export.hpp +0 -0
  119. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  120. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  121. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  122. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  123. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  124. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  125. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  126. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  127. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  128. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  129. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  130. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  131. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  132. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  133. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  134. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  135. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/value.hpp +0 -0
  136. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  137. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/python/openscad_cpp_evaluator/__init__.py +0 -0
  138. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/resources/fonts/LICENSE +0 -0
  139. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  140. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  141. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  142. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  143. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/CMakeLists.txt +0 -0
  144. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/booleans.cpp +0 -0
  145. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/builtins.hpp +0 -0
  146. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/call_args.cpp +0 -0
  147. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/color.cpp +0 -0
  148. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/control.cpp +0 -0
  149. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/dxf_dim.cpp +0 -0
  150. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/extrude.cpp +0 -0
  151. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/function_builtins.cpp +0 -0
  152. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/import.cpp +0 -0
  153. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/modifiers.cpp +0 -0
  154. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/primitives_2d.cpp +0 -0
  155. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/primitives_3d.cpp +0 -0
  156. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/profile_time.cpp +0 -0
  157. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/registry.cpp +0 -0
  158. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/roof.cpp +0 -0
  159. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/segments.cpp +0 -0
  160. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/surface.cpp +0 -0
  161. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/text.cpp +0 -0
  162. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/topology.cpp +0 -0
  163. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/builtins/transforms.cpp +0 -0
  164. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/bytecode_vm.cpp +0 -0
  165. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/colored_body.cpp +0 -0
  166. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/coverage.cpp +0 -0
  167. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/csg_generate.cpp +0 -0
  168. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/css_colors.cpp +0 -0
  169. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/debug/debug_repl.cpp +0 -0
  170. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/debug_profile.cpp +0 -0
  171. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/eval_context.cpp +0 -0
  172. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/eval_error.cpp +0 -0
  173. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/export.cpp +0 -0
  174. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/expr_eval.cpp +0 -0
  175. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/format_closure.cpp +0 -0
  176. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/import/dxf_import.cpp +0 -0
  177. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/import/mesh_import.cpp +0 -0
  178. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/import/scene_import.cpp +0 -0
  179. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/import/surface_load.cpp +0 -0
  180. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/import/svg_import.cpp +0 -0
  181. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/manifold_cache.cpp +0 -0
  182. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/measure_geometry.cpp +0 -0
  183. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/mesh_check.cpp +0 -0
  184. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/text/font_match.cpp +0 -0
  185. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/text/freetype_font_provider.cpp +0 -0
  186. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/text/text_metrics.cpp +0 -0
  187. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/user_calls.cpp +0 -0
  188. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/utf8.cpp +0 -0
  189. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/value.cpp +0 -0
  190. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/xkcd_colors.cpp +0 -0
  191. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/xkcd_colors.hpp +0 -0
  192. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/src/zip_stored.cpp +0 -0
  193. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/CMakeLists.txt +0 -0
  194. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_booleans.cpp +0 -0
  195. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_bytecode_compiler.cpp +0 -0
  196. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_children_separate.cpp +0 -0
  197. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_cli.cpp +0 -0
  198. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_control_flow.cpp +0 -0
  199. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_coverage.cpp +0 -0
  200. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_csg_tree.cpp +0 -0
  201. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_debug_hooks.cpp +0 -0
  202. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_discretizer.cpp +0 -0
  203. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_dxf_svg_import.cpp +0 -0
  204. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_eval_context.cpp +0 -0
  205. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_export.cpp +0 -0
  206. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_expr_eval.cpp +0 -0
  207. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_extrude_roof.cpp +0 -0
  208. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_feature_detection.cpp +0 -0
  209. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_function_builtins.cpp +0 -0
  210. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_helpers.hpp +0 -0
  211. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_import_export.cpp +0 -0
  212. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_include_cache.cpp +0 -0
  213. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_manifold_cache.cpp +0 -0
  214. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_mesh_check.cpp +0 -0
  215. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_multi_color_merge.cpp +0 -0
  216. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_openscad_parity.cpp +0 -0
  217. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_primitives.cpp +0 -0
  218. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_profile_time.cpp +0 -0
  219. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_profiling.cpp +0 -0
  220. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_python_bindings.py +0 -0
  221. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_render_expr.cpp +0 -0
  222. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_scope_trail.cpp +0 -0
  223. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_surface.cpp +0 -0
  224. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_tail_calls.cpp +0 -0
  225. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_text.cpp +0 -0
  226. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_transforms.cpp +0 -0
  227. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_undef_args.cpp +0 -0
  228. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_unexpected_args.cpp +0 -0
  229. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_value.cpp +0 -0
  230. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_viewport_params.cpp +0 -0
  231. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tests/test_zip_stored.cpp +0 -0
  232. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tools/cli/CMakeLists.txt +0 -0
  233. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tools/cli/cli_lib.cpp +0 -0
  234. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tools/cli/cli_lib.hpp +0 -0
  235. {openscad_cpp_evaluator-1.49.2 → openscad_cpp_evaluator-1.49.3}/tools/cli/main.cpp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.49.2
3
+ Version: 1.49.3
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT AND OFL-1.1
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include "openscad_cpp_evaluator/function_builtins.hpp"
4
+ #include "openscad_cpp_evaluator/reassign.hpp"
4
5
  #include "openscad_cpp_evaluator/value.hpp"
5
6
 
6
7
  #include "openscad_cpp_parser/ast/ast_node.hpp"
@@ -756,6 +757,9 @@ struct CompiledChunk {
756
757
  // with how many: the Evaluator warns for them once, when the chunk is
757
758
  // compiled (it has the warning channel; the compiler does not).
758
759
  std::vector<std::pair<const oscad::StringLiteral*, int>> undefinedEscapeLiterals;
760
+ // Reassignments merged in the statement lists compiled into this chunk
761
+ // (see mergeReassignments), warned about the same way.
762
+ std::vector<Reassignment> reassignments;
759
763
  struct Param {
760
764
  std::string name;
761
765
  int slot = 0; // unused when isDyn is true -- $-params are never slot-addressed
@@ -592,8 +592,11 @@ public:
592
592
  return false;
593
593
  }
594
594
  std::unordered_set<const oscad::StringLiteral*> undefinedEscapesWarned_;
595
+ // Warnings a chunk's compile found, given once it is built: undefined
596
+ // string escapes, and reassignments its statement lists merged.
595
597
  void warnUndefinedEscapes(const CompiledChunk& chunk) {
596
598
  for (const auto& [lit, n] : chunk.undefinedEscapeLiterals) warnUndefinedEscapes(*lit, n);
599
+ for (const Reassignment& r : chunk.reassignments) warnReassignment(r);
597
600
  }
598
601
  // Hands one already-formatted warning line to echoFn_, recording it in
599
602
  // warnCapture first when one is active. Every warning path goes through
@@ -1393,6 +1396,19 @@ private:
1393
1396
  };
1394
1397
  std::unordered_map<std::pair<const oscad::ASTNode*, size_t>, std::optional<CompiledChunk>, ChildrenListKeyHash>
1395
1398
  childrenListChunkCache_;
1399
+ // A statement list with its reassignments merged (see
1400
+ // mergedStatementList), or nullopt when it has none -- the common
1401
+ // case, which then costs one lookup. Same key, same clearing, same
1402
+ // dangling-pointer reasoning as childrenListChunkCache_ above.
1403
+ std::unordered_map<std::pair<const oscad::ASTNode*, size_t>, std::optional<std::vector<const oscad::ASTNode*>>,
1404
+ ChildrenListKeyHash>
1405
+ mergedListCache_;
1406
+ // "origin:line:name" of each reassignment already warned about, so a
1407
+ // cleared mergedListCache_ never warns twice. Strings, not node
1408
+ // pointers: these outlive the ASTs the cache is cleared for.
1409
+ std::unordered_set<std::string> warnedReassignments_;
1410
+ const std::vector<const oscad::ASTNode*>& mergedStatementList(const std::vector<const oscad::ASTNode*>& children);
1411
+ void warnReassignment(const Reassignment& r);
1396
1412
 
1397
1413
  // See stmtExprChunkCache_'s own doc comment, immediately above, for why
1398
1414
  // this exists. Not a reentrancy guard (resolveTreeImpl is never called
@@ -0,0 +1,61 @@
1
+ #pragma once
2
+
3
+ #include "openscad_cpp_parser/ast/expression.hpp"
4
+ #include "openscad_cpp_parser/position.hpp"
5
+
6
+ #include <optional>
7
+ #include <string>
8
+ #include <unordered_map>
9
+ #include <utility>
10
+ #include <vector>
11
+
12
+ namespace oscadeval {
13
+
14
+ // One name assigned again in the same statement list.
15
+ struct Reassignment {
16
+ std::string name;
17
+ const oscad::Position* first; // where the variable is evaluated
18
+ const oscad::Position* here; // the assignment whose value it takes
19
+ };
20
+
21
+ // OpenSCAD's handle_assignment (parser.y): a name assigned twice in one
22
+ // statement list is ONE assignment, made where it was FIRST assigned but
23
+ // with the LAST expression. `x = 1; y = x * 10; x = 2;` gives y = 20.
24
+ // Running them in order gave 10 -- and with include<> spliced into the top
25
+ // level, that broke the usual way of configuring a library (include it,
26
+ // then override its defaults) for every value the library derives from one
27
+ // (BelfrySCAD #809).
28
+ //
29
+ // Returns the merged list -- the last assignment's node in the first one's
30
+ // place, later slots dropped -- or nullopt when nothing repeats. ASTs are
31
+ // shared and never modified; only this list of pointers changes. Each merge
32
+ // is appended to `found` for the caller to warn about.
33
+ inline std::optional<std::vector<const oscad::ASTNode*>> mergeReassignments(
34
+ const std::vector<const oscad::ASTNode*>& stmts, std::vector<Reassignment>* found = nullptr) {
35
+ if (stmts.size() < 2) return std::nullopt;
36
+ std::vector<const oscad::ASTNode*> out;
37
+ out.reserve(stmts.size());
38
+ std::unordered_map<std::string, std::pair<size_t, const oscad::Position*>> seen;
39
+ bool merged = false;
40
+ for (const oscad::ASTNode* node : stmts) {
41
+ if (node->kind() != oscad::NodeKind::Assignment) {
42
+ out.push_back(node);
43
+ continue;
44
+ }
45
+ const auto& a = static_cast<const oscad::Assignment&>(*node);
46
+ const std::string& name = a.name->name;
47
+ auto it = seen.find(name);
48
+ if (it == seen.end()) {
49
+ seen.emplace(name, std::make_pair(out.size(), &a.position()));
50
+ out.push_back(node);
51
+ continue;
52
+ }
53
+ if (found) found->push_back({name, it->second.second, &a.position()});
54
+ out[it->second.first] = node;
55
+ merged = true;
56
+ }
57
+ if (!merged) return std::nullopt;
58
+ return out;
59
+ }
60
+
61
+ } // 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 = "1.49.2"
7
+ version = "1.49.3"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1283,7 +1283,11 @@ public:
1283
1283
  // necessarily one this Compiler's own declaration owns) -- see
1284
1284
  // tryCompileChildrenList's own doc comment, below, for the entry point
1285
1285
  // that needs this shape directly.
1286
- void compileStatementList(const std::vector<const oscad::ASTNode*>& children, std::vector<Instruction>& out) {
1286
+ void compileStatementList(const std::vector<const oscad::ASTNode*>& childrenIn, std::vector<Instruction>& out) {
1287
+ // Reassignments merged first, as Evaluator::evalChildren does for the
1288
+ // interpreted path: a list compiled inline here never reaches it.
1289
+ const auto merged = mergeReassignments(childrenIn, &chunk_.reassignments);
1290
+ const std::vector<const oscad::ASTNode*>& children = merged ? *merged : childrenIn;
1287
1291
  std::vector<const oscad::ASTNode*> assignments;
1288
1292
  std::vector<const oscad::ASTNode*> others;
1289
1293
  for (const oscad::ASTNode* c : children) {
@@ -247,6 +247,7 @@ std::vector<std::unique_ptr<CSGNode>> Evaluator::resolveTreeImpl(const NodeList&
247
247
  stmtExprChunkCache_.clear();
248
248
  assignBlockChunkCache_.clear();
249
249
  childrenListChunkCache_.clear();
250
+ mergedListCache_.clear();
250
251
  ResolvePassGuard resolvePassGuard(inResolvePass_);
251
252
  evalChildren(nodes, ctx);
252
253
  std::vector<std::unique_ptr<CSGNode>> tree = std::move(treeStack_.back());
@@ -1,7 +1,12 @@
1
1
  #include "openscad_cpp_evaluator/eval_use.hpp"
2
2
 
3
+ #include "openscad_cpp_evaluator/eval_error.hpp"
4
+ #include "openscad_cpp_evaluator/reassign.hpp"
3
5
  #include "openscad_cpp_parser/ast/declarations.hpp"
6
+ #include "openscad_cpp_parser/ast/expression.hpp"
4
7
 
8
+ #include <filesystem>
9
+ #include <unordered_map>
5
10
  #include <utility>
6
11
 
7
12
  namespace oscadeval {
@@ -19,6 +24,55 @@ ResolvedUseScopes resolveUseScopes(const std::vector<std::unique_ptr<oscad::ASTN
19
24
 
20
25
  namespace {
21
26
 
27
+ namespace fs = std::filesystem;
28
+
29
+ std::string normalPath(const std::string& p) {
30
+ std::error_code ec;
31
+ fs::path abs = fs::absolute(fs::path(p), ec);
32
+ return (ec ? fs::path(p) : abs).lexically_normal().generic_string();
33
+ }
34
+
35
+ // Each file's top-level list, merged before any scope is built (see
36
+ // mergeReassignments, reassign.hpp), so the interpreter, the compiled VM
37
+ // and the scope tables all see one assignment per name. This is where an
38
+ // include<>'d library's defaults meet the main file's overrides.
39
+ //
40
+ // Warnings follow parser.y's rules exactly. The deliberate silence is the
41
+ // main file overriding an included file's variable: that is configuration,
42
+ // not a mistake. Two different included files overriding each other are
43
+ // silent too.
44
+ std::vector<const oscad::ASTNode*> mergeTopLevel(const std::vector<const oscad::ASTNode*>& nodes,
45
+ const std::string& mainFile,
46
+ const std::function<void(const std::string&)>& logFn) {
47
+ std::vector<Reassignment> found;
48
+ auto merged = mergeReassignments(nodes, &found);
49
+ if (!merged) return nodes;
50
+ const std::string main = normalPath(mainFile);
51
+ for (const Reassignment& r : found) {
52
+ const std::string prevFile = normalPath(r.first->origin);
53
+ const std::string currFile = normalPath(r.here->origin);
54
+ std::string where; // the file named in the message, if not the main one
55
+ bool warnIt = false;
56
+ if (prevFile == main && currFile == main) {
57
+ warnIt = true;
58
+ } else if (prevFile == currFile) {
59
+ warnIt = r.first->line != r.here->line; // equal: one file included twice
60
+ where = prevFile;
61
+ } else if (prevFile == main) {
62
+ warnIt = true; // the main file's value overwritten by an include
63
+ where = prevFile;
64
+ }
65
+ if (!warnIt || !logFn) continue;
66
+ std::string msg = r.name + " was assigned on line " + std::to_string(r.first->line);
67
+ if (!where.empty()) {
68
+ const fs::path rel = fs::path(where).lexically_relative(fs::path(main).parent_path());
69
+ msg += " of " + (rel.empty() ? where : rel.generic_string());
70
+ }
71
+ logFn(formatWarning(msg + " but was overwritten", r.here, {}));
72
+ }
73
+ return *merged;
74
+ }
75
+
22
76
  // The recursion. `table` is threaded through every level rather than each
23
77
  // level building its own: `use <file>` gives each used file its own root
24
78
  // Scope, but one evaluation reads all of them back, so every node's scope
@@ -26,11 +80,13 @@ namespace {
26
80
  // could not see anything a nested resolution recorded -- every node of a
27
81
  // used file read back as having no scope, and `use` silently resolved to
28
82
  // undef. BelfrySCAD's own suite caught that; this repo's did not.
29
- ResolvedUseScopes resolveUseScopesInto(const std::vector<const oscad::ASTNode*>& ownNodes,
83
+ ResolvedUseScopes resolveUseScopesInto(const std::vector<const oscad::ASTNode*>& ownNodesIn,
30
84
  const std::string& currentFile,
85
+ const std::string& mainFile,
31
86
  const std::function<void(const std::string&)>& logFn,
32
87
  oscad::ScopeTable& table) {
33
88
  ResolvedUseScopes result;
89
+ const std::vector<const oscad::ASTNode*> ownNodes = mergeTopLevel(ownNodesIn, mainFile, logFn);
34
90
 
35
91
  std::vector<const oscad::ASTNode*> injected;
36
92
  // Declarations pulled in from one used file, paired with that file's
@@ -70,7 +126,7 @@ ResolvedUseScopes resolveUseScopesInto(const std::vector<const oscad::ASTNode*>&
70
126
  std::vector<const oscad::ASTNode*> libBorrowed;
71
127
  libBorrowed.reserve(libAst.size());
72
128
  for (const auto& n : libAst) libBorrowed.push_back(n.get());
73
- ResolvedUseScopes nested = resolveUseScopesInto(libBorrowed, lib.resolvedPath, logFn, table);
129
+ ResolvedUseScopes nested = resolveUseScopesInto(libBorrowed, lib.resolvedPath, mainFile, logFn, table);
74
130
 
75
131
  std::vector<const oscad::ASTNode*> libInjected;
76
132
  for (const oscad::ASTNode* n : nested.ownNodesFiltered) {
@@ -137,7 +193,7 @@ ResolvedUseScopes resolveUseScopes(const std::vector<const oscad::ASTNode*>& own
137
193
  // One table for the whole resolution, handed to the root scope at the
138
194
  // end so it lives exactly as long as the scopes it points into.
139
195
  auto table = std::make_unique<oscad::ScopeTable>();
140
- ResolvedUseScopes result = resolveUseScopesInto(ownNodes, currentFile, logFn, *table);
196
+ ResolvedUseScopes result = resolveUseScopesInto(ownNodes, currentFile, currentFile, logFn, *table);
141
197
  if (result.rootScope) result.rootScope->adoptTable(std::move(table));
142
198
  return result;
143
199
  }
@@ -1,5 +1,6 @@
1
1
  #include "openscad_cpp_evaluator/evaluator.hpp"
2
2
  #include "openscad_cpp_evaluator/format_closure.hpp"
3
+ #include "openscad_cpp_evaluator/reassign.hpp"
3
4
 
4
5
  #include "openscad_cpp_evaluator/call_args.hpp"
5
6
 
@@ -325,7 +326,37 @@ void Evaluator::evalStatement(const oscad::ASTNode& node, EvalContext& ctx) {
325
326
  }
326
327
  }
327
328
 
328
- void Evaluator::evalChildren(const std::vector<const oscad::ASTNode*>& children, EvalContext& ctx) {
329
+ // A statement list inside a module body or a block, with its reassignments
330
+ // merged (mergeReassignments, reassign.hpp). The top level of each file is
331
+ // merged once before scopes are built (eval_use.cpp); these lists live in
332
+ // shared, immutable ASTs, so they are merged here, as they are run, and
333
+ // cached. The compiler merges the lists it compiles inline itself
334
+ // (compileStatementList), so both paths agree.
335
+ const std::vector<const oscad::ASTNode*>& Evaluator::mergedStatementList(
336
+ const std::vector<const oscad::ASTNode*>& children) {
337
+ if (children.size() < 2) return children;
338
+ const auto key = std::make_pair(children.front(), children.size());
339
+ auto it = mergedListCache_.find(key);
340
+ if (it == mergedListCache_.end()) {
341
+ std::vector<Reassignment> found;
342
+ it = mergedListCache_.emplace(key, mergeReassignments(children, &found)).first;
343
+ for (const Reassignment& r : found) warnReassignment(r);
344
+ }
345
+ return it->second ? *it->second : children;
346
+ }
347
+
348
+ void Evaluator::warnReassignment(const Reassignment& r) {
349
+ // A body is one file, so parser.y's rule reduces to: always warn (its
350
+ // same-line exemption is for one file included twice, which only the
351
+ // top level can see). Once per assignment however often its list is
352
+ // run or recompiled.
353
+ const std::string tag = r.here->origin + ":" + std::to_string(r.here->start_offset) + ":" + r.name;
354
+ if (!warnedReassignments_.insert(tag).second) return;
355
+ warn(r.name + " was assigned on line " + std::to_string(r.first->line) + " but was overwritten", r.here);
356
+ }
357
+
358
+ void Evaluator::evalChildren(const std::vector<const oscad::ASTNode*>& childrenIn, EvalContext& ctx) {
359
+ const std::vector<const oscad::ASTNode*>& children = mergedStatementList(childrenIn);
329
360
  // Whole-LIST compile first (see tryRunCompiledChildren's own doc
330
361
  // comment, evaluator.hpp) -- tries the FULL `children` as one chunk
331
362
  // before falling back to assignments-then-others below. This is what
@@ -195,3 +195,20 @@ TEST(SpecialVariables, PreviewIsAlwaysFalse) {
195
195
  ASSERT_EQ(msgs.size(), 1u) << (msgs.empty() ? "" : msgs[0]);
196
196
  EXPECT_EQ(msgs[0], "ECHO: false, true, \"r\"");
197
197
  }
198
+
199
+ // OpenSCAD evaluates a reassigned variable once, at its FIRST assignment,
200
+ // with its LAST value (parser.y's handle_assignment) -- in a module body or
201
+ // a block as at the top level. Checked against OpenSCAD 2026.02.01.
202
+ TEST(Scoping, ReassignedVariableTakesItsLastValueAtItsFirstPosition) {
203
+ std::vector<std::string> out;
204
+ evaluateSrc("x = 1;\ny = x * 10;\nx = 2;\necho(y = y);\n"
205
+ "module m() {\n u = 1;\n v = u * 10;\n u = 2;\n echo(v = v);\n}\nm();\n"
206
+ "if (true) { a = 1; b = a + 1; a = 5; echo(b = b); }\n",
207
+ [&](const std::string& m) { out.push_back(m); });
208
+ EXPECT_TRUE(anyContains(out, "ECHO: y = 20"));
209
+ EXPECT_TRUE(anyContains(out, "ECHO: v = 20"));
210
+ EXPECT_TRUE(anyContains(out, "ECHO: b = 6"));
211
+ size_t warnings = 0;
212
+ for (const auto& m : out) warnings += m.find("but was overwritten") != std::string::npos;
213
+ EXPECT_EQ(warnings, 3u) << "one per reassignment, even though m() could run again";
214
+ }
@@ -173,3 +173,34 @@ TEST(UseStatement, MainFileGlobalReadFromFunctionIsStable) {
173
173
  EXPECT_EQ(echoed[2], "ECHO: undef");
174
174
  std::filesystem::remove(main);
175
175
  }
176
+
177
+ // BelfrySCAD #809: OpenSCAD evaluates a reassigned variable at its FIRST
178
+ // assignment with its LAST value, so a main file overriding an included
179
+ // library's default changes everything the library derives from it -- the
180
+ // standard way to configure a library. And it says nothing: overriding an
181
+ // included file's variable is configuration, not a mistake. Expected values
182
+ // and warnings checked against OpenSCAD 2026.02.01.
183
+ TEST(IncludeReassignment, MainFileOverrideReachesValuesTheLibraryDerives) {
184
+ auto lib = writeFile("reassign_lib.scad", "x = 1;\ny = x * 10;\no = object(k = 5);\np = o.k;\n");
185
+ auto main = writeFile("reassign_main.scad", "include <" + lib.string() + ">\n"
186
+ "x = 2;\no = object(k = 7);\necho(y = y, p = p);\n");
187
+ std::vector<std::string> out;
188
+ evalFile(main, [&](const std::string& m) { out.push_back(m); });
189
+ ASSERT_EQ(out.size(), 1u) << "no warnings: overriding an include is configuration";
190
+ EXPECT_EQ(out[0], "ECHO: y = 20, p = 7");
191
+ std::filesystem::remove(lib);
192
+ std::filesystem::remove(main);
193
+ }
194
+
195
+ TEST(IncludeReassignment, IncludeOverwritingTheMainFileWarnsNamingIt) {
196
+ auto lib = writeFile("reassign_lib2.scad", "a = 1;\n");
197
+ auto main = writeFile("reassign_main2.scad", "a = 2;\ninclude <" + lib.string() + ">\necho(a = a);\n");
198
+ std::vector<std::string> out;
199
+ evalFile(main, [&](const std::string& m) { out.push_back(m); });
200
+ ASSERT_EQ(out.size(), 2u);
201
+ EXPECT_EQ(out[0], "WARNING: a was assigned on line 1 of " + main.filename().string() +
202
+ " but was overwritten in file " + lib.string() + ", line 1");
203
+ EXPECT_EQ(out[1], "ECHO: a = 1");
204
+ std::filesystem::remove(lib);
205
+ std::filesystem::remove(main);
206
+ }
@@ -55,7 +55,7 @@ wheels = [
55
55
 
56
56
  [[package]]
57
57
  name = "openscad-cpp-evaluator"
58
- version = "1.49.2"
58
+ version = "1.49.3"
59
59
  source = { editable = "." }
60
60
  dependencies = [
61
61
  { name = "numpy" },