OR-1 dataflow CPU sketch
at main 120 lines 3.6 kB view raw
1"""Structured error types for OR1 assembler. 2 3Provides error categories, the AssemblyError dataclass, and utilities for 4formatting errors with source context in Rust style. 5""" 6 7from dataclasses import dataclass, field 8from enum import Enum 9 10from asm.ir import SourceLoc 11 12 13class ErrorSeverity(Enum): 14 """Severity level for assembly diagnostics.""" 15 ERROR = "error" 16 WARNING = "warning" 17 18 19class ErrorCategory(Enum): 20 """Classification of assembly errors.""" 21 PARSE = "parse" 22 NAME = "name" 23 SCOPE = "scope" 24 PLACEMENT = "placement" 25 RESOURCE = "resource" 26 ARITY = "arity" 27 PORT = "port" 28 UNREACHABLE = "unreachable" 29 VALUE = "value" 30 MACRO = "macro" 31 CALL = "call" 32 FRAME = "frame" 33 34 35@dataclass(frozen=True) 36class AssemblyError: 37 """Structured error with source location and context. 38 39 Attributes: 40 loc: Source location where the error occurred 41 category: Error classification (see ErrorCategory) 42 message: Human-readable error message 43 suggestions: Optional list of suggestions for fixing the error 44 context_lines: Optional source lines for context 45 """ 46 loc: SourceLoc 47 category: ErrorCategory 48 message: str 49 severity: ErrorSeverity = ErrorSeverity.ERROR 50 suggestions: list[str] = field(default_factory=list) 51 context_lines: list[str] = field(default_factory=list) 52 53 54def format_error( 55 error: AssemblyError, 56 source: str, 57 builtin_line_offset: int = 0, 58) -> str: 59 """Format an error with source context in Rust style. 60 61 Produces output like: 62 error[SCOPE]: Duplicate label '&add' in function '$main' 63 --> line 5, column 3 64 | 65 5 | &add <| sub 66 | ^^^ 67 = help: First defined at line 2 68 69 Args: 70 error: The AssemblyError to format 71 source: The original source text 72 builtin_line_offset: Number of lines to subtract from error locations 73 to account for prepended built-in macro definitions 74 75 Returns: 76 Formatted error string with source context 77 """ 78 lines = source.split('\n') 79 display_line = error.loc.line 80 in_builtins = False 81 if builtin_line_offset > 0: 82 if display_line > builtin_line_offset: 83 display_line -= builtin_line_offset 84 else: 85 in_builtins = True 86 87 # Build the header 88 result = f"{error.severity.value}[{error.category.name}]: {error.message}\n" 89 if in_builtins: 90 result += f" --> <builtin macros> line {display_line}, column {error.loc.column}\n" 91 else: 92 result += f" --> line {display_line}, column {error.loc.column}\n" 93 94 # Extract and display the source line 95 if 0 < error.loc.line <= len(lines): 96 source_line = lines[error.loc.line - 1] 97 98 # Compute gutter width based on line number 99 gutter_width = len(str(display_line)) 100 101 result += " " * (gutter_width + 1) + "|\n" 102 result += f"{display_line:>{gutter_width}} | {source_line}\n" 103 104 # Add carets pointing to the error column(s) 105 caret_col = error.loc.column 106 caret_end_col = error.loc.end_column if error.loc.end_column else caret_col + 1 107 caret_count = max(1, caret_end_col - caret_col) 108 carets = "^" * caret_count 109 110 result += " " * (gutter_width + 1) + "| " + " " * (caret_col - 1) + carets + "\n" 111 112 # Add suggestions 113 for suggestion in error.suggestions: 114 result += f" = help: {suggestion}\n" 115 116 # Add context lines if provided 117 for line in error.context_lines: 118 result += f" |\n | {line}\n" 119 120 return result