openscad-cpp-evaluator 1.8.0__tar.gz → 1.9.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.
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/bindings/module.cpp +12 -3
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +38 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/api.cpp +24 -4
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +3 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/parser.y +24 -2
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-1.9.0/external/openscad_cpp_parser/tests/test_strict_commas.cpp +117 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/python/openscad_cpp_evaluator/__init__.py +10 -2
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_python_bindings.py +37 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tools/cli/cli_lib.cpp +9 -1
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/uv.lock +0 -0
|
@@ -375,7 +375,7 @@ nb::list exportModelPy(const std::string& path, const Geometry& geom, const std:
|
|
|
375
375
|
|
|
376
376
|
nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
377
377
|
std::shared_ptr<oscadeval::ManifoldCache> manifoldCache, bool profile,
|
|
378
|
-
bool generate) {
|
|
378
|
+
bool generate, bool strictCommas) {
|
|
379
379
|
std::unordered_map<std::string, oscadeval::Value> vp = toViewportParams(viewportParams);
|
|
380
380
|
|
|
381
381
|
std::vector<oscadeval::ColoredBody> bodies;
|
|
@@ -389,6 +389,12 @@ nb::object evaluate(const std::string& path, nb::dict viewportParams,
|
|
|
389
389
|
nb::gil_scoped_release rel;
|
|
390
390
|
auto logFn = [&echoes](const std::string& m) { echoes.push_back(m); };
|
|
391
391
|
try {
|
|
392
|
+
// Constructed on the parsing thread, which is the one whose
|
|
393
|
+
// thread-local mode StrictCommaScope sets -- a flag flipped from
|
|
394
|
+
// Python before the call would sit on the wrong thread the
|
|
395
|
+
// moment a host evaluates off the main one.
|
|
396
|
+
std::optional<oscad::StrictCommaScope> strict;
|
|
397
|
+
if (strictCommas) strict.emplace();
|
|
392
398
|
oscad::ParsedProgram program = oscad::getProgramFromFile(path);
|
|
393
399
|
oscadeval::ResolvedUseScopes used = oscadeval::resolveUseScopes(program.nodes, path, logFn);
|
|
394
400
|
oscadeval::Evaluator ev(logFn, nullptr, manifoldCache, oscadeval::DebugHooks{}, profile);
|
|
@@ -801,11 +807,14 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
801
807
|
"rather than restated here, so the Python side cannot drift from what can actually be written.");
|
|
802
808
|
|
|
803
809
|
m.def("evaluate", &evaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("manifold_cache") = nullptr,
|
|
804
|
-
nb::arg("profile") = false, nb::arg("generate") = true,
|
|
810
|
+
nb::arg("profile") = false, nb::arg("generate") = true, nb::arg("strict_commas") = false,
|
|
805
811
|
"Evaluate a .scad file; return (bodies, echoes, id_to_node, csg_tree, profile_result, dyn, dyn_explicit).\n"
|
|
806
812
|
"generate=False stops after the resolve pass: the script runs and reports everything "
|
|
807
813
|
"it normally would, but no Manifold geometry is built, and neither bodies nor csg_tree "
|
|
808
|
-
"are populated
|
|
814
|
+
"are populated.\n\n"
|
|
815
|
+
"strict_commas=True makes a trailing comma in a call argument list or a let/for "
|
|
816
|
+
"assignment list a syntax error, as OpenSCAD 2021.01 did. List literals and parameter "
|
|
817
|
+
"declarations keep theirs, which 2021.01 accepted too.");
|
|
809
818
|
m.def("parse_decls", &parseDecls, nb::arg("path"),
|
|
810
819
|
"Parse a .scad file; return top-level declaration (namespace, name, start, end, line, column, origin) tuples.");
|
|
811
820
|
m.def("strip_slivers", &stripSliversPy, nb::arg("verts"), nb::arg("tris"),
|
|
@@ -60,6 +60,44 @@ std::unique_ptr<Scope> buildScopes(const std::vector<ASTNode*>& ast);
|
|
|
60
60
|
std::unique_ptr<Scope> buildScopesInto(const std::vector<std::unique_ptr<ASTNode>>& ast, ScopeTable& table);
|
|
61
61
|
std::unique_ptr<Scope> buildScopesInto(const std::vector<ASTNode*>& ast, ScopeTable& table);
|
|
62
62
|
|
|
63
|
+
// Makes a trailing comma in a CALL ARGUMENT LIST a syntax error for as long
|
|
64
|
+
// as it is in scope, matching OpenSCAD 2021.01:
|
|
65
|
+
//
|
|
66
|
+
// cube(1,); // error while this is in scope
|
|
67
|
+
// echo(let(x = 1, y = 2,) x) // error -- let() parses as a call
|
|
68
|
+
// a = [2, 4,]; // still fine: 2021.01 accepts it too
|
|
69
|
+
// module m(a, b,) {} // still fine, same reason
|
|
70
|
+
//
|
|
71
|
+
// One production (`arguments`) feeds every call form -- module
|
|
72
|
+
// instantiation, function calls, echo, assert, render and let -- so this is
|
|
73
|
+
// one rule, not a family of them. Parameter lists and list literals are
|
|
74
|
+
// deliberately untouched: 2021.01 accepts a trailing comma in both, and
|
|
75
|
+
// rejecting them would fail files it loads happily.
|
|
76
|
+
//
|
|
77
|
+
// A scope object rather than a parameter on all nine parse entry points:
|
|
78
|
+
// this is a parse-wide mode, the same shape ParseNumberingScope already
|
|
79
|
+
// uses, and threading a bool through getASTFromString/getASTFromFile/
|
|
80
|
+
// getASTFromLibraryFile/getProgramFromFile and their helpers would touch
|
|
81
|
+
// every one of them to say the same thing. Nests and restores on scope
|
|
82
|
+
// exit, exceptions included; thread-local, so one thread parsing strictly
|
|
83
|
+
// cannot change what another thread sees.
|
|
84
|
+
//
|
|
85
|
+
// getProgramFromFile()'s cache keys on this too -- a strict parse must not
|
|
86
|
+
// be handed a tree an earlier lenient parse of the same file left behind.
|
|
87
|
+
class StrictCommaScope {
|
|
88
|
+
public:
|
|
89
|
+
StrictCommaScope();
|
|
90
|
+
~StrictCommaScope();
|
|
91
|
+
StrictCommaScope(const StrictCommaScope&) = delete;
|
|
92
|
+
StrictCommaScope& operator=(const StrictCommaScope&) = delete;
|
|
93
|
+
|
|
94
|
+
private:
|
|
95
|
+
bool previous_;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Whether a StrictCommaScope is currently in effect on this thread.
|
|
99
|
+
bool strictCommasEnabled();
|
|
100
|
+
|
|
63
101
|
// Parses `code`. Throws ParseError (with the full caret diagnostic) on a
|
|
64
102
|
// syntax error.
|
|
65
103
|
//
|
|
@@ -89,6 +89,17 @@ std::string formatSyntaxError(const ParserDriver& driver, const std::string& cod
|
|
|
89
89
|
|
|
90
90
|
} // namespace
|
|
91
91
|
|
|
92
|
+
namespace {
|
|
93
|
+
// See StrictCommaScope (api.hpp). Thread-local so a strict parse on one
|
|
94
|
+
// thread cannot change what another thread is parsing.
|
|
95
|
+
thread_local bool g_strictCommas = false;
|
|
96
|
+
} // namespace
|
|
97
|
+
|
|
98
|
+
StrictCommaScope::StrictCommaScope() : previous_(g_strictCommas) { g_strictCommas = true; }
|
|
99
|
+
StrictCommaScope::~StrictCommaScope() { g_strictCommas = previous_; }
|
|
100
|
+
|
|
101
|
+
bool strictCommasEnabled() { return g_strictCommas; }
|
|
102
|
+
|
|
92
103
|
std::vector<std::unique_ptr<ASTNode>> parseAst(const std::string& code, const std::string& origin, SourceMap* sourceMap) {
|
|
93
104
|
// Stamps every node this parse builds with one treeId and a dense
|
|
94
105
|
// slot, so a ScopeTable can address it without the node carrying a
|
|
@@ -96,6 +107,7 @@ std::vector<std::unique_ptr<ASTNode>> parseAst(const std::string& code, const st
|
|
|
96
107
|
ParseNumberingScope numbering;
|
|
97
108
|
|
|
98
109
|
ParserDriver driver(origin);
|
|
110
|
+
driver.strictCommas = g_strictCommas;
|
|
99
111
|
lexerBeginString(code);
|
|
100
112
|
yy::parser parser(driver);
|
|
101
113
|
int rc = parser.parse();
|
|
@@ -258,7 +270,8 @@ namespace {
|
|
|
258
270
|
using FileAst = std::vector<std::unique_ptr<ASTNode>>;
|
|
259
271
|
using FileAstPtr = std::shared_ptr<const FileAst>;
|
|
260
272
|
|
|
261
|
-
// One entry per (file, comments) -- keyed by PATH, with the
|
|
273
|
+
// One entry per (file, comments, strict-commas) -- keyed by PATH, with the
|
|
274
|
+
// content stamp
|
|
262
275
|
// stored beside the tree rather than in the key. A stale stamp REPLACES the
|
|
263
276
|
// entry instead of adding a second one: an editor re-renders on every save,
|
|
264
277
|
// and a stamp-in-the-key cache would keep a full copy of every version the
|
|
@@ -266,11 +279,18 @@ using FileAstPtr = std::shared_ptr<const FileAst>;
|
|
|
266
279
|
struct CacheKey {
|
|
267
280
|
std::string path;
|
|
268
281
|
bool comments;
|
|
269
|
-
|
|
282
|
+
// Part of the key, not incidental: the same file parses differently
|
|
283
|
+
// under StrictCommaScope, so a strict parse must not be served a tree an
|
|
284
|
+
// earlier lenient parse of it left here (and vice versa).
|
|
285
|
+
bool strictCommas;
|
|
286
|
+
bool operator==(const CacheKey& o) const {
|
|
287
|
+
return comments == o.comments && strictCommas == o.strictCommas && path == o.path;
|
|
288
|
+
}
|
|
270
289
|
};
|
|
271
290
|
struct CacheKeyHash {
|
|
272
291
|
size_t operator()(const CacheKey& k) const {
|
|
273
|
-
return std::hash<std::string>{}(k.path) ^ (k.comments ? 0x5bf03635U : 0U)
|
|
292
|
+
return std::hash<std::string>{}(k.path) ^ (k.comments ? 0x5bf03635U : 0U)
|
|
293
|
+
^ (k.strictCommas ? 0x9e3779b9U : 0U);
|
|
274
294
|
}
|
|
275
295
|
};
|
|
276
296
|
struct CacheEntry {
|
|
@@ -290,7 +310,7 @@ FileAstPtr parseFileShared(const std::string& absPath, bool includeComments) {
|
|
|
290
310
|
const auto written = fs::last_write_time(absPath, ec);
|
|
291
311
|
const std::int64_t stampMtime = ec ? 0 : static_cast<std::int64_t>(written.time_since_epoch().count());
|
|
292
312
|
|
|
293
|
-
const CacheKey key{absPath, includeComments};
|
|
313
|
+
const CacheKey key{absPath, includeComments, g_strictCommas};
|
|
294
314
|
{
|
|
295
315
|
std::lock_guard<std::mutex> lock(g_astCacheMutex);
|
|
296
316
|
auto it = g_astCache.find(key);
|
|
@@ -39,6 +39,9 @@ public:
|
|
|
39
39
|
std::string origin_;
|
|
40
40
|
NodeList result;
|
|
41
41
|
bool hadError = false;
|
|
42
|
+
// Copied from the ambient StrictCommaScope at parse start (api.cpp), so
|
|
43
|
+
// one parse's mode cannot change under it mid-run.
|
|
44
|
+
bool strictCommas = false;
|
|
42
45
|
int errorLine = 0;
|
|
43
46
|
int errorColumn = 0;
|
|
44
47
|
int errorOffset = 0;
|
|
@@ -247,7 +247,18 @@ parameter:
|
|
|
247
247
|
arguments:
|
|
248
248
|
%empty { $$ = NodeList{}; }
|
|
249
249
|
| argument_seq { $$ = std::move($1); }
|
|
250
|
-
|
|
250
|
+
// The trailing comma OpenSCAD 2021.01 rejected. Still parsed, then
|
|
251
|
+
// reported -- @2 is the comma itself, so the caret lands on it rather
|
|
252
|
+
// than on the whole argument list, which a %expect-style grammar split
|
|
253
|
+
// could not manage. This one production feeds every call form (module
|
|
254
|
+
// instantiation, function calls, echo, assert, render, and let), which
|
|
255
|
+
// is why the whole feature is one rule. See StrictCommaScope (api.hpp).
|
|
256
|
+
| argument_seq "," {
|
|
257
|
+
if (driver.strictCommas) {
|
|
258
|
+
driver.reportError(@2, "trailing comma in argument list");
|
|
259
|
+
}
|
|
260
|
+
$$ = std::move($1);
|
|
261
|
+
}
|
|
251
262
|
;
|
|
252
263
|
|
|
253
264
|
argument_seq:
|
|
@@ -263,7 +274,18 @@ argument:
|
|
|
263
274
|
assignments_expr:
|
|
264
275
|
%empty { $$ = NodeList{}; }
|
|
265
276
|
| assignment_expr_seq { $$ = std::move($1); }
|
|
266
|
-
|
|
277
|
+
// 2021.01 rejected this one too. `let` does NOT go through `arguments`
|
|
278
|
+
// in this grammar -- it has its own assignment list, shared with `for`
|
|
279
|
+
// and `intersection_for` -- so the feature is two productions, not the
|
|
280
|
+
// one it looks like. 2021.01 rejects a trailing comma in all four:
|
|
281
|
+
// let(x=1,), for(i=[0:2],), intersection_for(i=[0:1],) and the list
|
|
282
|
+
// comprehension forms of for. See StrictCommaScope (api.hpp).
|
|
283
|
+
| assignment_expr_seq "," {
|
|
284
|
+
if (driver.strictCommas) {
|
|
285
|
+
driver.reportError(@2, "trailing comma in assignment list");
|
|
286
|
+
}
|
|
287
|
+
$$ = std::move($1);
|
|
288
|
+
}
|
|
267
289
|
;
|
|
268
290
|
|
|
269
291
|
assignment_expr_seq:
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// StrictCommaScope: a trailing comma in a call argument list is an error,
|
|
2
|
+
// matching OpenSCAD 2021.01 (BelfrySCAD issue #362).
|
|
3
|
+
//
|
|
4
|
+
// The scope is deliberately narrow. Measured against 2021.01 itself, it
|
|
5
|
+
// rejected a trailing comma in CALL ARGUMENTS and accepted one everywhere
|
|
6
|
+
// else -- list literals, list comprehensions, and module/function parameter
|
|
7
|
+
// declarations all take one, in 2021.01 as in every version since. Rejecting
|
|
8
|
+
// those would fail files 2021.01 loads happily, so they are left alone and
|
|
9
|
+
// this file says so case by case.
|
|
10
|
+
#include "test_helpers.hpp"
|
|
11
|
+
|
|
12
|
+
#include <gtest/gtest.h>
|
|
13
|
+
|
|
14
|
+
using namespace oscad;
|
|
15
|
+
|
|
16
|
+
namespace {
|
|
17
|
+
|
|
18
|
+
// Two productions carry it: `arguments` (every call form) and
|
|
19
|
+
// `assignments_expr` (let/for/intersection_for). `let` is NOT a call in this
|
|
20
|
+
// grammar -- it has its own assignment list -- which the first draft of this
|
|
21
|
+
// feature got wrong and this test caught.
|
|
22
|
+
const char* const kRejected[] = {
|
|
23
|
+
"cube(1,);", // module instantiation
|
|
24
|
+
"translate([0,0,0],) cube(1);", // ...with a child
|
|
25
|
+
"function g(x) = x; y = g(1,);", // user function call
|
|
26
|
+
"y = max(1, 2,);", // builtin function call
|
|
27
|
+
"y = str(\"a\", \"b\",);",
|
|
28
|
+
"echo(1, 2,);",
|
|
29
|
+
"assert(true, \"m\",);",
|
|
30
|
+
// assignments_expr, not arguments
|
|
31
|
+
"y = let(x = 1, y = 2,) x + y;",
|
|
32
|
+
"let(x = 1,) cube(x);",
|
|
33
|
+
"for (i = [0:2],) cube(i);",
|
|
34
|
+
"intersection_for (i = [0:1],) cube(1);",
|
|
35
|
+
"a = [for (i = [0:1],) i];",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Accepted by 2021.01, so accepted here even under the scope.
|
|
39
|
+
const char* const kAccepted[] = {
|
|
40
|
+
"a = [2, 4,];", // list literal
|
|
41
|
+
"a = [for (i = [0:2]) i,];", // list comprehension
|
|
42
|
+
"a = [each [1, 2],];",
|
|
43
|
+
"module m(a, b,) {} m(1, 2);", // module parameter declaration
|
|
44
|
+
"function f(a, b,) = a + b;", // function parameter declaration
|
|
45
|
+
"cube(1);", // no trailing comma at all
|
|
46
|
+
"y = max(1, 2);",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
} // namespace
|
|
50
|
+
|
|
51
|
+
TEST(StrictCommas, CallArgumentTrailingCommaIsAnErrorInScope) {
|
|
52
|
+
StrictCommaScope strict;
|
|
53
|
+
for (const char* src : kRejected) {
|
|
54
|
+
EXPECT_THROW(parseSrc(src), ParseError) << src;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
TEST(StrictCommas, EverythingElseKeepsItsTrailingComma) {
|
|
59
|
+
StrictCommaScope strict;
|
|
60
|
+
for (const char* src : kAccepted) {
|
|
61
|
+
EXPECT_NO_THROW(parseSrc(src)) << src;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
TEST(StrictCommas, OffByDefault) {
|
|
66
|
+
// The whole set parses without the scope -- this is opt-in, and every
|
|
67
|
+
// existing caller must be unaffected.
|
|
68
|
+
for (const char* src : kRejected) {
|
|
69
|
+
EXPECT_NO_THROW(parseSrc(src)) << src;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
TEST(StrictCommas, ScopeNestsAndRestores) {
|
|
74
|
+
EXPECT_FALSE(strictCommasEnabled());
|
|
75
|
+
{
|
|
76
|
+
StrictCommaScope outer;
|
|
77
|
+
EXPECT_TRUE(strictCommasEnabled());
|
|
78
|
+
{
|
|
79
|
+
StrictCommaScope inner;
|
|
80
|
+
EXPECT_TRUE(strictCommasEnabled());
|
|
81
|
+
}
|
|
82
|
+
EXPECT_TRUE(strictCommasEnabled()) << "an inner scope must not switch it off";
|
|
83
|
+
}
|
|
84
|
+
EXPECT_FALSE(strictCommasEnabled());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
TEST(StrictCommas, RestoresWhenAParseThrows) {
|
|
88
|
+
try {
|
|
89
|
+
StrictCommaScope strict;
|
|
90
|
+
parseSrc("cube(1,);");
|
|
91
|
+
FAIL() << "expected ParseError";
|
|
92
|
+
} catch (const ParseError&) {
|
|
93
|
+
}
|
|
94
|
+
EXPECT_FALSE(strictCommasEnabled()) << "the scope must unwind with the exception";
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
TEST(StrictCommas, TheErrorPointsAtTheComma) {
|
|
98
|
+
StrictCommaScope strict;
|
|
99
|
+
try {
|
|
100
|
+
parseSrc("cube(1,);");
|
|
101
|
+
FAIL() << "expected ParseError";
|
|
102
|
+
} catch (const ParseError& e) {
|
|
103
|
+
const std::string what = e.what();
|
|
104
|
+
EXPECT_NE(what.find("trailing comma in argument list"), std::string::npos) << what;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
TEST(StrictCommas, AnAssignmentListSaysSo) {
|
|
109
|
+
StrictCommaScope strict;
|
|
110
|
+
try {
|
|
111
|
+
parseSrc("y = let(x = 1,) x;");
|
|
112
|
+
FAIL() << "expected ParseError";
|
|
113
|
+
} catch (const ParseError& e) {
|
|
114
|
+
const std::string what = e.what();
|
|
115
|
+
EXPECT_NE(what.find("trailing comma in assignment list"), std::string::npos) << what;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -497,7 +497,7 @@ class Evaluator:
|
|
|
497
497
|
self.dyn_explicit = set()
|
|
498
498
|
|
|
499
499
|
def evaluate(self, source_path: str, viewport_params: Optional[dict] = None,
|
|
500
|
-
generate: bool = True):
|
|
500
|
+
generate: bool = True, strict_commas: bool = False):
|
|
501
501
|
"""Run `source_path` and return (bodies, id_to_node).
|
|
502
502
|
|
|
503
503
|
`generate=False` stops after the resolve pass. The script still runs
|
|
@@ -508,6 +508,13 @@ class Evaluator:
|
|
|
508
508
|
the geometry without skipping the language.
|
|
509
509
|
|
|
510
510
|
Ignored on the debugger path, which has no geometry handle anyway.
|
|
511
|
+
|
|
512
|
+
`strict_commas=True` makes a trailing comma in a call argument list
|
|
513
|
+
or a let/for assignment list a syntax error, as OpenSCAD 2021.01 did
|
|
514
|
+
-- `cube(1,)` and `let(x = 1,)`, but NOT `[2, 4,]` or
|
|
515
|
+
`module m(a, b,)`, which 2021.01 accepted. For checking a script
|
|
516
|
+
against that version; off, and no divergence from current OpenSCAD,
|
|
517
|
+
otherwise. Also ignored on the debugger path.
|
|
511
518
|
"""
|
|
512
519
|
vp = viewport_params or {}
|
|
513
520
|
try:
|
|
@@ -528,7 +535,8 @@ class Evaluator:
|
|
|
528
535
|
else:
|
|
529
536
|
(body_dicts, echoes, id_spans, csg_tree, profile_result, dyn,
|
|
530
537
|
dyn_explicit, geometry) = _ext.evaluate(
|
|
531
|
-
source_path, vp, self._manifold_cache, self._profile, generate
|
|
538
|
+
source_path, vp, self._manifold_cache, self._profile, generate,
|
|
539
|
+
strict_commas)
|
|
532
540
|
# The evaluated bodies, still on the C++ side. Stashed like
|
|
533
541
|
# csg_tree/profile_result rather than returned, so
|
|
534
542
|
# evaluate()'s own 2-tuple result is unchanged -- callers
|
|
@@ -659,3 +659,40 @@ def test_export_model_facade_accepts_split_components(tmp_path):
|
|
|
659
659
|
# Default matches OpenSCAD: one object however many pieces.
|
|
660
660
|
assert objects_in(tmp_path / "joined.3mf") == 1
|
|
661
661
|
assert objects_in(tmp_path / "split.3mf", split_components=True) == 3
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def test_strict_commas_reaches_the_parser(tmp_path):
|
|
665
|
+
"""Evaluator.evaluate(strict_commas=True) must survive both hand-written
|
|
666
|
+
parameter lists -- the facade's and the nanobind binding's. The last
|
|
667
|
+
argument added this way was dropped by the facade and no C++ test could
|
|
668
|
+
see it (see test_export_model_facade_accepts_split_components)."""
|
|
669
|
+
import pytest
|
|
670
|
+
from openscad_cpp_evaluator import Evaluator, EvalError
|
|
671
|
+
|
|
672
|
+
rejected = tmp_path / "call.scad"
|
|
673
|
+
rejected.write_text("cube(1,);\n")
|
|
674
|
+
accepted = tmp_path / "list.scad"
|
|
675
|
+
accepted.write_text("a = [2, 4,];\ncube(a[0]);\n")
|
|
676
|
+
|
|
677
|
+
# Off by default: both parse, as they do in current OpenSCAD.
|
|
678
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(rejected), {})
|
|
679
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(accepted), {})
|
|
680
|
+
|
|
681
|
+
# On: a call's trailing comma is a syntax error, a list literal's is not
|
|
682
|
+
# -- 2021.01 accepted the list.
|
|
683
|
+
with pytest.raises(EvalError):
|
|
684
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(rejected), {}, strict_commas=True)
|
|
685
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(accepted), {}, strict_commas=True)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def test_strict_commas_does_not_leak_between_evaluations(tmp_path):
|
|
689
|
+
"""The parser mode is a scope object; a strict parse must not leave it on
|
|
690
|
+
for the next caller."""
|
|
691
|
+
import pytest
|
|
692
|
+
from openscad_cpp_evaluator import Evaluator, EvalError
|
|
693
|
+
|
|
694
|
+
src = tmp_path / "call.scad"
|
|
695
|
+
src.write_text("cube(1,);\n")
|
|
696
|
+
with pytest.raises(EvalError):
|
|
697
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(src), {}, strict_commas=True)
|
|
698
|
+
Evaluator(echo_fn=lambda _m: None).evaluate(str(src), {}) # must not raise
|
|
@@ -222,6 +222,7 @@ int runCli(const std::vector<std::string>& args, std::istream& in, std::ostream&
|
|
|
222
222
|
std::string profileMinSelfStr;
|
|
223
223
|
std::string profileMinCallsStr;
|
|
224
224
|
bool debug = false;
|
|
225
|
+
bool strictCommas = false;
|
|
225
226
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
226
227
|
const std::string& arg = args[i];
|
|
227
228
|
if (arg == "-o" && i + 1 < args.size()) {
|
|
@@ -242,6 +243,8 @@ int runCli(const std::vector<std::string>& args, std::istream& in, std::ostream&
|
|
|
242
243
|
profileMinCallsStr = args[++i];
|
|
243
244
|
} else if (arg == "--debug") {
|
|
244
245
|
debug = true;
|
|
246
|
+
} else if (arg == "--strict-commas") {
|
|
247
|
+
strictCommas = true;
|
|
245
248
|
} else if (inputPath.empty()) {
|
|
246
249
|
inputPath = arg;
|
|
247
250
|
}
|
|
@@ -249,7 +252,7 @@ int runCli(const std::vector<std::string>& args, std::istream& in, std::ostream&
|
|
|
249
252
|
if (inputPath.empty() || outputPath.empty()) {
|
|
250
253
|
err << "usage: openscad-cpp-evaluator <input.scad> -o <output.{stl,obj,off,3mf,ply,wrl,x3d}> [--format stl|obj|off|3mf|ply|wrl|x3d] [--ascii-stl] "
|
|
251
254
|
"[--profile FILENAME [--profile-format text|csv] [--profile-sort self|cumulative|calls|name] "
|
|
252
|
-
"[--profile-min-self SECONDS] [--profile-min-calls N]] [--debug]\n";
|
|
255
|
+
"[--profile-min-self SECONDS] [--profile-min-calls N]] [--debug] [--strict-commas]\n";
|
|
253
256
|
return 1;
|
|
254
257
|
}
|
|
255
258
|
const std::string fmt = formatForPath(format, outputPath);
|
|
@@ -293,6 +296,11 @@ int runCli(const std::vector<std::string>& args, std::istream& in, std::ostream&
|
|
|
293
296
|
}
|
|
294
297
|
|
|
295
298
|
try {
|
|
299
|
+
// Scoped to the parse: a trailing comma in a call argument list or a
|
|
300
|
+
// let/for assignment list is a syntax error while it is in effect,
|
|
301
|
+
// as OpenSCAD 2021.01 had it. See oscad::StrictCommaScope.
|
|
302
|
+
std::optional<oscad::StrictCommaScope> strict;
|
|
303
|
+
if (strictCommas) strict.emplace();
|
|
296
304
|
std::vector<std::unique_ptr<oscad::ASTNode>> ast = oscad::getASTFromFile(inputPath);
|
|
297
305
|
ResolvedUseScopes used = resolveUseScopes(ast, inputPath, [&out](const std::string& msg) { out << msg << "\n"; });
|
|
298
306
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.8.0 → openscad_cpp_evaluator-1.9.0}/external/openscad_cpp_parser/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|