All files / transpiler/output/codegen/assignment/handlers SpecialHandlers.ts

95.83% Statements 23/24
91.66% Branches 11/12
100% Functions 4/4
95.83% Lines 23/24

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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                  48x       15x                         42x     42x 36x       6x 3x 3x       3x 3x                           6x 6x   6x                             36x 36x     36x 2x     34x   34x 33x 33x       1x           15x            
/**
 * Special assignment handlers (ADR-109).
 *
 * Handles special compound assignment operations:
 * - ATOMIC_RMW: atomic counter +<- 1
 * - OVERFLOW_CLAMP: clamp u8 saturated +<- 200
 */
import AssignmentKind from "../AssignmentKind";
import IAssignmentContext from "../IAssignmentContext";
import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
import TAssignmentHandler from "./TAssignmentHandler";
import CodeGenState from "../../../../state/CodeGenState";
import TTypeInfo from "../../types/TTypeInfo";
import type ICodeGenApi from "../../types/ICodeGenApi";
 
/** Get typed generator reference */
function gen(): ICodeGenApi {
  return CodeGenState.generator as ICodeGenApi;
}
 
/** Maps C operators to clamp helper operation names */
const CLAMP_OP_MAP: Record<string, string> = {
  "+=": "add",
  "-=": "sub",
  "*=": "mul",
};
 
/**
 * Get typeInfo for assignment target.
 * Handles simple identifiers, this.member, and global.member patterns.
 */
function getTargetTypeInfo(ctx: IAssignmentContext): {
  typeInfo: TTypeInfo | undefined;
} {
  const id = ctx.identifiers[0];
 
  // Simple identifier
  if (ctx.isSimpleIdentifier) {
    return { typeInfo: CodeGenState.getVariableTypeInfo(id) };
  }
 
  // this.member: lookup using scoped name
  if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
    const scopedName = `${CodeGenState.currentScope}_${id}`;
    return { typeInfo: CodeGenState.getVariableTypeInfo(scopedName) };
  }
 
  // global.member: lookup using direct name
  Eif (ctx.isSimpleGlobalAccess) {
    return { typeInfo: CodeGenState.getVariableTypeInfo(id) };
  }
 
  // Fallback to direct lookup
  return { typeInfo: CodeGenState.getVariableTypeInfo(id) };
}
 
/**
 * Handle atomic read-modify-write: atomic counter +<- 1
 *
 * Delegates to CodeGenerator's generateAtomicRMW which uses
 * LDREX/STREX on supported platforms or PRIMASK otherwise.
 */
function handleAtomicRMW(ctx: IAssignmentContext): string {
  const { typeInfo } = getTargetTypeInfo(ctx);
  const target = gen().generateAssignmentTarget(ctx.targetCtx);
 
  return gen().generateAtomicRMW(
    target,
    ctx.cOp,
    ctx.generatedValue,
    typeInfo!,
  );
}
 
/**
 * Handle overflow-clamped compound assignment: clamp u8 saturated +<- 200
 *
 * Generates calls to cnx_clamp_add_u8, cnx_clamp_sub_u8, etc.
 * Only applies to integers (floats use native C arithmetic with infinity).
 */
function handleOverflowClamp(ctx: IAssignmentContext): string {
  const { typeInfo } = getTargetTypeInfo(ctx);
  const target = gen().generateAssignmentTarget(ctx.targetCtx);
 
  // Floats use native C arithmetic (overflow to infinity)
  if (TypeCheckUtils.usesNativeArithmetic(typeInfo!.baseType)) {
    return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
  }
 
  const helperOp = CLAMP_OP_MAP[ctx.cOp];
 
  if (helperOp) {
    CodeGenState.markClampOpUsed(helperOp, typeInfo!.baseType);
    return `${target} = cnx_clamp_${helperOp}_${typeInfo!.baseType}(${target}, ${ctx.generatedValue});`;
  }
 
  // Fallback for operators without clamp helpers (e.g., /=)
  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;