openscad-cpp-evaluator 0.16.0__tar.gz → 0.17.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 (196) hide show
  1. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/csg_node.hpp +16 -0
  3. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/eval_error.hpp +12 -0
  4. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/evaluator.hpp +18 -0
  5. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/bytecode_vm.cpp +2 -0
  7. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/csg_generate.cpp +7 -0
  8. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/csg_resolve.cpp +3 -0
  9. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/eval_error.cpp +44 -0
  10. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/expr_eval.cpp +19 -1
  11. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_bytecode_compiler.cpp +11 -3
  12. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_csg_tree.cpp +70 -0
  13. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/.github/workflows/ci.yml +0 -0
  14. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/.github/workflows/wheels.yml +0 -0
  15. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/.gitignore +0 -0
  16. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/.gitmodules +0 -0
  17. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/CLAUDE.md +0 -0
  18. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/CMakeLists.txt +0 -0
  19. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/LICENSE +0 -0
  20. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/README.md +0 -0
  21. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/bindings/CMakeLists.txt +0 -0
  22. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/bindings/ast_to_py.cpp +0 -0
  23. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/bindings/module.cpp +0 -0
  24. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/cmake/embed_font.cmake +0 -0
  25. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/examples/CMakeLists.txt +0 -0
  26. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/examples/eval_perf_benchmark.cpp +0 -0
  27. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/examples/manifold_cache_reuse.cpp +0 -0
  28. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/examples/minimal_debugger.cpp +0 -0
  29. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  30. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/.gitignore +0 -0
  31. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  32. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  33. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/README.md +0 -0
  34. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  35. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  36. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  37. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  38. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  39. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  40. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  41. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  42. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  43. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  44. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  45. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  46. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  47. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  48. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  49. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  50. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  51. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  52. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  53. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  54. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  55. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  56. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  57. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  58. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  59. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  60. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  61. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  62. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  63. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  64. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  65. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  66. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  67. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  68. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  69. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  70. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  71. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  72. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  73. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  74. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  75. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  76. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  77. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  78. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  79. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  80. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  81. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  82. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  83. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  84. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  85. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  86. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  87. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  88. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  89. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  90. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  91. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  92. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  93. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  94. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  95. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  96. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  97. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  98. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  99. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  100. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  101. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  102. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  103. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  104. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  105. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  106. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  107. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  108. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  109. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  110. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  111. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  112. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  113. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  114. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  115. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  116. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  117. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  118. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
  119. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  120. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  121. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  122. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  123. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  124. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/resources/fonts/LICENSE +0 -0
  125. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  126. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/CMakeLists.txt +0 -0
  127. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/booleans.cpp +0 -0
  128. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/builtins.hpp +0 -0
  129. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/call_args.cpp +0 -0
  130. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/color.cpp +0 -0
  131. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/control.cpp +0 -0
  132. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/extrude.cpp +0 -0
  133. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/function_builtins.cpp +0 -0
  134. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/import.cpp +0 -0
  135. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/modifiers.cpp +0 -0
  136. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/primitives_2d.cpp +0 -0
  137. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/primitives_3d.cpp +0 -0
  138. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/registry.cpp +0 -0
  139. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/roof.cpp +0 -0
  140. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/segments.cpp +0 -0
  141. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/surface.cpp +0 -0
  142. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/text.cpp +0 -0
  143. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/topology.cpp +0 -0
  144. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/builtins/transforms.cpp +0 -0
  145. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/bytecode_compiler.cpp +0 -0
  146. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/colored_body.cpp +0 -0
  147. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/css_colors.cpp +0 -0
  148. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/debug/debug_repl.cpp +0 -0
  149. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/debug_profile.cpp +0 -0
  150. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/eval_context.cpp +0 -0
  151. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/eval_use.cpp +0 -0
  152. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/export.cpp +0 -0
  153. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/import/dxf_import.cpp +0 -0
  154. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/import/mesh_import.cpp +0 -0
  155. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/import/surface_load.cpp +0 -0
  156. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/import/svg_import.cpp +0 -0
  157. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/manifold_cache.cpp +0 -0
  158. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/stmt_eval.cpp +0 -0
  159. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/text/stb_font_provider.cpp +0 -0
  160. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/text/text_metrics.cpp +0 -0
  161. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/user_calls.cpp +0 -0
  162. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/value.cpp +0 -0
  163. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/src/zip_stored.cpp +0 -0
  164. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/CMakeLists.txt +0 -0
  165. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_booleans.cpp +0 -0
  166. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_cli.cpp +0 -0
  167. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_control_flow.cpp +0 -0
  168. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_debug_hooks.cpp +0 -0
  169. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_dxf_svg_import.cpp +0 -0
  170. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_eval_context.cpp +0 -0
  171. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_export.cpp +0 -0
  172. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_expr_eval.cpp +0 -0
  173. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_extrude_roof.cpp +0 -0
  174. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_function_builtins.cpp +0 -0
  175. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_helpers.hpp +0 -0
  176. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_import_export.cpp +0 -0
  177. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_manifold_cache.cpp +0 -0
  178. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_multi_color_merge.cpp +0 -0
  179. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_primitives.cpp +0 -0
  180. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_profiling.cpp +0 -0
  181. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_python_bindings.py +0 -0
  182. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_scope_trail.cpp +0 -0
  183. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_scoping.cpp +0 -0
  184. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_surface.cpp +0 -0
  185. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_tail_calls.cpp +0 -0
  186. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_text.cpp +0 -0
  187. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_transforms.cpp +0 -0
  188. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_use.cpp +0 -0
  189. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_value.cpp +0 -0
  190. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_viewport_params.cpp +0 -0
  191. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tests/test_zip_stored.cpp +0 -0
  192. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tools/cli/CMakeLists.txt +0 -0
  193. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tools/cli/cli_lib.cpp +0 -0
  194. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tools/cli/cli_lib.hpp +0 -0
  195. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/tools/cli/main.cpp +0 -0
  196. {openscad_cpp_evaluator-0.16.0 → openscad_cpp_evaluator-0.17.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.16.0
3
+ Version: 0.17.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -34,6 +34,22 @@ struct CSGNode {
34
34
  CSGParams params; // resolve step's plain-data output
35
35
  bool uncacheable = false; // set by a later phase (ManifoldCache, Phase 8)
36
36
 
37
+ // The call site that entered this node's call chain from the top
38
+ // level, captured at RESOLVE time -- non-owning, AST-lifetime-bound
39
+ // like `node`. nullptr for a node resolved at top level.
40
+ //
41
+ // Needed because a GenerateFn runs long after resolve has unwound the
42
+ // call stack, so a warning raised there (an open polyhedron(), a
43
+ // non-manifold import()) has no stack left to walk and could only ever
44
+ // name the library's own line. One pointer per node, deliberately, so
45
+ // this stays affordable on a BOSL2-scale tree; the full frame list a
46
+ // TRACE would need is not worth the per-node cost.
47
+ //
48
+ // Not part of cacheKey() (an explicit allowlist of kind/isBuiltin/
49
+ // params/children), so two identical subtrees reached from different
50
+ // call sites still share a cache entry.
51
+ const oscad::Position* warnEntry = nullptr;
52
+
37
53
  // 1 + the deepest child's own treeDepth (1 for a leaf) -- set once,
38
54
  // at construction, by whichever csg_resolve.cpp site finalizes this
39
55
  // node's own `children` (buildTreeNode, evalModularCall's non-splice
@@ -117,4 +117,16 @@ std::string formatError(const std::string& msg, const oscad::Position* nodePosit
117
117
  const std::vector<CallStackFrame>& callStack,
118
118
  const std::string& innermostFrame = "");
119
119
 
120
+ // "WARNING: {msg}{locSuffix(nodePosition)}, from {entry file}, line {N}"
121
+ // followed by traceLines(). The "from" clause names the OUTERMOST frame's
122
+ // call site -- the user's own line that entered the call chain -- because
123
+ // a warning raised inside a library otherwise reports only the library's
124
+ // own line, which the reader can neither act on nor trace back.
125
+ //
126
+ // Omitted when the stack is empty (a top-level warning, the common case,
127
+ // which stays a single line) or when it would merely repeat the headline.
128
+ // Deliberately richer than real OpenSCAD, which prints neither.
129
+ std::string formatWarning(const std::string& msg, const oscad::Position* nodePosition,
130
+ const std::vector<CallStackFrame>& callStack);
131
+
120
132
  } // namespace oscadeval
@@ -234,6 +234,24 @@ public:
234
234
  // GenerateFn is a free function, not a method -- it needs to call this
235
235
  // on the Evaluator& it's handed (see dispatch.hpp's GenerateFn doc
236
236
  // comment for why that reference exists at all).
237
+ // The call site that entered the current call chain from the top
238
+ // level (callStack_ is outermost-first), or nullptr at top level.
239
+ // Captured into each CSGNode at resolve time so a warning raised
240
+ // during generate -- after the stack has unwound -- can still name the
241
+ // user's own line. See CSGNode::warnEntry.
242
+ const oscad::Position* currentWarnEntry() const {
243
+ return callStack_.empty() ? nullptr : callStack_.front().callPosition;
244
+ }
245
+
246
+ // Set by generateTreeImpl() to the CSGNode currently being generated,
247
+ // so warn() can name the user's own call site during a phase where
248
+ // callStack_ is necessarily empty. Public for the same reason
249
+ // tagGenerated() is: a GenerateFn is a free function holding only an
250
+ // Evaluator&. Read only by warn(); a plain scoped save/restore rather
251
+ // than anything reentrancy-aware, since generateTreeImpl recurses
252
+ // depth-first on one thread.
253
+ const oscad::Position* generateWarnEntry = nullptr;
254
+
237
255
  ColoredBody tagGenerated(manifold::Manifold body, const oscad::ASTNode& node, const Value& colorValue);
238
256
 
239
257
  // tagGenerated()'s counterpart for a mesh Manifold refused to build --
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.16.0"
7
+ version = "0.17.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1168,6 +1168,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
1168
1168
  treeNode->kind = site.tagName;
1169
1169
  treeNode->node = site.node;
1170
1170
  treeNode->isBuiltin = true;
1171
+ treeNode->warnEntry = ev.currentWarnEntry();
1171
1172
  treeNode->children = std::move(children);
1172
1173
  treeNode->params = std::move(pending.params);
1173
1174
  treeNode->uncacheable = uncacheable;
@@ -1244,6 +1245,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
1244
1245
  treeNode->kind = site.op;
1245
1246
  treeNode->node = site.node;
1246
1247
  treeNode->isBuiltin = true;
1248
+ treeNode->warnEntry = ev.currentWarnEntry();
1247
1249
  treeNode->children = std::move(children);
1248
1250
  treeNode->params = std::move(params);
1249
1251
  treeNode->uncacheable = uncacheable;
@@ -59,7 +59,14 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
59
59
 
60
60
  auto it = dispatch.find(node.kind);
61
61
  if (node.isBuiltin && it != dispatch.end()) {
62
+ // Resolve captured which user-level call reached this node;
63
+ // republish it so a warning raised inside the GenerateFn
64
+ // can name that line. Restored after (rather than left set)
65
+ // so a sibling generated at top level doesn't inherit it.
66
+ const oscad::Position* savedWarnEntry = generateWarnEntry;
67
+ generateWarnEntry = node.warnEntry;
62
68
  node.bodies = it->second(*this, node.params, node.children, *node.node);
69
+ generateWarnEntry = savedWarnEntry;
63
70
  } else {
64
71
  // No registered GenerateFn for this kind (a builtin with
65
72
  // display-only semantics like render(), or a non-builtin
@@ -66,6 +66,7 @@ void Evaluator::buildTreeNode(const std::string& kind, const oscad::ASTNode& nod
66
66
  treeNode->kind = kind;
67
67
  treeNode->node = &node;
68
68
  treeNode->isBuiltin = true;
69
+ treeNode->warnEntry = currentWarnEntry();
69
70
  treeNode->children = std::move(children);
70
71
  treeNode->params = std::move(params);
71
72
  treeNode->uncacheable = uncacheable;
@@ -135,6 +136,7 @@ void Evaluator::evalModularCall(const oscad::ModularCall& node, EvalContext& ctx
135
136
  treeNode->kind = name;
136
137
  treeNode->node = &node;
137
138
  treeNode->isBuiltin = true;
139
+ treeNode->warnEntry = currentWarnEntry();
138
140
  treeNode->uncacheable = uncacheable;
139
141
  treeNode->children = std::move(children);
140
142
  treeNode->params = std::move(params);
@@ -159,6 +161,7 @@ void Evaluator::spliceModuleChildren(std::vector<std::unique_ptr<CSGNode>> child
159
161
  unionNode->kind = "union";
160
162
  unionNode->node = &callNode;
161
163
  unionNode->isBuiltin = false;
164
+ unionNode->warnEntry = currentWarnEntry();
162
165
  unionNode->uncacheable = std::any_of(children.begin(), children.end(), [](const auto& c) { return c->uncacheable; });
163
166
  unionNode->children = std::move(children);
164
167
  setTreeDepthOrThrow(*unionNode, callNode);
@@ -78,4 +78,48 @@ std::string formatError(const std::string& msg, const oscad::Position* nodePosit
78
78
  return full;
79
79
  }
80
80
 
81
+ std::string formatWarning(const std::string& msg, const oscad::Position* nodePosition,
82
+ const std::vector<CallStackFrame>& callStack) {
83
+ // The warning keeps its OWN location in the headline: that is where the
84
+ // problem actually is, and it's what you need in order to fix a genuine
85
+ // library bug. But on its own, a warning raised deep inside a library
86
+ // ("in file BOSL2/vnf.scad, line 1624") is close to useless -- the
87
+ // reader's next question is always "which line of MINE caused that?",
88
+ // and nothing in the message answered it.
89
+ //
90
+ // callStack is outermost-first, so front() is the call that entered
91
+ // this chain from the top level -- the user's own line, however deep
92
+ // the warning surfaced. Naming it inline makes the common case a
93
+ // one-line answer; the TRACE lines below carry the full chain for when
94
+ // an intermediate frame is the real culprit.
95
+ //
96
+ // Real OpenSCAD reports only the raising location and no trace at all
97
+ // (verified against 2022.08.22), so this is deliberately more than the
98
+ // reference gives: warnings there routinely point into library
99
+ // internals with no way back to the caller.
100
+ std::string full = "WARNING: " + msg + locSuffix(nodePosition);
101
+
102
+ if (!callStack.empty()) {
103
+ const oscad::Position* entry = callStack.front().callPosition;
104
+ // Skip the clause when it would only repeat the headline (a warning
105
+ // raised directly at the top-level call site), or when the entry
106
+ // frame recorded no call position.
107
+ const bool sameSpot = entry != nullptr && nodePosition != nullptr &&
108
+ entry->origin == nodePosition->origin && entry->line == nodePosition->line;
109
+ if (entry != nullptr && !sameSpot) {
110
+ full += ", from " + entry->origin + ", line " + std::to_string(entry->line);
111
+ }
112
+ }
113
+
114
+ // Same shape and truncation as an error's trace, including the
115
+ // 10-frames-each-end bound for pathologically deep chains. A warning
116
+ // raised outside any call has an empty stack and stays a single line --
117
+ // the overwhelmingly common case, which keeps ordinary warnings from
118
+ // sprouting a trace nobody needs.
119
+ for (const std::string& line : traceLines(nodePosition, callStack, "")) {
120
+ full += "\n" + line;
121
+ }
122
+ return full;
123
+ }
124
+
81
125
  } // namespace oscadeval
@@ -95,7 +95,25 @@ FontProvider& Evaluator::fontProvider() {
95
95
  }
96
96
 
97
97
  void Evaluator::warn(const std::string& message, const oscad::Position* position) {
98
- if (echoFn_) echoFn_("WARNING: " + message + locSuffix(position));
98
+ if (!echoFn_) return;
99
+ // During generate the call stack has already unwound, so fall back to
100
+ // the entry position resolve captured onto the CSGNode being generated
101
+ // (see CSGNode::warnEntry). Passed as a synthetic single-frame stack so
102
+ // formatWarning needs no second code path -- the frame carries no name,
103
+ // which traceLines renders as a bare "called by ''" line, so it is
104
+ // deliberately NOT included there; only the headline's "from" clause
105
+ // uses it.
106
+ if (callStack_.empty() && generateWarnEntry != nullptr) {
107
+ std::string out = formatWarning(message, position, {});
108
+ const bool sameSpot = position != nullptr && generateWarnEntry->origin == position->origin &&
109
+ generateWarnEntry->line == position->line;
110
+ if (!sameSpot) {
111
+ out += ", from " + generateWarnEntry->origin + ", line " + std::to_string(generateWarnEntry->line);
112
+ }
113
+ echoFn_(out);
114
+ return;
115
+ }
116
+ echoFn_(formatWarning(message, position, callStack_));
99
117
  }
100
118
 
101
119
  Value Evaluator::evalIdentifier(const std::string& name, const oscad::Position* position, EvalContext& ctx,
@@ -1623,9 +1623,17 @@ TEST(ModuleBodyCompiles, DollarArgPropagatesIntoCompiledHullWrapChildren) {
1623
1623
  // side effect to preserve).
1624
1624
  TEST(ModuleBodyCompiles, CompiledRoofUnknownMethodWarningStaysOrderedAfterChildrensOwnEcho) {
1625
1625
  ScopedVm vm(true);
1626
- EXPECT_EQ(runCapturingEcho("module m() { roof(method=\"bogus\") { echo(\"child\"); square(4, center=true); } }\n"
1627
- "m();"),
1628
- "ECHO: \"child\"\nWARNING: Unknown roof method 'bogus'. Using 'voronoi'.");
1626
+ const std::string out = runCapturingEcho(
1627
+ "module m() { roof(method=\"bogus\") { echo(\"child\"); square(4, center=true); } }\n"
1628
+ "m();");
1629
+ // Asserted as an ordering rather than one exact string: the warning also
1630
+ // carries call-site attribution (", from ... line N" plus TRACE lines,
1631
+ // see formatWarning), which is orthogonal to what this test pins.
1632
+ const size_t echoAt = out.find("ECHO: \"child\"");
1633
+ const size_t warnAt = out.find("WARNING: Unknown roof method 'bogus'. Using 'voronoi'.");
1634
+ ASSERT_NE(echoAt, std::string::npos) << out;
1635
+ ASSERT_NE(warnAt, std::string::npos) << out;
1636
+ EXPECT_LT(echoAt, warnAt) << out;
1629
1637
  }
1630
1638
 
1631
1639
  // -- intersection_for -- the TRUE last native-reentry gap, closed by -------
@@ -244,3 +244,73 @@ TEST(CsgTree, DeepNonTailChainErrorTraceStaysBoundedInsteadOfMegabytes) {
244
244
  EXPECT_LE(count, 41u); // 40 shown (20 each end, 2 lines/Module frame) + 1 marker
245
245
  }
246
246
  }
247
+
248
+ // -- Warning call-site attribution ----------------------------------------
249
+
250
+ // A warning raised inside a module reports where it happened AND which
251
+ // top-level line reached it. Without the latter, a warning from library
252
+ // code names only the library's own line, which the reader can neither act
253
+ // on nor trace back to their own script.
254
+ //
255
+ // Deliberately richer than real OpenSCAD, which prints the raising location
256
+ // alone and no trace (verified against 2022.08.22).
257
+ TEST(WarningTrace, EvalTimeWarningNamesTheTopLevelCallSite) {
258
+ std::string warning;
259
+ evalSrc("function helper(n) = n + nope;\n" // line 1: warning raised here
260
+ "module inner(v) { x = helper(v); cube(1); }\n"
261
+ "module outer(q) { inner(q); }\n"
262
+ "outer(2);\n", // line 4: the user's own line
263
+ [&](const std::string& m) { if (warning.empty()) warning = m; });
264
+
265
+ EXPECT_NE(warning.find("Ignoring unknown variable 'nope'"), std::string::npos) << warning;
266
+ EXPECT_NE(warning.find("line 1"), std::string::npos) << warning; // where it happened
267
+ EXPECT_NE(warning.find("from <string>, line 4"), std::string::npos) << warning; // who caused it
268
+ // Full chain follows, same shape as an error's trace.
269
+ EXPECT_NE(warning.find("TRACE:"), std::string::npos) << warning;
270
+ }
271
+
272
+ // A GenerateFn runs after resolve has unwound the call stack, so this case
273
+ // has no live frames to walk -- the entry position is captured onto the
274
+ // CSGNode at resolve time instead (CSGNode::warnEntry). This is the case
275
+ // that motivated the whole change: an open polyhedron() inside BOSL2 used
276
+ // to report only "BOSL2/vnf.scad, line 1624".
277
+ TEST(WarningTrace, GenerateTimeWarningNamesTheTopLevelCallSite) {
278
+ std::string warning;
279
+ evalSrc("module openbox() {\n"
280
+ " polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],\n"
281
+ " [0,0,10],[10,0,10],[10,10,10],[0,10,10]],\n"
282
+ " faces=[[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],[2,6,7,3]]);\n"
283
+ "}\n"
284
+ "openbox();\n", // line 6: the user's own line
285
+ [&](const std::string& m) { if (warning.empty()) warning = m; });
286
+
287
+ EXPECT_NE(warning.find("mesh is not closed"), std::string::npos) << warning;
288
+ EXPECT_NE(warning.find("from <string>, line 6"), std::string::npos) << warning;
289
+ }
290
+
291
+ // A warning with nothing above it stays exactly one line. The overwhelmingly
292
+ // common case, and the reason the "from" clause and TRACE are conditional --
293
+ // ordinary warnings must not sprout a trace nobody needs.
294
+ TEST(WarningTrace, TopLevelWarningStaysASingleLineWithNoTrace) {
295
+ std::string warning;
296
+ evalSrc("x = nope;\n", [&](const std::string& m) { if (warning.empty()) warning = m; });
297
+
298
+ EXPECT_NE(warning.find("Ignoring unknown variable 'nope'"), std::string::npos) << warning;
299
+ EXPECT_EQ(warning.find("TRACE:"), std::string::npos) << warning;
300
+ EXPECT_EQ(warning.find(", from "), std::string::npos) << warning;
301
+ EXPECT_EQ(warning.find('\n'), std::string::npos) << warning;
302
+ }
303
+
304
+ // The clause names the OUTERMOST frame, not the immediate caller: the
305
+ // question being answered is "which line of mine started this", and the
306
+ // intermediate frames are already in the TRACE below.
307
+ TEST(WarningTrace, FromClauseNamesOutermostFrameNotImmediateCaller) {
308
+ std::string warning;
309
+ evalSrc("module a() { y = nope; cube(1); }\n" // line 1: raised here
310
+ "module b() { a(); }\n" // line 2: immediate caller of a()
311
+ "b();\n", // line 3: the top-level entry
312
+ [&](const std::string& m) { if (warning.empty()) warning = m; });
313
+
314
+ EXPECT_NE(warning.find("from <string>, line 3"), std::string::npos) << warning;
315
+ EXPECT_EQ(warning.find("from <string>, line 2"), std::string::npos) << warning;
316
+ }