OR-1 dataflow CPU sketch
at ba08ffded3d3b2badb2a7e22816feafaacea5ded 119 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 33 34@dataclass(frozen=True) 35class AssemblyError: 36 """Structured error with source location and context. 37 38 Attributes: 39 loc: Source location where the error occurred 40 category: Error classification (see ErrorCategory) 41 message: Human-readable error message 42 suggestions: Optional list of suggestions for fixing the error 43 context_lines: Optional source lines for context 44 """ 45 loc: SourceLoc 46 category: ErrorCategory 47 message: str 48 severity: ErrorSeverity = ErrorSeverity.ERROR 49 suggestions: list[str] = field(default_factory=list) 50 context_lines: list[str] = field(default_factory=list) 51 52 53def format_error( 54 error: AssemblyError, 55 source: str, 56 builtin_line_offset: int = 0, 57) -> str: 58 """Format an error with source context in Rust style. 59 60 Produces output like: 61 error[SCOPE]: Duplicate label '&add' in function '$main' 62 --> line 5, column 3 63 | 64 5 | &add <| sub 65 | ^^^ 66 = help: First defined at line 2 67 68 Args: 69 error: The AssemblyError to format 70 source: The original source text 71 builtin_line_offset: Number of lines to subtract from error locations 72 to account for prepended built-in macro definitions 73 74 Returns: 75 Formatted error string with source context 76 """ 77 lines = source.split('\n') 78 display_line = error.loc.line 79 in_builtins = False 80 if builtin_line_offset > 0: 81 if display_line > builtin_line_offset: 82 display_line -= builtin_line_offset 83 else: 84 in_builtins = True 85 86 # Build the header 87 result = f"{error.severity.value}[{error.category.name}]: {error.message}\n" 88 if in_builtins: 89 result += f" --> <builtin macros> line {display_line}, column {error.loc.column}\n" 90 else: 91 result += f" --> line {display_line}, column {error.loc.column}\n" 92 93 # Extract and display the source line 94 if 0 < error.loc.line <= len(lines): 95 source_line = lines[error.loc.line - 1] 96 97 # Compute gutter width based on line number 98 gutter_width = len(str(display_line)) 99 100 result += " " * (gutter_width + 1) + "|\n" 101 result += f"{display_line:>{gutter_width}} | {source_line}\n" 102 103 # Add carets pointing to the error column(s) 104 caret_col = error.loc.column 105 caret_end_col = error.loc.end_column if error.loc.end_column else caret_col + 1 106 caret_count = max(1, caret_end_col - caret_col) 107 carets = "^" * caret_count 108 109 result += " " * (gutter_width + 1) + "| " + " " * (caret_col - 1) + carets + "\n" 110 111 # Add suggestions 112 for suggestion in error.suggestions: 113 result += f" = help: {suggestion}\n" 114 115 # Add context lines if provided 116 for line in error.context_lines: 117 result += f" |\n | {line}\n" 118 119 return result