o
    lijj                     @  sX   d Z ddlmZ ddlmZ G dd deZeG dd dZddddZdddZ	dS )a  Intel HEX encode/decode.

Intel HEX itself is a public, well-documented format (unlike the Roboteq
bytecode it will eventually carry -- see docs/reverse_engineering.md), so
this module is implemented for real rather than stubbed. It's also useful
right now for reverse-engineering work: `read_intel_hex` can load .hex
files exported from RoborunPlus so they can be diffed byte-for-byte.

Only record types 00 (Data) and 01 (End Of File) are handled -- Roboteq
scripts are small enough that extended segment/linear address records
(02/03/04/05) are not expected to be needed, but that assumption should be
verified against real exported files during reverse engineering.
    )annotations)	dataclassc                   @  s   e Zd ZdS )HexFormatErrorN)__name__
__module____qualname__ r   r   O/sessions/funny-vibrant-bardeen/mnt/compiler/src/microbasic_compiler/hexfile.pyr      s    r   c                   @  sB   e Zd ZU ded< ded< ded< ded< ddd	ZdddZdS )	HexRecordint
byte_countaddressrecord_typebytesdatareturnc                 C  s4   | j | jd?  | jd@  | j t| j }| d@ S )N      )r   r   r   sumr   )selftotalr   r   r	   checksum   s   
zHexRecord.checksumstrc                 C  sB   t | j| jd? | jd@ | jg| j }d|   |  d S )Nr   r   :02X)r   r   r   r   r   hexupperr   )r   bodyr   r   r	   to_line)   s   &zHexRecord.to_lineN)r   r   )r   r   )r   r   r   __annotations__r   r   r   r   r   r	   r
      s   
 

r
      r   r   start_addressr   bytes_per_liner   r   c           
      C  s   |dk s|dkrt dt| | }|r| d||   } g }|}tdt| |D ]#}| |||  }tt||d@ d|d}||  |t|7 }q(tddddd}	||	  d	|d	 S )
a,  Encode `data` as Intel HEX text (data records + trailing EOF record).

    CONFIRMED (gosub_distance corpus, 2026-07-28): real RoborunPlus-exported
    .hex always pads the final line out to a full `bytes_per_line` (16)
    bytes with 0xFF, rather than emitting a short last record for whatever
    remainder doesn't divide evenly. Every one of the 6 distance test cases
    (12/212/262/267/512/962 raw bytes) came back from RoborunPlus padded up
    to the next 16-byte boundary (16/224/272/272/... bytes) with the
    difference being solely trailing 0xFF -- 0 differing bytes in the shared
    range in all 6 cases, confirming GoSub codegen itself is correct
    (including across the 256-byte 1-vs-2-byte-address boundary). Padding
    here so our .hex output matches real compiler output byte-for-byte.
       r   z(bytes_per_line must be between 1 and 255   r   i  r   r   r   r       
)
ValueErrorlenranger
   appendr   join)
r   r!   r"   	remainderlinesaddroffsetchunkrecordeofr   r   r	   write_intel_hex.   s   r4   textc                 C  s\  t  }t|  ddD ]\}}| }|sq|ds#td| dzt|dd }W n tyC } z	td| d|d}~ww t	|dk rRtd| d	|d
 |d |d |d f\}}}	}
|dd|  }|d|  }t
||d> |	B |
|d}| |krtd| d|
d
kr|| q|
dkr t|S td| d|
dt|S )zDecode Intel HEX text back into a flat byte string (data records only,
    concatenated in file order -- does not attempt to place bytes at their
    absolute addresses since that's not needed for diffing bytecode dumps).
    r#   )startr   zline z: missing ':' start codeNz: invalid hex data   z: record too shortr            r   r%   z: checksum mismatchz: unsupported record type 0xr   )	bytearray	enumerate
splitlinesstrip
startswithr   r   fromhexr(   r)   r
   r   extend)r5   outlinenoraw_lineliner   excr   addr_hiaddr_lor   payloadr   r2   r   r   r	   read_intel_hexP   s8   
$rJ   N)r   r    )r   r   r!   r   r"   r   r   r   )r5   r   r   r   )
__doc__
__future__r   dataclassesr   	Exceptionr   r
   r4   rJ   r   r   r   r	   <module>   s    "