Source code for crosstl._crosstl

"""High-level translation API and command-line entry point for CrossGL Translator."""

from typing import Optional

from .translator.codegen import (
    get_codegen,
    get_backend_extension,
    normalize_backend_name,
    backend_names,
)
from .translator.source_registry import SOURCE_REGISTRY, register_default_sources
from .translator.plugin_loader import discover_backend_plugins
import argparse
import sys
import os

try:
    from .formatter import format_shader_code

    FORMATTER_AVAILABLE = True
except ImportError:
    FORMATTER_AVAILABLE = False


[docs] def translate( file_path: str, backend: str = "cgl", save_shader: Optional[str] = None, format_output: bool = True, ) -> str: """Translate a shader file to another language. Args: file_path (str): The path to the shader file backend (str, optional): The target language to translate to. Defaults to "cgl". save_shader (str, optional): The path to save the translated shader. Defaults to None. format_output (bool, optional): Whether to format the generated code. Defaults to True. Returns: str: The translated shader code """ register_default_sources() discover_backend_plugins() backend = (backend or "cgl").strip().lower() with open(file_path, "r", encoding="utf-8") as file: shader_code = file.read() source_spec = SOURCE_REGISTRY.get_by_extension(file_path) if not source_spec: supported = ", ".join(SOURCE_REGISTRY.extensions()) raise ValueError( f"Unsupported shader file type: {file_path}. Supported: {supported}" ) ast = source_spec.parse(shader_code) requested_backend = backend normalized_backend = normalize_backend_name(requested_backend) or requested_backend if source_spec.name == "cgl": if normalized_backend in ["cgl", "crossgl"]: generated_code = shader_code else: codegen = get_codegen(normalized_backend) generated_code = codegen.generate(ast) else: if normalized_backend in ["cgl", "crossgl"]: if not source_spec.reverse_codegen_factory: raise ValueError(f"Reverse translation not supported for: {file_path}") codegen = source_spec.reverse_codegen_factory() generated_code = codegen.generate(ast) else: if not source_spec.reverse_codegen_factory: raise ValueError( f"Unsupported translation scenario: {file_path} to {backend}" ) # Translate to CrossGL first, then to target backend reverse_codegen = source_spec.reverse_codegen_factory() intermediate_code = reverse_codegen.generate(ast) cgl_spec = SOURCE_REGISTRY.get("cgl") if not cgl_spec: raise ValueError("CrossGL parser not available for intermediate step") cgl_ast = cgl_spec.parse(intermediate_code) codegen = get_codegen(normalized_backend) generated_code = codegen.generate(cgl_ast) if ( format_output and FORMATTER_AVAILABLE and normalized_backend not in ["cgl", "crossgl"] ): generated_code = format_shader_code( generated_code, normalized_backend, save_shader ) if save_shader is not None: with open(save_shader, "w", encoding="utf-8") as file: file.write(generated_code) return generated_code
[docs] def main(): """Command-line entry point for CrossGL translation.""" parser = argparse.ArgumentParser(description="CrossGL Shader Translator") parser.add_argument("input", help="Input shader file path") supported_backends = ", ".join(backend_names() + ["cgl"]) parser.add_argument( "--backend", "-b", default="cgl", help=f"Target backend ({supported_backends})", ) parser.add_argument("--output", "-o", help="Output file path") parser.add_argument( "--no-format", action="store_true", help="Disable code formatting" ) args = parser.parse_args() try: if not os.path.exists(args.input): print(f"Error: Input file {args.input} not found") return 1 output_path = args.output if not output_path: base, _ = os.path.splitext(args.input) normalized_backend = normalize_backend_name(args.backend) or args.backend if normalized_backend in ["cgl", "crossgl"]: ext = ".cgl" else: ext = get_backend_extension(normalized_backend) or ".out" output_path = base + ext translate( args.input, backend=args.backend, save_shader=output_path, format_output=not args.no_format, ) print(f"Successfully translated to {output_path}") return 0 except Exception as e: print(f"Error: {e}") return 1
if __name__ == "__main__": sys.exit(main())