c-next 0.1.62 → 0.1.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -63
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +3 -2
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
- package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
- package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
- package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
- package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
- package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
|
@@ -132,6 +132,12 @@ import AssignmentTargetExtractor from "./helpers/AssignmentTargetExtractor";
|
|
|
132
132
|
import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
|
|
133
133
|
// Phase 5: Cast validation helper for improved testability
|
|
134
134
|
import CastValidator from "./helpers/CastValidator";
|
|
135
|
+
// Global state for code generation (simplifies debugging, eliminates DI complexity)
|
|
136
|
+
import CodeGenState from "./CodeGenState";
|
|
137
|
+
// Extracted resolvers that use CodeGenState
|
|
138
|
+
import SizeofResolver from "./resolution/SizeofResolver";
|
|
139
|
+
import EnumTypeResolver from "./resolution/EnumTypeResolver";
|
|
140
|
+
import ScopeResolver from "./resolution/ScopeResolver";
|
|
135
141
|
|
|
136
142
|
const {
|
|
137
143
|
generateOverflowHelpers: helperGenerateOverflowHelpers,
|
|
@@ -179,25 +185,6 @@ interface FunctionSignature {
|
|
|
179
185
|
}>;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
/**
|
|
183
|
-
* ADR-029: Callback type info for Function-as-Type pattern
|
|
184
|
-
* Each function definition creates both a callable function AND a type
|
|
185
|
-
*/
|
|
186
|
-
interface CallbackTypeInfo {
|
|
187
|
-
functionName: string; // The original function name (also the type name)
|
|
188
|
-
returnType: string; // Return type for typedef (C type)
|
|
189
|
-
parameters: Array<{
|
|
190
|
-
// Parameter info for typedef
|
|
191
|
-
name: string;
|
|
192
|
-
type: string; // C type
|
|
193
|
-
isConst: boolean;
|
|
194
|
-
isPointer: boolean; // ADR-006: Non-array params become pointers
|
|
195
|
-
isArray: boolean; // Array parameters pass naturally as pointers
|
|
196
|
-
arrayDims: string; // Array dimensions if applicable
|
|
197
|
-
}>;
|
|
198
|
-
typedefName: string; // e.g., "onReceive_fp"
|
|
199
|
-
}
|
|
200
|
-
|
|
201
188
|
/**
|
|
202
189
|
* ADR-049: Target platform capabilities for code generation
|
|
203
190
|
*/
|
|
@@ -249,7 +236,7 @@ interface GeneratorContext {
|
|
|
249
236
|
indentLevel: number;
|
|
250
237
|
scopeMembers: Map<string, Set<string>>; // scope -> member names (ADR-016)
|
|
251
238
|
currentParameters: Map<string, TParameterInfo>; // ADR-006: track params for pointer semantics
|
|
252
|
-
// Issue #558: modifiedParameters removed - now uses analysis-phase results from
|
|
239
|
+
// Issue #558: modifiedParameters removed - now uses analysis-phase results from CodeGenState.modifiedParameters
|
|
253
240
|
localArrays: Set<string>; // ADR-006: track local array variables (no & needed)
|
|
254
241
|
localVariables: Set<string>; // ADR-016: track local variables (allowed as bare identifiers)
|
|
255
242
|
floatBitShadows: Set<string>; // Track declared shadow variables for float bit indexing
|
|
@@ -279,9 +266,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
279
266
|
["f64", "0.0"],
|
|
280
267
|
]);
|
|
281
268
|
|
|
282
|
-
/** ADR-044: Debug mode generates panic-on-overflow helpers */
|
|
283
|
-
private debugMode: boolean = false;
|
|
284
|
-
|
|
285
269
|
private context: GeneratorContext =
|
|
286
270
|
CodeGenerator.createDefaultContext(DEFAULT_TARGET);
|
|
287
271
|
|
|
@@ -318,55 +302,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
318
302
|
};
|
|
319
303
|
}
|
|
320
304
|
|
|
321
|
-
// Issue #60: Symbol fields moved to SymbolCollector
|
|
322
|
-
// Remaining fields not yet extracted:
|
|
323
|
-
|
|
324
|
-
private knownFunctions: Set<string> = new Set(); // Track C-Next defined functions
|
|
325
|
-
|
|
326
|
-
private functionSignatures: Map<string, FunctionSignature> = new Map(); // ADR-013: Track function parameter const-ness
|
|
327
|
-
|
|
328
|
-
// Bug #8: Track compile-time const values for array size resolution at file scope
|
|
329
|
-
private constValues: Map<string, number> = new Map(); // constName -> numeric value
|
|
330
|
-
|
|
331
|
-
// ADR-029: Callback types registry
|
|
332
|
-
private callbackTypes: Map<string, CallbackTypeInfo> = new Map(); // funcName -> CallbackTypeInfo
|
|
333
|
-
|
|
334
|
-
private callbackFieldTypes: Map<string, string> = new Map(); // "Struct.field" -> callbackTypeName
|
|
335
|
-
|
|
336
|
-
// ADR-044: Track which overflow helper types and operations are needed
|
|
337
|
-
private usedClampOps: Set<string> = new Set(); // Format: "add_u8", "sub_u16", "mul_u32"
|
|
338
|
-
|
|
339
|
-
private usedSafeDivOps: Set<string> = new Set(); // ADR-051: Format: "div_u32", "mod_i16"
|
|
340
|
-
|
|
341
|
-
// Track required standard library includes
|
|
342
|
-
private needsStdint: boolean = false; // For u8, u16, u32, u64, i8, i16, i32, i64
|
|
343
|
-
|
|
344
|
-
private needsStdbool: boolean = false; // For bool type
|
|
345
|
-
|
|
346
|
-
private needsString: boolean = false; // ADR-045: For strlen, strncpy, etc.
|
|
347
|
-
|
|
348
|
-
private needsFloatStaticAssert: boolean = false; // For float bit indexing size verification
|
|
349
|
-
|
|
350
|
-
private needsISR: boolean = false; // ADR-040: For ISR function pointer type
|
|
351
|
-
|
|
352
|
-
private needsCMSIS: boolean = false; // ADR-049/050: For atomic intrinsics and critical sections
|
|
353
|
-
|
|
354
|
-
private needsLimits: boolean = false; // Issue #632: For float-to-int clamp casts
|
|
355
|
-
|
|
356
|
-
private needsIrqWrappers: boolean = false; // Issue #473: IRQ wrappers for critical sections
|
|
357
|
-
|
|
358
|
-
/** External symbol table for cross-language interop */
|
|
359
|
-
private symbolTable: SymbolTable | null = null;
|
|
360
|
-
|
|
361
|
-
/** ADR-010: Source file path for validating includes */
|
|
362
|
-
private sourcePath: string | null = null;
|
|
363
|
-
|
|
364
|
-
/** Issue #349: Include directories for resolving angle-bracket .cnx includes */
|
|
365
|
-
private includeDirs: string[] = [];
|
|
366
|
-
|
|
367
|
-
/** Issue #349: Input directories for calculating relative paths */
|
|
368
|
-
private inputs: string[] = [];
|
|
369
|
-
|
|
370
305
|
/** Token stream for comment extraction (ADR-043) */
|
|
371
306
|
private tokenStream: CommonTokenStream | null = null;
|
|
372
307
|
|
|
@@ -374,117 +309,18 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
374
309
|
|
|
375
310
|
private readonly commentFormatter: CommentFormatter = new CommentFormatter();
|
|
376
311
|
|
|
377
|
-
/** Type resolution and classification */
|
|
378
|
-
private typeResolver: TypeResolver | null = null;
|
|
312
|
+
/** Type resolution and classification - now a static class, no instance needed */
|
|
379
313
|
|
|
380
314
|
/** Symbol collection - ADR-055: Now uses ISymbolInfo from TSymbolInfoAdapter */
|
|
381
315
|
public symbols: ICodeGenSymbols | null = null;
|
|
382
316
|
|
|
383
|
-
/** Type validation - Issue #63: Extracted from CodeGenerator */
|
|
384
|
-
private typeValidator: TypeValidator | null = null;
|
|
385
|
-
|
|
386
|
-
/** Issue #644: String length counter for strlen caching optimization */
|
|
387
|
-
private stringLengthCounter: StringLengthCounter | null = null;
|
|
388
|
-
|
|
389
|
-
/** Issue #644: Member chain analyzer for bit access pattern detection */
|
|
390
|
-
private memberChainAnalyzer: MemberChainAnalyzer | null = null;
|
|
391
|
-
|
|
392
|
-
/** Issue #644: Float bit write helper for shadow variable pattern */
|
|
393
|
-
private floatBitHelper: FloatBitHelper | null = null;
|
|
394
|
-
|
|
395
317
|
/** Issue #644: String declaration helper for bounded/array/concat strings */
|
|
396
|
-
private stringDeclHelper: StringDeclHelper | null = null;
|
|
397
|
-
|
|
398
|
-
/** Issue #644: Enum assignment validator for type-safe enum assignments */
|
|
399
|
-
private enumValidator: EnumAssignmentValidator | null = null;
|
|
400
318
|
|
|
401
319
|
/** Issue #644: Array initialization helper for size inference and fill-all */
|
|
402
|
-
private arrayInitHelper: ArrayInitHelper | null = null;
|
|
403
|
-
|
|
404
|
-
/** Issue #644: Assignment expected type resolution helper */
|
|
405
|
-
private expectedTypeResolver: AssignmentExpectedTypeResolver | null = null;
|
|
406
|
-
|
|
407
|
-
/** Issue #644: Assignment validation coordinator helper */
|
|
408
|
-
private assignmentValidator: AssignmentValidator | null = null;
|
|
409
320
|
|
|
410
321
|
/** Generator registry for modular code generation (ADR-053) */
|
|
411
322
|
private readonly registry: GeneratorRegistry = new GeneratorRegistry();
|
|
412
323
|
|
|
413
|
-
/** Issue #250: C++ mode - use temp vars instead of compound literals */
|
|
414
|
-
private cppMode: boolean = false;
|
|
415
|
-
|
|
416
|
-
/** Issue #644: C/C++ mode helper for consolidated mode-specific patterns */
|
|
417
|
-
private cppHelper: CppModeHelper | null = null;
|
|
418
|
-
|
|
419
|
-
/** Issue #250: Pending temp variable declarations for C++ mode */
|
|
420
|
-
private pendingTempDeclarations: string[] = [];
|
|
421
|
-
|
|
422
|
-
/** Issue #250: Counter for unique temp variable names */
|
|
423
|
-
private tempVarCounter: number = 0;
|
|
424
|
-
|
|
425
|
-
/** Issue #517: Pending field assignments for C++ class struct init */
|
|
426
|
-
private pendingCppClassAssignments: string[] = [];
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Issue #269: Tracks which parameters are modified (directly or transitively)
|
|
430
|
-
* Map of functionName -> Set of modified parameter names
|
|
431
|
-
*/
|
|
432
|
-
private readonly modifiedParameters: Map<string, Set<string>> = new Map();
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Issue #579: Tracks which parameters have subscript access (read or write)
|
|
436
|
-
* These parameters must become pointers to support array access semantics
|
|
437
|
-
* Map of functionName -> Set of parameter names with subscript access
|
|
438
|
-
*/
|
|
439
|
-
private readonly subscriptAccessedParameters: Map<string, Set<string>> =
|
|
440
|
-
new Map();
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Issue #558: Pending cross-file modifications to inject after analyzePassByValue clears.
|
|
444
|
-
* Set by Pipeline before generate() to share modifications from previously processed files.
|
|
445
|
-
*/
|
|
446
|
-
private pendingCrossFileModifications: ReadonlyMap<
|
|
447
|
-
string,
|
|
448
|
-
ReadonlySet<string>
|
|
449
|
-
> | null = null;
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Issue #558: Pending cross-file parameter lists to inject for transitive propagation.
|
|
453
|
-
*/
|
|
454
|
-
private pendingCrossFileParamLists: ReadonlyMap<
|
|
455
|
-
string,
|
|
456
|
-
readonly string[]
|
|
457
|
-
> | null = null;
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Issue #269: Tracks which parameters should pass by value
|
|
461
|
-
* Map of functionName -> Set of passByValue parameter names
|
|
462
|
-
*/
|
|
463
|
-
private readonly passByValueParams: Map<string, Set<string>> = new Map();
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Issue #269: Tracks function call relationships for transitive modification analysis
|
|
467
|
-
* Map of functionName -> Array of {callee, paramIndex, argParamName}
|
|
468
|
-
* where argParamName is the caller's parameter passed as argument
|
|
469
|
-
*/
|
|
470
|
-
private readonly functionCallGraph: Map<
|
|
471
|
-
string,
|
|
472
|
-
Array<{ callee: string; paramIndex: number; argParamName: string }>
|
|
473
|
-
> = new Map();
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Issue #269: Tracks function parameter lists for call graph analysis
|
|
477
|
-
* Map of functionName -> Array of parameter names in order
|
|
478
|
-
*/
|
|
479
|
-
private readonly functionParamLists: Map<string, string[]> = new Map();
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Issue #369: Tracks whether self-include was added.
|
|
483
|
-
* When true, skip struct/enum/bitmap definitions in .c file because
|
|
484
|
-
* they'll be defined in the included header.
|
|
485
|
-
*/
|
|
486
|
-
private selfIncludeAdded: boolean = false;
|
|
487
|
-
|
|
488
324
|
/**
|
|
489
325
|
* Initialize generator registry with extracted generators.
|
|
490
326
|
* Called once before code generation begins.
|
|
@@ -617,17 +453,17 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
617
453
|
*/
|
|
618
454
|
getInput(): IGeneratorInput {
|
|
619
455
|
return {
|
|
620
|
-
symbolTable:
|
|
621
|
-
symbols:
|
|
622
|
-
typeRegistry:
|
|
623
|
-
functionSignatures:
|
|
624
|
-
knownFunctions:
|
|
625
|
-
knownStructs:
|
|
626
|
-
constValues:
|
|
627
|
-
callbackTypes:
|
|
628
|
-
callbackFieldTypes:
|
|
629
|
-
targetCapabilities:
|
|
630
|
-
debugMode:
|
|
456
|
+
symbolTable: CodeGenState.symbolTable,
|
|
457
|
+
symbols: CodeGenState.symbols,
|
|
458
|
+
typeRegistry: CodeGenState.typeRegistry,
|
|
459
|
+
functionSignatures: CodeGenState.functionSignatures,
|
|
460
|
+
knownFunctions: CodeGenState.knownFunctions,
|
|
461
|
+
knownStructs: CodeGenState.symbols?.knownStructs ?? new Set(),
|
|
462
|
+
constValues: CodeGenState.constValues,
|
|
463
|
+
callbackTypes: CodeGenState.callbackTypes,
|
|
464
|
+
callbackFieldTypes: CodeGenState.callbackFieldTypes,
|
|
465
|
+
targetCapabilities: CodeGenState.targetCapabilities,
|
|
466
|
+
debugMode: CodeGenState.debugMode,
|
|
631
467
|
};
|
|
632
468
|
}
|
|
633
469
|
|
|
@@ -637,20 +473,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
637
473
|
*/
|
|
638
474
|
getState(): IGeneratorState {
|
|
639
475
|
return {
|
|
640
|
-
currentScope:
|
|
641
|
-
indentLevel:
|
|
642
|
-
inFunctionBody:
|
|
643
|
-
currentParameters:
|
|
644
|
-
localVariables:
|
|
645
|
-
localArrays:
|
|
646
|
-
expectedType:
|
|
647
|
-
selfIncludeAdded:
|
|
476
|
+
currentScope: CodeGenState.currentScope,
|
|
477
|
+
indentLevel: CodeGenState.indentLevel,
|
|
478
|
+
inFunctionBody: CodeGenState.inFunctionBody,
|
|
479
|
+
currentParameters: CodeGenState.currentParameters,
|
|
480
|
+
localVariables: CodeGenState.localVariables,
|
|
481
|
+
localArrays: CodeGenState.localArrays,
|
|
482
|
+
expectedType: CodeGenState.expectedType,
|
|
483
|
+
selfIncludeAdded: CodeGenState.selfIncludeAdded, // Issue #369
|
|
648
484
|
// Issue #644: Postfix expression state
|
|
649
|
-
scopeMembers:
|
|
650
|
-
mainArgsName:
|
|
651
|
-
floatBitShadows:
|
|
652
|
-
floatShadowCurrent:
|
|
653
|
-
lengthCache:
|
|
485
|
+
scopeMembers: CodeGenState.scopeMembers,
|
|
486
|
+
mainArgsName: CodeGenState.mainArgsName,
|
|
487
|
+
floatBitShadows: CodeGenState.floatBitShadows,
|
|
488
|
+
floatShadowCurrent: CodeGenState.floatShadowCurrent,
|
|
489
|
+
lengthCache: CodeGenState.lengthCache,
|
|
654
490
|
};
|
|
655
491
|
}
|
|
656
492
|
|
|
@@ -671,64 +507,68 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
671
507
|
|
|
672
508
|
// Helper function effects
|
|
673
509
|
case "helper":
|
|
674
|
-
|
|
510
|
+
CodeGenState.usedClampOps.add(
|
|
511
|
+
`${effect.operation}_${effect.cnxType}`,
|
|
512
|
+
);
|
|
675
513
|
break;
|
|
676
514
|
case "safe-div":
|
|
677
|
-
|
|
515
|
+
CodeGenState.usedSafeDivOps.add(
|
|
516
|
+
`${effect.operation}_${effect.cnxType}`,
|
|
517
|
+
);
|
|
678
518
|
break;
|
|
679
519
|
|
|
680
520
|
// Type registration effects
|
|
681
521
|
case "register-type":
|
|
682
|
-
|
|
522
|
+
CodeGenState.typeRegistry.set(effect.name, effect.info);
|
|
683
523
|
break;
|
|
684
524
|
case "register-local":
|
|
685
|
-
|
|
525
|
+
CodeGenState.localVariables.add(effect.name);
|
|
686
526
|
if (effect.isArray) {
|
|
687
|
-
|
|
527
|
+
CodeGenState.localArrays.add(effect.name);
|
|
688
528
|
}
|
|
689
529
|
break;
|
|
690
530
|
case "register-const-value":
|
|
691
|
-
|
|
531
|
+
CodeGenState.constValues.set(effect.name, effect.value);
|
|
692
532
|
break;
|
|
693
533
|
|
|
694
534
|
// Scope effects (ADR-016)
|
|
695
535
|
case "set-scope":
|
|
696
|
-
|
|
536
|
+
CodeGenState.currentScope = effect.name;
|
|
697
537
|
break;
|
|
698
538
|
|
|
699
539
|
// Function body effects
|
|
700
540
|
case "enter-function-body":
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
541
|
+
CodeGenState.inFunctionBody = true;
|
|
542
|
+
CodeGenState.localVariables.clear();
|
|
543
|
+
CodeGenState.localArrays.clear();
|
|
544
|
+
CodeGenState.floatBitShadows.clear();
|
|
545
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
706
546
|
break;
|
|
707
547
|
case "exit-function-body":
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
548
|
+
CodeGenState.inFunctionBody = false;
|
|
549
|
+
CodeGenState.localVariables.clear();
|
|
550
|
+
CodeGenState.localArrays.clear();
|
|
551
|
+
CodeGenState.floatBitShadows.clear();
|
|
552
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
713
553
|
break;
|
|
714
554
|
case "set-parameters":
|
|
715
|
-
|
|
555
|
+
CodeGenState.currentParameters = new Map(effect.params);
|
|
716
556
|
break;
|
|
717
557
|
case "clear-parameters":
|
|
718
|
-
|
|
558
|
+
CodeGenState.currentParameters.clear();
|
|
719
559
|
break;
|
|
720
560
|
|
|
721
561
|
// Callback effects
|
|
722
562
|
case "register-callback-field":
|
|
723
|
-
|
|
563
|
+
CodeGenState.callbackFieldTypes.set(effect.key, effect.typeName);
|
|
724
564
|
break;
|
|
725
565
|
|
|
726
566
|
// Array initializer effects
|
|
727
567
|
case "set-array-init-count":
|
|
728
|
-
|
|
568
|
+
CodeGenState.lastArrayInitCount = effect.count;
|
|
729
569
|
break;
|
|
730
570
|
case "set-array-fill-value":
|
|
731
|
-
|
|
571
|
+
CodeGenState.lastArrayFillValue = effect.value;
|
|
732
572
|
break;
|
|
733
573
|
}
|
|
734
574
|
}
|
|
@@ -743,28 +583,28 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
743
583
|
private requireInclude(header: TIncludeHeader): void {
|
|
744
584
|
switch (header) {
|
|
745
585
|
case "stdint":
|
|
746
|
-
|
|
586
|
+
CodeGenState.needsStdint = true;
|
|
747
587
|
break;
|
|
748
588
|
case "stdbool":
|
|
749
|
-
|
|
589
|
+
CodeGenState.needsStdbool = true;
|
|
750
590
|
break;
|
|
751
591
|
case "string":
|
|
752
|
-
|
|
592
|
+
CodeGenState.needsString = true;
|
|
753
593
|
break;
|
|
754
594
|
case "cmsis":
|
|
755
|
-
|
|
595
|
+
CodeGenState.needsCMSIS = true;
|
|
756
596
|
break;
|
|
757
597
|
case "limits":
|
|
758
|
-
|
|
598
|
+
CodeGenState.needsLimits = true;
|
|
759
599
|
break;
|
|
760
600
|
case "isr":
|
|
761
|
-
|
|
601
|
+
CodeGenState.needsISR = true;
|
|
762
602
|
break;
|
|
763
603
|
case "float_static_assert":
|
|
764
|
-
|
|
604
|
+
CodeGenState.needsFloatStaticAssert = true;
|
|
765
605
|
break;
|
|
766
606
|
case "irq_wrappers":
|
|
767
|
-
|
|
607
|
+
CodeGenState.needsIrqWrappers = true;
|
|
768
608
|
break;
|
|
769
609
|
}
|
|
770
610
|
}
|
|
@@ -773,7 +613,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
773
613
|
* Get the current indentation string.
|
|
774
614
|
*/
|
|
775
615
|
getIndent(): string {
|
|
776
|
-
return FormatUtils.indent(
|
|
616
|
+
return FormatUtils.indent(CodeGenState.indentLevel);
|
|
777
617
|
}
|
|
778
618
|
|
|
779
619
|
/**
|
|
@@ -784,10 +624,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
784
624
|
*/
|
|
785
625
|
resolveIdentifier(identifier: string): string {
|
|
786
626
|
// Check current scope first (inner scope shadows outer)
|
|
787
|
-
if (
|
|
788
|
-
const members =
|
|
627
|
+
if (CodeGenState.currentScope) {
|
|
628
|
+
const members = CodeGenState.scopeMembers.get(CodeGenState.currentScope);
|
|
789
629
|
if (members?.has(identifier)) {
|
|
790
|
-
return `${
|
|
630
|
+
return `${CodeGenState.currentScope}_${identifier}`;
|
|
791
631
|
}
|
|
792
632
|
}
|
|
793
633
|
|
|
@@ -813,10 +653,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
813
653
|
ctx: Parser.ExpressionContext,
|
|
814
654
|
expectedType: string | null,
|
|
815
655
|
): string {
|
|
816
|
-
const savedExpectedType =
|
|
817
|
-
|
|
656
|
+
const savedExpectedType = CodeGenState.expectedType;
|
|
657
|
+
CodeGenState.expectedType = expectedType;
|
|
818
658
|
const result = this.generateExpression(ctx);
|
|
819
|
-
|
|
659
|
+
CodeGenState.expectedType = savedExpectedType;
|
|
820
660
|
return result;
|
|
821
661
|
}
|
|
822
662
|
|
|
@@ -833,12 +673,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
833
673
|
|
|
834
674
|
// Generate the C type using the helper with dependencies
|
|
835
675
|
return TypeGenerationHelper.generate(ctx, {
|
|
836
|
-
currentScope:
|
|
676
|
+
currentScope: CodeGenState.currentScope,
|
|
837
677
|
isCppScopeSymbol: (name) => this.isCppScopeSymbol(name),
|
|
838
678
|
checkNeedsStructKeyword: (name) =>
|
|
839
|
-
|
|
679
|
+
CodeGenState.symbolTable?.checkNeedsStructKeyword(name) ?? false,
|
|
840
680
|
validateCrossScopeVisibility: (scope, member) =>
|
|
841
|
-
|
|
681
|
+
ScopeResolver.validateCrossScopeVisibility(scope, member),
|
|
842
682
|
});
|
|
843
683
|
}
|
|
844
684
|
|
|
@@ -882,9 +722,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
882
722
|
*/
|
|
883
723
|
isKnownStruct(typeName: string): boolean {
|
|
884
724
|
return SymbolLookupHelper.isKnownStruct(
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
725
|
+
CodeGenState.symbols?.knownStructs,
|
|
726
|
+
CodeGenState.symbols?.knownBitmaps,
|
|
727
|
+
CodeGenState.symbolTable,
|
|
888
728
|
typeName,
|
|
889
729
|
);
|
|
890
730
|
}
|
|
@@ -894,7 +734,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
894
734
|
* Part of IOrchestrator interface - delegates to TypeResolver.
|
|
895
735
|
*/
|
|
896
736
|
isFloatType(typeName: string): boolean {
|
|
897
|
-
return
|
|
737
|
+
return TypeResolver.isFloatType(typeName);
|
|
898
738
|
}
|
|
899
739
|
|
|
900
740
|
/**
|
|
@@ -902,7 +742,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
902
742
|
* Part of IOrchestrator interface - delegates to TypeResolver.
|
|
903
743
|
*/
|
|
904
744
|
isIntegerType(typeName: string): boolean {
|
|
905
|
-
return
|
|
745
|
+
return TypeResolver.isIntegerType(typeName);
|
|
906
746
|
}
|
|
907
747
|
|
|
908
748
|
/**
|
|
@@ -911,8 +751,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
911
751
|
*/
|
|
912
752
|
isCNextFunction(name: string): boolean {
|
|
913
753
|
return SymbolLookupHelper.isCNextFunctionCombined(
|
|
914
|
-
|
|
915
|
-
|
|
754
|
+
CodeGenState.knownFunctions,
|
|
755
|
+
CodeGenState.symbolTable,
|
|
916
756
|
name,
|
|
917
757
|
);
|
|
918
758
|
}
|
|
@@ -926,7 +766,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
926
766
|
getExpressionEnumType(
|
|
927
767
|
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
928
768
|
): string | null {
|
|
929
|
-
return
|
|
769
|
+
return EnumTypeResolver.resolve(ctx);
|
|
930
770
|
}
|
|
931
771
|
|
|
932
772
|
/**
|
|
@@ -955,7 +795,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
955
795
|
|
|
956
796
|
// Check if it's a simple variable of string type
|
|
957
797
|
if (/^[a-zA-Z_]\w*$/.exec(text)) {
|
|
958
|
-
const typeInfo =
|
|
798
|
+
const typeInfo = CodeGenState.typeRegistry.get(text);
|
|
959
799
|
if (typeInfo?.isString) {
|
|
960
800
|
return true;
|
|
961
801
|
}
|
|
@@ -975,7 +815,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
975
815
|
return false;
|
|
976
816
|
}
|
|
977
817
|
const arrayName = arrayAccessMatch[1];
|
|
978
|
-
const typeInfo =
|
|
818
|
+
const typeInfo = CodeGenState.typeRegistry.get(arrayName);
|
|
979
819
|
// Check if base type is a string type
|
|
980
820
|
if (
|
|
981
821
|
typeInfo?.isString ||
|
|
@@ -1017,7 +857,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1017
857
|
memberName: string,
|
|
1018
858
|
isGlobalAccess: boolean = false,
|
|
1019
859
|
): void {
|
|
1020
|
-
|
|
860
|
+
ScopeResolver.validateCrossScopeVisibility(
|
|
861
|
+
scopeName,
|
|
862
|
+
memberName,
|
|
863
|
+
isGlobalAccess,
|
|
864
|
+
);
|
|
1021
865
|
}
|
|
1022
866
|
|
|
1023
867
|
/**
|
|
@@ -1030,7 +874,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1030
874
|
op: string,
|
|
1031
875
|
ctx: Parser.ShiftExpressionContext,
|
|
1032
876
|
): void {
|
|
1033
|
-
|
|
877
|
+
TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx);
|
|
1034
878
|
}
|
|
1035
879
|
|
|
1036
880
|
/**
|
|
@@ -1038,7 +882,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1038
882
|
* Part of IOrchestrator interface - delegates to TypeValidator.
|
|
1039
883
|
*/
|
|
1040
884
|
validateTernaryCondition(condition: Parser.OrExpressionContext): void {
|
|
1041
|
-
|
|
885
|
+
TypeValidator.validateTernaryCondition(condition);
|
|
1042
886
|
}
|
|
1043
887
|
|
|
1044
888
|
/**
|
|
@@ -1049,7 +893,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1049
893
|
expr: Parser.OrExpressionContext,
|
|
1050
894
|
branchName: string,
|
|
1051
895
|
): void {
|
|
1052
|
-
|
|
896
|
+
TypeValidator.validateNoNestedTernary(expr, branchName);
|
|
1053
897
|
}
|
|
1054
898
|
|
|
1055
899
|
// === Function Call Helpers (ADR-053 A2 Phase 5) ===
|
|
@@ -1078,7 +922,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1078
922
|
* Part of IOrchestrator interface - delegates to TypeValidator.
|
|
1079
923
|
*/
|
|
1080
924
|
isConstValue(name: string): boolean {
|
|
1081
|
-
return
|
|
925
|
+
return TypeValidator.isConstValue(name);
|
|
1082
926
|
}
|
|
1083
927
|
|
|
1084
928
|
/**
|
|
@@ -1086,7 +930,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1086
930
|
* Part of IOrchestrator interface.
|
|
1087
931
|
*/
|
|
1088
932
|
getKnownEnums(): ReadonlySet<string> {
|
|
1089
|
-
return
|
|
933
|
+
return CodeGenState.symbols!.knownEnums;
|
|
1090
934
|
}
|
|
1091
935
|
|
|
1092
936
|
/**
|
|
@@ -1094,7 +938,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1094
938
|
* Part of IOrchestrator interface.
|
|
1095
939
|
*/
|
|
1096
940
|
isCppMode(): boolean {
|
|
1097
|
-
return
|
|
941
|
+
return CodeGenState.cppMode;
|
|
1098
942
|
}
|
|
1099
943
|
|
|
1100
944
|
/**
|
|
@@ -1103,7 +947,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1103
947
|
* Part of IOrchestrator interface.
|
|
1104
948
|
*/
|
|
1105
949
|
isCppEnumClass(typeName: string): boolean {
|
|
1106
|
-
return SymbolLookupHelper.isCppEnumClass(
|
|
950
|
+
return SymbolLookupHelper.isCppEnumClass(
|
|
951
|
+
CodeGenState.symbolTable,
|
|
952
|
+
typeName,
|
|
953
|
+
);
|
|
1107
954
|
}
|
|
1108
955
|
|
|
1109
956
|
/**
|
|
@@ -1111,7 +958,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1111
958
|
* Part of IOrchestrator interface.
|
|
1112
959
|
*/
|
|
1113
960
|
getExpressionType(ctx: Parser.ExpressionContext): string | null {
|
|
1114
|
-
return
|
|
961
|
+
return TypeResolver.getExpressionType(ctx);
|
|
1115
962
|
}
|
|
1116
963
|
|
|
1117
964
|
/**
|
|
@@ -1124,9 +971,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1124
971
|
|
|
1125
972
|
for (const stmt of ctx.statement()) {
|
|
1126
973
|
// Temporarily increment for any nested context that needs absolute level
|
|
1127
|
-
|
|
974
|
+
CodeGenState.indentLevel++;
|
|
1128
975
|
const stmtCode = this.generateStatement(stmt);
|
|
1129
|
-
|
|
976
|
+
CodeGenState.indentLevel--;
|
|
1130
977
|
|
|
1131
978
|
if (stmtCode) {
|
|
1132
979
|
// Add one level of indent to each line (relative indentation)
|
|
@@ -1147,7 +994,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1147
994
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
1148
995
|
*/
|
|
1149
996
|
validateNoEarlyExits(ctx: Parser.BlockContext): void {
|
|
1150
|
-
|
|
997
|
+
TypeValidator.validateNoEarlyExits(ctx);
|
|
1151
998
|
}
|
|
1152
999
|
|
|
1153
1000
|
/**
|
|
@@ -1184,9 +1031,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1184
1031
|
}
|
|
1185
1032
|
|
|
1186
1033
|
// Issue #250: Prepend any pending temp variable declarations (C++ mode)
|
|
1187
|
-
if (
|
|
1188
|
-
const tempDecls =
|
|
1189
|
-
|
|
1034
|
+
if (CodeGenState.pendingTempDeclarations.length > 0) {
|
|
1035
|
+
const tempDecls = CodeGenState.pendingTempDeclarations.join("\n");
|
|
1036
|
+
CodeGenState.pendingTempDeclarations = [];
|
|
1190
1037
|
return tempDecls + "\n" + result;
|
|
1191
1038
|
}
|
|
1192
1039
|
|
|
@@ -1199,11 +1046,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1199
1046
|
* Part of IOrchestrator interface.
|
|
1200
1047
|
*/
|
|
1201
1048
|
flushPendingTempDeclarations(): string {
|
|
1202
|
-
if (
|
|
1049
|
+
if (CodeGenState.pendingTempDeclarations.length === 0) {
|
|
1203
1050
|
return "";
|
|
1204
1051
|
}
|
|
1205
|
-
const decls =
|
|
1206
|
-
|
|
1052
|
+
const decls = CodeGenState.pendingTempDeclarations.join("\n");
|
|
1053
|
+
CodeGenState.pendingTempDeclarations = [];
|
|
1207
1054
|
return decls;
|
|
1208
1055
|
}
|
|
1209
1056
|
|
|
@@ -1212,7 +1059,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1212
1059
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
1213
1060
|
*/
|
|
1214
1061
|
indent(text: string): string {
|
|
1215
|
-
return FormatUtils.indentAllLines(text,
|
|
1062
|
+
return FormatUtils.indentAllLines(text, CodeGenState.indentLevel);
|
|
1216
1063
|
}
|
|
1217
1064
|
|
|
1218
1065
|
/**
|
|
@@ -1223,7 +1070,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1223
1070
|
ctx: Parser.SwitchStatementContext,
|
|
1224
1071
|
switchExpr: Parser.ExpressionContext,
|
|
1225
1072
|
): void {
|
|
1226
|
-
|
|
1073
|
+
TypeValidator.validateSwitchStatement(ctx, switchExpr);
|
|
1227
1074
|
}
|
|
1228
1075
|
|
|
1229
1076
|
/**
|
|
@@ -1231,7 +1078,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1231
1078
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
1232
1079
|
*/
|
|
1233
1080
|
validateDoWhileCondition(ctx: Parser.ExpressionContext): void {
|
|
1234
|
-
|
|
1081
|
+
TypeValidator.validateDoWhileCondition(ctx);
|
|
1235
1082
|
}
|
|
1236
1083
|
|
|
1237
1084
|
/**
|
|
@@ -1242,7 +1089,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1242
1089
|
ctx: Parser.ExpressionContext,
|
|
1243
1090
|
conditionType: string,
|
|
1244
1091
|
): void {
|
|
1245
|
-
|
|
1092
|
+
TypeValidator.validateConditionNoFunctionCall(ctx, conditionType);
|
|
1246
1093
|
}
|
|
1247
1094
|
|
|
1248
1095
|
/**
|
|
@@ -1252,7 +1099,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1252
1099
|
validateTernaryConditionNoFunctionCall(
|
|
1253
1100
|
ctx: Parser.OrExpressionContext,
|
|
1254
1101
|
): void {
|
|
1255
|
-
|
|
1102
|
+
TypeValidator.validateTernaryConditionNoFunctionCall(ctx);
|
|
1256
1103
|
}
|
|
1257
1104
|
|
|
1258
1105
|
/**
|
|
@@ -1280,7 +1127,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1280
1127
|
safeIdentifier,
|
|
1281
1128
|
hasGlobal,
|
|
1282
1129
|
hasThis,
|
|
1283
|
-
|
|
1130
|
+
CodeGenState.currentScope,
|
|
1284
1131
|
);
|
|
1285
1132
|
|
|
1286
1133
|
// No postfix operations - return base
|
|
@@ -1321,8 +1168,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1321
1168
|
countStringLengthAccesses(
|
|
1322
1169
|
ctx: Parser.ExpressionContext,
|
|
1323
1170
|
): Map<string, number> {
|
|
1324
|
-
// Issue #644: Delegate to extracted StringLengthCounter
|
|
1325
|
-
return
|
|
1171
|
+
// Issue #644: Delegate to extracted StringLengthCounter (now static)
|
|
1172
|
+
return StringLengthCounter.countExpression(ctx);
|
|
1326
1173
|
}
|
|
1327
1174
|
|
|
1328
1175
|
/**
|
|
@@ -1333,8 +1180,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1333
1180
|
ctx: Parser.BlockContext,
|
|
1334
1181
|
counts: Map<string, number>,
|
|
1335
1182
|
): void {
|
|
1336
|
-
// Issue #644: Delegate to extracted StringLengthCounter
|
|
1337
|
-
|
|
1183
|
+
// Issue #644: Delegate to extracted StringLengthCounter (now static)
|
|
1184
|
+
StringLengthCounter.countBlockInto(ctx, counts);
|
|
1338
1185
|
}
|
|
1339
1186
|
|
|
1340
1187
|
/**
|
|
@@ -1354,7 +1201,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1354
1201
|
}
|
|
1355
1202
|
|
|
1356
1203
|
if (declarations.length > 0) {
|
|
1357
|
-
|
|
1204
|
+
CodeGenState.lengthCache = cache;
|
|
1358
1205
|
return declarations.join("\n") + "\n";
|
|
1359
1206
|
}
|
|
1360
1207
|
|
|
@@ -1366,7 +1213,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1366
1213
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
1367
1214
|
*/
|
|
1368
1215
|
clearLengthCache(): void {
|
|
1369
|
-
|
|
1216
|
+
CodeGenState.lengthCache = null;
|
|
1370
1217
|
}
|
|
1371
1218
|
|
|
1372
1219
|
/**
|
|
@@ -1374,7 +1221,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1374
1221
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
1375
1222
|
*/
|
|
1376
1223
|
registerLocalVariable(name: string): void {
|
|
1377
|
-
|
|
1224
|
+
CodeGenState.localVariables.add(name);
|
|
1378
1225
|
}
|
|
1379
1226
|
|
|
1380
1227
|
// === Declaration Generation (ADR-053 A4) ===
|
|
@@ -1384,7 +1231,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1384
1231
|
if (dim.expression()) {
|
|
1385
1232
|
// Bug #8: At file scope, resolve const values to numeric literals
|
|
1386
1233
|
// because C doesn't allow const variables as array sizes at file scope
|
|
1387
|
-
if (!
|
|
1234
|
+
if (!CodeGenState.inFunctionBody) {
|
|
1388
1235
|
const constValue = this.tryEvaluateConstant(dim.expression()!);
|
|
1389
1236
|
if (constValue !== undefined) {
|
|
1390
1237
|
return `[${constValue}]`;
|
|
@@ -1408,8 +1255,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1408
1255
|
// ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
|
|
1409
1256
|
if (ctx.scopedType()) {
|
|
1410
1257
|
const typeName = ctx.scopedType()!.IDENTIFIER().getText();
|
|
1411
|
-
if (
|
|
1412
|
-
return `${
|
|
1258
|
+
if (CodeGenState.currentScope) {
|
|
1259
|
+
return `${CodeGenState.currentScope}_${typeName}`;
|
|
1413
1260
|
}
|
|
1414
1261
|
return typeName;
|
|
1415
1262
|
}
|
|
@@ -1424,6 +1271,16 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1424
1271
|
const identifierNames = identifiers.map((id) => id.getText());
|
|
1425
1272
|
return this.resolveQualifiedType(identifierNames);
|
|
1426
1273
|
}
|
|
1274
|
+
// Handle C-Next array type syntax (Type[N]) - return base type without dimension
|
|
1275
|
+
if (ctx.arrayType()) {
|
|
1276
|
+
const arrayTypeCtx = ctx.arrayType()!;
|
|
1277
|
+
if (arrayTypeCtx.primitiveType()) {
|
|
1278
|
+
return arrayTypeCtx.primitiveType()!.getText();
|
|
1279
|
+
}
|
|
1280
|
+
if (arrayTypeCtx.userType()) {
|
|
1281
|
+
return arrayTypeCtx.userType()!.getText();
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1427
1284
|
if (ctx.userType()) {
|
|
1428
1285
|
return ctx.userType()!.getText();
|
|
1429
1286
|
}
|
|
@@ -1436,7 +1293,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1436
1293
|
/** Try to evaluate a constant expression at compile time */
|
|
1437
1294
|
tryEvaluateConstant(ctx: Parser.ExpressionContext): number | undefined {
|
|
1438
1295
|
return ArrayDimensionParser.parseSingleDimension(ctx, {
|
|
1439
|
-
constValues:
|
|
1296
|
+
constValues: CodeGenState.constValues,
|
|
1440
1297
|
typeWidths: TYPE_WIDTH,
|
|
1441
1298
|
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
1442
1299
|
});
|
|
@@ -1457,7 +1314,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1457
1314
|
const resolved = this._resolveTypeNameFromContext(typeCtx);
|
|
1458
1315
|
if (resolved) {
|
|
1459
1316
|
// Check if enum
|
|
1460
|
-
if (
|
|
1317
|
+
if (CodeGenState.symbols!.knownEnums.has(resolved.name)) {
|
|
1461
1318
|
return this._getEnumZeroValue(resolved.name, resolved.separator);
|
|
1462
1319
|
}
|
|
1463
1320
|
// Check if C++ type needing {} (only for userType, not qualified/scoped/global)
|
|
@@ -1531,7 +1388,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1531
1388
|
// Variable - check type registry
|
|
1532
1389
|
const identifierRegex = /^[a-zA-Z_]\w*$/;
|
|
1533
1390
|
if (identifierRegex.test(exprCode)) {
|
|
1534
|
-
const typeInfo =
|
|
1391
|
+
const typeInfo = CodeGenState.typeRegistry.get(exprCode);
|
|
1535
1392
|
if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
|
|
1536
1393
|
return typeInfo.stringCapacity;
|
|
1537
1394
|
}
|
|
@@ -1554,7 +1411,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1554
1411
|
|
|
1555
1412
|
/** Check if a callback type is used as a struct field type */
|
|
1556
1413
|
isCallbackTypeUsedAsFieldType(funcName: string): boolean {
|
|
1557
|
-
for (const callbackType of
|
|
1414
|
+
for (const callbackType of CodeGenState.callbackFieldTypes.values()) {
|
|
1558
1415
|
if (callbackType === funcName) {
|
|
1559
1416
|
return true;
|
|
1560
1417
|
}
|
|
@@ -1565,7 +1422,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1565
1422
|
// === Scope Management (A4) ===
|
|
1566
1423
|
|
|
1567
1424
|
setCurrentScope(name: string | null): void {
|
|
1568
|
-
|
|
1425
|
+
CodeGenState.currentScope = name;
|
|
1426
|
+
CodeGenState.currentScope = name;
|
|
1569
1427
|
}
|
|
1570
1428
|
|
|
1571
1429
|
/**
|
|
@@ -1573,7 +1431,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1573
1431
|
* Part of IOrchestrator interface.
|
|
1574
1432
|
*/
|
|
1575
1433
|
setCurrentFunctionName(name: string | null): void {
|
|
1576
|
-
|
|
1434
|
+
CodeGenState.currentFunctionName = name;
|
|
1435
|
+
CodeGenState.currentFunctionName = name;
|
|
1577
1436
|
}
|
|
1578
1437
|
|
|
1579
1438
|
/**
|
|
@@ -1581,36 +1440,43 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1581
1440
|
* Used by return statement generation to set expectedType.
|
|
1582
1441
|
*/
|
|
1583
1442
|
getCurrentFunctionReturnType(): string | null {
|
|
1584
|
-
return
|
|
1443
|
+
return CodeGenState.currentFunctionReturnType;
|
|
1585
1444
|
}
|
|
1586
1445
|
|
|
1587
1446
|
/**
|
|
1588
1447
|
* Issue #477: Set the current function's return type for enum inference.
|
|
1589
1448
|
*/
|
|
1590
1449
|
setCurrentFunctionReturnType(returnType: string | null): void {
|
|
1591
|
-
|
|
1450
|
+
CodeGenState.currentFunctionReturnType = returnType;
|
|
1451
|
+
CodeGenState.currentFunctionReturnType = returnType;
|
|
1592
1452
|
}
|
|
1593
1453
|
|
|
1594
1454
|
// === Function Body Management (A4) ===
|
|
1595
1455
|
|
|
1596
1456
|
enterFunctionBody(): void {
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1457
|
+
CodeGenState.localVariables.clear();
|
|
1458
|
+
CodeGenState.floatBitShadows.clear();
|
|
1459
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
1600
1460
|
// Issue #558: modifiedParameters tracking removed - uses analysis-phase results
|
|
1601
|
-
|
|
1461
|
+
CodeGenState.inFunctionBody = true;
|
|
1462
|
+
// Sync with CodeGenState
|
|
1463
|
+
CodeGenState.enterFunctionBody();
|
|
1602
1464
|
}
|
|
1603
1465
|
|
|
1604
1466
|
exitFunctionBody(): void {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1467
|
+
CodeGenState.inFunctionBody = false;
|
|
1468
|
+
CodeGenState.localVariables.clear();
|
|
1469
|
+
CodeGenState.floatBitShadows.clear();
|
|
1470
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
1471
|
+
CodeGenState.mainArgsName = null;
|
|
1472
|
+
// Sync with CodeGenState
|
|
1473
|
+
CodeGenState.exitFunctionBody();
|
|
1474
|
+
CodeGenState.mainArgsName = null;
|
|
1610
1475
|
}
|
|
1611
1476
|
|
|
1612
1477
|
setMainArgsName(name: string | null): void {
|
|
1613
|
-
|
|
1478
|
+
CodeGenState.mainArgsName = name;
|
|
1479
|
+
CodeGenState.mainArgsName = name;
|
|
1614
1480
|
}
|
|
1615
1481
|
|
|
1616
1482
|
isMainFunctionWithArgs(
|
|
@@ -1624,7 +1490,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1624
1490
|
* ADR-029: Generate typedef for callback type
|
|
1625
1491
|
*/
|
|
1626
1492
|
generateCallbackTypedef(funcName: string): string | null {
|
|
1627
|
-
const callbackInfo =
|
|
1493
|
+
const callbackInfo = CodeGenState.callbackTypes.get(funcName);
|
|
1628
1494
|
if (!callbackInfo) {
|
|
1629
1495
|
return null;
|
|
1630
1496
|
}
|
|
@@ -1674,8 +1540,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1674
1540
|
updateFunctionParamsAutoConst(functionName: string): void {
|
|
1675
1541
|
// Collect unmodified parameters for this function using analysis results
|
|
1676
1542
|
const unmodifiedParams = new Set<string>();
|
|
1677
|
-
const modifiedSet =
|
|
1678
|
-
for (const [paramName] of
|
|
1543
|
+
const modifiedSet = CodeGenState.modifiedParameters.get(functionName);
|
|
1544
|
+
for (const [paramName] of CodeGenState.currentParameters) {
|
|
1679
1545
|
if (!modifiedSet?.has(paramName)) {
|
|
1680
1546
|
unmodifiedParams.add(paramName);
|
|
1681
1547
|
}
|
|
@@ -1698,9 +1564,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1698
1564
|
* This is the unified source of truth for modification tracking.
|
|
1699
1565
|
*/
|
|
1700
1566
|
private _isCurrentParameterModified(paramName: string): boolean {
|
|
1701
|
-
const funcName =
|
|
1567
|
+
const funcName = CodeGenState.currentFunctionName;
|
|
1702
1568
|
if (!funcName) return false;
|
|
1703
|
-
return
|
|
1569
|
+
return (
|
|
1570
|
+
CodeGenState.modifiedParameters.get(funcName)?.has(paramName) ?? false
|
|
1571
|
+
);
|
|
1704
1572
|
}
|
|
1705
1573
|
|
|
1706
1574
|
/**
|
|
@@ -1708,7 +1576,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1708
1576
|
* Returns function name -> set of modified parameter names.
|
|
1709
1577
|
*/
|
|
1710
1578
|
getModifiedParameters(): ReadonlyMap<string, Set<string>> {
|
|
1711
|
-
return
|
|
1579
|
+
return CodeGenState.modifiedParameters;
|
|
1712
1580
|
}
|
|
1713
1581
|
|
|
1714
1582
|
/**
|
|
@@ -1719,15 +1587,15 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1719
1587
|
modifications: ReadonlyMap<string, ReadonlySet<string>>,
|
|
1720
1588
|
paramLists: ReadonlyMap<string, readonly string[]>,
|
|
1721
1589
|
): void {
|
|
1722
|
-
|
|
1723
|
-
|
|
1590
|
+
CodeGenState.pendingCrossFileModifications = modifications;
|
|
1591
|
+
CodeGenState.pendingCrossFileParamLists = paramLists;
|
|
1724
1592
|
}
|
|
1725
1593
|
|
|
1726
1594
|
/**
|
|
1727
1595
|
* Issue #558: Get the function parameter lists for cross-file propagation.
|
|
1728
1596
|
*/
|
|
1729
1597
|
getFunctionParamLists(): ReadonlyMap<string, string[]> {
|
|
1730
|
-
return
|
|
1598
|
+
return CodeGenState.functionParamLists;
|
|
1731
1599
|
}
|
|
1732
1600
|
|
|
1733
1601
|
/**
|
|
@@ -1750,14 +1618,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1750
1618
|
paramLists: Map<string, string[]>;
|
|
1751
1619
|
} {
|
|
1752
1620
|
// Save current state
|
|
1753
|
-
const savedModifications = new Map(
|
|
1754
|
-
const savedParamLists = new Map(
|
|
1755
|
-
const savedCallGraph = new Map(
|
|
1621
|
+
const savedModifications = new Map(CodeGenState.modifiedParameters);
|
|
1622
|
+
const savedParamLists = new Map(CodeGenState.functionParamLists);
|
|
1623
|
+
const savedCallGraph = new Map(CodeGenState.functionCallGraph);
|
|
1756
1624
|
|
|
1757
1625
|
// Clear for fresh analysis
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1626
|
+
CodeGenState.modifiedParameters.clear();
|
|
1627
|
+
CodeGenState.functionParamLists.clear();
|
|
1628
|
+
CodeGenState.functionCallGraph.clear();
|
|
1761
1629
|
|
|
1762
1630
|
// Issue #565: Inject cross-file data BEFORE collecting this file's info
|
|
1763
1631
|
this.injectCrossFileData(crossFileModifications, crossFileParamLists);
|
|
@@ -1770,9 +1638,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1770
1638
|
|
|
1771
1639
|
// Issue #565: Run transitive propagation with full context
|
|
1772
1640
|
TransitiveModificationPropagator.propagate(
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1641
|
+
CodeGenState.functionCallGraph,
|
|
1642
|
+
CodeGenState.functionParamLists,
|
|
1643
|
+
CodeGenState.modifiedParameters,
|
|
1776
1644
|
);
|
|
1777
1645
|
|
|
1778
1646
|
// Capture results - only include functions NOT from cross-file injection
|
|
@@ -1783,9 +1651,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1783
1651
|
const paramLists = this.extractThisFileParamLists(crossFileParamLists);
|
|
1784
1652
|
|
|
1785
1653
|
// Restore previous state
|
|
1786
|
-
this.restoreMapState(
|
|
1787
|
-
this.restoreMapState(
|
|
1788
|
-
this.restoreMapState(
|
|
1654
|
+
this.restoreMapState(CodeGenState.modifiedParameters, savedModifications);
|
|
1655
|
+
this.restoreMapState(CodeGenState.functionParamLists, savedParamLists);
|
|
1656
|
+
this.restoreMapState(CodeGenState.functionCallGraph, savedCallGraph);
|
|
1789
1657
|
|
|
1790
1658
|
return { modifications, paramLists };
|
|
1791
1659
|
}
|
|
@@ -1799,12 +1667,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1799
1667
|
): void {
|
|
1800
1668
|
if (crossFileModifications) {
|
|
1801
1669
|
for (const [funcName, params] of crossFileModifications) {
|
|
1802
|
-
|
|
1670
|
+
CodeGenState.modifiedParameters.set(funcName, new Set(params));
|
|
1803
1671
|
}
|
|
1804
1672
|
}
|
|
1805
1673
|
if (crossFileParamLists) {
|
|
1806
1674
|
for (const [funcName, params] of crossFileParamLists) {
|
|
1807
|
-
|
|
1675
|
+
CodeGenState.functionParamLists.set(funcName, [...params]);
|
|
1808
1676
|
}
|
|
1809
1677
|
}
|
|
1810
1678
|
}
|
|
@@ -1820,7 +1688,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1820
1688
|
): Map<string, Set<string>> {
|
|
1821
1689
|
const modifications = new Map<string, Set<string>>();
|
|
1822
1690
|
|
|
1823
|
-
for (const [funcName, params] of
|
|
1691
|
+
for (const [funcName, params] of CodeGenState.modifiedParameters) {
|
|
1824
1692
|
if (!injectedFuncs.has(funcName)) {
|
|
1825
1693
|
// Function defined in this file - include all its modifications
|
|
1826
1694
|
modifications.set(funcName, new Set(params));
|
|
@@ -1857,7 +1725,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1857
1725
|
crossFileParamLists?: ReadonlyMap<string, readonly string[]>,
|
|
1858
1726
|
): Map<string, string[]> {
|
|
1859
1727
|
return SetMapHelper.copyArrayValues(
|
|
1860
|
-
SetMapHelper.filterExclude(
|
|
1728
|
+
SetMapHelper.filterExclude(
|
|
1729
|
+
CodeGenState.functionParamLists,
|
|
1730
|
+
crossFileParamLists,
|
|
1731
|
+
),
|
|
1861
1732
|
);
|
|
1862
1733
|
}
|
|
1863
1734
|
|
|
@@ -1882,7 +1753,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1882
1753
|
}
|
|
1883
1754
|
|
|
1884
1755
|
// Get the parameter name at the given index from the function signature
|
|
1885
|
-
const sig =
|
|
1756
|
+
const sig = CodeGenState.functionSignatures.get(funcName);
|
|
1886
1757
|
if (!sig || paramIndex >= sig.parameters.length) {
|
|
1887
1758
|
return false;
|
|
1888
1759
|
}
|
|
@@ -1896,7 +1767,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1896
1767
|
* Issue #268: Check if a name is a parameter of the current function.
|
|
1897
1768
|
*/
|
|
1898
1769
|
isCurrentParameter(name: string): boolean {
|
|
1899
|
-
return
|
|
1770
|
+
return CodeGenState.currentParameters.has(name);
|
|
1900
1771
|
}
|
|
1901
1772
|
|
|
1902
1773
|
// === Postfix Expression Helpers (Issue #644) ===
|
|
@@ -1952,8 +1823,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1952
1823
|
*/
|
|
1953
1824
|
isKnownScope(name: string): boolean {
|
|
1954
1825
|
return SymbolLookupHelper.isKnownScope(
|
|
1955
|
-
|
|
1956
|
-
|
|
1826
|
+
CodeGenState.symbols?.knownScopes,
|
|
1827
|
+
CodeGenState.symbolTable,
|
|
1957
1828
|
name,
|
|
1958
1829
|
);
|
|
1959
1830
|
}
|
|
@@ -1965,7 +1836,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1965
1836
|
isCppScopeSymbol(name: string): boolean {
|
|
1966
1837
|
return CppNamespaceUtils.isCppNamespace(
|
|
1967
1838
|
name,
|
|
1968
|
-
|
|
1839
|
+
CodeGenState.symbolTable ?? undefined,
|
|
1969
1840
|
);
|
|
1970
1841
|
}
|
|
1971
1842
|
|
|
@@ -1986,8 +1857,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1986
1857
|
fieldName: string,
|
|
1987
1858
|
): { type: string; dimensions?: (number | string)[] } | null {
|
|
1988
1859
|
// First check SymbolTable (C header structs)
|
|
1989
|
-
if (
|
|
1990
|
-
const fieldInfo =
|
|
1860
|
+
if (CodeGenState.symbolTable) {
|
|
1861
|
+
const fieldInfo = CodeGenState.symbolTable.getStructFieldInfo(
|
|
1991
1862
|
structType,
|
|
1992
1863
|
fieldName,
|
|
1993
1864
|
);
|
|
@@ -2000,12 +1871,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2000
1871
|
}
|
|
2001
1872
|
|
|
2002
1873
|
// Fall back to local C-Next struct fields
|
|
2003
|
-
const localFields =
|
|
1874
|
+
const localFields = CodeGenState.symbols!.structFields.get(structType);
|
|
2004
1875
|
if (localFields) {
|
|
2005
1876
|
const fieldType = localFields.get(fieldName);
|
|
2006
1877
|
if (fieldType) {
|
|
2007
1878
|
const fieldDimensions =
|
|
2008
|
-
|
|
1879
|
+
CodeGenState.symbols!.structFieldDimensions.get(structType);
|
|
2009
1880
|
const dimensions = fieldDimensions?.get(fieldName);
|
|
2010
1881
|
return {
|
|
2011
1882
|
type: fieldType,
|
|
@@ -2027,7 +1898,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2027
1898
|
|
|
2028
1899
|
const isArray =
|
|
2029
1900
|
(fieldInfo.dimensions !== undefined && fieldInfo.dimensions.length > 0) ||
|
|
2030
|
-
(
|
|
1901
|
+
(CodeGenState.symbols!.structFieldArrays.get(structType)?.has(
|
|
1902
|
+
memberName,
|
|
1903
|
+
) ??
|
|
2031
1904
|
false);
|
|
2032
1905
|
const dims = fieldInfo.dimensions?.filter(
|
|
2033
1906
|
(d): d is number => typeof d === "number",
|
|
@@ -2057,7 +1930,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2057
1930
|
* Part of IOrchestrator interface.
|
|
2058
1931
|
*/
|
|
2059
1932
|
addPendingTempDeclaration(declaration: string): void {
|
|
2060
|
-
|
|
1933
|
+
CodeGenState.pendingTempDeclarations.push(declaration);
|
|
2061
1934
|
}
|
|
2062
1935
|
|
|
2063
1936
|
/**
|
|
@@ -2065,7 +1938,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2065
1938
|
* Part of IOrchestrator interface.
|
|
2066
1939
|
*/
|
|
2067
1940
|
registerFloatBitShadow(shadowName: string): void {
|
|
2068
|
-
|
|
1941
|
+
CodeGenState.floatBitShadows.add(shadowName);
|
|
2069
1942
|
}
|
|
2070
1943
|
|
|
2071
1944
|
/**
|
|
@@ -2073,7 +1946,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2073
1946
|
* Part of IOrchestrator interface.
|
|
2074
1947
|
*/
|
|
2075
1948
|
markFloatShadowCurrent(shadowName: string): void {
|
|
2076
|
-
|
|
1949
|
+
CodeGenState.floatShadowCurrent.add(shadowName);
|
|
2077
1950
|
}
|
|
2078
1951
|
|
|
2079
1952
|
/**
|
|
@@ -2081,7 +1954,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2081
1954
|
* Part of IOrchestrator interface.
|
|
2082
1955
|
*/
|
|
2083
1956
|
hasFloatBitShadow(shadowName: string): boolean {
|
|
2084
|
-
return
|
|
1957
|
+
return CodeGenState.floatBitShadows.has(shadowName);
|
|
2085
1958
|
}
|
|
2086
1959
|
|
|
2087
1960
|
/**
|
|
@@ -2089,7 +1962,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2089
1962
|
* Part of IOrchestrator interface.
|
|
2090
1963
|
*/
|
|
2091
1964
|
isFloatShadowCurrent(shadowName: string): boolean {
|
|
2092
|
-
return
|
|
1965
|
+
return CodeGenState.floatShadowCurrent.has(shadowName);
|
|
2093
1966
|
}
|
|
2094
1967
|
|
|
2095
1968
|
// ===========================================================================
|
|
@@ -2113,11 +1986,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2113
1986
|
return {
|
|
2114
1987
|
isFloatType: (typeName: string) => this._isFloatType(typeName),
|
|
2115
1988
|
isKnownPrimitive: (typeName: string) => this._isKnownPrimitive(typeName),
|
|
2116
|
-
knownEnums:
|
|
1989
|
+
knownEnums: CodeGenState.symbols!.knownEnums,
|
|
2117
1990
|
isParameterPassByValue: (funcName: string, paramName: string) =>
|
|
2118
1991
|
this._isParameterPassByValueByName(funcName, paramName),
|
|
2119
|
-
currentFunctionName:
|
|
2120
|
-
maybeDereference: (id: string) =>
|
|
1992
|
+
currentFunctionName: CodeGenState.currentFunctionName,
|
|
1993
|
+
maybeDereference: (id: string) => CppModeHelper.maybeDereference(id),
|
|
2121
1994
|
};
|
|
2122
1995
|
}
|
|
2123
1996
|
|
|
@@ -2128,7 +2001,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2128
2001
|
private _buildMemberSeparatorDeps(): IMemberSeparatorDeps {
|
|
2129
2002
|
return {
|
|
2130
2003
|
isKnownScope: (name: string) => this.isKnownScope(name),
|
|
2131
|
-
isKnownRegister: (name: string) =>
|
|
2004
|
+
isKnownRegister: (name: string) =>
|
|
2005
|
+
CodeGenState.symbols!.knownRegisters.has(name),
|
|
2132
2006
|
validateCrossScopeVisibility: (scopeName: string, memberName: string) =>
|
|
2133
2007
|
this.validateCrossScopeVisibility(scopeName, memberName),
|
|
2134
2008
|
validateRegisterAccess: (
|
|
@@ -2137,7 +2011,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2137
2011
|
hasGlobal: boolean,
|
|
2138
2012
|
) => this._validateRegisterAccess(registerName, memberName, hasGlobal),
|
|
2139
2013
|
getStructParamSeparator: () =>
|
|
2140
|
-
memberAccessChain.getStructParamSeparator({
|
|
2014
|
+
memberAccessChain.getStructParamSeparator({
|
|
2015
|
+
cppMode: CodeGenState.cppMode,
|
|
2016
|
+
}),
|
|
2141
2017
|
};
|
|
2142
2018
|
}
|
|
2143
2019
|
|
|
@@ -2150,10 +2026,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2150
2026
|
hasGlobal: boolean,
|
|
2151
2027
|
): void {
|
|
2152
2028
|
// Only validate when inside a scope and accessing without global. prefix
|
|
2153
|
-
if (
|
|
2029
|
+
if (CodeGenState.currentScope && !hasGlobal) {
|
|
2154
2030
|
throw new Error(
|
|
2155
2031
|
`Error: Use 'global.${registerName}.${memberName}' to access register '${registerName}' ` +
|
|
2156
|
-
`from inside scope '${
|
|
2032
|
+
`from inside scope '${CodeGenState.currentScope}'`,
|
|
2157
2033
|
);
|
|
2158
2034
|
}
|
|
2159
2035
|
}
|
|
@@ -2165,7 +2041,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2165
2041
|
* We check for the existence of a constructor symbol (TypeName::ClassName).
|
|
2166
2042
|
*/
|
|
2167
2043
|
private _isCppClassWithConstructor(typeName: string): boolean {
|
|
2168
|
-
return CppConstructorHelper.hasConstructor(
|
|
2044
|
+
return CppConstructorHelper.hasConstructor(
|
|
2045
|
+
typeName,
|
|
2046
|
+
CodeGenState.symbolTable,
|
|
2047
|
+
);
|
|
2169
2048
|
}
|
|
2170
2049
|
|
|
2171
2050
|
private foldBooleanToInt(expr: string): string {
|
|
@@ -2203,7 +2082,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2203
2082
|
* C++ types with constructors may fail with {0} but work with {}.
|
|
2204
2083
|
*/
|
|
2205
2084
|
private isCppType(typeName: string): boolean {
|
|
2206
|
-
return SymbolLookupHelper.isCppType(
|
|
2085
|
+
return SymbolLookupHelper.isCppType(CodeGenState.symbolTable, typeName);
|
|
2207
2086
|
}
|
|
2208
2087
|
|
|
2209
2088
|
/**
|
|
@@ -2219,12 +2098,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2219
2098
|
tokenStream?: CommonTokenStream,
|
|
2220
2099
|
options?: ICodeGeneratorOptions,
|
|
2221
2100
|
): string {
|
|
2222
|
-
// Store symbol table for function lookup
|
|
2223
|
-
this.symbolTable = symbolTable ?? null;
|
|
2224
|
-
|
|
2225
|
-
// Initialize options and configuration
|
|
2226
|
-
this.initializeGenerateOptions(options, tokenStream);
|
|
2227
|
-
|
|
2228
2101
|
// ADR-049: Determine target capabilities with priority: CLI > pragma > default
|
|
2229
2102
|
const targetCapabilities = this.resolveTargetCapabilities(
|
|
2230
2103
|
tree,
|
|
@@ -2237,16 +2110,22 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2237
2110
|
this.generatorsInitialized = true;
|
|
2238
2111
|
}
|
|
2239
2112
|
|
|
2240
|
-
// Reset state for fresh generation
|
|
2113
|
+
// Reset state for fresh generation (must be before any state assignments)
|
|
2241
2114
|
this.resetGeneratorState(targetCapabilities);
|
|
2242
2115
|
|
|
2116
|
+
// Initialize options and configuration (after reset)
|
|
2117
|
+
this.initializeGenerateOptions(options, tokenStream);
|
|
2118
|
+
|
|
2119
|
+
// Store symbol table for function lookup (after reset)
|
|
2120
|
+
CodeGenState.symbolTable = symbolTable ?? null;
|
|
2121
|
+
|
|
2243
2122
|
// ADR-055: Use pre-collected symbolInfo from Pipeline (TSymbolInfoAdapter)
|
|
2244
2123
|
if (!options?.symbolInfo) {
|
|
2245
2124
|
throw new Error(
|
|
2246
2125
|
"symbolInfo is required - use CNextResolver + TSymbolInfoAdapter",
|
|
2247
2126
|
);
|
|
2248
2127
|
}
|
|
2249
|
-
|
|
2128
|
+
CodeGenState.symbols = options.symbolInfo;
|
|
2250
2129
|
|
|
2251
2130
|
// Initialize symbol data and const values
|
|
2252
2131
|
this.initializeSymbolData();
|
|
@@ -2268,15 +2147,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2268
2147
|
options: ICodeGeneratorOptions | undefined,
|
|
2269
2148
|
tokenStream: CommonTokenStream | undefined,
|
|
2270
2149
|
): void {
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
this.pendingCppClassAssignments = [];
|
|
2150
|
+
CodeGenState.debugMode = options?.debugMode ?? false;
|
|
2151
|
+
CodeGenState.sourcePath = options?.sourcePath ?? null;
|
|
2152
|
+
CodeGenState.includeDirs = options?.includeDirs ?? [];
|
|
2153
|
+
CodeGenState.inputs = options?.inputs ?? [];
|
|
2154
|
+
CodeGenState.cppMode = options?.cppMode ?? false;
|
|
2155
|
+
CodeGenState.pendingTempDeclarations = [];
|
|
2156
|
+
CodeGenState.tempVarCounter = 0;
|
|
2157
|
+
CodeGenState.pendingCppClassAssignments = [];
|
|
2280
2158
|
|
|
2281
2159
|
this.tokenStream = tokenStream ?? null;
|
|
2282
2160
|
this.commentExtractor = this.tokenStream
|
|
@@ -2288,40 +2166,44 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2288
2166
|
* Reset all generator state for a fresh generation pass.
|
|
2289
2167
|
*/
|
|
2290
2168
|
private resetGeneratorState(targetCapabilities: TargetCapabilities): void {
|
|
2169
|
+
// Reset global state first
|
|
2170
|
+
CodeGenState.reset(targetCapabilities);
|
|
2171
|
+
|
|
2172
|
+
// Reset local context (will gradually migrate to CodeGenState)
|
|
2291
2173
|
this.context = CodeGenerator.createDefaultContext(targetCapabilities);
|
|
2292
2174
|
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2175
|
+
CodeGenState.knownFunctions = new Set();
|
|
2176
|
+
CodeGenState.functionSignatures = new Map();
|
|
2177
|
+
CodeGenState.callbackTypes = new Map();
|
|
2178
|
+
CodeGenState.callbackFieldTypes = new Map();
|
|
2179
|
+
CodeGenState.usedClampOps = new Set();
|
|
2180
|
+
CodeGenState.usedSafeDivOps = new Set();
|
|
2181
|
+
CodeGenState.needsStdint = false;
|
|
2182
|
+
CodeGenState.needsStdbool = false;
|
|
2183
|
+
CodeGenState.needsString = false;
|
|
2184
|
+
CodeGenState.needsFloatStaticAssert = false;
|
|
2185
|
+
CodeGenState.needsISR = false;
|
|
2186
|
+
CodeGenState.needsCMSIS = false;
|
|
2187
|
+
CodeGenState.needsLimits = false;
|
|
2188
|
+
CodeGenState.needsIrqWrappers = false;
|
|
2189
|
+
CodeGenState.selfIncludeAdded = false;
|
|
2308
2190
|
}
|
|
2309
2191
|
|
|
2310
2192
|
/**
|
|
2311
2193
|
* Initialize symbol data and const values from symbol table.
|
|
2312
2194
|
*/
|
|
2313
2195
|
private initializeSymbolData(): void {
|
|
2314
|
-
const symbols =
|
|
2196
|
+
const symbols = CodeGenState.symbols!;
|
|
2315
2197
|
|
|
2316
|
-
// Copy symbol data to
|
|
2198
|
+
// Copy symbol data to CodeGenState.scopeMembers
|
|
2317
2199
|
for (const [scopeName, members] of symbols.scopeMembers) {
|
|
2318
|
-
|
|
2200
|
+
CodeGenState.scopeMembers.set(scopeName, new Set(members));
|
|
2319
2201
|
}
|
|
2320
2202
|
|
|
2321
2203
|
// Issue #461: Initialize constValues from symbol table
|
|
2322
|
-
|
|
2323
|
-
if (
|
|
2324
|
-
for (const symbol of
|
|
2204
|
+
CodeGenState.constValues = new Map();
|
|
2205
|
+
if (CodeGenState.symbolTable) {
|
|
2206
|
+
for (const symbol of CodeGenState.symbolTable.getAllSymbols()) {
|
|
2325
2207
|
if (
|
|
2326
2208
|
symbol.kind === ESymbolKind.Variable &&
|
|
2327
2209
|
symbol.isConst &&
|
|
@@ -2329,7 +2211,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2329
2211
|
) {
|
|
2330
2212
|
const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
|
|
2331
2213
|
if (value !== undefined) {
|
|
2332
|
-
|
|
2214
|
+
CodeGenState.constValues.set(symbol.name, value);
|
|
2215
|
+
// Also populate CodeGenState
|
|
2216
|
+
CodeGenState.constValues.set(symbol.name, value);
|
|
2333
2217
|
}
|
|
2334
2218
|
}
|
|
2335
2219
|
}
|
|
@@ -2340,141 +2224,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2340
2224
|
* Initialize all helper objects needed for code generation.
|
|
2341
2225
|
*/
|
|
2342
2226
|
private initializeHelperObjects(tree: Parser.ProgramContext): void {
|
|
2343
|
-
const symbols = this.symbols!;
|
|
2344
|
-
|
|
2345
|
-
// Initialize type resolver
|
|
2346
|
-
this.typeResolver = new TypeResolver({
|
|
2347
|
-
symbols: symbols,
|
|
2348
|
-
symbolTable: this.symbolTable,
|
|
2349
|
-
typeRegistry: this.context.typeRegistry,
|
|
2350
|
-
resolveIdentifier: (name: string) => this.resolveIdentifier(name),
|
|
2351
|
-
});
|
|
2352
|
-
|
|
2353
2227
|
// Collect function/callback information
|
|
2354
2228
|
this.collectFunctionsAndCallbacks(tree);
|
|
2355
2229
|
this.analyzePassByValue(tree);
|
|
2356
|
-
|
|
2357
|
-
// Initialize type validator
|
|
2358
|
-
this.typeValidator = new TypeValidator({
|
|
2359
|
-
symbols: symbols,
|
|
2360
|
-
symbolTable: this.symbolTable,
|
|
2361
|
-
typeRegistry: this.context.typeRegistry,
|
|
2362
|
-
typeResolver: this.typeResolver,
|
|
2363
|
-
callbackTypes: this.callbackTypes,
|
|
2364
|
-
knownFunctions: this.knownFunctions,
|
|
2365
|
-
knownGlobals: new Set(),
|
|
2366
|
-
getCurrentScope: () => this.context.currentScope,
|
|
2367
|
-
getScopeMembers: () => this.context.scopeMembers,
|
|
2368
|
-
getCurrentParameters: () => this.context.currentParameters,
|
|
2369
|
-
getLocalVariables: () => this.context.localVariables,
|
|
2370
|
-
resolveIdentifier: (name: string) => this.resolveIdentifier(name),
|
|
2371
|
-
getExpressionType: (ctx: unknown) =>
|
|
2372
|
-
this.getExpressionType(ctx as Parser.ExpressionContext),
|
|
2373
|
-
});
|
|
2374
|
-
|
|
2375
|
-
// Initialize remaining helpers
|
|
2376
|
-
this.initializeAnalysisHelpers(symbols);
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
/**
|
|
2380
|
-
* Initialize analysis and generation helpers.
|
|
2381
|
-
*/
|
|
2382
|
-
private initializeAnalysisHelpers(symbols: ICodeGenSymbols): void {
|
|
2383
|
-
this.stringLengthCounter = new StringLengthCounter((name: string) =>
|
|
2384
|
-
this.context.typeRegistry.get(name),
|
|
2385
|
-
);
|
|
2386
|
-
|
|
2387
|
-
this.memberChainAnalyzer = new MemberChainAnalyzer({
|
|
2388
|
-
typeRegistry: this.context.typeRegistry,
|
|
2389
|
-
structFields: symbols.structFields,
|
|
2390
|
-
structFieldArrays: symbols.structFieldArrays,
|
|
2391
|
-
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
2392
|
-
generateExpression: (ctx) => this.generateExpression(ctx),
|
|
2393
|
-
});
|
|
2394
|
-
|
|
2395
|
-
this.floatBitHelper = new FloatBitHelper({
|
|
2396
|
-
cppMode: this.cppMode,
|
|
2397
|
-
state: {
|
|
2398
|
-
floatBitShadows: this.context.floatBitShadows,
|
|
2399
|
-
floatShadowCurrent: this.context.floatShadowCurrent,
|
|
2400
|
-
},
|
|
2401
|
-
generateBitMask: (width, is64Bit) => this.generateBitMask(width, is64Bit),
|
|
2402
|
-
foldBooleanToInt: (expr) => this.foldBooleanToInt(expr),
|
|
2403
|
-
requireInclude: (header) => this.requireInclude(header),
|
|
2404
|
-
});
|
|
2405
|
-
|
|
2406
|
-
// Create arrayInitState proxy
|
|
2407
|
-
const context = this.context;
|
|
2408
|
-
const arrayInitState = {
|
|
2409
|
-
get lastArrayInitCount() {
|
|
2410
|
-
return context.lastArrayInitCount;
|
|
2411
|
-
},
|
|
2412
|
-
set lastArrayInitCount(val: number) {
|
|
2413
|
-
context.lastArrayInitCount = val;
|
|
2414
|
-
},
|
|
2415
|
-
get lastArrayFillValue() {
|
|
2416
|
-
return context.lastArrayFillValue;
|
|
2417
|
-
},
|
|
2418
|
-
set lastArrayFillValue(val: string | undefined) {
|
|
2419
|
-
context.lastArrayFillValue = val;
|
|
2420
|
-
},
|
|
2421
|
-
};
|
|
2422
|
-
|
|
2423
|
-
this.stringDeclHelper = new StringDeclHelper({
|
|
2424
|
-
typeRegistry: this.context.typeRegistry,
|
|
2425
|
-
getInFunctionBody: () => this.context.inFunctionBody,
|
|
2426
|
-
getIndentLevel: () => this.context.indentLevel,
|
|
2427
|
-
arrayInitState,
|
|
2428
|
-
localArrays: this.context.localArrays,
|
|
2429
|
-
generateExpression: (ctx) => this.generateExpression(ctx),
|
|
2430
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
2431
|
-
getStringConcatOperands: (ctx) => this._getStringConcatOperands(ctx),
|
|
2432
|
-
getSubstringOperands: (ctx) => this._getSubstringOperands(ctx),
|
|
2433
|
-
getStringLiteralLength: (literal) => StringUtils.literalLength(literal),
|
|
2434
|
-
getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
|
|
2435
|
-
requireStringInclude: () => this.requireInclude("string"),
|
|
2436
|
-
});
|
|
2437
|
-
|
|
2438
|
-
this.enumValidator = new EnumAssignmentValidator({
|
|
2439
|
-
knownEnums: symbols.knownEnums,
|
|
2440
|
-
getCurrentScope: () => this.context.currentScope,
|
|
2441
|
-
getExpressionEnumType: (ctx) => this.getExpressionEnumType(ctx),
|
|
2442
|
-
isIntegerExpression: (ctx) => this._isIntegerExpression(ctx),
|
|
2443
|
-
});
|
|
2444
|
-
|
|
2445
|
-
this.arrayInitHelper = new ArrayInitHelper({
|
|
2446
|
-
typeRegistry: this.context.typeRegistry,
|
|
2447
|
-
localArrays: this.context.localArrays,
|
|
2448
|
-
arrayInitState: arrayInitState,
|
|
2449
|
-
getExpectedType: () => this.context.expectedType,
|
|
2450
|
-
setExpectedType: (type) => {
|
|
2451
|
-
this.context.expectedType = type;
|
|
2452
|
-
},
|
|
2453
|
-
generateExpression: (ctx) => this.generateExpression(ctx),
|
|
2454
|
-
getTypeName: (ctx) => this.getTypeName(ctx),
|
|
2455
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
2456
|
-
});
|
|
2457
|
-
|
|
2458
|
-
this.expectedTypeResolver = new AssignmentExpectedTypeResolver({
|
|
2459
|
-
typeRegistry: this.context.typeRegistry,
|
|
2460
|
-
structFields: symbols.structFields,
|
|
2461
|
-
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
2462
|
-
});
|
|
2463
|
-
|
|
2464
|
-
this.assignmentValidator = new AssignmentValidator({
|
|
2465
|
-
typeValidator: this.typeValidator!,
|
|
2466
|
-
enumValidator: this.enumValidator,
|
|
2467
|
-
typeRegistry: this.context.typeRegistry,
|
|
2468
|
-
floatShadowCurrent: this.context.floatShadowCurrent,
|
|
2469
|
-
registerMemberAccess: symbols.registerMemberAccess,
|
|
2470
|
-
callbackFieldTypes: this.callbackFieldTypes,
|
|
2471
|
-
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
2472
|
-
isIntegerType: (name) => this._isIntegerType(name),
|
|
2473
|
-
getExpressionType: (ctx) => this.getExpressionType(ctx),
|
|
2474
|
-
tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
|
|
2475
|
-
isCallbackTypeUsedAsFieldType: (name) =>
|
|
2476
|
-
this.isCallbackTypeUsedAsFieldType(name),
|
|
2477
|
-
});
|
|
2478
2230
|
}
|
|
2479
2231
|
|
|
2480
2232
|
/**
|
|
@@ -2485,9 +2237,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2485
2237
|
options: ICodeGeneratorOptions | undefined,
|
|
2486
2238
|
): string {
|
|
2487
2239
|
const output: string[] = [];
|
|
2488
|
-
const symbols =
|
|
2489
|
-
const typeValidator = this.typeValidator!;
|
|
2490
|
-
|
|
2240
|
+
const symbols = CodeGenState.symbols!;
|
|
2491
2241
|
// Add header comment
|
|
2492
2242
|
output.push(
|
|
2493
2243
|
"/**",
|
|
@@ -2498,16 +2248,17 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2498
2248
|
);
|
|
2499
2249
|
|
|
2500
2250
|
// Self-include for extern "C" linkage
|
|
2501
|
-
if (symbols.hasPublicSymbols() &&
|
|
2251
|
+
if (symbols.hasPublicSymbols() && CodeGenState.sourcePath) {
|
|
2502
2252
|
const pathToUse =
|
|
2503
|
-
options?.sourceRelativePath ||
|
|
2253
|
+
options?.sourceRelativePath ||
|
|
2254
|
+
CodeGenState.sourcePath.replace(/^.*[\\/]/, "");
|
|
2504
2255
|
const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
|
|
2505
2256
|
output.push(`#include "${headerName}"`, "");
|
|
2506
|
-
|
|
2257
|
+
CodeGenState.selfIncludeAdded = true;
|
|
2507
2258
|
}
|
|
2508
2259
|
|
|
2509
2260
|
// Process include directives
|
|
2510
|
-
this.processIncludeDirectives(tree, output
|
|
2261
|
+
this.processIncludeDirectives(tree, output);
|
|
2511
2262
|
|
|
2512
2263
|
// Process preprocessor directives
|
|
2513
2264
|
this.processPreprocessorDirectives(tree, output);
|
|
@@ -2531,10 +2282,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2531
2282
|
private processIncludeDirectives(
|
|
2532
2283
|
tree: Parser.ProgramContext,
|
|
2533
2284
|
output: string[],
|
|
2534
|
-
typeValidator: TypeValidator,
|
|
2535
2285
|
): void {
|
|
2536
|
-
const includePaths =
|
|
2537
|
-
? IncludeDiscovery.discoverIncludePaths(
|
|
2286
|
+
const includePaths = CodeGenState.sourcePath
|
|
2287
|
+
? IncludeDiscovery.discoverIncludePaths(CodeGenState.sourcePath)
|
|
2538
2288
|
: [];
|
|
2539
2289
|
|
|
2540
2290
|
for (const includeDir of tree.includeDirective()) {
|
|
@@ -2542,14 +2292,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2542
2292
|
output.push(...this.formatLeadingComments(leadingComments));
|
|
2543
2293
|
|
|
2544
2294
|
const lineNumber = includeDir.start?.line ?? 0;
|
|
2545
|
-
|
|
2295
|
+
TypeValidator.validateIncludeNotImplementationFile(
|
|
2546
2296
|
includeDir.getText(),
|
|
2547
2297
|
lineNumber,
|
|
2548
2298
|
);
|
|
2549
|
-
|
|
2299
|
+
TypeValidator.validateIncludeNoCnxAlternative(
|
|
2550
2300
|
includeDir.getText(),
|
|
2551
2301
|
lineNumber,
|
|
2552
|
-
|
|
2302
|
+
CodeGenState.sourcePath,
|
|
2553
2303
|
includePaths,
|
|
2554
2304
|
);
|
|
2555
2305
|
|
|
@@ -2607,11 +2357,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2607
2357
|
private addAutoIncludes(output: string[]): void {
|
|
2608
2358
|
const autoIncludes: string[] = [];
|
|
2609
2359
|
|
|
2610
|
-
if (
|
|
2611
|
-
if (
|
|
2612
|
-
if (
|
|
2613
|
-
if (
|
|
2614
|
-
if (
|
|
2360
|
+
if (CodeGenState.needsStdint) autoIncludes.push("#include <stdint.h>");
|
|
2361
|
+
if (CodeGenState.needsStdbool) autoIncludes.push("#include <stdbool.h>");
|
|
2362
|
+
if (CodeGenState.needsString) autoIncludes.push("#include <string.h>");
|
|
2363
|
+
if (CodeGenState.needsCMSIS) autoIncludes.push("#include <cmsis_gcc.h>");
|
|
2364
|
+
if (CodeGenState.needsLimits) autoIncludes.push("#include <limits.h>");
|
|
2615
2365
|
|
|
2616
2366
|
if (autoIncludes.length > 0) {
|
|
2617
2367
|
output.push(...autoIncludes, "");
|
|
@@ -2622,7 +2372,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2622
2372
|
* Add generated helpers (static asserts, IRQ wrappers, typedefs, etc.).
|
|
2623
2373
|
*/
|
|
2624
2374
|
private addGeneratedHelpers(output: string[]): void {
|
|
2625
|
-
if (
|
|
2375
|
+
if (CodeGenState.needsFloatStaticAssert) {
|
|
2626
2376
|
output.push(
|
|
2627
2377
|
'_Static_assert(sizeof(float) == 4, "Float bit indexing requires 32-bit float");',
|
|
2628
2378
|
'_Static_assert(sizeof(double) == 8, "Float bit indexing requires 64-bit double");',
|
|
@@ -2630,7 +2380,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2630
2380
|
);
|
|
2631
2381
|
}
|
|
2632
2382
|
|
|
2633
|
-
if (
|
|
2383
|
+
if (CodeGenState.needsIrqWrappers) {
|
|
2634
2384
|
output.push(
|
|
2635
2385
|
"// ADR-050: IRQ wrappers to avoid macro collisions with platform headers",
|
|
2636
2386
|
"static inline void __cnx_disable_irq(void) { __disable_irq(); }",
|
|
@@ -2640,7 +2390,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2640
2390
|
);
|
|
2641
2391
|
}
|
|
2642
2392
|
|
|
2643
|
-
if (
|
|
2393
|
+
if (CodeGenState.needsISR) {
|
|
2644
2394
|
output.push(
|
|
2645
2395
|
"/* ADR-040: ISR function pointer type */",
|
|
2646
2396
|
"typedef void (*ISR)(void);",
|
|
@@ -2722,9 +2472,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2722
2472
|
*/
|
|
2723
2473
|
private transformIncludeDirective(includeText: string): string {
|
|
2724
2474
|
return includeTransformIncludeDirective(includeText, {
|
|
2725
|
-
sourcePath:
|
|
2726
|
-
includeDirs:
|
|
2727
|
-
inputs:
|
|
2475
|
+
sourcePath: CodeGenState.sourcePath,
|
|
2476
|
+
includeDirs: CodeGenState.includeDirs,
|
|
2477
|
+
inputs: CodeGenState.inputs,
|
|
2728
2478
|
});
|
|
2729
2479
|
}
|
|
2730
2480
|
|
|
@@ -2765,8 +2515,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2765
2515
|
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
2766
2516
|
|
|
2767
2517
|
// Set scope context for scoped type resolution (this.Type)
|
|
2768
|
-
const savedScope =
|
|
2769
|
-
|
|
2518
|
+
const savedScope = CodeGenState.currentScope;
|
|
2519
|
+
CodeGenState.currentScope = scopeName;
|
|
2770
2520
|
|
|
2771
2521
|
for (const member of scopeDecl.scopeMember()) {
|
|
2772
2522
|
if (member.functionDeclaration()) {
|
|
@@ -2774,20 +2524,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2774
2524
|
const funcName = funcDecl.IDENTIFIER().getText();
|
|
2775
2525
|
// Track fully qualified function name: Scope_function
|
|
2776
2526
|
const fullName = `${scopeName}_${funcName}`;
|
|
2777
|
-
|
|
2527
|
+
CodeGenState.knownFunctions.add(fullName);
|
|
2778
2528
|
// ADR-013: Track function signature for const checking
|
|
2779
2529
|
const sig = this.extractFunctionSignature(
|
|
2780
2530
|
fullName,
|
|
2781
2531
|
funcDecl.parameterList() ?? null,
|
|
2782
2532
|
);
|
|
2783
|
-
|
|
2533
|
+
CodeGenState.functionSignatures.set(fullName, sig);
|
|
2784
2534
|
// ADR-029: Register scoped function as callback type
|
|
2785
2535
|
this.registerCallbackType(fullName, funcDecl);
|
|
2786
2536
|
}
|
|
2787
2537
|
}
|
|
2788
2538
|
|
|
2789
2539
|
// Restore previous scope context
|
|
2790
|
-
|
|
2540
|
+
CodeGenState.currentScope = savedScope;
|
|
2791
2541
|
}
|
|
2792
2542
|
|
|
2793
2543
|
/**
|
|
@@ -2803,8 +2553,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2803
2553
|
const fieldType = this.getTypeName(member.type());
|
|
2804
2554
|
|
|
2805
2555
|
// Track callback field types (needed for typedef generation)
|
|
2806
|
-
if (
|
|
2807
|
-
|
|
2556
|
+
if (CodeGenState.callbackTypes.has(fieldType)) {
|
|
2557
|
+
CodeGenState.callbackFieldTypes.set(
|
|
2558
|
+
`${structName}.${fieldName}`,
|
|
2559
|
+
fieldType,
|
|
2560
|
+
);
|
|
2808
2561
|
}
|
|
2809
2562
|
}
|
|
2810
2563
|
}
|
|
@@ -2816,13 +2569,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2816
2569
|
funcDecl: Parser.FunctionDeclarationContext,
|
|
2817
2570
|
): void {
|
|
2818
2571
|
const name = funcDecl.IDENTIFIER().getText();
|
|
2819
|
-
|
|
2572
|
+
CodeGenState.knownFunctions.add(name);
|
|
2820
2573
|
// ADR-013: Track function signature for const checking
|
|
2821
2574
|
const sig = this.extractFunctionSignature(
|
|
2822
2575
|
name,
|
|
2823
2576
|
funcDecl.parameterList() ?? null,
|
|
2824
2577
|
);
|
|
2825
|
-
|
|
2578
|
+
CodeGenState.functionSignatures.set(name, sig);
|
|
2826
2579
|
// ADR-029: Register function as callback type
|
|
2827
2580
|
this.registerCallbackType(name, funcDecl);
|
|
2828
2581
|
}
|
|
@@ -2865,7 +2618,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2865
2618
|
const constName = varDecl.IDENTIFIER().getText();
|
|
2866
2619
|
const constValue = this.tryEvaluateConstant(varDecl.expression()!);
|
|
2867
2620
|
if (constValue !== undefined) {
|
|
2868
|
-
|
|
2621
|
+
CodeGenState.constValues.set(constName, constValue);
|
|
2869
2622
|
}
|
|
2870
2623
|
}
|
|
2871
2624
|
}
|
|
@@ -2880,8 +2633,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2880
2633
|
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
2881
2634
|
|
|
2882
2635
|
// Set currentScope so that this.Type references resolve correctly
|
|
2883
|
-
const savedScope =
|
|
2884
|
-
this.
|
|
2636
|
+
const savedScope = CodeGenState.currentScope;
|
|
2637
|
+
this.setCurrentScope(scopeName);
|
|
2885
2638
|
|
|
2886
2639
|
for (const member of scopeDecl.scopeMember()) {
|
|
2887
2640
|
if (member.variableDeclaration()) {
|
|
@@ -2894,7 +2647,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2894
2647
|
}
|
|
2895
2648
|
|
|
2896
2649
|
// Restore previous scope
|
|
2897
|
-
this.
|
|
2650
|
+
this.setCurrentScope(savedScope);
|
|
2898
2651
|
}
|
|
2899
2652
|
|
|
2900
2653
|
// Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
|
|
@@ -2913,10 +2666,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2913
2666
|
*/
|
|
2914
2667
|
private analyzePassByValue(tree: Parser.ProgramContext): void {
|
|
2915
2668
|
// Reset analysis state
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2669
|
+
CodeGenState.modifiedParameters.clear();
|
|
2670
|
+
CodeGenState.passByValueParams.clear();
|
|
2671
|
+
CodeGenState.functionCallGraph.clear();
|
|
2672
|
+
CodeGenState.functionParamLists.clear();
|
|
2920
2673
|
|
|
2921
2674
|
// Phase 1: Collect function parameter lists and direct modifications
|
|
2922
2675
|
this.collectFunctionParametersAndModifications(tree);
|
|
@@ -2927,9 +2680,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2927
2680
|
|
|
2928
2681
|
// Phase 2: Fixed-point iteration for transitive modifications
|
|
2929
2682
|
TransitiveModificationPropagator.propagate(
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2683
|
+
CodeGenState.functionCallGraph,
|
|
2684
|
+
CodeGenState.functionParamLists,
|
|
2685
|
+
CodeGenState.modifiedParameters,
|
|
2933
2686
|
);
|
|
2934
2687
|
|
|
2935
2688
|
// Phase 3: Determine which parameters can pass by value
|
|
@@ -2941,19 +2694,22 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2941
2694
|
* SonarCloud S3776: Extracted from analyzePassByValue().
|
|
2942
2695
|
*/
|
|
2943
2696
|
private injectCrossFileModifications(): void {
|
|
2944
|
-
if (!
|
|
2697
|
+
if (!CodeGenState.pendingCrossFileModifications) return;
|
|
2945
2698
|
|
|
2946
|
-
for (const [
|
|
2947
|
-
|
|
2699
|
+
for (const [
|
|
2700
|
+
funcName,
|
|
2701
|
+
params,
|
|
2702
|
+
] of CodeGenState.pendingCrossFileModifications) {
|
|
2703
|
+
const existing = CodeGenState.modifiedParameters.get(funcName);
|
|
2948
2704
|
if (existing) {
|
|
2949
2705
|
for (const param of params) {
|
|
2950
2706
|
existing.add(param);
|
|
2951
2707
|
}
|
|
2952
2708
|
} else {
|
|
2953
|
-
|
|
2709
|
+
CodeGenState.modifiedParameters.set(funcName, new Set(params));
|
|
2954
2710
|
}
|
|
2955
2711
|
}
|
|
2956
|
-
|
|
2712
|
+
CodeGenState.pendingCrossFileModifications = null; // Clear after use
|
|
2957
2713
|
}
|
|
2958
2714
|
|
|
2959
2715
|
/**
|
|
@@ -2961,14 +2717,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2961
2717
|
* SonarCloud S3776: Extracted from analyzePassByValue().
|
|
2962
2718
|
*/
|
|
2963
2719
|
private injectCrossFileParamLists(): void {
|
|
2964
|
-
if (!
|
|
2720
|
+
if (!CodeGenState.pendingCrossFileParamLists) return;
|
|
2965
2721
|
|
|
2966
|
-
for (const [funcName, params] of
|
|
2967
|
-
if (!
|
|
2968
|
-
|
|
2722
|
+
for (const [funcName, params] of CodeGenState.pendingCrossFileParamLists) {
|
|
2723
|
+
if (!CodeGenState.functionParamLists.has(funcName)) {
|
|
2724
|
+
CodeGenState.functionParamLists.set(funcName, [...params]);
|
|
2969
2725
|
}
|
|
2970
2726
|
}
|
|
2971
|
-
|
|
2727
|
+
CodeGenState.pendingCrossFileParamLists = null; // Clear after use
|
|
2972
2728
|
}
|
|
2973
2729
|
|
|
2974
2730
|
/**
|
|
@@ -3020,13 +2776,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3020
2776
|
paramNames.push(param.IDENTIFIER().getText());
|
|
3021
2777
|
}
|
|
3022
2778
|
}
|
|
3023
|
-
|
|
2779
|
+
CodeGenState.functionParamLists.set(funcName, paramNames);
|
|
3024
2780
|
|
|
3025
2781
|
// Initialize modified set
|
|
3026
|
-
|
|
2782
|
+
CodeGenState.modifiedParameters.set(funcName, new Set());
|
|
3027
2783
|
// Issue #579: Initialize subscript access tracking
|
|
3028
|
-
|
|
3029
|
-
|
|
2784
|
+
CodeGenState.subscriptAccessedParameters.set(funcName, new Set());
|
|
2785
|
+
CodeGenState.functionCallGraph.set(funcName, []);
|
|
3030
2786
|
|
|
3031
2787
|
// Walk the function body to find modifications and calls
|
|
3032
2788
|
const block = funcDecl.block();
|
|
@@ -3102,12 +2858,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3102
2858
|
baseIdentifier &&
|
|
3103
2859
|
paramSet.has(baseIdentifier)
|
|
3104
2860
|
) {
|
|
3105
|
-
|
|
2861
|
+
CodeGenState.subscriptAccessedParameters
|
|
2862
|
+
.get(funcName)!
|
|
2863
|
+
.add(baseIdentifier);
|
|
3106
2864
|
}
|
|
3107
2865
|
|
|
3108
2866
|
// Track as modified parameter
|
|
3109
2867
|
if (baseIdentifier && paramSet.has(baseIdentifier)) {
|
|
3110
|
-
|
|
2868
|
+
CodeGenState.modifiedParameters.get(funcName)!.add(baseIdentifier);
|
|
3111
2869
|
}
|
|
3112
2870
|
}
|
|
3113
2871
|
|
|
@@ -3179,7 +2937,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3179
2937
|
(op) => op.expression().length === 1,
|
|
3180
2938
|
);
|
|
3181
2939
|
if (hasSingleIndexSubscript) {
|
|
3182
|
-
|
|
2940
|
+
CodeGenState.subscriptAccessedParameters.get(funcName)!.add(primaryId);
|
|
3183
2941
|
}
|
|
3184
2942
|
}
|
|
3185
2943
|
|
|
@@ -3356,7 +3114,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3356
3114
|
const arg = args[i];
|
|
3357
3115
|
const argName = ExpressionUtils.extractIdentifier(arg);
|
|
3358
3116
|
if (argName && paramSet.has(argName)) {
|
|
3359
|
-
|
|
3117
|
+
CodeGenState.functionCallGraph.get(funcName)!.push({
|
|
3360
3118
|
callee: calleeName,
|
|
3361
3119
|
paramIndex: i,
|
|
3362
3120
|
argParamName: argName,
|
|
@@ -3406,12 +3164,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3406
3164
|
"bool",
|
|
3407
3165
|
]);
|
|
3408
3166
|
|
|
3409
|
-
for (const [funcName, paramNames] of
|
|
3167
|
+
for (const [funcName, paramNames] of CodeGenState.functionParamLists) {
|
|
3410
3168
|
const passByValue = new Set<string>();
|
|
3411
|
-
const modified =
|
|
3169
|
+
const modified =
|
|
3170
|
+
CodeGenState.modifiedParameters.get(funcName) ?? new Set();
|
|
3412
3171
|
|
|
3413
3172
|
// Get function declaration to check parameter types
|
|
3414
|
-
const funcSig =
|
|
3173
|
+
const funcSig = CodeGenState.functionSignatures.get(funcName);
|
|
3415
3174
|
if (funcSig) {
|
|
3416
3175
|
for (let i = 0; i < paramNames.length; i++) {
|
|
3417
3176
|
const paramName = paramNames[i];
|
|
@@ -3429,8 +3188,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3429
3188
|
const isModified = modified.has(paramName);
|
|
3430
3189
|
// Issue #579: Parameters with subscript access must become pointers
|
|
3431
3190
|
const hasSubscriptAccess =
|
|
3432
|
-
|
|
3433
|
-
|
|
3191
|
+
CodeGenState.subscriptAccessedParameters
|
|
3192
|
+
.get(funcName)
|
|
3193
|
+
?.has(paramName) ?? false;
|
|
3434
3194
|
|
|
3435
3195
|
if (
|
|
3436
3196
|
isSmallPrimitive &&
|
|
@@ -3443,7 +3203,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3443
3203
|
}
|
|
3444
3204
|
}
|
|
3445
3205
|
|
|
3446
|
-
|
|
3206
|
+
CodeGenState.passByValueParams.set(funcName, passByValue);
|
|
3447
3207
|
}
|
|
3448
3208
|
}
|
|
3449
3209
|
|
|
@@ -3455,7 +3215,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3455
3215
|
funcName: string,
|
|
3456
3216
|
paramName: string,
|
|
3457
3217
|
): boolean {
|
|
3458
|
-
const passByValue =
|
|
3218
|
+
const passByValue = CodeGenState.passByValueParams.get(funcName);
|
|
3459
3219
|
return passByValue?.has(paramName) ?? false;
|
|
3460
3220
|
}
|
|
3461
3221
|
|
|
@@ -3464,7 +3224,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3464
3224
|
* Part of IOrchestrator interface - used by CallExprGenerator.
|
|
3465
3225
|
*/
|
|
3466
3226
|
isParameterPassByValue(funcName: string, paramIndex: number): boolean {
|
|
3467
|
-
const paramList =
|
|
3227
|
+
const paramList = CodeGenState.functionParamLists.get(funcName);
|
|
3468
3228
|
if (!paramList || paramIndex < 0 || paramIndex >= paramList.length) {
|
|
3469
3229
|
return false;
|
|
3470
3230
|
}
|
|
@@ -3478,7 +3238,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3478
3238
|
* Used by HeaderGenerator to ensure header and implementation signatures match.
|
|
3479
3239
|
*/
|
|
3480
3240
|
getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
|
|
3481
|
-
return
|
|
3241
|
+
return CodeGenState.passByValueParams;
|
|
3482
3242
|
}
|
|
3483
3243
|
|
|
3484
3244
|
/**
|
|
@@ -3498,7 +3258,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3498
3258
|
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3499
3259
|
): number[] | undefined {
|
|
3500
3260
|
return ArrayDimensionParser.parseAllDimensions(arrayDim, {
|
|
3501
|
-
constValues:
|
|
3261
|
+
constValues: CodeGenState.constValues,
|
|
3502
3262
|
typeWidths: TYPE_WIDTH,
|
|
3503
3263
|
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
3504
3264
|
});
|
|
@@ -3528,8 +3288,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3528
3288
|
// ADR-017: Check if this is an enum type
|
|
3529
3289
|
if (
|
|
3530
3290
|
TypeRegistrationUtils.tryRegisterEnumType(
|
|
3531
|
-
|
|
3532
|
-
|
|
3291
|
+
CodeGenState.typeRegistry,
|
|
3292
|
+
CodeGenState.symbols!,
|
|
3533
3293
|
registrationOptions,
|
|
3534
3294
|
)
|
|
3535
3295
|
) {
|
|
@@ -3540,8 +3300,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3540
3300
|
const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
|
|
3541
3301
|
if (
|
|
3542
3302
|
TypeRegistrationUtils.tryRegisterBitmapType(
|
|
3543
|
-
|
|
3544
|
-
|
|
3303
|
+
CodeGenState.typeRegistry,
|
|
3304
|
+
CodeGenState.symbols!,
|
|
3545
3305
|
registrationOptions,
|
|
3546
3306
|
bitmapDimensions,
|
|
3547
3307
|
)
|
|
@@ -3607,7 +3367,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3607
3367
|
const allDims =
|
|
3608
3368
|
additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
|
|
3609
3369
|
|
|
3610
|
-
|
|
3370
|
+
CodeGenState.typeRegistry.set(registryName, {
|
|
3611
3371
|
baseType: "char",
|
|
3612
3372
|
bitWidth: 8,
|
|
3613
3373
|
isArray: true,
|
|
@@ -3635,8 +3395,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3635
3395
|
if (typeCtx.scopedType()) {
|
|
3636
3396
|
// ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
|
|
3637
3397
|
const typeName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
3638
|
-
return
|
|
3639
|
-
? `${
|
|
3398
|
+
return CodeGenState.currentScope
|
|
3399
|
+
? `${CodeGenState.currentScope}_${typeName}`
|
|
3640
3400
|
: typeName;
|
|
3641
3401
|
}
|
|
3642
3402
|
|
|
@@ -3755,6 +3515,42 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3755
3515
|
if (arrayTypeCtx.primitiveType()) {
|
|
3756
3516
|
baseType = arrayTypeCtx.primitiveType()!.getText();
|
|
3757
3517
|
bitWidth = TYPE_WIDTH[baseType] || 0;
|
|
3518
|
+
} else if (arrayTypeCtx.userType()) {
|
|
3519
|
+
// Handle user types (structs, enums, bitmaps)
|
|
3520
|
+
baseType = arrayTypeCtx.userType()!.getText();
|
|
3521
|
+
|
|
3522
|
+
const combinedArrayDim = arrayDim ?? [];
|
|
3523
|
+
|
|
3524
|
+
// Check if this is an enum or bitmap type and delegate to proper registration
|
|
3525
|
+
if (
|
|
3526
|
+
this._tryRegisterEnumOrBitmapType(
|
|
3527
|
+
registryName,
|
|
3528
|
+
baseType,
|
|
3529
|
+
isConst,
|
|
3530
|
+
combinedArrayDim,
|
|
3531
|
+
overflowBehavior,
|
|
3532
|
+
isAtomic,
|
|
3533
|
+
)
|
|
3534
|
+
) {
|
|
3535
|
+
// Enum/bitmap was registered, but we need to update with arrayType dimension
|
|
3536
|
+
const existingInfo = CodeGenState.typeRegistry.get(registryName);
|
|
3537
|
+
if (existingInfo) {
|
|
3538
|
+
const arrayTypeDim =
|
|
3539
|
+
this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
|
|
3540
|
+
const allDims = arrayTypeDim
|
|
3541
|
+
? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
|
|
3542
|
+
: existingInfo.arrayDimensions;
|
|
3543
|
+
CodeGenState.typeRegistry.set(registryName, {
|
|
3544
|
+
...existingInfo,
|
|
3545
|
+
isArray: true,
|
|
3546
|
+
arrayDimensions: allDims,
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
// Not an enum/bitmap - register as regular user type (struct)
|
|
3553
|
+
// bitWidth already initialized to 0, no reassignment needed
|
|
3758
3554
|
}
|
|
3759
3555
|
|
|
3760
3556
|
if (!baseType) {
|
|
@@ -3766,7 +3562,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3766
3562
|
arrayDim,
|
|
3767
3563
|
);
|
|
3768
3564
|
|
|
3769
|
-
|
|
3565
|
+
CodeGenState.typeRegistry.set(registryName, {
|
|
3770
3566
|
baseType,
|
|
3771
3567
|
bitWidth,
|
|
3772
3568
|
isArray: true,
|
|
@@ -3777,6 +3573,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3777
3573
|
});
|
|
3778
3574
|
}
|
|
3779
3575
|
|
|
3576
|
+
/**
|
|
3577
|
+
* Parse array dimension from arrayType context.
|
|
3578
|
+
*/
|
|
3579
|
+
private _parseArrayTypeDimensionFromCtx(
|
|
3580
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
3581
|
+
): number | undefined {
|
|
3582
|
+
const sizeExpr = arrayTypeCtx.expression();
|
|
3583
|
+
if (!sizeExpr) {
|
|
3584
|
+
return undefined;
|
|
3585
|
+
}
|
|
3586
|
+
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
3587
|
+
return Number.isNaN(size) ? undefined : size;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3780
3590
|
/**
|
|
3781
3591
|
* Collect array dimensions from array type and additional dimensions
|
|
3782
3592
|
*/
|
|
@@ -3824,7 +3634,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3824
3634
|
? this._evaluateArrayDimensions(arrayDim)
|
|
3825
3635
|
: undefined;
|
|
3826
3636
|
|
|
3827
|
-
|
|
3637
|
+
CodeGenState.typeRegistry.set(registryName, {
|
|
3828
3638
|
baseType,
|
|
3829
3639
|
bitWidth,
|
|
3830
3640
|
isArray,
|
|
@@ -3840,14 +3650,15 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3840
3650
|
* Part of IOrchestrator interface.
|
|
3841
3651
|
*/
|
|
3842
3652
|
isStructType(typeName: string): boolean {
|
|
3843
|
-
return
|
|
3653
|
+
return TypeResolver.isStructType(typeName);
|
|
3844
3654
|
}
|
|
3845
3655
|
|
|
3846
3656
|
/**
|
|
3847
3657
|
* Set up parameter tracking for a function
|
|
3848
3658
|
*/
|
|
3849
3659
|
private _setParameters(params: Parser.ParameterListContext | null): void {
|
|
3850
|
-
|
|
3660
|
+
CodeGenState.currentParameters.clear();
|
|
3661
|
+
CodeGenState.currentParameters.clear();
|
|
3851
3662
|
if (!params) return;
|
|
3852
3663
|
|
|
3853
3664
|
for (const param of params.parameter()) {
|
|
@@ -3868,7 +3679,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3868
3679
|
const typeInfo = this._resolveParameterTypeInfo(typeCtx);
|
|
3869
3680
|
|
|
3870
3681
|
// Register in currentParameters
|
|
3871
|
-
|
|
3682
|
+
const paramInfo = {
|
|
3872
3683
|
name,
|
|
3873
3684
|
baseType: typeInfo.typeName,
|
|
3874
3685
|
isArray,
|
|
@@ -3876,7 +3687,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3876
3687
|
isConst,
|
|
3877
3688
|
isCallback: typeInfo.isCallback,
|
|
3878
3689
|
isString: typeInfo.isString,
|
|
3879
|
-
}
|
|
3690
|
+
};
|
|
3691
|
+
CodeGenState.currentParameters.set(name, paramInfo);
|
|
3880
3692
|
|
|
3881
3693
|
// Register in typeRegistry
|
|
3882
3694
|
this._registerParameterType(name, typeInfo, param, isArray, isConst);
|
|
@@ -3905,7 +3717,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3905
3717
|
return {
|
|
3906
3718
|
typeName,
|
|
3907
3719
|
isStruct: this.isStructType(typeName),
|
|
3908
|
-
isCallback:
|
|
3720
|
+
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3909
3721
|
isString: false,
|
|
3910
3722
|
};
|
|
3911
3723
|
}
|
|
@@ -3926,8 +3738,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3926
3738
|
|
|
3927
3739
|
if (typeCtx.scopedType()) {
|
|
3928
3740
|
const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
3929
|
-
const typeName =
|
|
3930
|
-
? `${
|
|
3741
|
+
const typeName = CodeGenState.currentScope
|
|
3742
|
+
? `${CodeGenState.currentScope}_${localTypeName}`
|
|
3931
3743
|
: localTypeName;
|
|
3932
3744
|
return {
|
|
3933
3745
|
typeName,
|
|
@@ -3978,8 +3790,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3978
3790
|
const { typeName, isString } = typeInfo;
|
|
3979
3791
|
const typeCtx = param.type();
|
|
3980
3792
|
|
|
3981
|
-
const isEnum =
|
|
3982
|
-
const isBitmap =
|
|
3793
|
+
const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
|
|
3794
|
+
const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
|
|
3983
3795
|
|
|
3984
3796
|
// Extract array dimensions
|
|
3985
3797
|
const arrayDimensions = isArray
|
|
@@ -3992,10 +3804,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3992
3804
|
arrayDimensions.push(stringCapacity + 1);
|
|
3993
3805
|
}
|
|
3994
3806
|
|
|
3995
|
-
|
|
3807
|
+
const registeredType = {
|
|
3996
3808
|
baseType: typeName,
|
|
3997
3809
|
bitWidth: isBitmap
|
|
3998
|
-
?
|
|
3810
|
+
? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
|
|
3999
3811
|
: TYPE_WIDTH[typeName] || 0,
|
|
4000
3812
|
isArray,
|
|
4001
3813
|
arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
|
|
@@ -4007,7 +3819,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4007
3819
|
isString,
|
|
4008
3820
|
stringCapacity,
|
|
4009
3821
|
isParameter: true,
|
|
4010
|
-
}
|
|
3822
|
+
};
|
|
3823
|
+
CodeGenState.typeRegistry.set(name, registeredType);
|
|
4011
3824
|
}
|
|
4012
3825
|
|
|
4013
3826
|
/**
|
|
@@ -4028,11 +3841,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4028
3841
|
*/
|
|
4029
3842
|
private _clearParameters(): void {
|
|
4030
3843
|
// ADR-025: Remove parameter types from typeRegistry
|
|
4031
|
-
for (const name of
|
|
4032
|
-
|
|
3844
|
+
for (const name of CodeGenState.currentParameters.keys()) {
|
|
3845
|
+
CodeGenState.typeRegistry.delete(name);
|
|
3846
|
+
CodeGenState.typeRegistry.delete(name);
|
|
4033
3847
|
}
|
|
4034
|
-
|
|
4035
|
-
|
|
3848
|
+
CodeGenState.currentParameters.clear();
|
|
3849
|
+
CodeGenState.localArrays.clear();
|
|
3850
|
+
CodeGenState.currentParameters.clear();
|
|
3851
|
+
CodeGenState.localArrays.clear();
|
|
4036
3852
|
}
|
|
4037
3853
|
|
|
4038
3854
|
/**
|
|
@@ -4090,14 +3906,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4090
3906
|
const isArray = dims.length > 0;
|
|
4091
3907
|
|
|
4092
3908
|
// ADR-029: Check if parameter type is itself a callback type
|
|
4093
|
-
const isCallbackParam =
|
|
3909
|
+
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
4094
3910
|
|
|
4095
3911
|
let paramType: string;
|
|
4096
3912
|
let isPointer: boolean;
|
|
4097
3913
|
|
|
4098
3914
|
if (isCallbackParam) {
|
|
4099
3915
|
// Use the callback typedef name
|
|
4100
|
-
const cbInfo =
|
|
3916
|
+
const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
4101
3917
|
paramType = cbInfo.typedefName;
|
|
4102
3918
|
isPointer = false; // Function pointers are already pointers
|
|
4103
3919
|
} else {
|
|
@@ -4120,7 +3936,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4120
3936
|
}
|
|
4121
3937
|
}
|
|
4122
3938
|
|
|
4123
|
-
|
|
3939
|
+
CodeGenState.callbackTypes.set(name, {
|
|
4124
3940
|
functionName: name,
|
|
4125
3941
|
returnType,
|
|
4126
3942
|
parameters,
|
|
@@ -4134,187 +3950,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4134
3950
|
// Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
|
|
4135
3951
|
// and validateBareIdentifierInScope moved to TypeValidator
|
|
4136
3952
|
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
private _getEnumTypeFromThisEnum(parts: string[]): string | null {
|
|
4141
|
-
if (parts[0] !== "this" || !this.context.currentScope || parts.length < 3) {
|
|
4142
|
-
return null;
|
|
4143
|
-
}
|
|
4144
|
-
const enumName = parts[1];
|
|
4145
|
-
const scopedEnumName = `${this.context.currentScope}_${enumName}`;
|
|
4146
|
-
return this.symbols!.knownEnums.has(scopedEnumName) ? scopedEnumName : null;
|
|
4147
|
-
}
|
|
4148
|
-
|
|
4149
|
-
/**
|
|
4150
|
-
* Issue #478: Check global.Enum.Member pattern (global.ECategory.CAT_A)
|
|
4151
|
-
*/
|
|
4152
|
-
private _getEnumTypeFromGlobalEnum(parts: string[]): string | null {
|
|
4153
|
-
if (parts[0] !== "global" || parts.length < 3) {
|
|
4154
|
-
return null;
|
|
4155
|
-
}
|
|
4156
|
-
const enumName = parts[1];
|
|
4157
|
-
return this.symbols!.knownEnums.has(enumName) ? enumName : null;
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
|
-
/**
|
|
4161
|
-
* ADR-016: Check this.variable pattern (this.varName where varName is enum type)
|
|
4162
|
-
*/
|
|
4163
|
-
private _getEnumTypeFromThisVariable(parts: string[]): string | null {
|
|
4164
|
-
if (
|
|
4165
|
-
parts[0] !== "this" ||
|
|
4166
|
-
!this.context.currentScope ||
|
|
4167
|
-
parts.length !== 2
|
|
4168
|
-
) {
|
|
4169
|
-
return null;
|
|
4170
|
-
}
|
|
4171
|
-
const varName = parts[1];
|
|
4172
|
-
const scopedVarName = `${this.context.currentScope}_${varName}`;
|
|
4173
|
-
const typeInfo = this.context.typeRegistry.get(scopedVarName);
|
|
4174
|
-
if (typeInfo?.isEnum && typeInfo.enumTypeName) {
|
|
4175
|
-
return typeInfo.enumTypeName;
|
|
4176
|
-
}
|
|
4177
|
-
return null;
|
|
4178
|
-
}
|
|
4179
|
-
|
|
4180
|
-
/**
|
|
4181
|
-
* Check scoped enum: Motor.State.IDLE -> Motor_State
|
|
4182
|
-
*/
|
|
4183
|
-
private _getEnumTypeFromScopedEnum(parts: string[]): string | null {
|
|
4184
|
-
if (parts.length < 3) {
|
|
4185
|
-
return null;
|
|
4186
|
-
}
|
|
4187
|
-
const scopeName = parts[0];
|
|
4188
|
-
const enumName = parts[1];
|
|
4189
|
-
const scopedEnumName = `${scopeName}_${enumName}`;
|
|
4190
|
-
return this.symbols!.knownEnums.has(scopedEnumName) ? scopedEnumName : null;
|
|
4191
|
-
}
|
|
4192
|
-
|
|
4193
|
-
/**
|
|
4194
|
-
* Check if parts represent an enum member access and return the enum type.
|
|
4195
|
-
*/
|
|
4196
|
-
private _getEnumTypeFromMemberAccess(parts: string[]): string | null {
|
|
4197
|
-
if (parts.length < 2) {
|
|
4198
|
-
return null;
|
|
4199
|
-
}
|
|
4200
|
-
|
|
4201
|
-
// ADR-016: Check this.State.IDLE pattern
|
|
4202
|
-
const thisEnumType = this._getEnumTypeFromThisEnum(parts);
|
|
4203
|
-
if (thisEnumType) return thisEnumType;
|
|
4204
|
-
|
|
4205
|
-
// Issue #478: Check global.Enum.Member pattern
|
|
4206
|
-
const globalEnumType = this._getEnumTypeFromGlobalEnum(parts);
|
|
4207
|
-
if (globalEnumType) return globalEnumType;
|
|
4208
|
-
|
|
4209
|
-
// ADR-016: Check this.variable pattern
|
|
4210
|
-
const thisVarType = this._getEnumTypeFromThisVariable(parts);
|
|
4211
|
-
if (thisVarType) return thisVarType;
|
|
4212
|
-
|
|
4213
|
-
// Check simple enum: State.IDLE
|
|
4214
|
-
const possibleEnum = parts[0];
|
|
4215
|
-
if (this.symbols!.knownEnums.has(possibleEnum)) {
|
|
4216
|
-
return possibleEnum;
|
|
4217
|
-
}
|
|
4218
|
-
|
|
4219
|
-
// Check scoped enum: Motor.State.IDLE -> Motor_State
|
|
4220
|
-
return this._getEnumTypeFromScopedEnum(parts);
|
|
4221
|
-
}
|
|
4222
|
-
|
|
4223
|
-
/**
|
|
4224
|
-
* ADR-017: Extract enum type from an expression.
|
|
4225
|
-
* Returns the enum type name if the expression is an enum value, null otherwise.
|
|
4226
|
-
*
|
|
4227
|
-
* Handles:
|
|
4228
|
-
* - Variable of enum type: `currentState` -> 'State'
|
|
4229
|
-
* - Enum member access: `State.IDLE` -> 'State'
|
|
4230
|
-
* - Scoped enum member: `Motor.State.IDLE` -> 'Motor_State'
|
|
4231
|
-
* - ADR-016: this.State.IDLE -> 'CurrentScope_State'
|
|
4232
|
-
* - ADR-016: this.variable -> enum type if variable is of enum type
|
|
4233
|
-
*/
|
|
4234
|
-
private _getExpressionEnumType(
|
|
4235
|
-
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
4236
|
-
): string | null {
|
|
4237
|
-
const text = ctx.getText();
|
|
4238
|
-
|
|
4239
|
-
// Check if it's a function call returning an enum
|
|
4240
|
-
const enumReturnType = this._getFunctionCallEnumType(text);
|
|
4241
|
-
if (enumReturnType) {
|
|
4242
|
-
return enumReturnType;
|
|
4243
|
-
}
|
|
4244
|
-
|
|
4245
|
-
// Check if it's a simple identifier that's an enum variable
|
|
4246
|
-
if (/^[a-zA-Z_]\w*$/.exec(text)) {
|
|
4247
|
-
const typeInfo = this.context.typeRegistry.get(text);
|
|
4248
|
-
if (typeInfo?.isEnum && typeInfo.enumTypeName) {
|
|
4249
|
-
return typeInfo.enumTypeName;
|
|
4250
|
-
}
|
|
4251
|
-
}
|
|
4252
|
-
|
|
4253
|
-
// Check member access patterns: EnumType.MEMBER, Scope.EnumType.MEMBER, etc.
|
|
4254
|
-
return this._getEnumTypeFromMemberAccess(text.split("."));
|
|
4255
|
-
}
|
|
4256
|
-
|
|
4257
|
-
/**
|
|
4258
|
-
* Check if an expression is a function call returning an enum type.
|
|
4259
|
-
* Handles patterns:
|
|
4260
|
-
* - func() or func(args) - global function
|
|
4261
|
-
* - Scope.method() or Scope.method(args) - scope method from outside
|
|
4262
|
-
* - this.method() or this.method(args) - scope method from inside
|
|
4263
|
-
* - global.func() or global.func(args) - global function from inside scope
|
|
4264
|
-
* - global.Scope.method() or global.Scope.method(args) - scope method from inside another scope
|
|
4265
|
-
*/
|
|
4266
|
-
private _getFunctionCallEnumType(text: string): string | null {
|
|
4267
|
-
// Check if this looks like a function call (contains parentheses)
|
|
4268
|
-
const parenIndex = text.indexOf("(");
|
|
4269
|
-
if (parenIndex === -1) {
|
|
4270
|
-
return null;
|
|
4271
|
-
}
|
|
4272
|
-
|
|
4273
|
-
// Extract the function reference (everything before the opening paren)
|
|
4274
|
-
const funcRef = text.substring(0, parenIndex);
|
|
4275
|
-
const parts = funcRef.split(".");
|
|
4276
|
-
|
|
4277
|
-
let fullFuncName: string | null = null;
|
|
4278
|
-
|
|
4279
|
-
if (parts.length === 1) {
|
|
4280
|
-
// Simple function call: func()
|
|
4281
|
-
fullFuncName = parts[0];
|
|
4282
|
-
} else if (parts.length === 2) {
|
|
4283
|
-
if (parts[0] === "this" && this.context.currentScope) {
|
|
4284
|
-
// this.method() -> Scope_method
|
|
4285
|
-
fullFuncName = `${this.context.currentScope}_${parts[1]}`;
|
|
4286
|
-
} else if (parts[0] === "global") {
|
|
4287
|
-
// global.func() -> func
|
|
4288
|
-
fullFuncName = parts[1];
|
|
4289
|
-
} else if (this.symbols!.knownScopes.has(parts[0])) {
|
|
4290
|
-
// Scope.method() -> Scope_method
|
|
4291
|
-
fullFuncName = `${parts[0]}_${parts[1]}`;
|
|
4292
|
-
}
|
|
4293
|
-
} else if (parts.length === 3) {
|
|
4294
|
-
if (parts[0] === "global" && this.symbols!.knownScopes.has(parts[1])) {
|
|
4295
|
-
// global.Scope.method() -> Scope_method
|
|
4296
|
-
fullFuncName = `${parts[1]}_${parts[2]}`;
|
|
4297
|
-
}
|
|
4298
|
-
}
|
|
4299
|
-
|
|
4300
|
-
if (!fullFuncName) {
|
|
4301
|
-
return null;
|
|
4302
|
-
}
|
|
4303
|
-
|
|
4304
|
-
// Look up the function's return type
|
|
4305
|
-
const returnType = this.symbols!.functionReturnTypes.get(fullFuncName);
|
|
4306
|
-
if (!returnType) {
|
|
4307
|
-
return null;
|
|
4308
|
-
}
|
|
4309
|
-
|
|
4310
|
-
// Check if the return type is an enum
|
|
4311
|
-
if (this.symbols!.knownEnums.has(returnType)) {
|
|
4312
|
-
return returnType;
|
|
4313
|
-
}
|
|
4314
|
-
|
|
4315
|
-
return null;
|
|
4316
|
-
}
|
|
4317
|
-
|
|
3953
|
+
// EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
|
|
3954
|
+
// _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
|
|
3955
|
+
// _getExpressionEnumType, _getFunctionCallEnumType
|
|
4318
3956
|
/**
|
|
4319
3957
|
* ADR-017: Check if an expression represents an integer literal or numeric type.
|
|
4320
3958
|
* Used to detect comparisons between enums and integers.
|
|
@@ -4322,30 +3960,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4322
3960
|
private _isIntegerExpression(
|
|
4323
3961
|
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
4324
3962
|
): boolean {
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
// Check for integer literals
|
|
4328
|
-
if (
|
|
4329
|
-
/^-?\d+$/.exec(text) ||
|
|
4330
|
-
/^0[xX][0-9a-fA-F]+$/.exec(text) ||
|
|
4331
|
-
/^0[bB][01]+$/.exec(text)
|
|
4332
|
-
) {
|
|
4333
|
-
return true;
|
|
4334
|
-
}
|
|
4335
|
-
|
|
4336
|
-
// Check if it's a variable of primitive integer type
|
|
4337
|
-
if (/^[a-zA-Z_]\w*$/.exec(text)) {
|
|
4338
|
-
const typeInfo = this.context.typeRegistry.get(text);
|
|
4339
|
-
if (
|
|
4340
|
-
typeInfo &&
|
|
4341
|
-
!typeInfo.isEnum &&
|
|
4342
|
-
TypeCheckUtils.isInteger(typeInfo.baseType)
|
|
4343
|
-
) {
|
|
4344
|
-
return true;
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
|
|
4348
|
-
return false;
|
|
3963
|
+
return EnumAssignmentValidator.isIntegerExpression(ctx);
|
|
4349
3964
|
}
|
|
4350
3965
|
|
|
4351
3966
|
/**
|
|
@@ -4358,38 +3973,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4358
3973
|
leftCapacity: number;
|
|
4359
3974
|
rightCapacity: number;
|
|
4360
3975
|
} | null {
|
|
4361
|
-
// Navigate to the additive expression level
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
const orExprs = ternary.orExpression();
|
|
4366
|
-
if (orExprs.length !== 1) return null;
|
|
4367
|
-
|
|
4368
|
-
const or = orExprs[0];
|
|
4369
|
-
if (or.andExpression().length !== 1) return null;
|
|
4370
|
-
|
|
4371
|
-
const and = or.andExpression()[0];
|
|
4372
|
-
if (and.equalityExpression().length !== 1) return null;
|
|
4373
|
-
|
|
4374
|
-
const eq = and.equalityExpression()[0];
|
|
4375
|
-
if (eq.relationalExpression().length !== 1) return null;
|
|
4376
|
-
|
|
4377
|
-
const rel = eq.relationalExpression()[0];
|
|
4378
|
-
if (rel.bitwiseOrExpression().length !== 1) return null;
|
|
4379
|
-
|
|
4380
|
-
const bor = rel.bitwiseOrExpression()[0];
|
|
4381
|
-
if (bor.bitwiseXorExpression().length !== 1) return null;
|
|
4382
|
-
|
|
4383
|
-
const bxor = bor.bitwiseXorExpression()[0];
|
|
4384
|
-
if (bxor.bitwiseAndExpression().length !== 1) return null;
|
|
4385
|
-
|
|
4386
|
-
const band = bxor.bitwiseAndExpression()[0];
|
|
4387
|
-
if (band.shiftExpression().length !== 1) return null;
|
|
4388
|
-
|
|
4389
|
-
const shift = band.shiftExpression()[0];
|
|
4390
|
-
if (shift.additiveExpression().length !== 1) return null;
|
|
4391
|
-
|
|
4392
|
-
const add = shift.additiveExpression()[0];
|
|
3976
|
+
// Navigate to the additive expression level using ExpressionUnwrapper
|
|
3977
|
+
// Issue #707: Deduplicated expression tree navigation
|
|
3978
|
+
const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
|
|
3979
|
+
if (!add) return null;
|
|
4393
3980
|
const multExprs = add.multiplicativeExpression();
|
|
4394
3981
|
|
|
4395
3982
|
// Need exactly 2 operands for simple concatenation
|
|
@@ -4460,7 +4047,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4460
4047
|
const sourceName = sourceId.getText();
|
|
4461
4048
|
|
|
4462
4049
|
// Check if source is a string type
|
|
4463
|
-
const typeInfo =
|
|
4050
|
+
const typeInfo = CodeGenState.typeRegistry.get(sourceName);
|
|
4464
4051
|
if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
|
|
4465
4052
|
return null;
|
|
4466
4053
|
}
|
|
@@ -4494,11 +4081,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4494
4081
|
// NOTE: Public isIntegerType and isFloatType moved to IOrchestrator interface (ADR-053 A2)
|
|
4495
4082
|
// Private versions kept for internal use
|
|
4496
4083
|
private _isIntegerType(typeName: string): boolean {
|
|
4497
|
-
return
|
|
4084
|
+
return TypeResolver.isIntegerType(typeName);
|
|
4498
4085
|
}
|
|
4499
4086
|
|
|
4500
4087
|
private _isFloatType(typeName: string): boolean {
|
|
4501
|
-
return
|
|
4088
|
+
return TypeResolver.isFloatType(typeName);
|
|
4502
4089
|
}
|
|
4503
4090
|
|
|
4504
4091
|
/**
|
|
@@ -4509,7 +4096,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4509
4096
|
sourceType: string,
|
|
4510
4097
|
targetType: string,
|
|
4511
4098
|
): boolean {
|
|
4512
|
-
return
|
|
4099
|
+
return TypeResolver.isNarrowingConversion(sourceType, targetType);
|
|
4513
4100
|
}
|
|
4514
4101
|
|
|
4515
4102
|
/**
|
|
@@ -4517,7 +4104,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4517
4104
|
* Sign change occurs when converting between signed and unsigned types
|
|
4518
4105
|
*/
|
|
4519
4106
|
private isSignConversion(sourceType: string, targetType: string): boolean {
|
|
4520
|
-
return
|
|
4107
|
+
return TypeResolver.isSignConversion(sourceType, targetType);
|
|
4521
4108
|
}
|
|
4522
4109
|
|
|
4523
4110
|
/**
|
|
@@ -4530,7 +4117,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4530
4117
|
literalText: string,
|
|
4531
4118
|
targetType: string,
|
|
4532
4119
|
): void {
|
|
4533
|
-
|
|
4120
|
+
TypeResolver.validateLiteralFitsType(literalText, targetType);
|
|
4534
4121
|
}
|
|
4535
4122
|
|
|
4536
4123
|
/**
|
|
@@ -4539,7 +4126,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4539
4126
|
private getUnaryExpressionType(
|
|
4540
4127
|
ctx: Parser.UnaryExpressionContext,
|
|
4541
4128
|
): string | null {
|
|
4542
|
-
return
|
|
4129
|
+
return TypeResolver.getUnaryExpressionType(ctx);
|
|
4543
4130
|
}
|
|
4544
4131
|
|
|
4545
4132
|
/**
|
|
@@ -4550,7 +4137,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4550
4137
|
targetType: string,
|
|
4551
4138
|
sourceType: string | null,
|
|
4552
4139
|
): void {
|
|
4553
|
-
|
|
4140
|
+
TypeResolver.validateTypeConversion(targetType, sourceType);
|
|
4554
4141
|
}
|
|
4555
4142
|
|
|
4556
4143
|
// Issue #63: checkConstAssignment moved to TypeValidator
|
|
@@ -4588,7 +4175,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4588
4175
|
ctx: Parser.ExpressionContext,
|
|
4589
4176
|
targetParamBaseType?: string,
|
|
4590
4177
|
): boolean {
|
|
4591
|
-
if (!
|
|
4178
|
+
if (!CodeGenState.cppMode) return false;
|
|
4592
4179
|
if (!targetParamBaseType) return false;
|
|
4593
4180
|
|
|
4594
4181
|
const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
|
|
@@ -4602,7 +4189,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4602
4189
|
const ops = postfix.postfixOp();
|
|
4603
4190
|
|
|
4604
4191
|
// Case 1: Direct parameter member access (cfg.value)
|
|
4605
|
-
const paramInfo =
|
|
4192
|
+
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4606
4193
|
if (paramInfo) {
|
|
4607
4194
|
return this._needsParamMemberConversion(paramInfo, targetParamBaseType);
|
|
4608
4195
|
}
|
|
@@ -4647,7 +4234,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4647
4234
|
baseId: string,
|
|
4648
4235
|
targetParamBaseType: string,
|
|
4649
4236
|
): boolean {
|
|
4650
|
-
const typeInfo =
|
|
4237
|
+
const typeInfo = CodeGenState.typeRegistry.get(baseId);
|
|
4651
4238
|
return CppMemberHelper.needsComplexMemberConversion(
|
|
4652
4239
|
this._toPostfixOps(ops),
|
|
4653
4240
|
typeInfo,
|
|
@@ -4674,8 +4261,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4674
4261
|
const baseId = primary.IDENTIFIER()?.getText();
|
|
4675
4262
|
if (!baseId) return false;
|
|
4676
4263
|
|
|
4677
|
-
const typeInfo =
|
|
4678
|
-
const paramInfo =
|
|
4264
|
+
const typeInfo = CodeGenState.typeRegistry.get(baseId);
|
|
4265
|
+
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4679
4266
|
|
|
4680
4267
|
return CppMemberHelper.isStringSubscriptPattern(
|
|
4681
4268
|
hasPostfixOps,
|
|
@@ -4728,11 +4315,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4728
4315
|
// 2. Parameter: currentParameters.get(baseId).baseType
|
|
4729
4316
|
let structType: string | undefined;
|
|
4730
4317
|
|
|
4731
|
-
const typeInfo =
|
|
4318
|
+
const typeInfo = CodeGenState.typeRegistry.get(baseId);
|
|
4732
4319
|
if (typeInfo) {
|
|
4733
4320
|
structType = typeInfo.baseType;
|
|
4734
4321
|
} else {
|
|
4735
|
-
const paramInfo =
|
|
4322
|
+
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4736
4323
|
if (paramInfo) {
|
|
4737
4324
|
structType = paramInfo.baseType;
|
|
4738
4325
|
}
|
|
@@ -4784,26 +4371,33 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4784
4371
|
*/
|
|
4785
4372
|
private _handleIdentifierArg(id: string): string {
|
|
4786
4373
|
// Parameters are already pointers
|
|
4787
|
-
if (
|
|
4374
|
+
if (CodeGenState.currentParameters.get(id)) {
|
|
4788
4375
|
return id;
|
|
4789
4376
|
}
|
|
4790
4377
|
|
|
4791
4378
|
// Local arrays decay to pointers
|
|
4792
|
-
if (
|
|
4379
|
+
if (CodeGenState.localArrays.has(id)) {
|
|
4380
|
+
return id;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// Global arrays also decay to pointers (check typeRegistry)
|
|
4384
|
+
// But NOT strings - strings need & (they're char arrays but passed by reference)
|
|
4385
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
4386
|
+
if (typeInfo?.isArray && !typeInfo.isString) {
|
|
4793
4387
|
return id;
|
|
4794
4388
|
}
|
|
4795
4389
|
|
|
4796
4390
|
// Scope member - may need prefixing
|
|
4797
|
-
if (
|
|
4798
|
-
const members =
|
|
4391
|
+
if (CodeGenState.currentScope) {
|
|
4392
|
+
const members = CodeGenState.scopeMembers.get(CodeGenState.currentScope);
|
|
4799
4393
|
if (members?.has(id)) {
|
|
4800
|
-
const scopedName = `${
|
|
4801
|
-
return
|
|
4394
|
+
const scopedName = `${CodeGenState.currentScope}_${id}`;
|
|
4395
|
+
return CppModeHelper.maybeAddressOf(scopedName);
|
|
4802
4396
|
}
|
|
4803
4397
|
}
|
|
4804
4398
|
|
|
4805
4399
|
// Local variable - add & (except in C++ mode)
|
|
4806
|
-
return
|
|
4400
|
+
return CppModeHelper.maybeAddressOf(id);
|
|
4807
4401
|
}
|
|
4808
4402
|
|
|
4809
4403
|
/**
|
|
@@ -4825,7 +4419,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4825
4419
|
|
|
4826
4420
|
// Generate expression with address-of
|
|
4827
4421
|
const generatedExpr = this.generateExpression(ctx);
|
|
4828
|
-
const expr =
|
|
4422
|
+
const expr = CppModeHelper.maybeAddressOf(generatedExpr);
|
|
4829
4423
|
|
|
4830
4424
|
// String subscript access may need cast
|
|
4831
4425
|
if (lvalueType === "array") {
|
|
@@ -4869,10 +4463,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4869
4463
|
): string {
|
|
4870
4464
|
const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
|
|
4871
4465
|
const value = this.generateExpression(ctx);
|
|
4872
|
-
const tempName = `_cnx_tmp_${
|
|
4873
|
-
const castExpr =
|
|
4874
|
-
|
|
4875
|
-
|
|
4466
|
+
const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
|
|
4467
|
+
const castExpr = CppModeHelper.cast(cType, value);
|
|
4468
|
+
CodeGenState.pendingTempDeclarations.push(
|
|
4469
|
+
`${cType} ${tempName} = ${castExpr};`,
|
|
4470
|
+
);
|
|
4471
|
+
return CppModeHelper.maybeAddressOf(tempName);
|
|
4876
4472
|
}
|
|
4877
4473
|
|
|
4878
4474
|
/**
|
|
@@ -4889,7 +4485,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4889
4485
|
|
|
4890
4486
|
const cType = TYPE_MAP[targetParamBaseType];
|
|
4891
4487
|
if (cType && !["float", "double", "bool", "void"].includes(cType)) {
|
|
4892
|
-
return
|
|
4488
|
+
return CppModeHelper.reinterpretCast(`${cType}*`, expr);
|
|
4893
4489
|
}
|
|
4894
4490
|
|
|
4895
4491
|
return expr;
|
|
@@ -4914,7 +4510,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4914
4510
|
const value = this.generateExpression(ctx);
|
|
4915
4511
|
|
|
4916
4512
|
// C++ mode: rvalues can bind to const T&
|
|
4917
|
-
if (
|
|
4513
|
+
if (CodeGenState.cppMode) {
|
|
4918
4514
|
return value;
|
|
4919
4515
|
}
|
|
4920
4516
|
|
|
@@ -4937,21 +4533,21 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4937
4533
|
// Issue #369: Skip struct/enum/bitmap definitions when self-include is added
|
|
4938
4534
|
// These types will be defined in the included header file
|
|
4939
4535
|
if (ctx.structDeclaration()) {
|
|
4940
|
-
if (
|
|
4536
|
+
if (CodeGenState.selfIncludeAdded) {
|
|
4941
4537
|
return ""; // Definition will come from header
|
|
4942
4538
|
}
|
|
4943
4539
|
return this.generateStruct(ctx.structDeclaration()!);
|
|
4944
4540
|
}
|
|
4945
4541
|
// ADR-017: Handle enum declarations
|
|
4946
4542
|
if (ctx.enumDeclaration()) {
|
|
4947
|
-
if (
|
|
4543
|
+
if (CodeGenState.selfIncludeAdded) {
|
|
4948
4544
|
return ""; // Definition will come from header
|
|
4949
4545
|
}
|
|
4950
4546
|
return this.generateEnum(ctx.enumDeclaration()!);
|
|
4951
4547
|
}
|
|
4952
4548
|
// ADR-034: Handle bitmap declarations
|
|
4953
4549
|
if (ctx.bitmapDeclaration()) {
|
|
4954
|
-
if (
|
|
4550
|
+
if (CodeGenState.selfIncludeAdded) {
|
|
4955
4551
|
return ""; // Definition will come from header
|
|
4956
4552
|
}
|
|
4957
4553
|
return this.generateBitmap(ctx.bitmapDeclaration()!);
|
|
@@ -4980,7 +4576,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4980
4576
|
|
|
4981
4577
|
// Fallback to inline implementation (will be removed after migration)
|
|
4982
4578
|
const name = ctx.IDENTIFIER().getText();
|
|
4983
|
-
|
|
4579
|
+
CodeGenState.currentScope = name;
|
|
4984
4580
|
|
|
4985
4581
|
const lines: string[] = [];
|
|
4986
4582
|
lines.push(`/* Scope: ${name} */`);
|
|
@@ -4990,7 +4586,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4990
4586
|
}
|
|
4991
4587
|
|
|
4992
4588
|
lines.push("");
|
|
4993
|
-
|
|
4589
|
+
CodeGenState.currentScope = null;
|
|
4994
4590
|
return lines.join("\n");
|
|
4995
4591
|
}
|
|
4996
4592
|
|
|
@@ -5046,10 +4642,18 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5046
4642
|
const prefix = isPrivate ? "static " : "";
|
|
5047
4643
|
|
|
5048
4644
|
const arrayDims = varDecl.arrayDimension();
|
|
5049
|
-
const
|
|
4645
|
+
const hasArrayTypeSyntax = varDecl.type().arrayType() !== null;
|
|
4646
|
+
const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
|
|
5050
4647
|
|
|
5051
4648
|
let decl = `${prefix}${type} ${fullName}`;
|
|
5052
|
-
|
|
4649
|
+
|
|
4650
|
+
// Handle arrayType dimension (C-Next style: u8[16] data)
|
|
4651
|
+
if (hasArrayTypeSyntax) {
|
|
4652
|
+
decl += this._getArrayTypeDimension(varDecl.type());
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4655
|
+
// Handle arrayDimension (C-style or additional dimensions)
|
|
4656
|
+
if (arrayDims.length > 0) {
|
|
5053
4657
|
decl += this.generateArrayDimensions(arrayDims);
|
|
5054
4658
|
}
|
|
5055
4659
|
|
|
@@ -5091,9 +4695,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5091
4695
|
const prefix = isPrivate ? "static " : "";
|
|
5092
4696
|
|
|
5093
4697
|
// Issue #269: Set current function name for pass-by-value lookup
|
|
5094
|
-
|
|
4698
|
+
CodeGenState.currentFunctionName = fullName;
|
|
5095
4699
|
// Issue #477: Set return type for enum inference in return statements
|
|
5096
|
-
|
|
4700
|
+
CodeGenState.currentFunctionReturnType = funcDecl.type().getText();
|
|
5097
4701
|
|
|
5098
4702
|
// Track parameters for ADR-006 pointer semantics
|
|
5099
4703
|
this._setParameters(funcDecl.parameterList() ?? null);
|
|
@@ -5114,8 +4718,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5114
4718
|
|
|
5115
4719
|
// ADR-016: Exit function body context
|
|
5116
4720
|
this.exitFunctionBody();
|
|
5117
|
-
|
|
5118
|
-
|
|
4721
|
+
CodeGenState.currentFunctionName = null;
|
|
4722
|
+
CodeGenState.currentFunctionReturnType = null;
|
|
5119
4723
|
this._clearParameters();
|
|
5120
4724
|
|
|
5121
4725
|
lines.push("", `${prefix}${returnType} ${fullName}(${params}) ${body}`);
|
|
@@ -5198,155 +4802,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5198
4802
|
// ========================================================================
|
|
5199
4803
|
|
|
5200
4804
|
private generateStruct(ctx: Parser.StructDeclarationContext): string {
|
|
5201
|
-
// ADR-053:
|
|
4805
|
+
// ADR-053: Delegates to extracted StructGenerator
|
|
5202
4806
|
const generator = this.registry.getDeclaration("struct");
|
|
5203
|
-
if (generator) {
|
|
5204
|
-
|
|
5205
|
-
this.applyEffects(result.effects);
|
|
5206
|
-
return result.code;
|
|
5207
|
-
}
|
|
5208
|
-
|
|
5209
|
-
// Fallback to inline implementation (will be removed after migration)
|
|
5210
|
-
const name = ctx.IDENTIFIER().getText();
|
|
5211
|
-
const callbackFields: Array<{ fieldName: string; callbackType: string }> =
|
|
5212
|
-
[];
|
|
5213
|
-
|
|
5214
|
-
const lines: string[] = [];
|
|
5215
|
-
lines.push(`typedef struct {`);
|
|
5216
|
-
|
|
5217
|
-
for (const member of ctx.structMember()) {
|
|
5218
|
-
const fieldLine = this.generateStructFieldLine(
|
|
5219
|
-
name,
|
|
5220
|
-
member,
|
|
5221
|
-
callbackFields,
|
|
5222
|
-
);
|
|
5223
|
-
lines.push(fieldLine);
|
|
5224
|
-
}
|
|
5225
|
-
|
|
5226
|
-
lines.push(`} ${name};`, "");
|
|
5227
|
-
|
|
5228
|
-
// ADR-029: Generate init function if struct has callback fields
|
|
5229
|
-
if (callbackFields.length > 0) {
|
|
5230
|
-
lines.push(this.generateStructInitFunction(name, callbackFields));
|
|
5231
|
-
}
|
|
5232
|
-
|
|
5233
|
-
return lines.join("\n");
|
|
5234
|
-
}
|
|
5235
|
-
|
|
5236
|
-
/**
|
|
5237
|
-
* Generate a single struct field line.
|
|
5238
|
-
* SonarCloud S3776: Extracted from generateStruct().
|
|
5239
|
-
*/
|
|
5240
|
-
private generateStructFieldLine(
|
|
5241
|
-
structName: string,
|
|
5242
|
-
member: Parser.StructMemberContext,
|
|
5243
|
-
callbackFields: Array<{ fieldName: string; callbackType: string }>,
|
|
5244
|
-
): string {
|
|
5245
|
-
const fieldName = member.IDENTIFIER().getText();
|
|
5246
|
-
const typeName = this.getTypeName(member.type());
|
|
5247
|
-
const arrayDims = member.arrayDimension();
|
|
5248
|
-
const isArray = arrayDims.length > 0;
|
|
5249
|
-
|
|
5250
|
-
// ADR-029: Check if this is a callback type field
|
|
5251
|
-
if (this.callbackTypes.has(typeName)) {
|
|
5252
|
-
return this.generateCallbackFieldLine(
|
|
5253
|
-
structName,
|
|
5254
|
-
fieldName,
|
|
5255
|
-
typeName,
|
|
5256
|
-
arrayDims,
|
|
5257
|
-
isArray,
|
|
5258
|
-
callbackFields,
|
|
5259
|
-
);
|
|
5260
|
-
}
|
|
5261
|
-
|
|
5262
|
-
return this.generateRegularFieldLine(
|
|
5263
|
-
structName,
|
|
5264
|
-
fieldName,
|
|
5265
|
-
member,
|
|
5266
|
-
arrayDims,
|
|
5267
|
-
isArray,
|
|
5268
|
-
);
|
|
5269
|
-
}
|
|
5270
|
-
|
|
5271
|
-
/**
|
|
5272
|
-
* Generate a callback type field line.
|
|
5273
|
-
* SonarCloud S3776: Extracted from generateStruct().
|
|
5274
|
-
*/
|
|
5275
|
-
private generateCallbackFieldLine(
|
|
5276
|
-
structName: string,
|
|
5277
|
-
fieldName: string,
|
|
5278
|
-
typeName: string,
|
|
5279
|
-
arrayDims: Parser.ArrayDimensionContext[],
|
|
5280
|
-
isArray: boolean,
|
|
5281
|
-
callbackFields: Array<{ fieldName: string; callbackType: string }>,
|
|
5282
|
-
): string {
|
|
5283
|
-
const callbackInfo = this.callbackTypes.get(typeName)!;
|
|
5284
|
-
callbackFields.push({ fieldName, callbackType: typeName });
|
|
5285
|
-
|
|
5286
|
-
// Track callback field for assignment validation
|
|
5287
|
-
this.callbackFieldTypes.set(`${structName}.${fieldName}`, typeName);
|
|
5288
|
-
|
|
5289
|
-
if (isArray) {
|
|
5290
|
-
const dims = this.generateArrayDimensions(arrayDims);
|
|
5291
|
-
return ` ${callbackInfo.typedefName} ${fieldName}${dims};`;
|
|
5292
|
-
}
|
|
5293
|
-
return ` ${callbackInfo.typedefName} ${fieldName};`;
|
|
5294
|
-
}
|
|
5295
|
-
|
|
5296
|
-
/**
|
|
5297
|
-
* Generate a regular (non-callback) field line.
|
|
5298
|
-
* SonarCloud S3776: Extracted from generateStruct().
|
|
5299
|
-
*/
|
|
5300
|
-
private generateRegularFieldLine(
|
|
5301
|
-
structName: string,
|
|
5302
|
-
fieldName: string,
|
|
5303
|
-
member: Parser.StructMemberContext,
|
|
5304
|
-
arrayDims: Parser.ArrayDimensionContext[],
|
|
5305
|
-
isArray: boolean,
|
|
5306
|
-
): string {
|
|
5307
|
-
const type = this.generateType(member.type());
|
|
5308
|
-
|
|
5309
|
-
// Check if we have tracked dimensions for this field
|
|
5310
|
-
const trackedDimensions =
|
|
5311
|
-
this.symbols!.structFieldDimensions.get(structName);
|
|
5312
|
-
const fieldDims = trackedDimensions?.get(fieldName);
|
|
5313
|
-
|
|
5314
|
-
if (fieldDims && fieldDims.length > 0) {
|
|
5315
|
-
const dimsStr = fieldDims.map((d) => `[${d}]`).join("");
|
|
5316
|
-
return ` ${type} ${fieldName}${dimsStr};`;
|
|
5317
|
-
}
|
|
5318
|
-
|
|
5319
|
-
if (isArray) {
|
|
5320
|
-
const dims = this.generateArrayDimensions(arrayDims);
|
|
5321
|
-
return ` ${type} ${fieldName}${dims};`;
|
|
5322
|
-
}
|
|
5323
|
-
|
|
5324
|
-
return ` ${type} ${fieldName};`;
|
|
5325
|
-
}
|
|
5326
|
-
|
|
5327
|
-
/**
|
|
5328
|
-
* ADR-029: Generate init function for structs with callback fields
|
|
5329
|
-
* Sets all callback fields to their default functions
|
|
5330
|
-
*/
|
|
5331
|
-
private generateStructInitFunction(
|
|
5332
|
-
structName: string,
|
|
5333
|
-
callbackFields: Array<{ fieldName: string; callbackType: string }>,
|
|
5334
|
-
): string {
|
|
5335
|
-
const lines: string[] = [];
|
|
5336
|
-
lines.push(
|
|
5337
|
-
`${structName} ${structName}_init(void) {`,
|
|
5338
|
-
` return (${structName}){`,
|
|
5339
|
-
);
|
|
5340
|
-
|
|
5341
|
-
for (let i = 0; i < callbackFields.length; i++) {
|
|
5342
|
-
const field = callbackFields[i];
|
|
5343
|
-
const comma = i < callbackFields.length - 1 ? "," : "";
|
|
5344
|
-
lines.push(` .${field.fieldName} = ${field.callbackType}${comma}`);
|
|
4807
|
+
if (!generator) {
|
|
4808
|
+
throw new Error("Error: struct generator not registered");
|
|
5345
4809
|
}
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
return lines.join("\n");
|
|
4810
|
+
const result = generator(ctx, this.getInput(), this.getState(), this);
|
|
4811
|
+
this.applyEffects(result.effects);
|
|
4812
|
+
return result.code;
|
|
5350
4813
|
}
|
|
5351
4814
|
|
|
5352
4815
|
// ========================================================================
|
|
@@ -5358,44 +4821,16 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5358
4821
|
* enum State { IDLE, RUNNING, ERROR <- 255 }
|
|
5359
4822
|
* -> typedef enum { State_IDLE = 0, State_RUNNING = 1, State_ERROR = 255 } State;
|
|
5360
4823
|
*
|
|
5361
|
-
* ADR-053: Delegates to extracted
|
|
4824
|
+
* ADR-053: Delegates to extracted EnumGenerator.
|
|
5362
4825
|
*/
|
|
5363
4826
|
private generateEnum(ctx: Parser.EnumDeclarationContext): string {
|
|
5364
|
-
// ADR-053: Check registry for extracted generator
|
|
5365
4827
|
const generator = this.registry.getDeclaration("enum");
|
|
5366
|
-
if (generator) {
|
|
5367
|
-
|
|
5368
|
-
this.applyEffects(result.effects);
|
|
5369
|
-
return result.code;
|
|
5370
|
-
}
|
|
5371
|
-
|
|
5372
|
-
// Fallback to inline implementation (will be removed after migration)
|
|
5373
|
-
const name = ctx.IDENTIFIER().getText();
|
|
5374
|
-
const prefix = this.context.currentScope
|
|
5375
|
-
? `${this.context.currentScope}_`
|
|
5376
|
-
: "";
|
|
5377
|
-
const fullName = `${prefix}${name}`;
|
|
5378
|
-
|
|
5379
|
-
const lines: string[] = [];
|
|
5380
|
-
lines.push(`typedef enum {`);
|
|
5381
|
-
|
|
5382
|
-
const members = this.symbols!.enumMembers.get(fullName);
|
|
5383
|
-
if (!members) {
|
|
5384
|
-
throw new Error(`Error: Enum ${fullName} not found in registry`);
|
|
5385
|
-
}
|
|
5386
|
-
|
|
5387
|
-
const memberEntries = Array.from(members.entries());
|
|
5388
|
-
|
|
5389
|
-
for (let i = 0; i < memberEntries.length; i++) {
|
|
5390
|
-
const [memberName, value] = memberEntries[i];
|
|
5391
|
-
const fullMemberName = `${fullName}_${memberName}`;
|
|
5392
|
-
const comma = i < memberEntries.length - 1 ? "," : "";
|
|
5393
|
-
lines.push(` ${fullMemberName} = ${value}${comma}`);
|
|
4828
|
+
if (!generator) {
|
|
4829
|
+
throw new Error("Error: enum generator not registered");
|
|
5394
4830
|
}
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
return lines.join("\n");
|
|
4831
|
+
const result = generator(ctx, this.getInput(), this.getState(), this);
|
|
4832
|
+
this.applyEffects(result.effects);
|
|
4833
|
+
return result.code;
|
|
5399
4834
|
}
|
|
5400
4835
|
|
|
5401
4836
|
/**
|
|
@@ -5416,12 +4851,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5416
4851
|
|
|
5417
4852
|
// Fallback to inline implementation (will be removed after migration)
|
|
5418
4853
|
const name = ctx.IDENTIFIER().getText();
|
|
5419
|
-
const prefix =
|
|
5420
|
-
? `${
|
|
4854
|
+
const prefix = CodeGenState.currentScope
|
|
4855
|
+
? `${CodeGenState.currentScope}_`
|
|
5421
4856
|
: "";
|
|
5422
4857
|
const fullName = `${prefix}${name}`;
|
|
5423
4858
|
|
|
5424
|
-
const backingType =
|
|
4859
|
+
const backingType = CodeGenState.symbols!.bitmapBackingType.get(fullName);
|
|
5425
4860
|
if (!backingType) {
|
|
5426
4861
|
throw new Error(`Error: Bitmap ${fullName} not found in registry`);
|
|
5427
4862
|
}
|
|
@@ -5433,7 +4868,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5433
4868
|
// Generate comment with field layout
|
|
5434
4869
|
lines.push(`/* Bitmap: ${fullName} */`);
|
|
5435
4870
|
|
|
5436
|
-
const fields =
|
|
4871
|
+
const fields = CodeGenState.symbols!.bitmapFields.get(fullName);
|
|
5437
4872
|
if (fields) {
|
|
5438
4873
|
lines.push("/* Fields:");
|
|
5439
4874
|
for (const [fieldName, info] of fields.entries()) {
|
|
@@ -5467,7 +4902,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5467
4902
|
// Reject redundant type in struct initializer
|
|
5468
4903
|
// Wrong: const Point p <- Point { x: 0 };
|
|
5469
4904
|
// Right: const Point p <- { x: 0 };
|
|
5470
|
-
if (ctx.IDENTIFIER() &&
|
|
4905
|
+
if (ctx.IDENTIFIER() && CodeGenState.expectedType) {
|
|
5471
4906
|
const explicitType = ctx.IDENTIFIER()!.getText();
|
|
5472
4907
|
throw new Error(
|
|
5473
4908
|
`Redundant type '${explicitType}' in struct initializer. ` +
|
|
@@ -5479,8 +4914,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5479
4914
|
let typeName: string;
|
|
5480
4915
|
if (ctx.IDENTIFIER()) {
|
|
5481
4916
|
typeName = ctx.IDENTIFIER()!.getText();
|
|
5482
|
-
} else if (
|
|
5483
|
-
typeName =
|
|
4917
|
+
} else if (CodeGenState.expectedType) {
|
|
4918
|
+
typeName = CodeGenState.expectedType;
|
|
5484
4919
|
} else {
|
|
5485
4920
|
// This should not happen in valid code
|
|
5486
4921
|
throw new Error(
|
|
@@ -5495,7 +4930,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5495
4930
|
// so designated initializers { .field = value } don't work with them.
|
|
5496
4931
|
// We check the SymbolTable for a constructor symbol (TypeName::TypeName).
|
|
5497
4932
|
const isCppClass =
|
|
5498
|
-
|
|
4933
|
+
CodeGenState.cppMode && this._isCppClassWithConstructor(typeName);
|
|
5499
4934
|
|
|
5500
4935
|
if (!fieldList) {
|
|
5501
4936
|
// Empty initializer: Point {} -> (Point){ 0 } or {} for C++ classes
|
|
@@ -5504,13 +4939,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5504
4939
|
|
|
5505
4940
|
// Get field type info for nested initializers
|
|
5506
4941
|
// Issue #502: Check both local struct fields and SymbolTable (for C++ header structs)
|
|
5507
|
-
const structFieldTypes =
|
|
4942
|
+
const structFieldTypes = CodeGenState.symbols!.structFields.get(typeName);
|
|
5508
4943
|
|
|
5509
4944
|
const fields = fieldList.fieldInitializer().map((field) => {
|
|
5510
4945
|
const fieldName = field.IDENTIFIER().getText();
|
|
5511
4946
|
|
|
5512
4947
|
// Set expected type for nested initializers
|
|
5513
|
-
const savedExpectedType =
|
|
4948
|
+
const savedExpectedType = CodeGenState.expectedType;
|
|
5514
4949
|
if (structFieldTypes?.has(fieldName)) {
|
|
5515
4950
|
// Issue #502: Convert underscore format to correct output format
|
|
5516
4951
|
// C-Next struct fields may store C++ types with _ separator (e.g., SeaDash_Parse_ParseResult)
|
|
@@ -5524,13 +4959,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5524
4959
|
fieldType = parts.join("::");
|
|
5525
4960
|
}
|
|
5526
4961
|
}
|
|
5527
|
-
|
|
4962
|
+
CodeGenState.expectedType = fieldType;
|
|
5528
4963
|
}
|
|
5529
4964
|
|
|
5530
4965
|
const value = this.generateExpression(field.expression());
|
|
5531
4966
|
|
|
5532
4967
|
// Restore expected type
|
|
5533
|
-
|
|
4968
|
+
CodeGenState.expectedType = savedExpectedType;
|
|
5534
4969
|
|
|
5535
4970
|
return { fieldName, value };
|
|
5536
4971
|
});
|
|
@@ -5538,7 +4973,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5538
4973
|
// Issue #517: For C++ classes, store assignments for later and return {}
|
|
5539
4974
|
if (isCppClass) {
|
|
5540
4975
|
for (const { fieldName, value } of fields) {
|
|
5541
|
-
|
|
4976
|
+
CodeGenState.pendingCppClassAssignments.push(
|
|
4977
|
+
`${fieldName} = ${value};`,
|
|
4978
|
+
);
|
|
5542
4979
|
}
|
|
5543
4980
|
return "{}";
|
|
5544
4981
|
}
|
|
@@ -5562,8 +4999,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5562
4999
|
// Fill-all: [0*] -> {0}
|
|
5563
5000
|
const fillValue = this.generateExpression(ctx.expression()!);
|
|
5564
5001
|
// Store element count as 0 to signal fill-all (size comes from declaration)
|
|
5565
|
-
|
|
5566
|
-
|
|
5002
|
+
CodeGenState.lastArrayInitCount = 0;
|
|
5003
|
+
CodeGenState.lastArrayFillValue = fillValue;
|
|
5567
5004
|
return `{${fillValue}}`;
|
|
5568
5005
|
}
|
|
5569
5006
|
|
|
@@ -5587,8 +5024,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5587
5024
|
}
|
|
5588
5025
|
|
|
5589
5026
|
// Store element count for size inference
|
|
5590
|
-
|
|
5591
|
-
|
|
5027
|
+
CodeGenState.lastArrayInitCount = generatedElements.length;
|
|
5028
|
+
CodeGenState.lastArrayFillValue = undefined;
|
|
5592
5029
|
|
|
5593
5030
|
return `{${generatedElements.join(", ")}}`;
|
|
5594
5031
|
}
|
|
@@ -5656,21 +5093,21 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5656
5093
|
ctx: Parser.FunctionDeclarationContext,
|
|
5657
5094
|
): void {
|
|
5658
5095
|
// Issue #269: Set current function name for pass-by-value lookup
|
|
5659
|
-
const fullFuncName =
|
|
5660
|
-
? `${
|
|
5096
|
+
const fullFuncName = CodeGenState.currentScope
|
|
5097
|
+
? `${CodeGenState.currentScope}_${name}`
|
|
5661
5098
|
: name;
|
|
5662
|
-
|
|
5099
|
+
CodeGenState.currentFunctionName = fullFuncName;
|
|
5663
5100
|
// Issue #477: Set return type for enum inference in return statements
|
|
5664
|
-
|
|
5101
|
+
CodeGenState.currentFunctionReturnType = ctx.type().getText();
|
|
5665
5102
|
|
|
5666
5103
|
// Track parameters for ADR-006 pointer semantics
|
|
5667
5104
|
this._setParameters(ctx.parameterList() ?? null);
|
|
5668
5105
|
|
|
5669
5106
|
// ADR-016: Clear local variables and mark that we're in a function body
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5107
|
+
CodeGenState.localVariables.clear();
|
|
5108
|
+
CodeGenState.floatBitShadows.clear();
|
|
5109
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
5110
|
+
CodeGenState.inFunctionBody = true;
|
|
5674
5111
|
}
|
|
5675
5112
|
|
|
5676
5113
|
/**
|
|
@@ -5685,7 +5122,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5685
5122
|
if (isMainWithArgs) {
|
|
5686
5123
|
// Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
|
|
5687
5124
|
const argsParam = ctx.parameterList()!.parameter()[0];
|
|
5688
|
-
|
|
5125
|
+
CodeGenState.mainArgsName = argsParam.IDENTIFIER().getText();
|
|
5689
5126
|
return {
|
|
5690
5127
|
actualReturnType: "int",
|
|
5691
5128
|
initialParams: "int argc, char *argv[]",
|
|
@@ -5701,13 +5138,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5701
5138
|
* Clean up context after function generation
|
|
5702
5139
|
*/
|
|
5703
5140
|
private _cleanupFunctionContext(): void {
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5141
|
+
CodeGenState.inFunctionBody = false;
|
|
5142
|
+
CodeGenState.localVariables.clear();
|
|
5143
|
+
CodeGenState.floatBitShadows.clear();
|
|
5144
|
+
CodeGenState.floatShadowCurrent.clear();
|
|
5145
|
+
CodeGenState.mainArgsName = null;
|
|
5146
|
+
CodeGenState.currentFunctionName = null;
|
|
5147
|
+
CodeGenState.currentFunctionReturnType = null;
|
|
5711
5148
|
this._clearParameters();
|
|
5712
5149
|
}
|
|
5713
5150
|
|
|
@@ -5737,8 +5174,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5737
5174
|
const dims = ctx.arrayDimension();
|
|
5738
5175
|
|
|
5739
5176
|
// ADR-029: Check if this is a callback type parameter
|
|
5740
|
-
if (
|
|
5741
|
-
const callbackInfo =
|
|
5177
|
+
if (CodeGenState.callbackTypes.has(typeName)) {
|
|
5178
|
+
const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
5742
5179
|
return `${callbackInfo.typedefName} ${name}`;
|
|
5743
5180
|
}
|
|
5744
5181
|
|
|
@@ -5825,12 +5262,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5825
5262
|
// ISR, float, enum types
|
|
5826
5263
|
if (typeName === "ISR") return true;
|
|
5827
5264
|
if (this._isFloatType(typeName)) return true;
|
|
5828
|
-
if (
|
|
5265
|
+
if (CodeGenState.symbols!.knownEnums.has(typeName)) return true;
|
|
5829
5266
|
|
|
5830
5267
|
// Small unmodified primitives
|
|
5831
5268
|
if (
|
|
5832
|
-
|
|
5833
|
-
this._isParameterPassByValueByName(
|
|
5269
|
+
CodeGenState.currentFunctionName &&
|
|
5270
|
+
this._isParameterPassByValueByName(CodeGenState.currentFunctionName, name)
|
|
5834
5271
|
) {
|
|
5835
5272
|
return true;
|
|
5836
5273
|
}
|
|
@@ -5871,7 +5308,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5871
5308
|
|
|
5872
5309
|
const wasModified = this._isCurrentParameterModified(name);
|
|
5873
5310
|
const autoConst = !wasModified && !constMod ? "const " : "";
|
|
5874
|
-
const refOrPtr =
|
|
5311
|
+
const refOrPtr = CppModeHelper.refOrPtr();
|
|
5875
5312
|
return `${autoConst}${constMod}${type}${refOrPtr} ${name}`;
|
|
5876
5313
|
}
|
|
5877
5314
|
|
|
@@ -5889,24 +5326,39 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5889
5326
|
// Issue #696: Use helper for modifier extraction and validation
|
|
5890
5327
|
const modifiers = VariableModifierBuilder.build(
|
|
5891
5328
|
ctx,
|
|
5892
|
-
|
|
5329
|
+
CodeGenState.inFunctionBody,
|
|
5893
5330
|
);
|
|
5894
5331
|
|
|
5895
5332
|
const name = ctx.IDENTIFIER().getText();
|
|
5896
5333
|
const typeCtx = ctx.type();
|
|
5334
|
+
|
|
5335
|
+
// Reject C-style array declarations (u16 arr[8]) - require C-Next style (u16[8] arr)
|
|
5336
|
+
this._validateArrayDeclarationSyntax(ctx, typeCtx, name);
|
|
5337
|
+
|
|
5897
5338
|
const type = this._inferVariableType(ctx, name);
|
|
5898
5339
|
|
|
5899
5340
|
// Track local variable metadata
|
|
5900
5341
|
this._trackLocalVariable(ctx, name);
|
|
5901
5342
|
|
|
5902
5343
|
// ADR-045: Handle bounded string type specially - early return
|
|
5903
|
-
const stringResult =
|
|
5344
|
+
const stringResult = StringDeclHelper.generateStringDecl(
|
|
5904
5345
|
typeCtx,
|
|
5905
5346
|
name,
|
|
5906
5347
|
ctx.expression() ?? null,
|
|
5907
5348
|
ctx.arrayDimension(),
|
|
5908
5349
|
modifiers,
|
|
5909
5350
|
ctx.constModifier() !== null,
|
|
5351
|
+
{
|
|
5352
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
5353
|
+
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
5354
|
+
getStringConcatOperands: (concatCtx) =>
|
|
5355
|
+
this._getStringConcatOperands(concatCtx),
|
|
5356
|
+
getSubstringOperands: (substrCtx) =>
|
|
5357
|
+
this._getSubstringOperands(substrCtx),
|
|
5358
|
+
getStringExprCapacity: (exprCode) =>
|
|
5359
|
+
this.getStringExprCapacity(exprCode),
|
|
5360
|
+
requireStringInclude: () => this.requireInclude("string"),
|
|
5361
|
+
},
|
|
5910
5362
|
);
|
|
5911
5363
|
if (stringResult.handled) {
|
|
5912
5364
|
return stringResult.code;
|
|
@@ -5965,24 +5417,25 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5965
5417
|
ctx: Parser.VariableDeclarationContext,
|
|
5966
5418
|
name: string,
|
|
5967
5419
|
): void {
|
|
5968
|
-
if (!
|
|
5420
|
+
if (!CodeGenState.inFunctionBody) {
|
|
5969
5421
|
return;
|
|
5970
5422
|
}
|
|
5971
5423
|
|
|
5972
5424
|
this.trackVariableType(ctx);
|
|
5973
|
-
|
|
5425
|
+
CodeGenState.localVariables.add(name);
|
|
5974
5426
|
|
|
5975
5427
|
// Bug #8: Track local const values for array size and bit index resolution
|
|
5976
5428
|
if (ctx.constModifier() && ctx.expression()) {
|
|
5977
5429
|
const constValue = this.tryEvaluateConstant(ctx.expression()!);
|
|
5978
5430
|
if (constValue !== undefined) {
|
|
5979
|
-
|
|
5431
|
+
CodeGenState.constValues.set(name, constValue);
|
|
5980
5432
|
}
|
|
5981
5433
|
}
|
|
5982
5434
|
}
|
|
5983
5435
|
|
|
5984
5436
|
/**
|
|
5985
5437
|
* Issue #696: Handle array declaration with dimension parsing and init.
|
|
5438
|
+
* Bug fix: Also handles C-Next style arrayType syntax (u16[8] myArray).
|
|
5986
5439
|
*/
|
|
5987
5440
|
private _handleArrayDeclaration(
|
|
5988
5441
|
ctx: Parser.VariableDeclarationContext,
|
|
@@ -5991,42 +5444,97 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5991
5444
|
decl: string,
|
|
5992
5445
|
): { handled: boolean; code: string; decl: string; isArray: boolean } {
|
|
5993
5446
|
const arrayDims = ctx.arrayDimension();
|
|
5994
|
-
const
|
|
5447
|
+
const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
|
|
5448
|
+
const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
|
|
5995
5449
|
|
|
5996
5450
|
if (!isArray) {
|
|
5997
5451
|
return { handled: false, code: "", decl, isArray: false };
|
|
5998
5452
|
}
|
|
5999
5453
|
|
|
5454
|
+
// Generate dimension string from arrayType syntax (u16[8] myArray)
|
|
5455
|
+
const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
|
|
5456
|
+
|
|
6000
5457
|
const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
|
|
6001
|
-
const declaredSize =
|
|
5458
|
+
const declaredSize =
|
|
5459
|
+
this._parseArrayTypeDimension(typeCtx) ??
|
|
5460
|
+
this._parseFirstArrayDimension(arrayDims);
|
|
6002
5461
|
|
|
6003
5462
|
// ADR-035: Handle array initializers with size inference
|
|
6004
5463
|
if (ctx.expression()) {
|
|
6005
|
-
const arrayInitResult =
|
|
5464
|
+
const arrayInitResult = ArrayInitHelper.processArrayInit(
|
|
6006
5465
|
name,
|
|
6007
5466
|
typeCtx,
|
|
6008
5467
|
ctx.expression()!,
|
|
6009
5468
|
arrayDims,
|
|
6010
5469
|
hasEmptyArrayDim,
|
|
6011
5470
|
declaredSize,
|
|
5471
|
+
{
|
|
5472
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
5473
|
+
getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
|
|
5474
|
+
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
5475
|
+
},
|
|
6012
5476
|
);
|
|
6013
5477
|
if (arrayInitResult) {
|
|
5478
|
+
// Track as local array for type resolution
|
|
5479
|
+
CodeGenState.localArrays.add(name);
|
|
5480
|
+
// Include arrayType dimension before arrayDimension dimensions
|
|
5481
|
+
const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
|
|
6014
5482
|
return {
|
|
6015
5483
|
handled: true,
|
|
6016
|
-
code: `${decl}${
|
|
5484
|
+
code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
|
|
6017
5485
|
decl,
|
|
6018
5486
|
isArray: true,
|
|
6019
5487
|
};
|
|
6020
5488
|
}
|
|
6021
5489
|
}
|
|
6022
5490
|
|
|
6023
|
-
// Generate dimensions
|
|
6024
|
-
const newDecl =
|
|
6025
|
-
|
|
5491
|
+
// Generate dimensions: arrayType dimension first, then arrayDimension dimensions
|
|
5492
|
+
const newDecl =
|
|
5493
|
+
decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
|
|
5494
|
+
CodeGenState.localArrays.add(name);
|
|
6026
5495
|
|
|
6027
5496
|
return { handled: false, code: "", decl: newDecl, isArray: true };
|
|
6028
5497
|
}
|
|
6029
5498
|
|
|
5499
|
+
/**
|
|
5500
|
+
* Get array dimension string from arrayType syntax (u16[8] -> "[8]").
|
|
5501
|
+
* Evaluates const expressions to their numeric values for C compatibility.
|
|
5502
|
+
*/
|
|
5503
|
+
private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
|
|
5504
|
+
if (!typeCtx.arrayType()) {
|
|
5505
|
+
return "";
|
|
5506
|
+
}
|
|
5507
|
+
const sizeExpr = typeCtx.arrayType()!.expression();
|
|
5508
|
+
if (!sizeExpr) {
|
|
5509
|
+
return "[]";
|
|
5510
|
+
}
|
|
5511
|
+
// Try to evaluate as constant first (required for C file-scope arrays)
|
|
5512
|
+
const constValue = this.tryEvaluateConstant(sizeExpr);
|
|
5513
|
+
if (constValue !== undefined) {
|
|
5514
|
+
return `[${constValue}]`;
|
|
5515
|
+
}
|
|
5516
|
+
// Fall back to expression text (for macros, enums, etc.)
|
|
5517
|
+
return `[${this.generateExpression(sizeExpr)}]`;
|
|
5518
|
+
}
|
|
5519
|
+
|
|
5520
|
+
/**
|
|
5521
|
+
* Parse array dimension from arrayType syntax for size validation.
|
|
5522
|
+
*/
|
|
5523
|
+
private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
|
|
5524
|
+
if (!typeCtx.arrayType()) {
|
|
5525
|
+
return null;
|
|
5526
|
+
}
|
|
5527
|
+
const sizeExpr = typeCtx.arrayType()!.expression();
|
|
5528
|
+
if (!sizeExpr) {
|
|
5529
|
+
return null;
|
|
5530
|
+
}
|
|
5531
|
+
const sizeText = sizeExpr.getText();
|
|
5532
|
+
if (/^\d+$/.exec(sizeText)) {
|
|
5533
|
+
return Number.parseInt(sizeText, 10);
|
|
5534
|
+
}
|
|
5535
|
+
return null;
|
|
5536
|
+
}
|
|
5537
|
+
|
|
6030
5538
|
/**
|
|
6031
5539
|
* Issue #696: Parse first array dimension for validation.
|
|
6032
5540
|
*/
|
|
@@ -6043,6 +5551,95 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6043
5551
|
return null;
|
|
6044
5552
|
}
|
|
6045
5553
|
|
|
5554
|
+
/**
|
|
5555
|
+
* Validate array declaration syntax - reject C-style, require C-Next style.
|
|
5556
|
+
* C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
|
|
5557
|
+
* C-Next style: u16[8] arr (first dimension in type) - REQUIRED
|
|
5558
|
+
* Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
|
|
5559
|
+
* Exceptions (grammar limitations):
|
|
5560
|
+
* - Empty dimensions for size inference: u8 arr[] <- [...]
|
|
5561
|
+
* - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
|
|
5562
|
+
* - Scoped/global types: this.Type arr[3], global.Type arr[3]
|
|
5563
|
+
* - String types: string<N> arr[3]
|
|
5564
|
+
*/
|
|
5565
|
+
private _validateArrayDeclarationSyntax(
|
|
5566
|
+
ctx: Parser.VariableDeclarationContext,
|
|
5567
|
+
typeCtx: Parser.TypeContext,
|
|
5568
|
+
name: string,
|
|
5569
|
+
): void {
|
|
5570
|
+
const arrayDims = ctx.arrayDimension();
|
|
5571
|
+
if (arrayDims.length === 0) {
|
|
5572
|
+
return; // Not an array declaration
|
|
5573
|
+
}
|
|
5574
|
+
|
|
5575
|
+
// If type already has arrayType, additional dimensions are allowed (multi-dim)
|
|
5576
|
+
if (typeCtx.arrayType()) {
|
|
5577
|
+
return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5580
|
+
// Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
|
|
5581
|
+
// The grammar doesn't support u8[] arr syntax, so this is the only way
|
|
5582
|
+
if (arrayDims.length === 1 && !arrayDims[0].expression()) {
|
|
5583
|
+
return; // Size inference pattern allowed
|
|
5584
|
+
}
|
|
5585
|
+
|
|
5586
|
+
// Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
|
|
5587
|
+
// The arrayType grammar only supports single dimension, so multi-dim needs C-style
|
|
5588
|
+
if (arrayDims.length > 1) {
|
|
5589
|
+
return; // Multi-dimensional arrays need C-style
|
|
5590
|
+
}
|
|
5591
|
+
|
|
5592
|
+
// Allow C-style for types that don't support arrayType syntax:
|
|
5593
|
+
// - Qualified types (Scope.Type, Namespace::Type)
|
|
5594
|
+
// - Scoped types (this.Type)
|
|
5595
|
+
// - Global types (global.Type)
|
|
5596
|
+
// - String types (string<N>)
|
|
5597
|
+
// - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
|
|
5598
|
+
if (
|
|
5599
|
+
typeCtx.qualifiedType() ||
|
|
5600
|
+
typeCtx.scopedType() ||
|
|
5601
|
+
typeCtx.globalType() ||
|
|
5602
|
+
typeCtx.stringType()
|
|
5603
|
+
) {
|
|
5604
|
+
return; // Grammar limitation - these can't use arrayType
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5607
|
+
// C-style array declaration detected - reject with helpful error
|
|
5608
|
+
const baseType = this._extractBaseTypeName(typeCtx);
|
|
5609
|
+
const dimensions = arrayDims
|
|
5610
|
+
.map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
|
|
5611
|
+
.join("");
|
|
5612
|
+
const line = ctx.start?.line ?? 0;
|
|
5613
|
+
const col = ctx.start?.column ?? 0;
|
|
5614
|
+
|
|
5615
|
+
throw new Error(
|
|
5616
|
+
`${line}:${col} C-style array declaration is not allowed. ` +
|
|
5617
|
+
`Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
|
|
5618
|
+
);
|
|
5619
|
+
}
|
|
5620
|
+
|
|
5621
|
+
/**
|
|
5622
|
+
* Extract base type name from type context for error messages.
|
|
5623
|
+
*/
|
|
5624
|
+
private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
|
|
5625
|
+
if (typeCtx.primitiveType()) {
|
|
5626
|
+
return typeCtx.primitiveType()!.getText();
|
|
5627
|
+
}
|
|
5628
|
+
if (typeCtx.userType()) {
|
|
5629
|
+
return typeCtx.userType()!.getText();
|
|
5630
|
+
}
|
|
5631
|
+
if (typeCtx.arrayType()) {
|
|
5632
|
+
const arrCtx = typeCtx.arrayType()!;
|
|
5633
|
+
if (arrCtx.primitiveType()) {
|
|
5634
|
+
return arrCtx.primitiveType()!.getText();
|
|
5635
|
+
}
|
|
5636
|
+
if (arrCtx.userType()) {
|
|
5637
|
+
return arrCtx.userType()!.getText();
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
return typeCtx.getText();
|
|
5641
|
+
}
|
|
5642
|
+
|
|
6046
5643
|
/**
|
|
6047
5644
|
* Issue #696: Generate variable initializer with validation.
|
|
6048
5645
|
*/
|
|
@@ -6058,17 +5655,17 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6058
5655
|
}
|
|
6059
5656
|
|
|
6060
5657
|
const typeName = this.getTypeName(typeCtx);
|
|
6061
|
-
const savedExpectedType =
|
|
6062
|
-
|
|
5658
|
+
const savedExpectedType = CodeGenState.expectedType;
|
|
5659
|
+
CodeGenState.expectedType = typeName;
|
|
6063
5660
|
|
|
6064
5661
|
// ADR-017: Validate enum type for initialization
|
|
6065
|
-
|
|
5662
|
+
EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
|
|
6066
5663
|
|
|
6067
5664
|
// ADR-024: Validate integer literals and type conversions
|
|
6068
5665
|
this._validateIntegerInitializer(ctx, typeName);
|
|
6069
5666
|
|
|
6070
5667
|
const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
|
|
6071
|
-
|
|
5668
|
+
CodeGenState.expectedType = savedExpectedType;
|
|
6072
5669
|
|
|
6073
5670
|
return result;
|
|
6074
5671
|
}
|
|
@@ -6116,20 +5713,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6116
5713
|
name: string,
|
|
6117
5714
|
decl: string,
|
|
6118
5715
|
): string {
|
|
6119
|
-
if (
|
|
5716
|
+
if (CodeGenState.pendingCppClassAssignments.length === 0) {
|
|
6120
5717
|
return `${decl};`;
|
|
6121
5718
|
}
|
|
6122
5719
|
|
|
6123
|
-
if (
|
|
6124
|
-
const assignments =
|
|
5720
|
+
if (CodeGenState.inFunctionBody) {
|
|
5721
|
+
const assignments = CodeGenState.pendingCppClassAssignments
|
|
6125
5722
|
.map((a) => `${name}.${a}`)
|
|
6126
5723
|
.join("\n");
|
|
6127
|
-
|
|
5724
|
+
CodeGenState.pendingCppClassAssignments = [];
|
|
6128
5725
|
return `${decl};\n${assignments}`;
|
|
6129
5726
|
}
|
|
6130
5727
|
|
|
6131
5728
|
// At global scope, we can't emit assignment statements.
|
|
6132
|
-
|
|
5729
|
+
CodeGenState.pendingCppClassAssignments = [];
|
|
6133
5730
|
throw new Error(
|
|
6134
5731
|
`Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
|
|
6135
5732
|
`syntax at global scope. Use constructor syntax or initialize fields separately.`,
|
|
@@ -6157,14 +5754,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6157
5754
|
const argName = argNode.getText();
|
|
6158
5755
|
|
|
6159
5756
|
// Check if it exists in type registry
|
|
6160
|
-
const typeInfo =
|
|
5757
|
+
const typeInfo = CodeGenState.typeRegistry.get(argName);
|
|
6161
5758
|
|
|
6162
5759
|
// Also check scoped variables if inside a scope
|
|
6163
5760
|
let scopedArgName = argName;
|
|
6164
5761
|
let scopedTypeInfo = typeInfo;
|
|
6165
|
-
if (!typeInfo &&
|
|
6166
|
-
scopedArgName = `${
|
|
6167
|
-
scopedTypeInfo =
|
|
5762
|
+
if (!typeInfo && CodeGenState.currentScope) {
|
|
5763
|
+
scopedArgName = `${CodeGenState.currentScope}_${argName}`;
|
|
5764
|
+
scopedTypeInfo = CodeGenState.typeRegistry.get(scopedArgName);
|
|
6168
5765
|
}
|
|
6169
5766
|
|
|
6170
5767
|
if (!typeInfo && !scopedTypeInfo) {
|
|
@@ -6188,7 +5785,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6188
5785
|
}
|
|
6189
5786
|
|
|
6190
5787
|
// Track the variable in type registry (as an external C++ type)
|
|
6191
|
-
|
|
5788
|
+
CodeGenState.typeRegistry.set(name, {
|
|
6192
5789
|
baseType: type,
|
|
6193
5790
|
bitWidth: 0, // Unknown for C++ types
|
|
6194
5791
|
isArray: false,
|
|
@@ -6198,8 +5795,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6198
5795
|
});
|
|
6199
5796
|
|
|
6200
5797
|
// Track as local variable if inside function body
|
|
6201
|
-
if (
|
|
6202
|
-
|
|
5798
|
+
if (CodeGenState.inFunctionBody) {
|
|
5799
|
+
CodeGenState.localVariables.add(name);
|
|
6203
5800
|
}
|
|
6204
5801
|
|
|
6205
5802
|
return `${type} ${name}(${resolvedArgs.join(", ")});`;
|
|
@@ -6231,7 +5828,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6231
5828
|
* ADR-017: Enums initialize to first member
|
|
6232
5829
|
*/
|
|
6233
5830
|
private _getEnumZeroValue(enumName: string, separator: string = "_"): string {
|
|
6234
|
-
const members =
|
|
5831
|
+
const members = CodeGenState.symbols!.enumMembers.get(enumName);
|
|
6235
5832
|
if (!members) {
|
|
6236
5833
|
return `(${enumName})0`;
|
|
6237
5834
|
}
|
|
@@ -6264,8 +5861,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6264
5861
|
// ADR-016: Check for scoped types (this.Type)
|
|
6265
5862
|
if (typeCtx.scopedType()) {
|
|
6266
5863
|
const localName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
6267
|
-
const name =
|
|
6268
|
-
? `${
|
|
5864
|
+
const name = CodeGenState.currentScope
|
|
5865
|
+
? `${CodeGenState.currentScope}_${localName}`
|
|
6269
5866
|
: localName;
|
|
6270
5867
|
return { name, separator: "_", checkCppType: false };
|
|
6271
5868
|
}
|
|
@@ -6312,7 +5909,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6312
5909
|
}
|
|
6313
5910
|
// In C++ mode, unknown user types may have non-trivial constructors
|
|
6314
5911
|
// Known structs (C-Next or C headers) are POD types where {0} works
|
|
6315
|
-
return
|
|
5912
|
+
return CodeGenState.cppMode && !this.isKnownStruct(typeName);
|
|
6316
5913
|
}
|
|
6317
5914
|
|
|
6318
5915
|
/**
|
|
@@ -6329,11 +5926,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6329
5926
|
// ADR-109: Build handler dependencies for assignment dispatch
|
|
6330
5927
|
private buildHandlerDeps(): IHandlerDeps {
|
|
6331
5928
|
return {
|
|
6332
|
-
symbols:
|
|
6333
|
-
typeRegistry:
|
|
6334
|
-
currentScope:
|
|
6335
|
-
currentParameters:
|
|
6336
|
-
targetCapabilities:
|
|
5929
|
+
symbols: CodeGenState.symbols!,
|
|
5930
|
+
typeRegistry: CodeGenState.typeRegistry,
|
|
5931
|
+
currentScope: CodeGenState.currentScope,
|
|
5932
|
+
currentParameters: CodeGenState.currentParameters,
|
|
5933
|
+
targetCapabilities: CodeGenState.targetCapabilities,
|
|
6337
5934
|
generateExpression: (ctx) => this.generateExpression(ctx),
|
|
6338
5935
|
tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
|
|
6339
5936
|
generateAssignmentTarget: (ctx) => this.generateAssignmentTarget(ctx),
|
|
@@ -6342,11 +5939,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6342
5939
|
getMemberTypeInfo: (structType, memberName) =>
|
|
6343
5940
|
this.getMemberTypeInfo(structType, memberName),
|
|
6344
5941
|
validateBitmapFieldLiteral: (expr, width, fieldName) =>
|
|
6345
|
-
|
|
5942
|
+
TypeValidator.validateBitmapFieldLiteral(expr, width, fieldName),
|
|
6346
5943
|
validateCrossScopeVisibility: (scopeName, memberName) =>
|
|
6347
5944
|
this.validateCrossScopeVisibility(scopeName, memberName),
|
|
6348
5945
|
checkArrayBounds: (arrayName, dimensions, indexExprs, line) =>
|
|
6349
|
-
|
|
5946
|
+
TypeValidator.checkArrayBounds(
|
|
6350
5947
|
arrayName,
|
|
6351
5948
|
[...dimensions],
|
|
6352
5949
|
[...indexExprs],
|
|
@@ -6379,7 +5976,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6379
5976
|
bitIndex?: string;
|
|
6380
5977
|
baseType?: string;
|
|
6381
5978
|
} {
|
|
6382
|
-
|
|
5979
|
+
// Issue #644: MemberChainAnalyzer is now static, pass generateExpression callback
|
|
5980
|
+
return MemberChainAnalyzer.analyze(targetCtx, (ctx) =>
|
|
5981
|
+
this.generateExpression(ctx),
|
|
5982
|
+
);
|
|
6383
5983
|
}
|
|
6384
5984
|
|
|
6385
5985
|
/**
|
|
@@ -6393,12 +5993,18 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6393
5993
|
width: string | null,
|
|
6394
5994
|
value: string,
|
|
6395
5995
|
): string | null {
|
|
6396
|
-
|
|
5996
|
+
// Issue #644: FloatBitHelper is now static, pass callbacks
|
|
5997
|
+
return FloatBitHelper.generateFloatBitWrite(
|
|
6397
5998
|
name,
|
|
6398
5999
|
typeInfo,
|
|
6399
6000
|
bitIndex,
|
|
6400
6001
|
width,
|
|
6401
6002
|
value,
|
|
6003
|
+
{
|
|
6004
|
+
generateBitMask: (w, is64Bit) => this.generateBitMask(w, is64Bit),
|
|
6005
|
+
foldBooleanToInt: (expr) => this.foldBooleanToInt(expr),
|
|
6006
|
+
requireInclude: (header) => this.requireInclude(header),
|
|
6007
|
+
},
|
|
6402
6008
|
);
|
|
6403
6009
|
}
|
|
6404
6010
|
|
|
@@ -6408,22 +6014,23 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6408
6014
|
|
|
6409
6015
|
// Issue #644: Set expected type for inferred struct initializers and overflow behavior
|
|
6410
6016
|
// Delegated to AssignmentExpectedTypeResolver helper
|
|
6411
|
-
const savedExpectedType =
|
|
6412
|
-
const savedAssignmentContext = { ...
|
|
6017
|
+
const savedExpectedType = CodeGenState.expectedType;
|
|
6018
|
+
const savedAssignmentContext = { ...CodeGenState.assignmentContext };
|
|
6413
6019
|
|
|
6414
|
-
|
|
6020
|
+
// Issue #644: AssignmentExpectedTypeResolver is now static
|
|
6021
|
+
const resolved = AssignmentExpectedTypeResolver.resolve(targetCtx);
|
|
6415
6022
|
if (resolved.expectedType) {
|
|
6416
|
-
|
|
6023
|
+
CodeGenState.expectedType = resolved.expectedType;
|
|
6417
6024
|
}
|
|
6418
6025
|
if (resolved.assignmentContext) {
|
|
6419
|
-
|
|
6026
|
+
CodeGenState.assignmentContext = resolved.assignmentContext;
|
|
6420
6027
|
}
|
|
6421
6028
|
|
|
6422
6029
|
const value = this.generateExpression(ctx.expression());
|
|
6423
6030
|
|
|
6424
6031
|
// Restore expected type and assignment context
|
|
6425
|
-
|
|
6426
|
-
|
|
6032
|
+
CodeGenState.expectedType = savedExpectedType;
|
|
6033
|
+
CodeGenState.assignmentContext = savedAssignmentContext;
|
|
6427
6034
|
|
|
6428
6035
|
// Get the assignment operator and map to C equivalent
|
|
6429
6036
|
const operatorCtx = ctx.assignmentOperator();
|
|
@@ -6433,29 +6040,27 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6433
6040
|
|
|
6434
6041
|
// Issue #644: Validate assignment (const, enum, integer, array bounds, callbacks)
|
|
6435
6042
|
// Delegated to AssignmentValidator helper to reduce cognitive complexity
|
|
6436
|
-
|
|
6043
|
+
AssignmentValidator.validate(
|
|
6437
6044
|
targetCtx,
|
|
6438
6045
|
ctx.expression(),
|
|
6439
6046
|
isCompound,
|
|
6440
6047
|
ctx.start?.line ?? 0,
|
|
6048
|
+
{
|
|
6049
|
+
getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
|
|
6050
|
+
tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
|
|
6051
|
+
isCallbackTypeUsedAsFieldType: (name) =>
|
|
6052
|
+
this.isCallbackTypeUsedAsFieldType(name),
|
|
6053
|
+
},
|
|
6441
6054
|
);
|
|
6442
6055
|
|
|
6443
6056
|
// ADR-109: Dispatch to assignment handlers
|
|
6444
6057
|
// Build context, classify, and dispatch - all patterns handled by handlers
|
|
6445
6058
|
const assignCtx = buildAssignmentContext(ctx, {
|
|
6446
|
-
typeRegistry:
|
|
6059
|
+
typeRegistry: CodeGenState.typeRegistry,
|
|
6447
6060
|
generateExpression: () => value,
|
|
6448
6061
|
});
|
|
6449
6062
|
const handlerDeps = this.buildHandlerDeps();
|
|
6450
|
-
const
|
|
6451
|
-
symbols: handlerDeps.symbols,
|
|
6452
|
-
typeRegistry: handlerDeps.typeRegistry,
|
|
6453
|
-
currentScope: handlerDeps.currentScope,
|
|
6454
|
-
isKnownStruct: handlerDeps.isKnownStruct,
|
|
6455
|
-
isKnownScope: handlerDeps.isKnownScope,
|
|
6456
|
-
getMemberTypeInfo: handlerDeps.getMemberTypeInfo,
|
|
6457
|
-
});
|
|
6458
|
-
const assignmentKind = classifier.classify(assignCtx);
|
|
6063
|
+
const assignmentKind = AssignmentClassifier.classify(assignCtx);
|
|
6459
6064
|
const handler = AssignmentHandlerRegistry.getHandler(assignmentKind);
|
|
6460
6065
|
return handler(assignCtx, handlerDeps);
|
|
6461
6066
|
}
|
|
@@ -6475,7 +6080,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6475
6080
|
cOp,
|
|
6476
6081
|
value,
|
|
6477
6082
|
typeInfo,
|
|
6478
|
-
|
|
6083
|
+
CodeGenState.targetCapabilities,
|
|
6479
6084
|
);
|
|
6480
6085
|
this.applyEffects(result.effects);
|
|
6481
6086
|
return result.code;
|
|
@@ -6487,16 +6092,16 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6487
6092
|
private _buildSimpleIdentifierDeps(): ISimpleIdentifierDeps {
|
|
6488
6093
|
return {
|
|
6489
6094
|
getParameterInfo: (name: string) =>
|
|
6490
|
-
|
|
6095
|
+
CodeGenState.currentParameters.get(name),
|
|
6491
6096
|
resolveParameter: (name: string, paramInfo: TParameterInfo) =>
|
|
6492
6097
|
ParameterDereferenceResolver.resolve(
|
|
6493
6098
|
name,
|
|
6494
6099
|
paramInfo,
|
|
6495
6100
|
this._buildParameterDereferenceDeps(),
|
|
6496
6101
|
),
|
|
6497
|
-
isLocalVariable: (name: string) =>
|
|
6102
|
+
isLocalVariable: (name: string) => CodeGenState.localVariables.has(name),
|
|
6498
6103
|
resolveBareIdentifier: (name: string, isLocal: boolean) =>
|
|
6499
|
-
|
|
6104
|
+
TypeValidator.resolveBareIdentifier(name, isLocal, (n: string) =>
|
|
6500
6105
|
this.isKnownStruct(n),
|
|
6501
6106
|
),
|
|
6502
6107
|
};
|
|
@@ -6522,7 +6127,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6522
6127
|
hasGlobal: boolean,
|
|
6523
6128
|
hasThis: boolean,
|
|
6524
6129
|
): IPostfixChainDeps {
|
|
6525
|
-
const paramInfo =
|
|
6130
|
+
const paramInfo = CodeGenState.currentParameters.get(firstId);
|
|
6526
6131
|
const isStructParam = paramInfo?.isStruct ?? false;
|
|
6527
6132
|
const isCppAccess = hasGlobal && this.isCppScopeSymbol(firstId);
|
|
6528
6133
|
const separatorDeps = this._buildMemberSeparatorDeps();
|
|
@@ -6532,7 +6137,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6532
6137
|
firstId,
|
|
6533
6138
|
hasGlobal,
|
|
6534
6139
|
hasThis,
|
|
6535
|
-
|
|
6140
|
+
CodeGenState.currentScope,
|
|
6536
6141
|
isStructParam,
|
|
6537
6142
|
separatorDeps,
|
|
6538
6143
|
isCppAccess,
|
|
@@ -6556,37 +6161,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6556
6161
|
};
|
|
6557
6162
|
}
|
|
6558
6163
|
|
|
6559
|
-
// ADR-016:
|
|
6560
|
-
private _validateCrossScopeVisibility(
|
|
6561
|
-
scopeName: string,
|
|
6562
|
-
memberName: string,
|
|
6563
|
-
isGlobalAccess: boolean = false,
|
|
6564
|
-
): void {
|
|
6565
|
-
// Error if referencing own scope by name (must use this. prefix)
|
|
6566
|
-
// Exception: global.Scope.member is allowed for explicit qualification
|
|
6567
|
-
if (!isGlobalAccess && this.context.currentScope === scopeName) {
|
|
6568
|
-
throw new Error(
|
|
6569
|
-
`Error: Cannot reference own scope '${scopeName}' by name. ` +
|
|
6570
|
-
`Use 'this.${memberName}' instead of '${scopeName}.${memberName}'`,
|
|
6571
|
-
);
|
|
6572
|
-
}
|
|
6573
|
-
|
|
6574
|
-
// Check private member access (skip for own scope - we can access our own privates)
|
|
6575
|
-
const isOwnScope = this.context.currentScope === scopeName;
|
|
6576
|
-
if (!isOwnScope) {
|
|
6577
|
-
const visibility =
|
|
6578
|
-
this.symbols!.scopeMemberVisibility.get(scopeName)?.get(memberName);
|
|
6579
|
-
if (visibility === "private") {
|
|
6580
|
-
const context = this.context.currentScope
|
|
6581
|
-
? `from scope '${this.context.currentScope}'`
|
|
6582
|
-
: "from outside the scope";
|
|
6583
|
-
throw new Error(
|
|
6584
|
-
`Cannot access private member '${memberName}' of scope '${scopeName}' ${context}. ` +
|
|
6585
|
-
`Only public members are accessible outside their scope.`,
|
|
6586
|
-
);
|
|
6587
|
-
}
|
|
6588
|
-
}
|
|
6589
|
-
}
|
|
6164
|
+
// ADR-016: _validateCrossScopeVisibility moved to ScopeResolver
|
|
6590
6165
|
|
|
6591
6166
|
// Issue #387: Dead methods removed (generateGlobalMemberAccess, generateGlobalArrayAccess,
|
|
6592
6167
|
// generateThisMemberAccess, generateThisArrayAccess) - now handled by unified doGenerateAssignmentTarget
|
|
@@ -6672,7 +6247,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6672
6247
|
* ADR-016: 'this' returns a marker that postfixOps will transform to Scope_member
|
|
6673
6248
|
*/
|
|
6674
6249
|
private _resolveThisKeyword(): string {
|
|
6675
|
-
if (!
|
|
6250
|
+
if (!CodeGenState.currentScope) {
|
|
6676
6251
|
throw new Error("Error: 'this' can only be used inside a scope");
|
|
6677
6252
|
}
|
|
6678
6253
|
return "__THIS_SCOPE__";
|
|
@@ -6684,12 +6259,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6684
6259
|
*/
|
|
6685
6260
|
private _resolveIdentifierExpression(id: string): string {
|
|
6686
6261
|
// Special case: main function's args parameter -> argv
|
|
6687
|
-
if (
|
|
6262
|
+
if (CodeGenState.mainArgsName && id === CodeGenState.mainArgsName) {
|
|
6688
6263
|
return "argv";
|
|
6689
6264
|
}
|
|
6690
6265
|
|
|
6691
6266
|
// ADR-006: Check if it's a function parameter
|
|
6692
|
-
const paramInfo =
|
|
6267
|
+
const paramInfo = CodeGenState.currentParameters.get(id);
|
|
6693
6268
|
if (paramInfo) {
|
|
6694
6269
|
return ParameterDereferenceResolver.resolve(
|
|
6695
6270
|
id,
|
|
@@ -6699,15 +6274,16 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6699
6274
|
}
|
|
6700
6275
|
|
|
6701
6276
|
// ADR-016: Resolve bare identifier using local -> scope -> global priority
|
|
6702
|
-
const isLocalVariable =
|
|
6703
|
-
const resolved =
|
|
6277
|
+
const isLocalVariable = CodeGenState.localVariables.has(id);
|
|
6278
|
+
const resolved = TypeValidator.resolveBareIdentifier(
|
|
6704
6279
|
id,
|
|
6705
6280
|
isLocalVariable,
|
|
6706
6281
|
(name: string) => this.isKnownStruct(name),
|
|
6707
6282
|
);
|
|
6708
6283
|
if (resolved !== null) {
|
|
6709
6284
|
// Issue #741: Check if this is a private const that should be inlined
|
|
6710
|
-
const constValue =
|
|
6285
|
+
const constValue =
|
|
6286
|
+
CodeGenState.symbols!.scopePrivateConstValues.get(resolved);
|
|
6711
6287
|
if (constValue !== undefined) {
|
|
6712
6288
|
return constValue;
|
|
6713
6289
|
}
|
|
@@ -6731,19 +6307,21 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6731
6307
|
private _resolveUnqualifiedEnumMember(id: string): string | null {
|
|
6732
6308
|
// Type-aware resolution: check only the expected enum type
|
|
6733
6309
|
if (
|
|
6734
|
-
|
|
6735
|
-
|
|
6310
|
+
CodeGenState.expectedType &&
|
|
6311
|
+
CodeGenState.symbols!.knownEnums.has(CodeGenState.expectedType)
|
|
6736
6312
|
) {
|
|
6737
|
-
const members =
|
|
6313
|
+
const members = CodeGenState.symbols!.enumMembers.get(
|
|
6314
|
+
CodeGenState.expectedType,
|
|
6315
|
+
);
|
|
6738
6316
|
if (members?.has(id)) {
|
|
6739
|
-
return `${
|
|
6317
|
+
return `${CodeGenState.expectedType}${this.getScopeSeparator(false)}${id}`;
|
|
6740
6318
|
}
|
|
6741
6319
|
return null;
|
|
6742
6320
|
}
|
|
6743
6321
|
|
|
6744
6322
|
// No expected enum type - search all enums but error on ambiguity
|
|
6745
6323
|
const matchingEnums: string[] = [];
|
|
6746
|
-
for (const [enumName, members] of
|
|
6324
|
+
for (const [enumName, members] of CodeGenState.symbols!.enumMembers) {
|
|
6747
6325
|
if (members.has(id)) {
|
|
6748
6326
|
matchingEnums.push(enumName);
|
|
6749
6327
|
}
|
|
@@ -6771,7 +6349,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6771
6349
|
|
|
6772
6350
|
// Issue #304/#644: Transform NULL → nullptr in C++ mode
|
|
6773
6351
|
if (result.code === "NULL") {
|
|
6774
|
-
return
|
|
6352
|
+
return CppModeHelper.nullLiteral();
|
|
6775
6353
|
}
|
|
6776
6354
|
|
|
6777
6355
|
return result.code;
|
|
@@ -6837,7 +6415,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6837
6415
|
}
|
|
6838
6416
|
|
|
6839
6417
|
// Issue #267/#644: Use C++ casts when cppMode is enabled for MISRA compliance
|
|
6840
|
-
return
|
|
6418
|
+
return CppModeHelper.cast(targetType, expr);
|
|
6841
6419
|
}
|
|
6842
6420
|
|
|
6843
6421
|
/**
|
|
@@ -6863,7 +6441,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6863
6441
|
|
|
6864
6442
|
if (!maxValue) {
|
|
6865
6443
|
// Unknown type, fall back to raw cast - Issue #644
|
|
6866
|
-
return
|
|
6444
|
+
return CppModeHelper.cast(targetType, expr);
|
|
6867
6445
|
}
|
|
6868
6446
|
|
|
6869
6447
|
// Mark that we need limits.h for the type limit macros
|
|
@@ -6883,161 +6461,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6883
6461
|
// Generate clamping expression:
|
|
6884
6462
|
// (expr > MAX) ? MAX : (expr < MIN) ? MIN : (type)(expr)
|
|
6885
6463
|
// Note: For unsigned targets, MIN is 0 so we check < 0.0
|
|
6886
|
-
const finalCast =
|
|
6464
|
+
const finalCast = CppModeHelper.cast(targetType, `(${expr})`);
|
|
6887
6465
|
return `((${expr}) > ${maxComparison} ? ${maxValue} : (${expr}) < ${minComparison} ? ${minValue} : ${finalCast})`;
|
|
6888
6466
|
}
|
|
6889
6467
|
|
|
6890
6468
|
/**
|
|
6891
6469
|
* ADR-023: Generate sizeof expression
|
|
6892
|
-
*
|
|
6893
|
-
* sizeof(variable) -> sizeof(variable)
|
|
6894
|
-
* With safety checks:
|
|
6895
|
-
* - E0601: sizeof on array parameter is error
|
|
6896
|
-
* - E0602: Side effects in sizeof are error
|
|
6470
|
+
* Delegates to SizeofResolver which uses CodeGenState.
|
|
6897
6471
|
*/
|
|
6898
6472
|
private generateSizeofExpr(ctx: Parser.SizeofExpressionContext): string {
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
}
|
|
6905
|
-
return this._sizeofExpression(ctx.expression()!);
|
|
6906
|
-
}
|
|
6907
|
-
|
|
6908
|
-
/**
|
|
6909
|
-
* Handle sizeof(type) - may actually be sizeof(variable) due to grammar ambiguity
|
|
6910
|
-
*/
|
|
6911
|
-
private _sizeofType(typeCtx: Parser.TypeContext): string {
|
|
6912
|
-
// qualifiedType matches IDENTIFIER.IDENTIFIER, could be struct.member
|
|
6913
|
-
if (typeCtx.qualifiedType()) {
|
|
6914
|
-
const result = this._sizeofQualifiedType(typeCtx.qualifiedType()!);
|
|
6915
|
-
if (result) return result;
|
|
6916
|
-
// Fall through to generateType for actual type references (Scope.Type)
|
|
6917
|
-
}
|
|
6918
|
-
|
|
6919
|
-
// userType is just IDENTIFIER, could be a variable reference
|
|
6920
|
-
if (typeCtx.userType()) {
|
|
6921
|
-
return this._sizeofUserType(typeCtx.getText());
|
|
6922
|
-
}
|
|
6923
|
-
|
|
6924
|
-
// It's a primitive or other type - generate normally
|
|
6925
|
-
return `sizeof(${this.generateType(typeCtx)})`;
|
|
6926
|
-
}
|
|
6927
|
-
|
|
6928
|
-
/**
|
|
6929
|
-
* Handle sizeof(qualified.type) - may be struct.member access
|
|
6930
|
-
* Returns null if this is actually a type reference (Scope.Type)
|
|
6931
|
-
*/
|
|
6932
|
-
private _sizeofQualifiedType(
|
|
6933
|
-
qualifiedCtx: Parser.QualifiedTypeContext,
|
|
6934
|
-
): string | null {
|
|
6935
|
-
const identifiers = qualifiedCtx.IDENTIFIER();
|
|
6936
|
-
const firstName = identifiers[0].getText();
|
|
6937
|
-
const memberName = identifiers[1].getText();
|
|
6938
|
-
|
|
6939
|
-
// Check if first identifier is a local variable (struct instance)
|
|
6940
|
-
if (this.context.localVariables.has(firstName)) {
|
|
6941
|
-
return `sizeof(${firstName}.${memberName})`;
|
|
6942
|
-
}
|
|
6943
|
-
|
|
6944
|
-
// Check if first identifier is a parameter (struct parameter)
|
|
6945
|
-
const paramInfo = this.context.currentParameters.get(firstName);
|
|
6946
|
-
if (paramInfo) {
|
|
6947
|
-
const sep = paramInfo.isStruct ? "->" : ".";
|
|
6948
|
-
return `sizeof(${firstName}${sep}${memberName})`;
|
|
6949
|
-
}
|
|
6950
|
-
|
|
6951
|
-
// Check if first identifier is a global variable
|
|
6952
|
-
// If not a scope or enum, it's likely a global struct variable
|
|
6953
|
-
if (
|
|
6954
|
-
!this.isKnownScope(firstName) &&
|
|
6955
|
-
!this.symbols!.knownEnums.has(firstName)
|
|
6956
|
-
) {
|
|
6957
|
-
return `sizeof(${firstName}.${memberName})`;
|
|
6958
|
-
}
|
|
6959
|
-
|
|
6960
|
-
// It's an actual type reference (Scope.Type), return null to fall through
|
|
6961
|
-
return null;
|
|
6962
|
-
}
|
|
6963
|
-
|
|
6964
|
-
/**
|
|
6965
|
-
* Handle sizeof(identifier) - could be variable or type name
|
|
6966
|
-
*/
|
|
6967
|
-
private _sizeofUserType(varName: string): string {
|
|
6968
|
-
// Check if it's a known parameter
|
|
6969
|
-
const paramInfo = this.context.currentParameters.get(varName);
|
|
6970
|
-
if (paramInfo) {
|
|
6971
|
-
return this._sizeofParameter(varName, paramInfo);
|
|
6972
|
-
}
|
|
6973
|
-
|
|
6974
|
-
// Check if it's a known local variable, struct type, or enum type
|
|
6975
|
-
// For all these cases, generate sizeof(name) directly
|
|
6976
|
-
// Unknown identifiers are also treated as variables for safety
|
|
6977
|
-
return `sizeof(${varName})`;
|
|
6978
|
-
}
|
|
6979
|
-
|
|
6980
|
-
/**
|
|
6981
|
-
* Handle sizeof on a parameter - validates and generates appropriate code
|
|
6982
|
-
*/
|
|
6983
|
-
private _sizeofParameter(
|
|
6984
|
-
varName: string,
|
|
6985
|
-
paramInfo: { isArray?: boolean; isCallback?: boolean; isStruct?: boolean },
|
|
6986
|
-
): string {
|
|
6987
|
-
// E0601: Array parameters decay to pointers
|
|
6988
|
-
if (paramInfo.isArray) {
|
|
6989
|
-
this._throwArrayParamSizeofError(varName);
|
|
6990
|
-
}
|
|
6991
|
-
// For pass-by-reference parameters (non-array, non-callback, non-struct),
|
|
6992
|
-
// use pointer dereference
|
|
6993
|
-
if (!paramInfo.isCallback && !paramInfo.isStruct) {
|
|
6994
|
-
return `sizeof(*${varName})`;
|
|
6995
|
-
}
|
|
6996
|
-
return `sizeof(${varName})`;
|
|
6997
|
-
}
|
|
6998
|
-
|
|
6999
|
-
/**
|
|
7000
|
-
* Throw E0601 error for sizeof on array parameter
|
|
7001
|
-
*/
|
|
7002
|
-
private _throwArrayParamSizeofError(varName: string): never {
|
|
7003
|
-
throw new Error(
|
|
7004
|
-
`Error[E0601]: sizeof() on array parameter '${varName}' returns pointer size. ` +
|
|
7005
|
-
`Use ${varName}.length for element count or sizeof(elementType) * ${varName}.length for bytes`,
|
|
7006
|
-
);
|
|
7007
|
-
}
|
|
7008
|
-
|
|
7009
|
-
/**
|
|
7010
|
-
* Handle sizeof(expression) with validation
|
|
7011
|
-
*/
|
|
7012
|
-
private _sizeofExpression(expr: Parser.ExpressionContext): string {
|
|
7013
|
-
// E0601: Check if expression is an array parameter
|
|
7014
|
-
const varName = this.getSingleIdentifierFromExpr(expr);
|
|
7015
|
-
if (varName) {
|
|
7016
|
-
const paramInfo = this.context.currentParameters.get(varName);
|
|
7017
|
-
if (paramInfo?.isArray) {
|
|
7018
|
-
this._throwArrayParamSizeofError(varName);
|
|
7019
|
-
}
|
|
7020
|
-
}
|
|
7021
|
-
|
|
7022
|
-
// E0602: Check for side effects
|
|
7023
|
-
if (this.hasSideEffects(expr)) {
|
|
7024
|
-
throw new Error(
|
|
7025
|
-
`Error[E0602]: sizeof() operand must not have side effects (MISRA C:2012 Rule 13.6)`,
|
|
7026
|
-
);
|
|
7027
|
-
}
|
|
7028
|
-
|
|
7029
|
-
return `sizeof(${this.generateExpression(expr)})`;
|
|
7030
|
-
}
|
|
7031
|
-
|
|
7032
|
-
/**
|
|
7033
|
-
* ADR-023: Extract simple identifier from expression for parameter checking
|
|
7034
|
-
* Returns the identifier name if expression is a simple variable reference, null otherwise
|
|
7035
|
-
* Issue #707: Delegates to ExpressionUnwrapper utility.
|
|
7036
|
-
*/
|
|
7037
|
-
private getSingleIdentifierFromExpr(
|
|
7038
|
-
expr: Parser.ExpressionContext,
|
|
7039
|
-
): string | null {
|
|
7040
|
-
return ExpressionUnwrapper.getSimpleIdentifier(expr);
|
|
6473
|
+
return SizeofResolver.generate(ctx, {
|
|
6474
|
+
generateType: (typeCtx) => this.generateType(typeCtx),
|
|
6475
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
6476
|
+
hasSideEffects: (exprCtx) => this.hasSideEffects(exprCtx),
|
|
6477
|
+
});
|
|
7041
6478
|
}
|
|
7042
6479
|
|
|
7043
6480
|
/**
|
|
@@ -7099,7 +6536,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
7099
6536
|
* ADR-053 A5: Delegates to HelperGenerator
|
|
7100
6537
|
*/
|
|
7101
6538
|
private generateOverflowHelpers(): string[] {
|
|
7102
|
-
return helperGenerateOverflowHelpers(
|
|
6539
|
+
return helperGenerateOverflowHelpers(
|
|
6540
|
+
CodeGenState.usedClampOps,
|
|
6541
|
+
CodeGenState.debugMode,
|
|
6542
|
+
);
|
|
7103
6543
|
}
|
|
7104
6544
|
|
|
7105
6545
|
/**
|
|
@@ -7108,7 +6548,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
7108
6548
|
private markClampOpUsed(operation: string, cnxType: string): void {
|
|
7109
6549
|
// Only generate helpers for integer types (not float/bool)
|
|
7110
6550
|
if (TYPE_WIDTH[cnxType] && TypeCheckUtils.isInteger(cnxType)) {
|
|
7111
|
-
|
|
6551
|
+
CodeGenState.usedClampOps.add(`${operation}_${cnxType}`);
|
|
7112
6552
|
}
|
|
7113
6553
|
}
|
|
7114
6554
|
|
|
@@ -7144,7 +6584,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
7144
6584
|
* Format leading comments with current indentation
|
|
7145
6585
|
*/
|
|
7146
6586
|
private formatLeadingComments(comments: IComment[]): string[] {
|
|
7147
|
-
const indent = FormatUtils.indent(
|
|
6587
|
+
const indent = FormatUtils.indent(CodeGenState.indentLevel);
|
|
7148
6588
|
return commentFormatLeadingComments(
|
|
7149
6589
|
comments,
|
|
7150
6590
|
this.commentFormatter,
|
|
@@ -7157,6 +6597,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
7157
6597
|
* ADR-053 A5: Delegates to HelperGenerator
|
|
7158
6598
|
*/
|
|
7159
6599
|
private generateSafeDivHelpers(): string[] {
|
|
7160
|
-
return helperGenerateSafeDivHelpers(
|
|
6600
|
+
return helperGenerateSafeDivHelpers(CodeGenState.usedSafeDivOps);
|
|
7161
6601
|
}
|
|
7162
6602
|
}
|