openscad-cpp-evaluator 1.28.5__tar.gz → 1.29.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.28.5 → openscad_cpp_evaluator-1.29.0}/CLAUDE.md +9 -3
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/PKG-INFO +1 -1
- openscad_cpp_evaluator-1.29.0/external/openscad_cpp_parser/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/api.cpp +24 -9
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +1 -0
- openscad_cpp_evaluator-1.29.0/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +56 -0
- openscad_cpp_evaluator-1.29.0/include/openscad_cpp_evaluator/css_colors.hpp +20 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/CMakeLists.txt +1 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/color.cpp +44 -17
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/css_colors.cpp +39 -31
- openscad_cpp_evaluator-1.29.0/src/xkcd_colors.cpp +967 -0
- openscad_cpp_evaluator-1.29.0/src/xkcd_colors.hpp +13 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_python_bindings.py +34 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_transforms.cpp +103 -30
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/uv.lock +1 -1
- openscad_cpp_evaluator-1.28.5/include/openscad_cpp_evaluator/css_colors.hpp +0 -19
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.28.5 → openscad_cpp_evaluator-1.29.0}/tools/cli/main.cpp +0 -0
|
@@ -819,9 +819,15 @@ grep for `ponytail:`.
|
|
|
819
819
|
geometric-correctness test in Phase 3, not a hypothetical.
|
|
820
820
|
- `include/openscad_cpp_evaluator/segments.hpp`, `src/builtins/segments.cpp` — `$fn`/`$fa`/`$fs` ->
|
|
821
821
|
circular-shape segment count (`fnSegments`/`fnSegmentsFromCtx`), used by sphere/cylinder/circle.
|
|
822
|
-
- `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp` —
|
|
823
|
-
|
|
824
|
-
|
|
822
|
+
- `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp`, `src/xkcd_colors.{hpp,cpp}` —
|
|
823
|
+
`parseColor`, OpenSCAD's `parse_color` (ColorUtil.cc): CSS Color Level 4 names (148, with
|
|
824
|
+
`rebeccapurple`) plus `transparent` (alpha 0), `"xkcd:<name>"` over the 949 xkcd survey names
|
|
825
|
+
(generated from OpenSCAD's `XkcdColors.h`, CC0), all case-insensitive, then strict `#rgb` /
|
|
826
|
+
`#rgba` / `#rrggbb` / `#rrggbbaa`. `color()` (`src/builtins/color.cpp`) follows `builtin_color`:
|
|
827
|
+
an unreadable string warns `Unable to parse color "…"` and sets NO colour (children keep their
|
|
828
|
+
own, or the outer one) -- it used to draw white; a list fills missing channels with 1 and warns
|
|
829
|
+
outside 0..1; a numeric `alpha` replaces any alpha, a 4-list's included (checked on the 2026.02.01
|
|
830
|
+
binary's 3MF export). `cssColor` (white fallback) is only for SVG/PDF export options.
|
|
825
831
|
- `src/builtins/{primitives_2d,primitives_3d,transforms,color,booleans,modifiers,control}.cpp` —
|
|
826
832
|
one file per builtin group, each a `ResolveFn`/`GenerateFn` pair (or a few, where several builtin
|
|
827
833
|
names share one pair — circle/square/polygon, translate/rotate/scale/mirror/multmatrix/resize,
|
|
Binary file
|
|
@@ -119,10 +119,25 @@ std::vector<std::unique_ptr<ASTNode>> parseAst(const std::string& code, const st
|
|
|
119
119
|
|
|
120
120
|
ParserDriver driver(origin);
|
|
121
121
|
driver.strictCommas = g_strictCommas;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
int rc;
|
|
123
|
+
{
|
|
124
|
+
// The flex scanner is global state (grammar/lexer_api.hpp), so two
|
|
125
|
+
// threads parsing at once lexed each other's input and crashed -- in
|
|
126
|
+
// BelfrySCAD, a render worker parsing its file while the UI thread
|
|
127
|
+
// parsed the buffer for the Customizer: an intermittent 0xC0000005
|
|
128
|
+
// on Windows. One parse at a time; a parse is milliseconds, and the
|
|
129
|
+
// shared file cache means a library is parsed once, not per thread.
|
|
130
|
+
// ponytail: a global lock; a reentrant scanner (%option reentrant +
|
|
131
|
+
// a yyscan_t through the driver) if parsing ever needs to scale.
|
|
132
|
+
static std::mutex scannerMutex;
|
|
133
|
+
std::lock_guard<std::mutex> lock(scannerMutex);
|
|
134
|
+
struct EndLexer { // lexerEnd() even when parse() throws
|
|
135
|
+
~EndLexer() { lexerEnd(); }
|
|
136
|
+
} endLexer;
|
|
137
|
+
lexerBeginString(code);
|
|
138
|
+
yy::parser parser(driver);
|
|
139
|
+
rc = parser.parse();
|
|
140
|
+
}
|
|
126
141
|
|
|
127
142
|
if (rc != 0 || driver.hadError) {
|
|
128
143
|
throw ParseError(formatSyntaxError(driver, code, origin, sourceMap));
|
|
@@ -409,11 +424,11 @@ FileAstPtr parseFileShared(const std::string& absPath, bool includeComments) {
|
|
|
409
424
|
return it->second.ast;
|
|
410
425
|
}
|
|
411
426
|
|
|
412
|
-
// Parsed
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
427
|
+
// Parsed outside THIS lock, so a cache lookup never waits behind a
|
|
428
|
+
// parse. (parseAst serialises the scanner itself: this comment once
|
|
429
|
+
// called concurrent parses "never wrong", and they were -- the scanner
|
|
430
|
+
// is global state.) Two threads racing the same file each parse it in
|
|
431
|
+
// turn and one result is dropped: wasteful once, never wrong.
|
|
417
432
|
auto parsed = std::make_shared<const FileAst>(parseSingleFile(absPath, includeComments));
|
|
418
433
|
std::lock_guard<std::mutex> lock(g_astCacheMutex);
|
|
419
434
|
CacheEntry& entry = g_astCache[key];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// The flex scanner is non-reentrant, global state (grammar/lexer_api.hpp),
|
|
2
|
+
// so two threads parsing at once used to lex each other's input. In
|
|
3
|
+
// BelfrySCAD that was an intermittent 0xC0000005 on Windows: a render worker
|
|
4
|
+
// parsing its file while the UI thread parsed the buffer for the Customizer.
|
|
5
|
+
// parseAst now serialises the scanner. Every thread here parses its OWN
|
|
6
|
+
// source and checks it got its own tree back, so corruption fails the test
|
|
7
|
+
// even where it does not crash.
|
|
8
|
+
#include "openscad_cpp_parser/api.hpp"
|
|
9
|
+
|
|
10
|
+
#include <gtest/gtest.h>
|
|
11
|
+
|
|
12
|
+
#include <atomic>
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <thread>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
using namespace oscad;
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
std::string sourceFor(int thread, int round) {
|
|
21
|
+
// Different identifiers and lengths per thread, so a lexer reading
|
|
22
|
+
// another thread's buffer produces a different tree, not an equal one.
|
|
23
|
+
std::string name = "v" + std::to_string(thread) + "_" + std::to_string(round);
|
|
24
|
+
std::string src;
|
|
25
|
+
for (int i = 0; i < 20 + thread; ++i) {
|
|
26
|
+
src += name + "_" + std::to_string(i) + " = [" + std::to_string(i) + ", " +
|
|
27
|
+
std::to_string(thread) + ", \"s" + std::to_string(round) + "\"];\n";
|
|
28
|
+
}
|
|
29
|
+
return src;
|
|
30
|
+
}
|
|
31
|
+
} // namespace
|
|
32
|
+
|
|
33
|
+
TEST(ConcurrentParse, ThreadsParsingAtOnceEachGetTheirOwnTree) {
|
|
34
|
+
constexpr int kThreads = 8, kRounds = 150;
|
|
35
|
+
std::atomic<int> wrong{0};
|
|
36
|
+
std::vector<std::thread> threads;
|
|
37
|
+
for (int t = 0; t < kThreads; ++t) {
|
|
38
|
+
threads.emplace_back([t, &wrong] {
|
|
39
|
+
for (int r = 0; r < kRounds; ++r) {
|
|
40
|
+
const std::string src = sourceFor(t, r);
|
|
41
|
+
try {
|
|
42
|
+
auto ast = parseAst(src);
|
|
43
|
+
const auto* first = ast.empty() ? nullptr : dynamic_cast<const Assignment*>(ast[0].get());
|
|
44
|
+
const std::string want = "v" + std::to_string(t) + "_" + std::to_string(r) + "_0";
|
|
45
|
+
if (ast.size() != static_cast<size_t>(20 + t) || !first || first->name->name != want) {
|
|
46
|
+
++wrong;
|
|
47
|
+
}
|
|
48
|
+
} catch (...) {
|
|
49
|
+
++wrong; // a syntax error from lexing another thread's input
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
for (auto& th : threads) th.join();
|
|
55
|
+
EXPECT_EQ(wrong.load(), 0);
|
|
56
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <array>
|
|
4
|
+
#include <optional>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
namespace oscadeval {
|
|
8
|
+
|
|
9
|
+
// A colour string as OpenSCAD's parse_color reads it (ColorUtil.cc):
|
|
10
|
+
// a CSS Color Level 4 name or OpenSCAD's "transparent" (alpha 0), an
|
|
11
|
+
// "xkcd:<name>" from the xkcd colour survey, all case-insensitive; else
|
|
12
|
+
// "#rgb", "#rgba", "#rrggbb" or "#rrggbbaa". Nothing if it is none of
|
|
13
|
+
// those -- color() then warns and leaves its children's colour alone.
|
|
14
|
+
std::optional<std::array<double, 4>> parseColor(const std::string& text);
|
|
15
|
+
|
|
16
|
+
// parseColor with the alpha replaced, and white for anything unparseable.
|
|
17
|
+
// For export options (SVG/PDF fill and stroke), which have no warning path.
|
|
18
|
+
std::array<double, 4> cssColor(const std::string& name, double alpha = 1.0);
|
|
19
|
+
|
|
20
|
+
} // namespace oscadeval
|
|
@@ -1,38 +1,63 @@
|
|
|
1
1
|
#include "builtins.hpp"
|
|
2
2
|
|
|
3
|
+
#include <cstdio>
|
|
4
|
+
|
|
3
5
|
#include "openscad_cpp_evaluator/call_args.hpp"
|
|
4
6
|
#include "openscad_cpp_evaluator/css_colors.hpp"
|
|
5
7
|
#include "openscad_cpp_evaluator/evaluator.hpp"
|
|
6
8
|
|
|
7
9
|
namespace oscadeval {
|
|
8
10
|
|
|
9
|
-
// color(c
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// color(c, alpha), as OpenSCAD's builtin_color (ColorNode.cc):
|
|
12
|
+
// - a string goes through parseColor (CSS / "xkcd:" names, hex with or
|
|
13
|
+
// without alpha); one it cannot read warns "Unable to parse color" and
|
|
14
|
+
// leaves the children's colour alone -- inherited from outside, not reset;
|
|
15
|
+
// - a list fills [r, g, b, a] in order, 1.0 for any it lacks, warning on a
|
|
16
|
+
// component outside 0..1;
|
|
17
|
+
// - a numeric `alpha` then replaces the alpha of whatever `c` gave -- even a
|
|
18
|
+
// 4-element list's, and even "#rrggbbaa"'s -- warning when outside 0..1;
|
|
19
|
+
// - anything else for `c`, or no `c` at all, sets no colour (OpenSCAD's
|
|
20
|
+
// unset Color4f is (-1,-1,-1,-1), which is not a colour).
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
std::string oneDecimal(double v) {
|
|
24
|
+
char buf[64];
|
|
25
|
+
std::snprintf(buf, sizeof buf, "%.1f", v);
|
|
26
|
+
return buf;
|
|
27
|
+
}
|
|
28
|
+
} // namespace
|
|
14
29
|
|
|
15
30
|
BuiltinWrapParams computeColorParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
|
|
16
31
|
auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
|
|
17
|
-
const Value
|
|
18
|
-
|
|
19
|
-
Value cArg = getArg(args, 0, "c", defaultC);
|
|
20
|
-
const double alpha = toDoubleLenient(getArg(args, 1, "alpha", Value{1.0}));
|
|
32
|
+
const Value cArg = getArg(args, 0, "c");
|
|
33
|
+
const Value alphaArg = getArg(args, 1, "alpha");
|
|
21
34
|
|
|
22
|
-
std::array<double, 4
|
|
35
|
+
std::optional<std::array<double, 4>> rgba;
|
|
23
36
|
if (const std::string* s = std::get_if<std::string>(&cArg)) {
|
|
24
|
-
rgba =
|
|
37
|
+
rgba = parseColor(*s);
|
|
38
|
+
if (!rgba) ev.warn("Unable to parse color \"" + *s + "\"", &node.position());
|
|
25
39
|
} else if (const ListPtr* l = std::get_if<ListPtr>(&cArg); l && *l) {
|
|
26
40
|
const auto& items = (*l)->items;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
std::array<double, 4> c{1.0, 1.0, 1.0, 1.0};
|
|
42
|
+
for (size_t i = 0; i < 4; ++i) {
|
|
43
|
+
if (i < items.size()) c[i] = toDoubleLenient(items[i]);
|
|
44
|
+
if (c[i] > 1 || c[i] < 0)
|
|
45
|
+
ev.warn("color() expects numbers between 0.0 and 1.0. Value of " + oneDecimal(c[i]) +
|
|
46
|
+
" is out of range",
|
|
47
|
+
&node.position());
|
|
32
48
|
}
|
|
49
|
+
rgba = c;
|
|
50
|
+
}
|
|
51
|
+
if (const double* a = std::get_if<double>(&alphaArg)) {
|
|
52
|
+
if (rgba) (*rgba)[3] = *a;
|
|
53
|
+
if (*a < 0.0 || *a > 1.0)
|
|
54
|
+
ev.warn("color() expects alpha between 0.0 and 1.0. Value of " + oneDecimal(*a) + " is out of range",
|
|
55
|
+
&node.position());
|
|
33
56
|
}
|
|
34
57
|
|
|
35
|
-
|
|
58
|
+
// No colour: the child context inherits the outer one (childCtx's
|
|
59
|
+
// nullopt), and generateColor passes the children through untouched.
|
|
60
|
+
EvalContext childCtx = effCtx.childCtx(nullptr, rgba);
|
|
36
61
|
CSGParams params;
|
|
37
62
|
params["rgba"] = colorToValue(rgba);
|
|
38
63
|
return BuiltinWrapParams{std::move(params), std::move(childCtx)};
|
|
@@ -70,6 +95,8 @@ std::shared_ptr<const std::vector<ColoredBody>> recolorParts(const std::vector<C
|
|
|
70
95
|
std::vector<ColoredBody> generateColor(Evaluator& ev, const CSGParams& params,
|
|
71
96
|
const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode&) {
|
|
72
97
|
const auto rgba = valueToColor(params.at("rgba"));
|
|
98
|
+
// An unreadable colour sets none: the children keep their own.
|
|
99
|
+
if (!rgba) return flattenCsgTree(children);
|
|
73
100
|
std::vector<ColoredBody> result;
|
|
74
101
|
for (ColoredBody b : flattenCsgTree(children)) {
|
|
75
102
|
b.color = rgba;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
#include "openscad_cpp_evaluator/css_colors.hpp"
|
|
2
|
+
#include "xkcd_colors.hpp"
|
|
2
3
|
|
|
3
4
|
#include <cctype>
|
|
5
|
+
#include <optional>
|
|
4
6
|
#include <unordered_map>
|
|
5
7
|
|
|
6
8
|
namespace oscadeval {
|
|
7
9
|
|
|
8
10
|
namespace {
|
|
9
11
|
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// Originally generated from the Python reference's _css_colors.py (itself
|
|
13
|
+
// from a live PySide6 install). Now OpenSCAD's own WebColors.h list: every
|
|
14
|
+
// RGB here matches it, `rebeccapurple` (CSS Color Level 4) is added, and
|
|
15
|
+
// `transparent`, which needs an alpha of 0, is handled in parseColor.
|
|
14
16
|
const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
15
17
|
static const std::unordered_map<std::string, std::array<double, 3>> table = {
|
|
16
18
|
{"aliceblue", {0.9411764740943909, 0.9725490212440491, 1.0}},
|
|
@@ -132,6 +134,7 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
|
132
134
|
{"plum", {0.8666666746139526, 0.6274510025978088, 0.8666666746139526}},
|
|
133
135
|
{"powderblue", {0.6901960968971252, 0.8784313797950745, 0.9019607901573181}},
|
|
134
136
|
{"purple", {0.501960813999176, 0.0, 0.501960813999176}},
|
|
137
|
+
{"rebeccapurple", {0.4, 0.2, 0.6}},
|
|
135
138
|
{"red", {1.0, 0.0, 0.0}},
|
|
136
139
|
{"rosybrown", {0.7372549176216125, 0.5607843399047852, 0.5607843399047852}},
|
|
137
140
|
{"royalblue", {0.2549019753932953, 0.4117647111415863, 0.8823529481887817}},
|
|
@@ -153,7 +156,6 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
|
|
|
153
156
|
{"teal", {0.0, 0.501960813999176, 0.501960813999176}},
|
|
154
157
|
{"thistle", {0.8470588326454163, 0.7490196228027344, 0.8470588326454163}},
|
|
155
158
|
{"tomato", {1.0, 0.38823530077934265, 0.27843138575553894}},
|
|
156
|
-
{"transparent", {0.0, 0.0, 0.0}},
|
|
157
159
|
{"turquoise", {0.250980406999588, 0.8784313797950745, 0.8156862854957581}},
|
|
158
160
|
{"violet", {0.9333333373069763, 0.5098039507865906, 0.9333333373069763}},
|
|
159
161
|
{"wheat", {0.9607843160629272, 0.8705882430076599, 0.7019608020782471}},
|
|
@@ -171,38 +173,44 @@ std::string toLower(const std::string& s) {
|
|
|
171
173
|
return r;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
// OpenSCAD's parse_hex_color (ColorUtil.cc): "#rgb", "#rgba", "#rrggbb" or
|
|
177
|
+
// "#rrggbbaa", every character after '#' a hex digit, or nothing at all.
|
|
178
|
+
std::optional<std::array<double, 4>> parseHex(const std::string& hex) {
|
|
179
|
+
const bool shortForm = hex.size() == 4 || hex.size() == 5;
|
|
180
|
+
const bool longForm = hex.size() == 7 || hex.size() == 9;
|
|
181
|
+
if ((!shortForm && !longForm) || hex[0] != '#') return std::nullopt;
|
|
182
|
+
for (size_t i = 1; i < hex.size(); ++i)
|
|
183
|
+
if (!std::isxdigit(static_cast<unsigned char>(hex[i]))) return std::nullopt;
|
|
184
|
+
const size_t stride = shortForm ? 1 : 2;
|
|
185
|
+
const double channelMax = shortForm ? 15.0 : 255.0;
|
|
186
|
+
std::array<double, 4> rgba{0.0, 0.0, 0.0, 1.0};
|
|
187
|
+
for (size_t i = 0; i < (hex.size() - 1) / stride; ++i)
|
|
188
|
+
rgba[i] = std::stoi(hex.substr(1 + i * stride, stride), nullptr, 16) / channelMax;
|
|
189
|
+
return rgba;
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
} // namespace
|
|
182
193
|
|
|
183
|
-
std::array<double, 4
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
}
|
|
192
|
-
if (h.size() == 3) {
|
|
193
|
-
const double r = hexDigit(h[0]) / 15.0;
|
|
194
|
-
const double g = hexDigit(h[1]) / 15.0;
|
|
195
|
-
const double b = hexDigit(h[2]) / 15.0;
|
|
196
|
-
return {r, g, b, alpha};
|
|
197
|
-
}
|
|
198
|
-
return {1.0, 1.0, 1.0, alpha};
|
|
194
|
+
std::optional<std::array<double, 4>> parseColor(const std::string& text) {
|
|
195
|
+
// OpenSCAD's parse_color: a name first (case-insensitive; "xkcd:" reaches
|
|
196
|
+
// the xkcd survey table, falling back to the CSS table), then hex.
|
|
197
|
+
const std::string name = toLower(text);
|
|
198
|
+
if (name.rfind("xkcd:", 0) == 0) {
|
|
199
|
+
const auto& xk = xkcdColorTable();
|
|
200
|
+
if (auto it = xk.find(name.substr(5)); it != xk.end())
|
|
201
|
+
return std::array<double, 4>{it->second[0] / 255.0, it->second[1] / 255.0, it->second[2] / 255.0, 1.0};
|
|
199
202
|
}
|
|
203
|
+
// OpenSCAD's own addition to the CSS list: fully transparent black.
|
|
204
|
+
if (name == "transparent") return std::array<double, 4>{0.0, 0.0, 0.0, 0.0};
|
|
205
|
+
if (auto it = colorTable().find(name); it != colorTable().end())
|
|
206
|
+
return std::array<double, 4>{it->second[0], it->second[1], it->second[2], 1.0};
|
|
207
|
+
return parseHex(text);
|
|
208
|
+
}
|
|
200
209
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
return {1.0, 1.0, 1.0, alpha};
|
|
210
|
+
std::array<double, 4> cssColor(const std::string& name, double alpha) {
|
|
211
|
+
auto c = parseColor(name);
|
|
212
|
+
if (!c) return {1.0, 1.0, 1.0, alpha};
|
|
213
|
+
return {(*c)[0], (*c)[1], (*c)[2], alpha};
|
|
206
214
|
}
|
|
207
215
|
|
|
208
216
|
} // namespace oscadeval
|