All files / TRANSPILE/3-Render/codegen/assignment/handlers SpecialHandlers.ts

100% Statements 13/13
100% Branches 2/2
100% Functions 3/3
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                                    76x                     16x 16x   16x                                   60x 60x 60x   60x           56x 56x 56x     4x           49x            
/**
 * Special assignment handlers (ADR-065).
 *
 * Handles special compound assignment operations:
 * - ATOMIC_RMW: atomic counter +<- 1
 * - OVERFLOW_CLAMP: clamp u8 saturated +<- 200
 */
import AssignmentKind from "../../../../../types/AssignmentKind";
import IAssignmentContext from "../../../../2-Plan/types/IAssignmentContext";
import AssignmentClassifier from "../../../../2-Plan/AssignmentClassifier";
import TAssignmentHandler from "./TAssignmentHandler";
import TTypeInfo from "../../../../../types/TTypeInfo";
import AdrProvenance from "../../../../../instrumentation/AdrProvenance";
 
/**
 * The target's type info. Both kinds are classified only when it resolved.
 */
function targetTypeInfo(ctx: IAssignmentContext): TTypeInfo {
  return AssignmentClassifier.targetTypeInfo(ctx)!;
}
 
/**
 * Handle atomic read-modify-write: atomic counter +<- 1
 *
 * Delegates to CodeGenerator's generateAtomicRMW which uses
 * LDREX/STREX on supported platforms or PRIMASK otherwise. Whether the inner
 * operation saturates is the classifier's decision, passed in.
 */
function handleAtomicRMW(ctx: IAssignmentContext): string {
  const typeInfo = targetTypeInfo(ctx);
  const target = ctx.renderTarget();
 
  return ctx.state
    .requireGenerator()
    .generateAtomicRMW(
      target,
      ctx.cOp,
      ctx.generatedValue,
      typeInfo,
      AssignmentClassifier.compoundClampOp(ctx, typeInfo),
    );
}
 
/**
 * Handle overflow-clamped compound assignment: clamp u8 saturated +<- 200
 *
 * Generates calls to cnx_clamp_add_u8, cnx_clamp_sub_u8, etc. Classified only
 * when `AssignmentClassifier.compoundClampOp` names a helper.
 */
function handleOverflowClamp(ctx: IAssignmentContext): string {
  const typeInfo = targetTypeInfo(ctx);
  const target = ctx.renderTarget();
  const helperOp = AssignmentClassifier.compoundClampOp(ctx, typeInfo);
 
  if (helperOp) {
    // #1241: ADR-044's rule firing on the COMPOUND form. The expression form
    // (`a <- a + b`) records in BinaryExprGenerator; this is the `a +<- b` path,
    // which reaches a different decision and would otherwise leave every
    // compound-only fixture without a derivable context. Recorded past the
    // helper decision, so only an actually-lowered clamp claims a cell.
    AdrProvenance.record("044", ctx.targetLine);
    ctx.state.markClampOpUsed(helperOp, typeInfo.baseType);
    return `${target} = cnx_clamp_${helperOp}_${typeInfo.baseType}(${target}, ${ctx.generatedValue});`;
  }
 
  return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
}
 
/**
 * All special handlers for registration.
 */
const specialHandlers: ReadonlyArray<[AssignmentKind, TAssignmentHandler]> = [
  [AssignmentKind.ATOMIC_RMW, handleAtomicRMW],
  [AssignmentKind.OVERFLOW_CLAMP, handleOverflowClamp],
];
 
export default specialHandlers;