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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | 550x 248x 168x 61x 57x 9x 5x 2x 6x 248x 248x 248x 248x 135x 135x 248x 248x 248x 248x 168x 168x 168x 168x 168x 135x 135x 129x 6x 6x 3x 3x 61x 61x 61x 57x 57x 57x 9x 9x 9x 5x 5x 5x 2x | /**
* HeaderSymbolAdapter - Converts TSymbol to IHeaderSymbol.
*
* ADR-055 Phase 7: This adapter converts the TSymbol discriminated union
* to IHeaderSymbol for header generation.
*/
import DeclaredTypeInfo from "../../../2-Plan/DeclaredTypeInfo";
import TSymbol from "../../../../types/symbols/TSymbol";
import IHeaderSymbol from "../types/IHeaderSymbol";
import IParameterSymbol from "../../../../utils/types/IParameterSymbol";
import TypeResolver from "../../../../utils/TypeResolver";
import ScopeUtils from "../../../../utils/ScopeUtils";
import type TType from "../../../../types/TType";
import type TranspileState from "../../../TranspileState";
/**
* Adapter to convert TSymbol to IHeaderSymbol
*/
class HeaderSymbolAdapter {
/**
* Convert a TSymbol to IHeaderSymbol
*/
static fromTSymbol(symbol: TSymbol, state: TranspileState): IHeaderSymbol {
switch (symbol.kind) {
case "function":
return HeaderSymbolAdapter.convertFunction(symbol);
case "variable":
return HeaderSymbolAdapter.convertVariable(symbol, state);
case "struct":
return HeaderSymbolAdapter.convertStruct(symbol);
case "enum":
return HeaderSymbolAdapter.convertEnum(symbol);
case "bitmap":
return HeaderSymbolAdapter.convertBitmap(symbol);
case "register":
return HeaderSymbolAdapter.convertRegister(symbol);
case "scope":
return HeaderSymbolAdapter.convertScope(symbol);
}
}
/**
* Convert an array of TSymbols to IHeaderSymbols
*/
static fromTSymbols(
symbols: TSymbol[],
state: TranspileState,
): IHeaderSymbol[] {
return symbols.map((s) => HeaderSymbolAdapter.fromTSymbol(s, state));
}
// ========================================================================
// Private conversion methods for each TSymbol kind
// ========================================================================
private static convertFunction(
func: import("../../../../types/symbols/IFunctionSymbol").default,
): IHeaderSymbol {
// Convert TType return type to string
const returnTypeStr = TypeResolver.getTypeName(func.returnType);
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(func);
const isGlobal = ScopeUtils.isGlobalScopePath(func.scopePath);
// ADR-057: type names arrive already scope-qualified from the symbol
// layer (CNextResolver pre-pass), so no qualification is needed here.
const parameters: IParameterSymbol[] = func.parameters.map((p) => {
const type = TypeResolver.getTypeName(p.type);
return {
name: p.name,
type,
isConst: p.isConst,
isArray: p.isArray,
arrayDimensions: HeaderSymbolAdapter.headerArrayDimensions(p),
isAutoConst: p.isAutoConst,
// ADR-030 / #1722: the stamp 1.4 set on the parameter, which the `.c`
// prototype and its call sites read too. This asked
// `isHeldThroughPointer` itself, a second decision that agreed with the
// `.c`'s only because both called one predicate.
isOpaqueHandle: p.isOpaqueHandle || undefined,
};
});
// Build signature with return type and param types
const qualifiedReturn = returnTypeStr;
const paramTypes = parameters.map((p) => p.type);
const signature = `${qualifiedReturn} ${cName}(${paramTypes.join(", ")})`;
return {
name: cName,
kind: "function",
type: qualifiedReturn,
parameters,
signature,
parent: isGlobal ? undefined : func.scopePath,
sourceFile: func.sourceFile,
sourceLine: func.span.line,
};
}
private static convertVariable(
variable: import("../../../../types/symbols/IVariableSymbol").default,
state: TranspileState,
): IHeaderSymbol {
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(variable);
const isGlobal = ScopeUtils.isGlobalScopePath(variable.scopePath);
// ADR-057: the symbol layer already qualified scope-local type names.
const typeStr = TypeResolver.getTypeName(variable.type);
// #1175: 1.4 settled each dimension to its value, or, for one only C can
// evaluate (a header macro), to its C -- there is nothing left to resolve
const arrayDimensions = variable.arrayDimensions?.map(String);
return {
name: cName,
kind: "variable",
type: typeStr,
isConst: variable.isConst,
isAtomic: variable.isAtomic,
isVolatile: variable.isVolatile,
isArray: variable.isArray,
isPointer:
DeclaredTypeInfo.of(
{ kind: "variable", symbol: variable },
state.symbols,
state.symbolTable,
state.targetDescription,
)?.isPointer ?? false,
arrayDimensions,
parent: isGlobal ? undefined : variable.scopePath,
sourceFile: variable.sourceFile,
sourceLine: variable.span.line,
};
}
/**
* A parameter's array dimensions as the C declaration needs them.
*
* A bounded string array carries its capacity as the innermost dimension --
* `string<32>[5]` is `char[5][33]`. ParameterSignatureBuilder documents that
* "dimensions include capacity" and the .c path supplies it; the header did
* not, so it declared `char arr[5]` against a `char arr[5][33]` definition
* (#1164).
*/
private static headerArrayDimensions(parameter: {
readonly type: TType;
readonly arrayDimensions?: ReadonlyArray<number | string>;
}): string[] | undefined {
// #1664 box 7: 1.4 folded each dimension it could, with the const values
// visible at the function; what is left (a C macro) is the C compiler's
const dimensions = parameter.arrayDimensions?.map(String);
if (!dimensions) {
return undefined;
}
const capacityMatch = /^string<(\d+)>$/.exec(
TypeResolver.getTypeName(parameter.type),
);
if (!capacityMatch) {
return dimensions;
}
// Whether the capacity is present is structural, not something to infer
// from the trailing value: a guard comparing it to `capacity + 1` misfires
// for any `string<N>[N+1]` and silently declares a different type than the
// .c defines. IParameterSymbol.arrayDimensions never carries the capacity --
// FunctionCollector.collectParameters records only the declared dimensions --
// so it is always appended here.
return [...dimensions, String(Number.parseInt(capacityMatch[1], 10) + 1)];
}
private static convertStruct(
struct: import("../../../../types/symbols/IStructSymbol").default,
): IHeaderSymbol {
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(struct);
const isGlobal = ScopeUtils.isGlobalScopePath(struct.scopePath);
return {
name: cName,
kind: "struct",
parent: isGlobal ? undefined : struct.scopePath,
sourceFile: struct.sourceFile,
sourceLine: struct.span.line,
};
}
private static convertEnum(
enumSym: import("../../../../types/symbols/IEnumSymbol").default,
): IHeaderSymbol {
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(enumSym);
const isGlobal = ScopeUtils.isGlobalScopePath(enumSym.scopePath);
return {
name: cName,
kind: "enum",
parent: isGlobal ? undefined : enumSym.scopePath,
sourceFile: enumSym.sourceFile,
sourceLine: enumSym.span.line,
};
}
private static convertBitmap(
bitmap: import("../../../../types/symbols/IBitmapSymbol").default,
): IHeaderSymbol {
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(bitmap);
const isGlobal = ScopeUtils.isGlobalScopePath(bitmap.scopePath);
return {
name: cName,
kind: "bitmap",
type: bitmap.backingType,
parent: isGlobal ? undefined : bitmap.scopePath,
sourceFile: bitmap.sourceFile,
sourceLine: bitmap.span.line,
};
}
private static convertRegister(
register: import("../../../../types/symbols/IRegisterSymbol").default,
): IHeaderSymbol {
// Get transpiled C name (scope-prefixed)
const cName = ScopeUtils.getTranspiledCName(register);
const isGlobal = ScopeUtils.isGlobalScopePath(register.scopePath);
return {
name: cName,
kind: "register",
parent: isGlobal ? undefined : register.scopePath,
sourceFile: register.sourceFile,
sourceLine: register.span.line,
};
}
private static convertScope(
scope: import("../../../../types/symbols/IScopeSymbol").default,
): IHeaderSymbol {
return {
name: scope.name,
kind: "scope",
// #1298: a scope states where it sits, like every other kind converted
// here. This literal used to omit `parent` entirely -- the shape with no
// parent that `getScopePath`'s guard existed to catch, built deliberately,
// and the one kind that could not say which scope contained it.
parent: ScopeUtils.isGlobalScopePath(scope.scopePath)
? undefined
: scope.scopePath,
sourceFile: scope.sourceFile,
sourceLine: scope.span.line,
};
}
}
export default HeaderSymbolAdapter;
|