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 | 14x 40x 40x 34x 6x 3x 3x 3x 3x 5x 5x 5x 35x 35x 35x 2x 33x 33x 32x 32x 1x 14x | /**
* 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 IHandlerDeps from "./IHandlerDeps";
import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
import TAssignmentHandler from "./TAssignmentHandler";
/** 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,
deps: IHandlerDeps,
): { typeInfo: ReturnType<typeof deps.typeRegistry.get> } {
const id = ctx.identifiers[0];
// Simple identifier
if (ctx.isSimpleIdentifier) {
return { typeInfo: deps.typeRegistry.get(id) };
}
// this.member: lookup using scoped name
if (ctx.isSimpleThisAccess && deps.currentScope) {
const scopedName = `${deps.currentScope}_${id}`;
return { typeInfo: deps.typeRegistry.get(scopedName) };
}
// global.member: lookup using direct name
Eif (ctx.isSimpleGlobalAccess) {
return { typeInfo: deps.typeRegistry.get(id) };
}
// Fallback to direct lookup
return { typeInfo: deps.typeRegistry.get(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, deps: IHandlerDeps): string {
const { typeInfo } = getTargetTypeInfo(ctx, deps);
const target = deps.generateAssignmentTarget(ctx.targetCtx);
return deps.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,
deps: IHandlerDeps,
): string {
const { typeInfo } = getTargetTypeInfo(ctx, deps);
const target = deps.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) {
deps.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;
|