C++ code emitter with context-aware LLType resolution and scope tracking. - Avoids redundant type declarations for in-scope variables (parameters/previous assignments) - Enforces basic type safety for reassignments - Resolves namespace aliases via user-provided context (e.g., 'lk.ui
| 37 | |
| 38 | |
| 39 | class CppEmitter(ExpressionCodegenMixin, StatementCodegenMixin, ControlFlowCodegenMixin, CallCodegenMixin, |
| 40 | ast.NodeVisitor): |
| 41 | """ |
| 42 | C++ code emitter with context-aware LLType resolution and scope tracking. |
| 43 | - Avoids redundant type declarations for in-scope variables (parameters/previous assignments) |
| 44 | - Enforces basic type safety for reassignments |
| 45 | - Resolves namespace aliases via user-provided context (e.g., 'lk.uint32') |
| 46 | """ |
| 47 | |
| 48 | def __init__(self, ctx: Dict[str, object], all_types=None): |
| 49 | """ |
| 50 | Initialize the C++ emitter with a user-provided context. |
| 51 | |
| 52 | Args: |
| 53 | ctx: A dictionary representing the namespace context (e.g., function.__globals__). |
| 54 | Must contain the alias used to import `little_kernel.language` (e.g., 'll' or 'lk'). |
| 55 | """ |
| 56 | # Code buffers (headers -> structs -> main code) |
| 57 | self.header_buffer = StringIO() |
| 58 | self.header_cache = set() |
| 59 | self.struct_buffer = StringIO() |
| 60 | self.main_buffer = StringIO() |
| 61 | self.builtin_buffer = StringIO() |
| 62 | self.builtin_cache = set() |
| 63 | self.builtin_body_cache = set() # Track emitted function names to prevent duplicates |
| 64 | |
| 65 | # State management |
| 66 | self.indent_level = 0 |
| 67 | self.indent_unit = " " # 4-space indentation |
| 68 | |
| 69 | # LLType tracking: StructType -> C++ struct name |
| 70 | self.struct_types: Dict["ll.StructType", str] = {} |
| 71 | |
| 72 | # Special struct tracking: Track which special structs are used |
| 73 | self.used_special_structs: set = set() |
| 74 | |
| 75 | # Enum tracking: Track which Enum types are used |
| 76 | self.used_enums: set = set() |
| 77 | |
| 78 | # Context & annotation cache |
| 79 | self.ctx = ctx # User's namespace (for alias resolution) |
| 80 | self.annotation_cache: Dict[ast.AST, "ll.LLType"] = {} |
| 81 | |
| 82 | # Scope tracking: Maps variable names to their LLType (per function scope) |
| 83 | # Reset when entering/exiting a FunctionDef |
| 84 | self.scope_vars: Dict[str, "ll.LLType"] = {} |
| 85 | self.all_types = all_types if all_types is not None else {} |
| 86 | |
| 87 | # Add required C++ headers |
| 88 | self._add_basic_headers() |
| 89 | |
| 90 | # Validate context (ensure LLType-related objects are present) |
| 91 | self._validate_context() |
| 92 | |
| 93 | def _add_basic_headers(self) -> None: |
| 94 | """Add C++ headers for std types.""" |
| 95 | headers = [ |
| 96 | "<cstdint>", # For stdint types (uint32_t, int64_t) |
no outgoing calls