openscad-cpp-evaluator 0.14.0__tar.gz → 0.16.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-0.14.0 → openscad_cpp_evaluator-0.16.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/bindings/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-0.16.0/bindings/ast_to_py.cpp +326 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/bindings/module.cpp +23 -3
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/colored_body.hpp +21 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/evaluator.hpp +12 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/python/openscad_cpp_evaluator/__init__.py +36 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/booleans.cpp +15 -2
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/builtins.hpp +13 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/import.cpp +33 -24
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/primitives_3d.cpp +64 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/topology.cpp +2 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/csg_generate.cpp +23 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_import_export.cpp +8 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_primitives.cpp +92 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_python_bindings.py +116 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.16.0}/uv.lock +0 -0
|
@@ -15,6 +15,7 @@ find_package(nanobind CONFIG REQUIRED)
|
|
|
15
15
|
# from-source Manifold/Boost rebuild per interpreter in CI.
|
|
16
16
|
nanobind_add_module(_openscad_cpp_evaluator NB_STATIC STABLE_ABI
|
|
17
17
|
module.cpp
|
|
18
|
+
ast_to_py.cpp
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
# The static evaluator lib PUBLIC-links parser + manifold + Boost::polygon,
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// Snapshots the parser's AST into plain Python dicts.
|
|
2
|
+
//
|
|
3
|
+
// Deliberately a COPY rather than wrappers around live ASTNode pointers.
|
|
4
|
+
// The tree is owned by a `std::vector<std::unique_ptr<ASTNode>>` local to
|
|
5
|
+
// whichever binding parsed it, and dies when that call returns; handing
|
|
6
|
+
// Python raw pointers into it would be a use-after-free the moment anything
|
|
7
|
+
// outlived the call, and this project has already shipped one dangling
|
|
8
|
+
// pointer of exactly that shape (the bodyCtx bug fixed in v0.13.1). It also
|
|
9
|
+
// sidesteps the threading problem entirely -- a render worker thread can
|
|
10
|
+
// parse, hand the snapshot to the GUI thread, and exit, with nothing shared.
|
|
11
|
+
//
|
|
12
|
+
// The cost is one walk plus allocation per parse. That is affordable
|
|
13
|
+
// because callers ask for this explicitly (parse_ast()), not on the render
|
|
14
|
+
// path, which never needs it.
|
|
15
|
+
//
|
|
16
|
+
// Every node dict carries at least:
|
|
17
|
+
// kind -- str, the NodeKind name ("NumberLiteral", "ModularCall", ...)
|
|
18
|
+
// position -- dict(origin, line, column, start_offset, end_offset)
|
|
19
|
+
// plus that kind's own fields, named in snake_case. Child nodes are nested
|
|
20
|
+
// dicts; child lists are lists of dicts; an absent optional child is None.
|
|
21
|
+
//
|
|
22
|
+
// `position.start_offset`/`end_offset` are the point of the whole exercise:
|
|
23
|
+
// they let a caller recover the ORIGINAL source text of any subexpression
|
|
24
|
+
// and reuse it verbatim, rather than re-serialising a parsed value and
|
|
25
|
+
// losing how the author wrote it (1.500 -> 1.5, 1e3 -> 1000).
|
|
26
|
+
|
|
27
|
+
#include "openscad_cpp_parser/api.hpp"
|
|
28
|
+
#include "openscad_cpp_parser/ast/ast_node.hpp"
|
|
29
|
+
#include "openscad_cpp_parser/ast/comments.hpp"
|
|
30
|
+
#include "openscad_cpp_parser/ast/declarations.hpp"
|
|
31
|
+
#include "openscad_cpp_parser/ast/expression.hpp"
|
|
32
|
+
#include "openscad_cpp_parser/ast/module_instantiation.hpp"
|
|
33
|
+
#include "openscad_cpp_parser/ast/vector_element.hpp"
|
|
34
|
+
|
|
35
|
+
#include <nanobind/nanobind.h>
|
|
36
|
+
#include <nanobind/stl/string.h>
|
|
37
|
+
|
|
38
|
+
#include <memory>
|
|
39
|
+
#include <vector>
|
|
40
|
+
|
|
41
|
+
namespace nb = nanobind;
|
|
42
|
+
|
|
43
|
+
namespace oscadbind {
|
|
44
|
+
|
|
45
|
+
namespace {
|
|
46
|
+
|
|
47
|
+
nb::dict positionToPy(const oscad::Position& p) {
|
|
48
|
+
nb::dict d;
|
|
49
|
+
// origin is "" for the main file (matching how the evaluator reports
|
|
50
|
+
// it); left as-is rather than mapped to None, so a caller can compare
|
|
51
|
+
// it against a path without a null check.
|
|
52
|
+
d["origin"] = p.origin;
|
|
53
|
+
d["line"] = p.line;
|
|
54
|
+
d["column"] = p.column;
|
|
55
|
+
d["start_offset"] = p.start_offset;
|
|
56
|
+
d["end_offset"] = p.end_offset;
|
|
57
|
+
return d;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
nb::object nodeToPy(const oscad::ASTNode* n);
|
|
61
|
+
|
|
62
|
+
// A null unique_ptr child (e.g. a parameter with no default) becomes None
|
|
63
|
+
// rather than being omitted, so a consumer can index the key unconditionally.
|
|
64
|
+
template <typename T>
|
|
65
|
+
nb::object childToPy(const std::unique_ptr<T>& p) {
|
|
66
|
+
return p ? nodeToPy(p.get()) : nb::none();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
template <typename T>
|
|
70
|
+
nb::list listToPy(const std::vector<std::unique_ptr<T>>& v) {
|
|
71
|
+
nb::list out;
|
|
72
|
+
for (const std::unique_ptr<T>& item : v) out.append(nodeToPy(item.get()));
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
nb::dict baseDict(const oscad::ASTNode* n) {
|
|
77
|
+
nb::dict d;
|
|
78
|
+
d["kind"] = oscad::nodeKindName(n->kind());
|
|
79
|
+
d["position"] = positionToPy(n->position());
|
|
80
|
+
return d;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
nb::object nodeToPy(const oscad::ASTNode* n) {
|
|
84
|
+
if (n == nullptr) return nb::none();
|
|
85
|
+
nb::dict d = baseDict(n);
|
|
86
|
+
|
|
87
|
+
// kind() is authoritative about the concrete type (every leaf class sets
|
|
88
|
+
// its own), so static_cast is safe here and avoids a dynamic_cast per
|
|
89
|
+
// node on what is already an allocation-heavy walk.
|
|
90
|
+
#define OSC_NODE(KindName, Type) case oscad::NodeKind::KindName: { const auto* x = static_cast<const oscad::Type*>(n); (void)x;
|
|
91
|
+
#define OSC_END break; }
|
|
92
|
+
|
|
93
|
+
switch (n->kind()) {
|
|
94
|
+
// -- comments ---------------------------------------------------
|
|
95
|
+
OSC_NODE(CommentLine, CommentLine) d["text"] = x->text; OSC_END
|
|
96
|
+
OSC_NODE(BlankLine, BlankLine) OSC_END
|
|
97
|
+
OSC_NODE(CommentSpan, CommentSpan) d["text"] = x->text; OSC_END
|
|
98
|
+
OSC_NODE(CommentedExpr, CommentedExpr)
|
|
99
|
+
d["leading_comments"] = listToPy(x->leadingComments);
|
|
100
|
+
d["trailing_comments"] = listToPy(x->trailingComments);
|
|
101
|
+
d["expr"] = childToPy(x->expr);
|
|
102
|
+
OSC_END
|
|
103
|
+
|
|
104
|
+
// -- primaries / literals ---------------------------------------
|
|
105
|
+
OSC_NODE(Identifier, Identifier) d["name"] = x->name; OSC_END
|
|
106
|
+
// `val` is the DECODED string minus its quotes; escape sequences
|
|
107
|
+
// are kept raw (a source \n stays two characters). Use the span to
|
|
108
|
+
// recover exactly what was written.
|
|
109
|
+
OSC_NODE(StringLiteral, StringLiteral) d["val"] = x->val; OSC_END
|
|
110
|
+
// Parsed to double, so the source spelling (1.500, 1e3, 0x10) is
|
|
111
|
+
// NOT recoverable from here -- that is what the span is for.
|
|
112
|
+
OSC_NODE(NumberLiteral, NumberLiteral) d["val"] = x->val; OSC_END
|
|
113
|
+
OSC_NODE(BooleanLiteral, BooleanLiteral) d["val"] = x->val; OSC_END
|
|
114
|
+
OSC_NODE(UndefinedLiteral, UndefinedLiteral) OSC_END
|
|
115
|
+
OSC_NODE(RangeLiteral, RangeLiteral)
|
|
116
|
+
d["start"] = childToPy(x->start);
|
|
117
|
+
d["end"] = childToPy(x->end);
|
|
118
|
+
// Never null: the parser defaults an omitted step to 1.
|
|
119
|
+
d["step"] = childToPy(x->step);
|
|
120
|
+
OSC_END
|
|
121
|
+
|
|
122
|
+
// -- declarations / arguments -----------------------------------
|
|
123
|
+
OSC_NODE(ParameterDeclaration, ParameterDeclaration)
|
|
124
|
+
d["name"] = childToPy(x->name);
|
|
125
|
+
d["default_value"] = childToPy(x->defaultValue); // nullable
|
|
126
|
+
d["leading_comments"] = listToPy(x->leadingComments);
|
|
127
|
+
d["trailing_comments"] = listToPy(x->trailingComments);
|
|
128
|
+
OSC_END
|
|
129
|
+
OSC_NODE(PositionalArgument, PositionalArgument) d["expr"] = childToPy(x->expr); OSC_END
|
|
130
|
+
OSC_NODE(NamedArgument, NamedArgument)
|
|
131
|
+
d["name"] = childToPy(x->name);
|
|
132
|
+
d["expr"] = childToPy(x->expr);
|
|
133
|
+
OSC_END
|
|
134
|
+
OSC_NODE(Assignment, Assignment)
|
|
135
|
+
d["name"] = childToPy(x->name);
|
|
136
|
+
d["expr"] = childToPy(x->expr);
|
|
137
|
+
OSC_END
|
|
138
|
+
|
|
139
|
+
// -- prefix expression forms ------------------------------------
|
|
140
|
+
OSC_NODE(LetOp, LetOp)
|
|
141
|
+
d["assignments"] = listToPy(x->assignments);
|
|
142
|
+
d["body"] = childToPy(x->body);
|
|
143
|
+
OSC_END
|
|
144
|
+
OSC_NODE(EchoOp, EchoOp)
|
|
145
|
+
d["arguments"] = listToPy(x->arguments);
|
|
146
|
+
d["body"] = childToPy(x->body);
|
|
147
|
+
OSC_END
|
|
148
|
+
OSC_NODE(AssertOp, AssertOp)
|
|
149
|
+
d["arguments"] = listToPy(x->arguments);
|
|
150
|
+
d["body"] = childToPy(x->body);
|
|
151
|
+
OSC_END
|
|
152
|
+
OSC_NODE(FunctionLiteral, FunctionLiteral)
|
|
153
|
+
d["parameters"] = listToPy(x->parameters);
|
|
154
|
+
d["body"] = childToPy(x->body);
|
|
155
|
+
OSC_END
|
|
156
|
+
|
|
157
|
+
// -- unary operators --------------------------------------------
|
|
158
|
+
#define OSC_UNARY(KindName) OSC_NODE(KindName, KindName) d["expr"] = childToPy(x->expr); OSC_END
|
|
159
|
+
OSC_UNARY(UnaryMinusOp)
|
|
160
|
+
OSC_UNARY(LogicalNotOp)
|
|
161
|
+
OSC_UNARY(BitwiseNotOp)
|
|
162
|
+
#undef OSC_UNARY
|
|
163
|
+
|
|
164
|
+
// -- binary operators -------------------------------------------
|
|
165
|
+
#define OSC_BINARY(KindName) \
|
|
166
|
+
OSC_NODE(KindName, KindName) d["left"] = childToPy(x->left); d["right"] = childToPy(x->right); OSC_END
|
|
167
|
+
OSC_BINARY(AdditionOp)
|
|
168
|
+
OSC_BINARY(SubtractionOp)
|
|
169
|
+
OSC_BINARY(MultiplicationOp)
|
|
170
|
+
OSC_BINARY(DivisionOp)
|
|
171
|
+
OSC_BINARY(ModuloOp)
|
|
172
|
+
OSC_BINARY(ExponentOp)
|
|
173
|
+
OSC_BINARY(BitwiseAndOp)
|
|
174
|
+
OSC_BINARY(BitwiseOrOp)
|
|
175
|
+
OSC_BINARY(BitwiseShiftLeftOp)
|
|
176
|
+
OSC_BINARY(BitwiseShiftRightOp)
|
|
177
|
+
OSC_BINARY(LogicalAndOp)
|
|
178
|
+
OSC_BINARY(LogicalOrOp)
|
|
179
|
+
OSC_BINARY(EqualityOp)
|
|
180
|
+
OSC_BINARY(InequalityOp)
|
|
181
|
+
OSC_BINARY(GreaterThanOp)
|
|
182
|
+
OSC_BINARY(GreaterThanOrEqualOp)
|
|
183
|
+
OSC_BINARY(LessThanOp)
|
|
184
|
+
OSC_BINARY(LessThanOrEqualOp)
|
|
185
|
+
#undef OSC_BINARY
|
|
186
|
+
|
|
187
|
+
OSC_NODE(TernaryOp, TernaryOp)
|
|
188
|
+
d["condition"] = childToPy(x->condition);
|
|
189
|
+
d["true_expr"] = childToPy(x->trueExpr);
|
|
190
|
+
d["false_expr"] = childToPy(x->falseExpr);
|
|
191
|
+
OSC_END
|
|
192
|
+
|
|
193
|
+
// -- postfix ----------------------------------------------------
|
|
194
|
+
OSC_NODE(PrimaryCall, PrimaryCall)
|
|
195
|
+
d["left"] = childToPy(x->left);
|
|
196
|
+
d["arguments"] = listToPy(x->arguments);
|
|
197
|
+
OSC_END
|
|
198
|
+
OSC_NODE(PrimaryIndex, PrimaryIndex)
|
|
199
|
+
d["left"] = childToPy(x->left);
|
|
200
|
+
d["index"] = childToPy(x->index);
|
|
201
|
+
OSC_END
|
|
202
|
+
OSC_NODE(PrimaryMember, PrimaryMember)
|
|
203
|
+
d["left"] = childToPy(x->left);
|
|
204
|
+
d["member"] = childToPy(x->member);
|
|
205
|
+
OSC_END
|
|
206
|
+
|
|
207
|
+
// -- list comprehension clauses ---------------------------------
|
|
208
|
+
OSC_NODE(ListCompLet, ListCompLet)
|
|
209
|
+
d["assignments"] = listToPy(x->assignments);
|
|
210
|
+
d["body"] = childToPy(x->body);
|
|
211
|
+
OSC_END
|
|
212
|
+
OSC_NODE(ListCompEach, ListCompEach) d["body"] = childToPy(x->body); OSC_END
|
|
213
|
+
OSC_NODE(ListCompFor, ListCompFor)
|
|
214
|
+
d["assignments"] = listToPy(x->assignments);
|
|
215
|
+
d["body"] = childToPy(x->body);
|
|
216
|
+
OSC_END
|
|
217
|
+
OSC_NODE(ListCompCFor, ListCompCFor)
|
|
218
|
+
d["inits"] = listToPy(x->inits);
|
|
219
|
+
d["condition"] = childToPy(x->condition);
|
|
220
|
+
d["incrs"] = listToPy(x->incrs);
|
|
221
|
+
d["body"] = childToPy(x->body);
|
|
222
|
+
OSC_END
|
|
223
|
+
OSC_NODE(ListCompIf, ListCompIf)
|
|
224
|
+
d["condition"] = childToPy(x->condition);
|
|
225
|
+
d["true_expr"] = childToPy(x->trueExpr);
|
|
226
|
+
OSC_END
|
|
227
|
+
OSC_NODE(ListCompIfElse, ListCompIfElse)
|
|
228
|
+
d["condition"] = childToPy(x->condition);
|
|
229
|
+
d["true_expr"] = childToPy(x->trueExpr);
|
|
230
|
+
d["false_expr"] = childToPy(x->falseExpr);
|
|
231
|
+
OSC_END
|
|
232
|
+
// Also how a plain vector literal ([1,2,3]) is represented --
|
|
233
|
+
// elements mix comprehension clauses and bare expressions.
|
|
234
|
+
OSC_NODE(ListComprehension, ListComprehension) d["elements"] = listToPy(x->elements); OSC_END
|
|
235
|
+
|
|
236
|
+
// -- module instantiation ---------------------------------------
|
|
237
|
+
OSC_NODE(ModularCall, ModularCall)
|
|
238
|
+
d["name"] = childToPy(x->name);
|
|
239
|
+
d["arguments"] = listToPy(x->arguments);
|
|
240
|
+
d["children"] = listToPy(x->children);
|
|
241
|
+
OSC_END
|
|
242
|
+
OSC_NODE(ModularFor, ModularFor)
|
|
243
|
+
d["assignments"] = listToPy(x->assignments);
|
|
244
|
+
d["body"] = listToPy(x->body);
|
|
245
|
+
OSC_END
|
|
246
|
+
OSC_NODE(ModularIntersectionFor, ModularIntersectionFor)
|
|
247
|
+
d["assignments"] = listToPy(x->assignments);
|
|
248
|
+
d["body"] = listToPy(x->body);
|
|
249
|
+
OSC_END
|
|
250
|
+
OSC_NODE(ModularLet, ModularLet)
|
|
251
|
+
d["assignments"] = listToPy(x->assignments);
|
|
252
|
+
d["children"] = listToPy(x->children);
|
|
253
|
+
OSC_END
|
|
254
|
+
OSC_NODE(ModularEcho, ModularEcho)
|
|
255
|
+
d["arguments"] = listToPy(x->arguments);
|
|
256
|
+
d["children"] = listToPy(x->children);
|
|
257
|
+
OSC_END
|
|
258
|
+
OSC_NODE(ModularAssert, ModularAssert)
|
|
259
|
+
d["arguments"] = listToPy(x->arguments);
|
|
260
|
+
d["children"] = listToPy(x->children);
|
|
261
|
+
OSC_END
|
|
262
|
+
OSC_NODE(ModularIf, ModularIf)
|
|
263
|
+
d["condition"] = childToPy(x->condition);
|
|
264
|
+
d["true_branch"] = listToPy(x->trueBranch);
|
|
265
|
+
OSC_END
|
|
266
|
+
OSC_NODE(ModularIfElse, ModularIfElse)
|
|
267
|
+
d["condition"] = childToPy(x->condition);
|
|
268
|
+
d["true_branch"] = listToPy(x->trueBranch);
|
|
269
|
+
d["false_branch"] = listToPy(x->falseBranch);
|
|
270
|
+
OSC_END
|
|
271
|
+
|
|
272
|
+
// -- modifier wrappers (! # % *) --------------------------------
|
|
273
|
+
#define OSC_MODIFIER(KindName) OSC_NODE(KindName, KindName) d["child"] = childToPy(x->child); OSC_END
|
|
274
|
+
OSC_MODIFIER(ModularModifierShowOnly)
|
|
275
|
+
OSC_MODIFIER(ModularModifierHighlight)
|
|
276
|
+
OSC_MODIFIER(ModularModifierBackground)
|
|
277
|
+
OSC_MODIFIER(ModularModifierDisable)
|
|
278
|
+
#undef OSC_MODIFIER
|
|
279
|
+
|
|
280
|
+
// -- top-level declarations -------------------------------------
|
|
281
|
+
OSC_NODE(ModuleDeclaration, ModuleDeclaration)
|
|
282
|
+
d["name"] = childToPy(x->name);
|
|
283
|
+
d["parameters"] = listToPy(x->parameters);
|
|
284
|
+
d["children"] = listToPy(x->children);
|
|
285
|
+
d["pre_name_comments"] = listToPy(x->preNameComments);
|
|
286
|
+
d["post_name_comments"] = listToPy(x->postNameComments);
|
|
287
|
+
d["post_params_comments"] = listToPy(x->postParamsComments);
|
|
288
|
+
OSC_END
|
|
289
|
+
OSC_NODE(FunctionDeclaration, FunctionDeclaration)
|
|
290
|
+
d["name"] = childToPy(x->name);
|
|
291
|
+
d["parameters"] = listToPy(x->parameters);
|
|
292
|
+
d["expr"] = childToPy(x->expr);
|
|
293
|
+
d["pre_name_comments"] = listToPy(x->preNameComments);
|
|
294
|
+
d["post_name_comments"] = listToPy(x->postNameComments);
|
|
295
|
+
d["post_params_comments"] = listToPy(x->postParamsComments);
|
|
296
|
+
OSC_END
|
|
297
|
+
OSC_NODE(UseStatement, UseStatement) d["filepath"] = childToPy(x->filepath); OSC_END
|
|
298
|
+
OSC_NODE(IncludeStatement, IncludeStatement) d["filepath"] = childToPy(x->filepath); OSC_END
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
#undef OSC_NODE
|
|
302
|
+
#undef OSC_END
|
|
303
|
+
|
|
304
|
+
// No default: above -- the switch is exhaustive over NodeKind, so
|
|
305
|
+
// adding a node kind to the parser without handling it here is a
|
|
306
|
+
// compiler warning rather than a silently field-less dict.
|
|
307
|
+
return d;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
} // namespace
|
|
311
|
+
|
|
312
|
+
nb::list astToPy(const std::vector<std::unique_ptr<oscad::ASTNode>>& ast) {
|
|
313
|
+
nb::list out;
|
|
314
|
+
for (const std::unique_ptr<oscad::ASTNode>& n : ast) out.append(nodeToPy(n.get()));
|
|
315
|
+
return out;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
nb::list parseAstFromFile(const std::string& path, bool includeComments) {
|
|
319
|
+
return astToPy(oscad::getASTFromFile(path, includeComments));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
nb::list parseAstFromString(const std::string& code, bool includeComments) {
|
|
323
|
+
return astToPy(oscad::getASTFromString(code, includeComments));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
} // namespace oscadbind
|
|
@@ -40,6 +40,14 @@
|
|
|
40
40
|
|
|
41
41
|
namespace nb = nanobind;
|
|
42
42
|
|
|
43
|
+
// Defined in ast_to_py.cpp -- snapshots the parser's AST into plain Python
|
|
44
|
+
// dicts. Declared here rather than in a header since these two entry points
|
|
45
|
+
// are the whole interface and only this file calls them.
|
|
46
|
+
namespace oscadbind {
|
|
47
|
+
nb::list parseAstFromFile(const std::string& path, bool includeComments);
|
|
48
|
+
nb::list parseAstFromString(const std::string& code, bool includeComments);
|
|
49
|
+
} // namespace oscadbind
|
|
50
|
+
|
|
43
51
|
namespace {
|
|
44
52
|
|
|
45
53
|
// Moves a std::vector's storage into a NumPy array that owns it via a
|
|
@@ -129,7 +137,11 @@ const char* roleToString(oscadeval::BodyRole role) {
|
|
|
129
137
|
// tri_verts (nTri, 3), run_original_id (nRun,), run_index (nRun+1,) -- the
|
|
130
138
|
// same flat 3*triangle units manifold3d's own run_index uses).
|
|
131
139
|
nb::dict bodyToDict(oscadeval::ColoredBody& cb) {
|
|
132
|
-
|
|
140
|
+
// A display-only body's Manifold is empty by construction, so its
|
|
141
|
+
// GetMeshGL() would hand back nothing -- take the raw triangle soup
|
|
142
|
+
// that failed to build instead. Everything downstream reads plain
|
|
143
|
+
// arrays, so the two cases are indistinguishable from here on.
|
|
144
|
+
manifold::MeshGL mesh = cb.isDisplayOnly() ? *cb.rawMesh : cb.body->GetMeshGL();
|
|
133
145
|
const size_t numProp = mesh.numProp;
|
|
134
146
|
const size_t numVert = numProp ? mesh.vertProperties.size() / numProp : 0;
|
|
135
147
|
const size_t numTri = mesh.triVerts.size() / 3;
|
|
@@ -184,7 +196,9 @@ void collectIdSpans(const oscadeval::Evaluator& ev, std::vector<IdSpan>& out) {
|
|
|
184
196
|
nb::list bodiesToList(std::vector<oscadeval::ColoredBody>& bodies) {
|
|
185
197
|
nb::list out;
|
|
186
198
|
for (oscadeval::ColoredBody& cb : bodies) {
|
|
187
|
-
|
|
199
|
+
// isDisplayOnly() bodies are ALWAYS IsEmpty() -- that's what made
|
|
200
|
+
// an open polyhedron() silently vanish here rather than render.
|
|
201
|
+
if (!cb.isDisplayOnly() && (!cb.body || cb.body->IsEmpty())) continue;
|
|
188
202
|
out.append(bodyToDict(cb));
|
|
189
203
|
}
|
|
190
204
|
return out;
|
|
@@ -210,7 +224,7 @@ nb::object csgNodeToPy(const oscadeval::CSGNode& node) {
|
|
|
210
224
|
for (const auto& [k, v] : node.params) params[nb::str(k.c_str())] = valueToPy(v);
|
|
211
225
|
nb::list bodies;
|
|
212
226
|
for (const oscadeval::ColoredBody& cb : node.bodies) {
|
|
213
|
-
if (!cb.body || cb.body->IsEmpty()) continue;
|
|
227
|
+
if (!cb.isDisplayOnly() && (!cb.body || cb.body->IsEmpty())) continue;
|
|
214
228
|
// ColoredBody here is const in this walk (tree ownership stays with
|
|
215
229
|
// the caller) -- GetMeshGL() itself is logically read-only, so a
|
|
216
230
|
// const_cast here is safe/local, mirroring bodyToDict's mutating
|
|
@@ -643,6 +657,12 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
643
657
|
"Evaluate a .scad file; return (bodies, echoes, id_to_node, csg_tree, profile_result, dyn, dyn_explicit).");
|
|
644
658
|
m.def("parse_decls", &parseDecls, nb::arg("path"),
|
|
645
659
|
"Parse a .scad file; return top-level declaration (namespace, name, start, end, line, column, origin) tuples.");
|
|
660
|
+
m.def("parse_ast", &oscadbind::parseAstFromFile, nb::arg("path"), nb::arg("include_comments") = false,
|
|
661
|
+
"Parse a .scad file; return the AST as a list of plain nested dicts "
|
|
662
|
+
"(kind, position, plus that kind's own fields). A snapshot, not a view -- "
|
|
663
|
+
"safe to keep, share across threads, and outlive the parse.");
|
|
664
|
+
m.def("parse_ast_string", &oscadbind::parseAstFromString, nb::arg("code"), nb::arg("include_comments") = false,
|
|
665
|
+
"As parse_ast(), but parses a source string instead of a file.");
|
|
646
666
|
m.def("debug_evaluate", &debugEvaluate, nb::arg("path"), nb::arg("viewport_params"), nb::arg("debug_hook"),
|
|
647
667
|
nb::arg("error_break"), nb::arg("echo_fn"), nb::arg("manifold_cache") = nullptr,
|
|
648
668
|
nb::arg("return_hook") = nb::none(), nb::arg("fast_continue_signal") = nullptr,
|
|
@@ -26,6 +26,27 @@ struct ColoredBody {
|
|
|
26
26
|
bool flatPreview = false;
|
|
27
27
|
BodyRole role = BodyRole::Normal;
|
|
28
28
|
std::optional<std::vector<std::array<float, 4>>> triColors; // per-triangle RGBA, multi-color CSG merges only
|
|
29
|
+
|
|
30
|
+
// Set ONLY when a mesh could not be built into a valid Manifold -- in
|
|
31
|
+
// practice a polyhedron() whose faces don't close the surface (it has
|
|
32
|
+
// boundary edges), which Manifold reports by returning an *empty* body
|
|
33
|
+
// with Status() == NotManifold rather than by failing. Note the status
|
|
34
|
+
// name is misleading: a closed mesh with reversed winding, non-manifold
|
|
35
|
+
// vertices or self-intersections builds fine; only an OPEN one lands
|
|
36
|
+
// here.
|
|
37
|
+
//
|
|
38
|
+
// Carrying the raw triangle soup alongside lets the renderer still draw
|
|
39
|
+
// what the script described, which is far more use for spotting the
|
|
40
|
+
// missing face than an empty viewport. `body` is deliberately left set
|
|
41
|
+
// (and empty), so every existing `cb.body->...` path keeps working.
|
|
42
|
+
//
|
|
43
|
+
// Such a body is display-only: it can never take part in a CSG
|
|
44
|
+
// operation, since there is no Manifold for Manifold to operate on.
|
|
45
|
+
// splitByRole() pulls it aside much as it does a `%` background body,
|
|
46
|
+
// and the CSG/hull/minkowski generators re-join it unchanged.
|
|
47
|
+
std::optional<manifold::MeshGL> rawMesh;
|
|
48
|
+
|
|
49
|
+
bool isDisplayOnly() const { return rawMesh.has_value(); }
|
|
29
50
|
};
|
|
30
51
|
|
|
31
52
|
// `EvalContext::color`/CSGParams round-trip: a resolve function reads
|
|
@@ -236,6 +236,18 @@ public:
|
|
|
236
236
|
// comment for why that reference exists at all).
|
|
237
237
|
ColoredBody tagGenerated(manifold::Manifold body, const oscad::ASTNode& node, const Value& colorValue);
|
|
238
238
|
|
|
239
|
+
// tagGenerated()'s counterpart for a mesh Manifold refused to build --
|
|
240
|
+
// an open polyhedron(). Returns a display-only ColoredBody (see
|
|
241
|
+
// ColoredBody::rawMesh) carrying the triangle soup as-is, so it can
|
|
242
|
+
// still be drawn even though no CSG operation can ever touch it.
|
|
243
|
+
//
|
|
244
|
+
// A failed Manifold has no run IDs of its own, so one is reserved here
|
|
245
|
+
// and written onto the raw mesh -- otherwise the body would be
|
|
246
|
+
// invisible to selection and to the originalID -> AST node mapping
|
|
247
|
+
// that drives click-to-source, which is exactly when a user most wants
|
|
248
|
+
// to click the broken thing and be shown the line that made it.
|
|
249
|
+
ColoredBody tagDisplayOnly(manifold::MeshGL mesh, const oscad::ASTNode& node, const Value& colorValue);
|
|
250
|
+
|
|
239
251
|
// Raises an OpenSCAD-level runtime error: throws EvalError with the
|
|
240
252
|
// formatted "ERROR: {msg}{TRACE lines}" message (see eval_error.hpp),
|
|
241
253
|
// walking the real user function/module call stack for the TRACE lines
|
|
@@ -18,7 +18,7 @@ from ._openscad_cpp_evaluator import FastContinueSignal, ManifoldCache
|
|
|
18
18
|
__all__ = [
|
|
19
19
|
"Evaluator", "ColoredBody", "EvalError", "ParseError", "OscObject", "parse", "to_renderable_bodies",
|
|
20
20
|
"ManifoldCache", "CallSiteProfile", "ProfileResult", "format_csg_tree", "bodies_from_dicts",
|
|
21
|
-
"FastContinueSignal",
|
|
21
|
+
"FastContinueSignal", "parse_ast", "parse_ast_string",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
|
|
@@ -256,6 +256,41 @@ def parse(path: str) -> RootScope:
|
|
|
256
256
|
return RootScope(decls)
|
|
257
257
|
|
|
258
258
|
|
|
259
|
+
def parse_ast(path: str, include_comments: bool = False) -> list:
|
|
260
|
+
"""Parse a .scad file; return its AST as a list of plain nested dicts.
|
|
261
|
+
|
|
262
|
+
Each node is `{"kind": str, "position": {...}, **fields}`, where fields
|
|
263
|
+
are that kind's own (e.g. NumberLiteral has "val"; ModularCall has
|
|
264
|
+
"name"/"arguments"/"children"). Child nodes nest as dicts, child lists
|
|
265
|
+
as lists, and an absent optional child is None.
|
|
266
|
+
|
|
267
|
+
`position` carries `start_offset`/`end_offset`, which is the point of
|
|
268
|
+
this API: they let a caller slice the ORIGINAL source text of any
|
|
269
|
+
subexpression and reuse it verbatim, instead of re-serialising a parsed
|
|
270
|
+
value and losing how it was written (`1.500` -> `1.5`, `1e3` -> `1000`).
|
|
271
|
+
|
|
272
|
+
This is a SNAPSHOT, not a view of live parser memory: it is safe to
|
|
273
|
+
keep, mutate, share across threads, and outlive the parse. That costs
|
|
274
|
+
one walk per call, which is why it is a separate entry point rather
|
|
275
|
+
than something evaluate() always pays for.
|
|
276
|
+
|
|
277
|
+
Raises ParseError on a syntax error.
|
|
278
|
+
"""
|
|
279
|
+
try:
|
|
280
|
+
return _ext.parse_ast(path, include_comments)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
raise ParseError(str(e)) from e
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def parse_ast_string(code: str, include_comments: bool = False) -> list:
|
|
286
|
+
"""As `parse_ast`, but parses a source string. `position.origin` is
|
|
287
|
+
"<string>" for every node. Raises ParseError on a syntax error."""
|
|
288
|
+
try:
|
|
289
|
+
return _ext.parse_ast_string(code, include_comments)
|
|
290
|
+
except Exception as e:
|
|
291
|
+
raise ParseError(str(e)) from e
|
|
292
|
+
|
|
293
|
+
|
|
259
294
|
class _MeshShim:
|
|
260
295
|
"""Duck-types a manifold3d mesh: the four arrays the renderer reads."""
|
|
261
296
|
__slots__ = ("vert_properties", "tri_verts", "run_original_id", "run_index", "num_prop")
|
|
@@ -27,8 +27,19 @@ RoleSplit splitByRole(const std::vector<ColoredBody>& bodies) {
|
|
|
27
27
|
for (const ColoredBody& c : bodies) {
|
|
28
28
|
if (c.role == BodyRole::Background) r.background.push_back(c);
|
|
29
29
|
}
|
|
30
|
+
// Checked before the foreground sweep below and excluded from it: a
|
|
31
|
+
// display-only body has an empty Manifold, so letting it reach a
|
|
32
|
+
// boolean would silently zero the whole operation (the same failure
|
|
33
|
+
// mode invalid operands caused before they were filtered out).
|
|
30
34
|
for (const ColoredBody& c : bodies) {
|
|
31
|
-
if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly)
|
|
35
|
+
if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly) {
|
|
36
|
+
r.displayOnly.push_back(c);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const ColoredBody& c : bodies) {
|
|
40
|
+
if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && !c.isDisplayOnly()) {
|
|
41
|
+
r.foreground.push_back(c);
|
|
42
|
+
}
|
|
32
43
|
}
|
|
33
44
|
for (const ColoredBody& c : r.foreground) {
|
|
34
45
|
if (c.role == BodyRole::Highlight) r.highlight.push_back(c);
|
|
@@ -160,7 +171,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
160
171
|
const std::string& op = std::get<std::string>(params.at("op"));
|
|
161
172
|
const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
|
|
162
173
|
|
|
163
|
-
std::vector<ColoredBody> allBg, allHi, allSo;
|
|
174
|
+
std::vector<ColoredBody> allBg, allHi, allSo, allDo;
|
|
164
175
|
std::optional<ColoredBody> csgResult;
|
|
165
176
|
size_t idx = 0;
|
|
166
177
|
|
|
@@ -173,6 +184,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
173
184
|
allBg.insert(allBg.end(), split.background.begin(), split.background.end());
|
|
174
185
|
allHi.insert(allHi.end(), split.highlight.begin(), split.highlight.end());
|
|
175
186
|
allSo.insert(allSo.end(), split.showOnly.begin(), split.showOnly.end());
|
|
187
|
+
allDo.insert(allDo.end(), split.displayOnly.begin(), split.displayOnly.end());
|
|
176
188
|
|
|
177
189
|
std::vector<ColoredBody> bodies3d, sections2d;
|
|
178
190
|
for (const ColoredBody& c : split.foreground) {
|
|
@@ -251,6 +263,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
251
263
|
result.insert(result.end(), allBg.begin(), allBg.end());
|
|
252
264
|
result.insert(result.end(), allHi.begin(), allHi.end());
|
|
253
265
|
result.insert(result.end(), allSo.begin(), allSo.end());
|
|
266
|
+
result.insert(result.end(), allDo.begin(), allDo.end());
|
|
254
267
|
return result;
|
|
255
268
|
}
|
|
256
269
|
|
|
@@ -77,11 +77,23 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params,
|
|
|
77
77
|
// splitting/2D-merge logic.
|
|
78
78
|
struct RoleSplit {
|
|
79
79
|
std::vector<ColoredBody> background;
|
|
80
|
-
std::vector<ColoredBody> foreground; // role != Background && role != ShowOnly
|
|
80
|
+
std::vector<ColoredBody> foreground; // role != Background && role != ShowOnly, and not display-only
|
|
81
81
|
std::vector<ColoredBody> highlight; // the subset of `foreground` that's role == Highlight
|
|
82
82
|
std::vector<ColoredBody> showOnly;
|
|
83
|
+
// Bodies with no Manifold to operate on (an open polyhedron -- see
|
|
84
|
+
// ColoredBody::rawMesh). Split out for the same reason showOnly is:
|
|
85
|
+
// they must survive a CSG/hull/minkowski step untouched rather than be
|
|
86
|
+
// merged into it, since there is nothing to merge. Kept separate from
|
|
87
|
+
// `background` because they render as ordinary geometry, not as a
|
|
88
|
+
// translucent ghost.
|
|
89
|
+
std::vector<ColoredBody> displayOnly;
|
|
83
90
|
};
|
|
84
91
|
RoleSplit splitByRole(const std::vector<ColoredBody>& bodies);
|
|
92
|
+
|
|
93
|
+
// manifold::ToString(Manifold::Error) only exists under MANIFOLD_DEBUG --
|
|
94
|
+
// not enabled in this build -- so this mirrors it. Shared by import.cpp and
|
|
95
|
+
// primitives_3d.cpp, both of which report why a mesh wouldn't build.
|
|
96
|
+
std::string manifoldErrorName(manifold::Manifold::Error e);
|
|
85
97
|
std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBody>& bodies);
|
|
86
98
|
|
|
87
99
|
// Merges a statement's bodies into one (3D union, else 2D union, else an
|