c-next 0.2.15 → 0.2.17

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.
Files changed (67) hide show
  1. package/README.md +16 -0
  2. package/dist/index.js +1403 -427
  3. package/dist/index.js.map +3 -3
  4. package/grammar/CNext.g4 +4 -0
  5. package/package.json +5 -1
  6. package/src/transpiler/Transpiler.ts +90 -22
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  8. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +57 -10
  9. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
  10. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
  11. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
  12. package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
  13. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
  14. package/src/transpiler/logic/parser/grammar/CNext.interp +1 -1
  15. package/src/transpiler/logic/parser/grammar/CNextParser.ts +154 -86
  16. package/src/transpiler/logic/symbols/SymbolTable.ts +54 -12
  17. package/src/transpiler/logic/symbols/SymbolUtils.ts +21 -8
  18. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +39 -4
  19. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +2 -1
  20. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +2 -1
  21. package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +5 -2
  22. package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +5 -2
  23. package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +7 -2
  24. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
  25. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
  26. package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +4 -2
  27. package/src/transpiler/output/codegen/CodeGenerator.ts +151 -94
  28. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +167 -18
  29. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +150 -34
  30. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
  31. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +11 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +32 -8
  33. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +91 -1
  34. package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
  35. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +48 -43
  36. package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
  37. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
  38. package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
  39. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
  40. package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
  41. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +227 -32
  42. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
  43. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
  44. package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
  45. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
  46. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
  47. package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +268 -1
  49. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
  50. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
  51. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
  52. package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
  53. package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
  54. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
  55. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +75 -0
  56. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
  57. package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
  58. package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
  59. package/src/transpiler/state/CodeGenState.ts +71 -6
  60. package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
  61. package/src/transpiler/types/symbols/c/ICFieldInfo.ts +6 -2
  62. package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +5 -2
  63. package/src/utils/LiteralUtils.ts +23 -0
  64. package/src/utils/ScopeUtils.ts +19 -0
  65. package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
  66. package/src/utils/__tests__/ScopeUtils.test.ts +10 -0
  67. package/src/utils/types/IParameterSymbol.ts +1 -0
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { hideBin } from "yargs/helpers";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "c-next",
14
- version: "0.2.15",
14
+ version: "0.2.17",
15
15
  description: "A safer C for embedded systems development. Transpiles to clean, readable C.",
16
16
  packageManager: "npm@11.9.0",
17
17
  type: "module",
@@ -35,6 +35,10 @@ var package_default = {
35
35
  "test:update": "tsx scripts/test.ts --update",
36
36
  "integration:transpile": "tsx scripts/test.ts --transpile-only",
37
37
  "integration:execute": "tsx scripts/test.ts --execute-only",
38
+ "test:bugs": "tsx scripts/test.ts -- bugs",
39
+ "test:bugs:q": "tsx scripts/test.ts -- bugs -q",
40
+ "integration:bugs:transpile": "tsx scripts/test.ts -- bugs --transpile-only",
41
+ "integration:bugs:execute": "tsx scripts/test.ts -- bugs --execute-only",
38
42
  analyze: "./scripts/static-analysis.sh",
39
43
  clean: "rm -rf dist src/transpiler/logic/parser/grammar src/transpiler/logic/parser/c/grammar src/transpiler/logic/parser/cpp/grammar",
40
44
  "prettier:check": "prettier --check .",
@@ -16039,21 +16043,10 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16039
16043
  this.enterRule(localContext, 170, _CNextParser.RULE_arrayType);
16040
16044
  let _la;
16041
16045
  try {
16042
- this.state = 921;
16046
+ this.state = 939;
16043
16047
  this.errorHandler.sync(this);
16044
- switch (this.tokenStream.LA(1)) {
16045
- case _CNextParser.U8:
16046
- case _CNextParser.U16:
16047
- case _CNextParser.U32:
16048
- case _CNextParser.U64:
16049
- case _CNextParser.I8:
16050
- case _CNextParser.I16:
16051
- case _CNextParser.I32:
16052
- case _CNextParser.I64:
16053
- case _CNextParser.F32:
16054
- case _CNextParser.F64:
16055
- case _CNextParser.BOOL:
16056
- case _CNextParser.ISR_TYPE:
16048
+ switch (this.interpreter.adaptivePredict(this.tokenStream, 98, this.context)) {
16049
+ case 1:
16057
16050
  this.enterOuterAlt(localContext, 1);
16058
16051
  {
16059
16052
  this.state = 903;
@@ -16074,7 +16067,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16074
16067
  } while (_la === 100);
16075
16068
  }
16076
16069
  break;
16077
- case _CNextParser.IDENTIFIER:
16070
+ case 2:
16078
16071
  this.enterOuterAlt(localContext, 2);
16079
16072
  {
16080
16073
  this.state = 909;
@@ -16095,7 +16088,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16095
16088
  } while (_la === 100);
16096
16089
  }
16097
16090
  break;
16098
- case _CNextParser.STRING:
16091
+ case 3:
16099
16092
  this.enterOuterAlt(localContext, 3);
16100
16093
  {
16101
16094
  this.state = 915;
@@ -16116,8 +16109,69 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16116
16109
  } while (_la === 100);
16117
16110
  }
16118
16111
  break;
16119
- default:
16120
- throw new antlr2.NoViableAltException(this);
16112
+ case 4:
16113
+ this.enterOuterAlt(localContext, 4);
16114
+ {
16115
+ this.state = 921;
16116
+ this.scopedType();
16117
+ this.state = 923;
16118
+ this.errorHandler.sync(this);
16119
+ _la = this.tokenStream.LA(1);
16120
+ do {
16121
+ {
16122
+ {
16123
+ this.state = 922;
16124
+ this.arrayTypeDimension();
16125
+ }
16126
+ }
16127
+ this.state = 925;
16128
+ this.errorHandler.sync(this);
16129
+ _la = this.tokenStream.LA(1);
16130
+ } while (_la === 100);
16131
+ }
16132
+ break;
16133
+ case 5:
16134
+ this.enterOuterAlt(localContext, 5);
16135
+ {
16136
+ this.state = 927;
16137
+ this.qualifiedType();
16138
+ this.state = 929;
16139
+ this.errorHandler.sync(this);
16140
+ _la = this.tokenStream.LA(1);
16141
+ do {
16142
+ {
16143
+ {
16144
+ this.state = 928;
16145
+ this.arrayTypeDimension();
16146
+ }
16147
+ }
16148
+ this.state = 931;
16149
+ this.errorHandler.sync(this);
16150
+ _la = this.tokenStream.LA(1);
16151
+ } while (_la === 100);
16152
+ }
16153
+ break;
16154
+ case 6:
16155
+ this.enterOuterAlt(localContext, 6);
16156
+ {
16157
+ this.state = 933;
16158
+ this.globalType();
16159
+ this.state = 935;
16160
+ this.errorHandler.sync(this);
16161
+ _la = this.tokenStream.LA(1);
16162
+ do {
16163
+ {
16164
+ {
16165
+ this.state = 934;
16166
+ this.arrayTypeDimension();
16167
+ }
16168
+ }
16169
+ this.state = 937;
16170
+ this.errorHandler.sync(this);
16171
+ _la = this.tokenStream.LA(1);
16172
+ } while (_la === 100);
16173
+ }
16174
+ break;
16121
16175
  }
16122
16176
  } catch (re) {
16123
16177
  if (re instanceof antlr2.RecognitionException) {
@@ -16138,18 +16192,18 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16138
16192
  try {
16139
16193
  this.enterOuterAlt(localContext, 1);
16140
16194
  {
16141
- this.state = 923;
16195
+ this.state = 941;
16142
16196
  this.match(_CNextParser.LBRACKET);
16143
- this.state = 925;
16197
+ this.state = 943;
16144
16198
  this.errorHandler.sync(this);
16145
16199
  _la = this.tokenStream.LA(1);
16146
16200
  if ((_la & ~31) === 0 && (1 << _la & 2147532800) !== 0 || (_la - 32 & ~31) === 0 && (1 << _la - 32 & 1966091) !== 0 || (_la - 83 & ~31) === 0 && (1 << _la - 83 & 2130879681) !== 0) {
16147
16201
  {
16148
- this.state = 924;
16202
+ this.state = 942;
16149
16203
  this.expression();
16150
16204
  }
16151
16205
  }
16152
- this.state = 927;
16206
+ this.state = 945;
16153
16207
  this.match(_CNextParser.RBRACKET);
16154
16208
  }
16155
16209
  } catch (re) {
@@ -16171,7 +16225,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16171
16225
  try {
16172
16226
  this.enterOuterAlt(localContext, 1);
16173
16227
  {
16174
- this.state = 929;
16228
+ this.state = 947;
16175
16229
  _la = this.tokenStream.LA(1);
16176
16230
  if (!((_la - 31 & ~31) === 0 && (1 << _la - 31 & 3932167) !== 0 || (_la - 107 & ~31) === 0 && (1 << _la - 107 & 63) !== 0)) {
16177
16231
  this.errorHandler.recoverInline(this);
@@ -16196,7 +16250,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
16196
16250
  4,
16197
16251
  1,
16198
16252
  117,
16199
- 932,
16253
+ 950,
16200
16254
  2,
16201
16255
  0,
16202
16256
  7,
@@ -18171,9 +18225,51 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
18171
18225
  12,
18172
18226
  85,
18173
18227
  919,
18228
+ 1,
18229
+ 85,
18230
+ 1,
18231
+ 85,
18232
+ 4,
18233
+ 85,
18234
+ 924,
18235
+ 8,
18236
+ 85,
18237
+ 11,
18238
+ 85,
18239
+ 12,
18240
+ 85,
18241
+ 925,
18242
+ 1,
18243
+ 85,
18244
+ 1,
18245
+ 85,
18246
+ 4,
18247
+ 85,
18248
+ 930,
18249
+ 8,
18250
+ 85,
18251
+ 11,
18252
+ 85,
18253
+ 12,
18254
+ 85,
18255
+ 931,
18256
+ 1,
18257
+ 85,
18258
+ 1,
18259
+ 85,
18260
+ 4,
18261
+ 85,
18262
+ 936,
18263
+ 8,
18264
+ 85,
18265
+ 11,
18266
+ 85,
18267
+ 12,
18268
+ 85,
18269
+ 937,
18174
18270
  3,
18175
18271
  85,
18176
- 922,
18272
+ 940,
18177
18273
  8,
18178
18274
  85,
18179
18275
  1,
@@ -18182,7 +18278,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
18182
18278
  86,
18183
18279
  3,
18184
18280
  86,
18185
- 926,
18281
+ 944,
18186
18282
  8,
18187
18283
  86,
18188
18284
  1,
@@ -18348,7 +18444,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
18348
18444
  52,
18349
18445
  107,
18350
18446
  112,
18351
- 988,
18447
+ 1012,
18352
18448
  0,
18353
18449
  180,
18354
18450
  1,
@@ -18860,19 +18956,19 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
18860
18956
  0,
18861
18957
  0,
18862
18958
  170,
18863
- 921,
18959
+ 939,
18864
18960
  1,
18865
18961
  0,
18866
18962
  0,
18867
18963
  0,
18868
18964
  172,
18869
- 923,
18965
+ 941,
18870
18966
  1,
18871
18967
  0,
18872
18968
  0,
18873
18969
  0,
18874
18970
  174,
18875
- 929,
18971
+ 947,
18876
18972
  1,
18877
18973
  0,
18878
18974
  0,
@@ -24110,7 +24206,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
24110
24206
  0,
24111
24207
  0,
24112
24208
  908,
24113
- 922,
24209
+ 940,
24114
24210
  1,
24115
24211
  0,
24116
24212
  0,
@@ -24152,7 +24248,7 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
24152
24248
  0,
24153
24249
  0,
24154
24250
  914,
24155
- 922,
24251
+ 940,
24156
24252
  1,
24157
24253
  0,
24158
24254
  0,
@@ -24194,90 +24290,234 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
24194
24290
  0,
24195
24291
  0,
24196
24292
  920,
24197
- 922,
24293
+ 940,
24198
24294
  1,
24199
24295
  0,
24200
24296
  0,
24201
24297
  0,
24202
24298
  921,
24299
+ 923,
24300
+ 3,
24301
+ 152,
24302
+ 76,
24303
+ 0,
24304
+ 922,
24305
+ 924,
24306
+ 3,
24307
+ 172,
24308
+ 86,
24309
+ 0,
24310
+ 923,
24311
+ 922,
24312
+ 1,
24313
+ 0,
24314
+ 0,
24315
+ 0,
24316
+ 924,
24317
+ 925,
24318
+ 1,
24319
+ 0,
24320
+ 0,
24321
+ 0,
24322
+ 925,
24323
+ 923,
24324
+ 1,
24325
+ 0,
24326
+ 0,
24327
+ 0,
24328
+ 925,
24329
+ 926,
24330
+ 1,
24331
+ 0,
24332
+ 0,
24333
+ 0,
24334
+ 926,
24335
+ 940,
24336
+ 1,
24337
+ 0,
24338
+ 0,
24339
+ 0,
24340
+ 927,
24341
+ 929,
24342
+ 3,
24343
+ 156,
24344
+ 78,
24345
+ 0,
24346
+ 928,
24347
+ 930,
24348
+ 3,
24349
+ 172,
24350
+ 86,
24351
+ 0,
24352
+ 929,
24353
+ 928,
24354
+ 1,
24355
+ 0,
24356
+ 0,
24357
+ 0,
24358
+ 930,
24359
+ 931,
24360
+ 1,
24361
+ 0,
24362
+ 0,
24363
+ 0,
24364
+ 931,
24365
+ 929,
24366
+ 1,
24367
+ 0,
24368
+ 0,
24369
+ 0,
24370
+ 931,
24371
+ 932,
24372
+ 1,
24373
+ 0,
24374
+ 0,
24375
+ 0,
24376
+ 932,
24377
+ 940,
24378
+ 1,
24379
+ 0,
24380
+ 0,
24381
+ 0,
24382
+ 933,
24383
+ 935,
24384
+ 3,
24385
+ 154,
24386
+ 77,
24387
+ 0,
24388
+ 934,
24389
+ 936,
24390
+ 3,
24391
+ 172,
24392
+ 86,
24393
+ 0,
24394
+ 935,
24395
+ 934,
24396
+ 1,
24397
+ 0,
24398
+ 0,
24399
+ 0,
24400
+ 936,
24401
+ 937,
24402
+ 1,
24403
+ 0,
24404
+ 0,
24405
+ 0,
24406
+ 937,
24407
+ 935,
24408
+ 1,
24409
+ 0,
24410
+ 0,
24411
+ 0,
24412
+ 937,
24413
+ 938,
24414
+ 1,
24415
+ 0,
24416
+ 0,
24417
+ 0,
24418
+ 938,
24419
+ 940,
24420
+ 1,
24421
+ 0,
24422
+ 0,
24423
+ 0,
24424
+ 939,
24203
24425
  903,
24204
24426
  1,
24205
24427
  0,
24206
24428
  0,
24207
24429
  0,
24208
- 921,
24430
+ 939,
24209
24431
  909,
24210
24432
  1,
24211
24433
  0,
24212
24434
  0,
24213
24435
  0,
24214
- 921,
24436
+ 939,
24215
24437
  915,
24216
24438
  1,
24217
24439
  0,
24218
24440
  0,
24219
24441
  0,
24220
- 922,
24442
+ 939,
24443
+ 921,
24444
+ 1,
24445
+ 0,
24446
+ 0,
24447
+ 0,
24448
+ 939,
24449
+ 927,
24450
+ 1,
24451
+ 0,
24452
+ 0,
24453
+ 0,
24454
+ 939,
24455
+ 933,
24456
+ 1,
24457
+ 0,
24458
+ 0,
24459
+ 0,
24460
+ 940,
24221
24461
  171,
24222
24462
  1,
24223
24463
  0,
24224
24464
  0,
24225
24465
  0,
24226
- 923,
24227
- 925,
24466
+ 941,
24467
+ 943,
24228
24468
  5,
24229
24469
  100,
24230
24470
  0,
24231
24471
  0,
24232
- 924,
24233
- 926,
24472
+ 942,
24473
+ 944,
24234
24474
  3,
24235
24475
  102,
24236
24476
  51,
24237
24477
  0,
24238
- 925,
24239
- 924,
24478
+ 943,
24479
+ 942,
24240
24480
  1,
24241
24481
  0,
24242
24482
  0,
24243
24483
  0,
24244
- 925,
24245
- 926,
24484
+ 943,
24485
+ 944,
24246
24486
  1,
24247
24487
  0,
24248
24488
  0,
24249
24489
  0,
24250
- 926,
24251
- 927,
24490
+ 944,
24491
+ 945,
24252
24492
  1,
24253
24493
  0,
24254
24494
  0,
24255
24495
  0,
24256
- 927,
24257
- 928,
24496
+ 945,
24497
+ 946,
24258
24498
  5,
24259
24499
  101,
24260
24500
  0,
24261
24501
  0,
24262
- 928,
24502
+ 946,
24263
24503
  173,
24264
24504
  1,
24265
24505
  0,
24266
24506
  0,
24267
24507
  0,
24268
- 929,
24269
- 930,
24508
+ 947,
24509
+ 948,
24270
24510
  7,
24271
24511
  13,
24272
24512
  0,
24273
24513
  0,
24274
- 930,
24514
+ 948,
24275
24515
  175,
24276
24516
  1,
24277
24517
  0,
24278
24518
  0,
24279
24519
  0,
24280
- 97,
24520
+ 100,
24281
24521
  178,
24282
24522
  180,
24283
24523
  186,
@@ -24373,8 +24613,11 @@ var CNextParser = class _CNextParser extends antlr2.Parser {
24373
24613
  907,
24374
24614
  913,
24375
24615
  919,
24376
- 921,
24377
- 925
24616
+ 925,
24617
+ 931,
24618
+ 937,
24619
+ 939,
24620
+ 943
24378
24621
  ];
24379
24622
  static __ATN;
24380
24623
  static get _ATN() {
@@ -27875,6 +28118,15 @@ var ArrayTypeContext = class extends antlr2.ParserRuleContext {
27875
28118
  stringType() {
27876
28119
  return this.getRuleContext(0, StringTypeContext);
27877
28120
  }
28121
+ scopedType() {
28122
+ return this.getRuleContext(0, ScopedTypeContext);
28123
+ }
28124
+ qualifiedType() {
28125
+ return this.getRuleContext(0, QualifiedTypeContext);
28126
+ }
28127
+ globalType() {
28128
+ return this.getRuleContext(0, GlobalTypeContext);
28129
+ }
27878
28130
  get ruleIndex() {
27879
28131
  return CNextParser.RULE_arrayType;
27880
28132
  }
@@ -111383,7 +111635,7 @@ var ESourceLanguage = /* @__PURE__ */ ((ESourceLanguage2) => {
111383
111635
  var ESourceLanguage_default = ESourceLanguage;
111384
111636
 
111385
111637
  // src/utils/LiteralUtils.ts
111386
- var LiteralUtils = class {
111638
+ var LiteralUtils = class _LiteralUtils {
111387
111639
  /**
111388
111640
  * Check if a literal represents zero.
111389
111641
  *
@@ -111418,8 +111670,25 @@ var LiteralUtils = class {
111418
111670
  if (ctx.SUFFIXED_BINARY()) {
111419
111671
  return text.startsWith("0b0u") || text.startsWith("0b0i") || text.startsWith("0B0u") || text.startsWith("0B0i");
111420
111672
  }
111673
+ if (ctx.FLOAT_LITERAL()) {
111674
+ return _LiteralUtils.isFloatZero(text);
111675
+ }
111421
111676
  return false;
111422
111677
  }
111678
+ /**
111679
+ * Check if a float literal string represents zero.
111680
+ * Issue #1010: Detect float zero for division-by-zero checking.
111681
+ *
111682
+ * Handles: 0.0, .0, 0., 0.0f, 0.0F, 0.0e0, 0.0E0, etc.
111683
+ *
111684
+ * @param text - The float literal text
111685
+ * @returns true if the float is zero
111686
+ */
111687
+ static isFloatZero(text) {
111688
+ const withoutSuffix = text.replace(/[fF]$/, "");
111689
+ const value = Number.parseFloat(withoutSuffix);
111690
+ return value === 0;
111691
+ }
111423
111692
  /**
111424
111693
  * Check if a literal is a floating-point number.
111425
111694
  *
@@ -111792,19 +112061,17 @@ var SymbolTable = class {
111792
112061
  /**
111793
112062
  * Register struct fields in structFields map for cross-file type resolution.
111794
112063
  * Called automatically when adding struct symbols.
112064
+ * Issue #981: Now preserves string dimensions (macro names) for proper array detection.
111795
112065
  */
111796
112066
  registerStructFields(struct) {
111797
112067
  const cName = SymbolNameUtils_default.getTranspiledCName(struct);
111798
112068
  for (const [fieldName, fieldInfo] of struct.fields) {
111799
112069
  const typeString = TypeResolver_default.getTypeName(fieldInfo.type);
111800
- const numericDims = fieldInfo.dimensions?.filter(
111801
- (d) => typeof d === "number"
111802
- );
111803
112070
  this.addStructField(
111804
112071
  cName,
111805
112072
  fieldName,
111806
112073
  typeString,
111807
- numericDims && numericDims.length > 0 ? numericDims : void 0
112074
+ fieldInfo.dimensions && fieldInfo.dimensions.length > 0 ? fieldInfo.dimensions : void 0
111808
112075
  );
111809
112076
  }
111810
112077
  }
@@ -111917,6 +112184,7 @@ var SymbolTable = class {
111917
112184
  // ========================================================================
111918
112185
  /**
111919
112186
  * Add a C symbol to the table
112187
+ * Issue #981: Also register struct fields for type resolution
111920
112188
  */
111921
112189
  addCSymbol(symbol) {
111922
112190
  const existing = this.cSymbols.get(symbol.name);
@@ -111931,6 +112199,23 @@ var SymbolTable = class {
111931
112199
  } else {
111932
112200
  this.cSymbolsByFile.set(symbol.sourceFile, [symbol]);
111933
112201
  }
112202
+ if (symbol.kind === "struct" && symbol.fields) {
112203
+ this.registerCStructFields(symbol.name, symbol.fields);
112204
+ }
112205
+ }
112206
+ /**
112207
+ * Register C struct fields in structFields map for cross-file type resolution.
112208
+ * Issue #981: Required for macro-sized array field detection on local struct variables.
112209
+ */
112210
+ registerCStructFields(structName, fields) {
112211
+ for (const [fieldName, fieldInfo] of fields) {
112212
+ this.addStructField(
112213
+ structName,
112214
+ fieldName,
112215
+ fieldInfo.type,
112216
+ fieldInfo.arrayDimensions
112217
+ );
112218
+ }
111934
112219
  }
111935
112220
  /**
111936
112221
  * Add multiple C symbols at once
@@ -112265,11 +112550,12 @@ Rename the C-Next symbol to resolve.`
112265
112550
  // Struct Field Information
112266
112551
  // ========================================================================
112267
112552
  /**
112268
- * Add struct field information
112553
+ * Add struct field information.
112554
+ * Issue #981: Accept (number | string)[] for arrayDimensions to support macro-sized arrays.
112269
112555
  * @param structName Name of the struct
112270
112556
  * @param fieldName Name of the field
112271
112557
  * @param fieldType Type of the field (e.g., "uint32_t")
112272
- * @param arrayDimensions Optional array dimensions if field is an array
112558
+ * @param arrayDimensions Optional array dimensions - numbers for resolved, strings for macros
112273
112559
  */
112274
112560
  addStructField(structName, fieldName, fieldType, arrayDimensions) {
112275
112561
  let fields = this.structFields.get(structName);
@@ -112279,7 +112565,7 @@ Rename the C-Next symbol to resolve.`
112279
112565
  }
112280
112566
  fields.set(fieldName, {
112281
112567
  type: fieldType,
112282
- arrayDimensions
112568
+ arrayDimensions: arrayDimensions ? [...arrayDimensions] : void 0
112283
112569
  });
112284
112570
  }
112285
112571
  /**
@@ -112522,12 +112808,23 @@ Rename the C-Next symbol to resolve.`
112522
112808
  * Issue #958: Check if a typedef aliases a struct type.
112523
112809
  * Used for scope variables, function parameters, and local variables
112524
112810
  * which should be pointers for C-header struct types.
112811
+ *
112812
+ * Issue #948: Performs query-time resolution - if the underlying struct
112813
+ * tag has a full body definition, this is NOT an external typedef struct
112814
+ * (it's a complete type that can use value semantics).
112815
+ *
112525
112816
  * @param typeName The type name to check
112526
112817
  * @returns true if this is a typedef'd struct type from C headers
112527
112818
  */
112528
112819
  isTypedefStructType(typeName) {
112529
- const result = this.structState.typedefStructTypes.has(typeName);
112530
- return result;
112820
+ if (!this.structState.typedefStructTypes.has(typeName)) {
112821
+ return false;
112822
+ }
112823
+ const tag = this.structState.typedefToTag.get(typeName);
112824
+ if (tag && this.structState.structTagsWithBodies.has(tag)) {
112825
+ return false;
112826
+ }
112827
+ return true;
112531
112828
  }
112532
112829
  /**
112533
112830
  * Issue #958: Get all typedef struct types for cache serialization.
@@ -112781,6 +113078,11 @@ var CodeGenState = class _CodeGenState {
112781
113078
  static indentLevel = 0;
112782
113079
  /** Whether we're inside a function body */
112783
113080
  static inFunctionBody = false;
113081
+ /** Whether we're generating the RHS of a variable declaration initializer.
113082
+ * When true, struct literals use { .field = value } instead of (Type){ .field = value }
113083
+ * because plain designated initializers are valid C99 at any scope, while compound
113084
+ * literals are not constant expressions and fail at file scope on GCC < 13. */
113085
+ static inDeclarationInit = false;
112784
113086
  /** Expected type for struct initializers and enum inference */
112785
113087
  static expectedType = null;
112786
113088
  /**
@@ -112893,6 +113195,7 @@ var CodeGenState = class _CodeGenState {
112893
113195
  this.floatShadowCurrent = /* @__PURE__ */ new Set();
112894
113196
  this.indentLevel = 0;
112895
113197
  this.inFunctionBody = false;
113198
+ this.inDeclarationInit = false;
112896
113199
  this.expectedType = null;
112897
113200
  this.suppressBareEnumResolution = false;
112898
113201
  this.mainArgsName = null;
@@ -112972,6 +113275,46 @@ var CodeGenState = class _CodeGenState {
112972
113275
  this.suppressBareEnumResolution = savedSuppress;
112973
113276
  }
112974
113277
  }
113278
+ /** Execute fn with inDeclarationInit=true, restoring prior value on exit. */
113279
+ static withDeclarationInit(fn) {
113280
+ const saved = this.inDeclarationInit;
113281
+ this.inDeclarationInit = true;
113282
+ try {
113283
+ return fn();
113284
+ } finally {
113285
+ this.inDeclarationInit = saved;
113286
+ }
113287
+ }
113288
+ /** Execute fn with inDeclarationInit=false, restoring prior value on exit.
113289
+ * Used in sub-expression contexts (function args, ternary arms) where
113290
+ * plain designated initializers are not valid C. */
113291
+ static withoutDeclarationInit(fn) {
113292
+ const saved = this.inDeclarationInit;
113293
+ this.inDeclarationInit = false;
113294
+ try {
113295
+ return fn();
113296
+ } finally {
113297
+ this.inDeclarationInit = saved;
113298
+ }
113299
+ }
113300
+ /**
113301
+ * Execute fn with expectedType=null, restoring prior value on exit.
113302
+ * Issue #1032: Used in comparison contexts (relational/equality expressions)
113303
+ * where MISRA 7.2 U suffix should NOT be applied - comparing `i32 < 0`
113304
+ * should not generate `signedIdx < 0U` which changes comparison semantics.
113305
+ */
113306
+ static withoutExpectedType(fn) {
113307
+ const savedType = this.expectedType;
113308
+ const savedSuppress = this.suppressBareEnumResolution;
113309
+ this.expectedType = null;
113310
+ this.suppressBareEnumResolution = false;
113311
+ try {
113312
+ return fn();
113313
+ } finally {
113314
+ this.expectedType = savedType;
113315
+ this.suppressBareEnumResolution = savedSuppress;
113316
+ }
113317
+ }
112975
113318
  // ===========================================================================
112976
113319
  // CONVENIENCE LOOKUP METHODS
112977
113320
  // ===========================================================================
@@ -113508,14 +113851,27 @@ var CodeGenState = class _CodeGenState {
113508
113851
  this.opaqueScopeVariables.add(qualifiedName);
113509
113852
  }
113510
113853
  /**
113511
- * Check if a scope variable has an opaque type (and is thus a pointer).
113512
- * Used during access generation to determine if & prefix is needed.
113854
+ * Check if generated code accesses an opaque scope variable (and is thus
113855
+ * already a pointer). Used during argument generation to decide whether an
113856
+ * address-of (&) prefix is needed.
113513
113857
  *
113514
- * @param qualifiedName - The fully qualified variable name (e.g., "MyScope_widget")
113515
- * @returns true if this is an opaque scope variable (already a pointer)
113858
+ * Handles two forms:
113859
+ * - Direct access: "MyScope_widget" → the handle itself (pointer)
113860
+ * - Array-element access: "MyScope_widgets[i]" → an element of an opaque
113861
+ * handle array, which is itself a pointer (Issue #996)
113862
+ *
113863
+ * @param generatedCode - The generated access expression (e.g. "UI_widgets[i]")
113864
+ * @returns true if this resolves to an opaque scope variable (already a pointer)
113516
113865
  */
113517
- static isOpaqueScopeVariable(qualifiedName) {
113518
- return this.opaqueScopeVariables.has(qualifiedName);
113866
+ static isOpaqueScopeVariableAccess(generatedCode) {
113867
+ if (this.opaqueScopeVariables.has(generatedCode)) {
113868
+ return true;
113869
+ }
113870
+ const bracketIndex = generatedCode.indexOf("[");
113871
+ if (bracketIndex === -1) {
113872
+ return false;
113873
+ }
113874
+ return this.opaqueScopeVariables.has(generatedCode.slice(0, bracketIndex));
113519
113875
  }
113520
113876
  // ===========================================================================
113521
113877
  // C++ MODE HELPERS
@@ -113675,6 +114031,22 @@ var ScopeUtils = class _ScopeUtils {
113675
114031
  return scope.name === "" && scope.parent === scope;
113676
114032
  }
113677
114033
  // ============================================================================
114034
+ // Visibility Utilities
114035
+ // ============================================================================
114036
+ /**
114037
+ * ADR-016: Get the default visibility for a scope member based on its type.
114038
+ *
114039
+ * Member-type-aware defaults reduce boilerplate:
114040
+ * - Functions: public by default (API surface)
114041
+ * - Variables/types: private by default (internal state)
114042
+ *
114043
+ * @param isFunction - Whether the member is a function declaration
114044
+ * @returns The default visibility for this member type
114045
+ */
114046
+ static getDefaultVisibility(isFunction) {
114047
+ return isFunction ? "public" : "private";
114048
+ }
114049
+ // ============================================================================
113678
114050
  // Path Utilities
113679
114051
  // ============================================================================
113680
114052
  /**
@@ -114409,41 +114781,73 @@ var TypeRegistrationEngine = class _TypeRegistrationEngine {
114409
114781
  });
114410
114782
  return true;
114411
114783
  }
114784
+ /**
114785
+ * Issue #1029: Register type info for string arrays (string<N>[M]).
114786
+ *
114787
+ * String arrays are parsed as arrayType with stringType inside:
114788
+ * arrayType -> stringType arrayTypeDimension+
114789
+ *
114790
+ * For `string<32>[4] items`:
114791
+ * - stringType gives capacity 32
114792
+ * - arrayTypeDimension gives [4]
114793
+ * - Result: char items[4][33] with dimensions [4, 33]
114794
+ */
114795
+ static _registerStringArrayType(registryName, arrayTypeCtx, arrayDim, isConst, overflowBehavior, isAtomic, callbacks) {
114796
+ const stringCtx = arrayTypeCtx.stringType();
114797
+ const intLiteral = stringCtx.INTEGER_LITERAL();
114798
+ if (!intLiteral) {
114799
+ return;
114800
+ }
114801
+ const capacity = Number.parseInt(intLiteral.getText(), 10);
114802
+ callbacks.requireInclude("string");
114803
+ const stringDim = capacity + 1;
114804
+ const arrayTypeDims = arrayTypeCtx.arrayTypeDimension().map((dim) => dim.expression()).filter((expr) => expr !== null).map((expr) => Number.parseInt(expr.getText(), 10)).filter((size) => !Number.isNaN(size));
114805
+ const additionalDims = ArrayDimensionParser_default.parseSimpleDimensions(arrayDim);
114806
+ const dimensions = [...arrayTypeDims, ...additionalDims, stringDim];
114807
+ CodeGenState.setVariableTypeInfo(registryName, {
114808
+ baseType: "char",
114809
+ bitWidth: 8,
114810
+ isArray: true,
114811
+ arrayDimensions: dimensions,
114812
+ isConst,
114813
+ isString: true,
114814
+ stringCapacity: capacity,
114815
+ overflowBehavior,
114816
+ isAtomic
114817
+ });
114818
+ }
114412
114819
  // ============================================================================
114413
114820
  // Array and standard type registration
114414
114821
  // ============================================================================
114415
114822
  static _registerArrayTypeVariable(registryName, arrayTypeCtx, arrayDim, isConst, overflowBehavior, isAtomic, callbacks) {
114416
- let baseType = "";
114417
- let bitWidth = 0;
114418
- if (arrayTypeCtx.primitiveType()) {
114419
- baseType = arrayTypeCtx.primitiveType().getText();
114420
- bitWidth = TYPE_WIDTH_default[baseType] || 0;
114421
- } else if (arrayTypeCtx.userType()) {
114422
- baseType = arrayTypeCtx.userType().getText();
114423
- const combinedArrayDim = arrayDim ?? [];
114424
- if (_TypeRegistrationEngine._tryRegisterEnumOrBitmapType(
114823
+ if (arrayTypeCtx.stringType()) {
114824
+ _TypeRegistrationEngine._registerStringArrayType(
114425
114825
  registryName,
114426
- baseType,
114826
+ arrayTypeCtx,
114827
+ arrayDim,
114427
114828
  isConst,
114428
- combinedArrayDim,
114429
114829
  overflowBehavior,
114430
114830
  isAtomic,
114431
114831
  callbacks
114432
- )) {
114433
- const existingInfo = CodeGenState.getVariableTypeInfo(registryName);
114434
- if (existingInfo) {
114435
- const arrayTypeDim = _TypeRegistrationEngine.parseArrayTypeDimension(arrayTypeCtx);
114436
- const allDims = arrayTypeDim ? [arrayTypeDim, ...existingInfo.arrayDimensions ?? []] : existingInfo.arrayDimensions;
114437
- CodeGenState.setVariableTypeInfo(registryName, {
114438
- ...existingInfo,
114439
- isArray: true,
114440
- arrayDimensions: allDims
114441
- });
114442
- }
114832
+ );
114833
+ return;
114834
+ }
114835
+ if (arrayTypeCtx.userType()) {
114836
+ const registered = _TypeRegistrationEngine._tryRegisterUserTypeArray(
114837
+ registryName,
114838
+ arrayTypeCtx,
114839
+ arrayDim,
114840
+ isConst,
114841
+ overflowBehavior,
114842
+ isAtomic,
114843
+ callbacks
114844
+ );
114845
+ if (registered) {
114443
114846
  return;
114444
114847
  }
114445
114848
  }
114446
- if (!baseType) {
114849
+ const typeInfo = _TypeRegistrationEngine._extractArrayBaseTypeInfo(arrayTypeCtx);
114850
+ if (!typeInfo.baseType) {
114447
114851
  return;
114448
114852
  }
114449
114853
  const arrayDimensions = _TypeRegistrationEngine._collectArrayDimensions(
@@ -114452,8 +114856,8 @@ var TypeRegistrationEngine = class _TypeRegistrationEngine {
114452
114856
  callbacks
114453
114857
  );
114454
114858
  CodeGenState.setVariableTypeInfo(registryName, {
114455
- baseType,
114456
- bitWidth,
114859
+ baseType: typeInfo.baseType,
114860
+ bitWidth: typeInfo.bitWidth,
114457
114861
  isArray: true,
114458
114862
  arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : void 0,
114459
114863
  isConst,
@@ -114461,6 +114865,64 @@ var TypeRegistrationEngine = class _TypeRegistrationEngine {
114461
114865
  isAtomic
114462
114866
  });
114463
114867
  }
114868
+ /**
114869
+ * Extract base type and bit width from an array type context.
114870
+ * Handles primitive, qualified, scoped, and user types.
114871
+ */
114872
+ static _extractArrayBaseTypeInfo(arrayTypeCtx) {
114873
+ if (arrayTypeCtx.primitiveType()) {
114874
+ const baseType = arrayTypeCtx.primitiveType().getText();
114875
+ return { baseType, bitWidth: TYPE_WIDTH_default[baseType] || 0 };
114876
+ }
114877
+ if (arrayTypeCtx.qualifiedType()) {
114878
+ const parts = arrayTypeCtx.qualifiedType().IDENTIFIER();
114879
+ return { baseType: parts.map((p) => p.getText()).join("_"), bitWidth: 0 };
114880
+ }
114881
+ if (arrayTypeCtx.scopedType()) {
114882
+ const typeName = arrayTypeCtx.scopedType().IDENTIFIER().getText();
114883
+ const baseType = CodeGenState.currentScope ? `${CodeGenState.currentScope}_${typeName}` : typeName;
114884
+ return { baseType, bitWidth: 0 };
114885
+ }
114886
+ if (arrayTypeCtx.globalType()) {
114887
+ const typeName = arrayTypeCtx.globalType().IDENTIFIER().getText();
114888
+ return { baseType: typeName, bitWidth: 0 };
114889
+ }
114890
+ if (arrayTypeCtx.userType()) {
114891
+ return { baseType: arrayTypeCtx.userType().getText(), bitWidth: 0 };
114892
+ }
114893
+ return { baseType: "", bitWidth: 0 };
114894
+ }
114895
+ /**
114896
+ * Try to register a user type array as enum or bitmap.
114897
+ * Returns true if registration was handled, false if it should fall through.
114898
+ */
114899
+ static _tryRegisterUserTypeArray(registryName, arrayTypeCtx, arrayDim, isConst, overflowBehavior, isAtomic, callbacks) {
114900
+ const baseType = arrayTypeCtx.userType().getText();
114901
+ const combinedArrayDim = arrayDim ?? [];
114902
+ const registered = _TypeRegistrationEngine._tryRegisterEnumOrBitmapType(
114903
+ registryName,
114904
+ baseType,
114905
+ isConst,
114906
+ combinedArrayDim,
114907
+ overflowBehavior,
114908
+ isAtomic,
114909
+ callbacks
114910
+ );
114911
+ if (!registered) {
114912
+ return false;
114913
+ }
114914
+ const existingInfo = CodeGenState.getVariableTypeInfo(registryName);
114915
+ if (existingInfo) {
114916
+ const arrayTypeDim = _TypeRegistrationEngine.parseArrayTypeDimension(arrayTypeCtx);
114917
+ const allDims = arrayTypeDim ? [arrayTypeDim, ...existingInfo.arrayDimensions ?? []] : existingInfo.arrayDimensions;
114918
+ CodeGenState.setVariableTypeInfo(registryName, {
114919
+ ...existingInfo,
114920
+ isArray: true,
114921
+ arrayDimensions: allDims
114922
+ });
114923
+ }
114924
+ return true;
114925
+ }
114464
114926
  static _collectArrayDimensions(arrayTypeCtx, arrayDim, callbacks) {
114465
114927
  const arrayDimensions = [];
114466
114928
  for (const dim of arrayTypeCtx.arrayTypeDimension()) {
@@ -116956,18 +117418,10 @@ var generateEqualityExpr = (node, input, state, orchestrator) => {
116956
117418
  const rightIsString = orchestrator.isStringExpression(exprs[1]);
116957
117419
  if (leftIsString || rightIsString) {
116958
117420
  effects.push({ type: "include", header: "string" });
116959
- const leftResult = generateRelationalExpr(
116960
- exprs[0],
116961
- input,
116962
- state,
116963
- orchestrator
116964
- );
116965
- const rightResult = generateRelationalExpr(
116966
- exprs[1],
116967
- input,
116968
- state,
116969
- orchestrator
116970
- );
117421
+ const [leftResult, rightResult] = CodeGenState.withoutExpectedType(() => [
117422
+ generateRelationalExpr(exprs[0], input, state, orchestrator),
117423
+ generateRelationalExpr(exprs[1], input, state, orchestrator)
117424
+ ]);
116971
117425
  effects.push(...leftResult.effects, ...rightResult.effects);
116972
117426
  const fullText = node.getText();
116973
117427
  const isNotEqual = fullText.includes("!=");
@@ -116982,13 +117436,15 @@ var generateEqualityExpr = (node, input, state, orchestrator) => {
116982
117436
  }
116983
117437
  }
116984
117438
  const operators = orchestrator.getOperatorsFromChildren(node);
116985
- return accumulateBinaryExprs(
116986
- exprs,
116987
- operators,
116988
- "=",
116989
- generateRelationalExpr,
116990
- { input, state, orchestrator },
116991
- BinaryExprUtils_default.mapEqualityOperator
117439
+ return CodeGenState.withoutExpectedType(
117440
+ () => accumulateBinaryExprs(
117441
+ exprs,
117442
+ operators,
117443
+ "=",
117444
+ generateRelationalExpr,
117445
+ { input, state, orchestrator },
117446
+ BinaryExprUtils_default.mapEqualityOperator
117447
+ )
116992
117448
  );
116993
117449
  };
116994
117450
  var generateRelationalExpr = (node, input, state, orchestrator) => {
@@ -116997,11 +117453,13 @@ var generateRelationalExpr = (node, input, state, orchestrator) => {
116997
117453
  return generateBitwiseOrExpr(exprs[0], input, state, orchestrator);
116998
117454
  }
116999
117455
  const operators = orchestrator.getOperatorsFromChildren(node);
117000
- return accumulateBinaryExprs(exprs, operators, "<", generateBitwiseOrExpr, {
117001
- input,
117002
- state,
117003
- orchestrator
117004
- });
117456
+ return CodeGenState.withoutExpectedType(
117457
+ () => accumulateBinaryExprs(exprs, operators, "<", generateBitwiseOrExpr, {
117458
+ input,
117459
+ state,
117460
+ orchestrator
117461
+ })
117462
+ );
117005
117463
  };
117006
117464
  var generateBitwiseOrExpr = (node, input, state, orchestrator) => {
117007
117465
  const effects = [];
@@ -117191,8 +117649,12 @@ var generateTernaryExpr = (node, _input, _state, orchestrator) => {
117191
117649
  orchestrator.validateNoNestedTernary(falseExpr, "false branch");
117192
117650
  orchestrator.validateTernaryConditionNoFunctionCall(condition);
117193
117651
  const condCode = orchestrator.generateOrExpr(condition);
117194
- const trueCode = orchestrator.generateOrExpr(trueExpr);
117195
- const falseCode = orchestrator.generateOrExpr(falseExpr);
117652
+ const trueCode = CodeGenState.withoutDeclarationInit(
117653
+ () => orchestrator.generateOrExpr(trueExpr)
117654
+ );
117655
+ const falseCode = CodeGenState.withoutDeclarationInit(
117656
+ () => orchestrator.generateOrExpr(falseExpr)
117657
+ );
117196
117658
  return { code: `(${condCode}) ? ${trueCode} : ${falseCode}`, effects };
117197
117659
  };
117198
117660
  var expressionGenerators = {
@@ -117403,7 +117865,7 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
117403
117865
  if (typeInfo?.isPointer) {
117404
117866
  isPointerVariable = true;
117405
117867
  }
117406
- const isOpaqueScopeVar = CodeGenState.isOpaqueScopeVariable(argCode);
117868
+ const isOpaqueScopeVar = CodeGenState.isOpaqueScopeVariableAccess(argCode);
117407
117869
  const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && !isOpaqueScopeVar && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
117408
117870
  const finalArgCode = needsAddressOf ? `&${argCode}` : argCode;
117409
117871
  return wrapWithCppEnumCast(
@@ -117440,39 +117902,41 @@ var generateFunctionCall = (funcExpr, argCtx, input, _state, orchestrator) => {
117440
117902
  trackPassThroughModifications(funcExpr, argExprs, orchestrator);
117441
117903
  }
117442
117904
  const sig = input.functionSignatures.get(funcExpr);
117443
- const args = argExprs.map((e, idx) => {
117444
- const resolved = CallExprUtils_default.resolveTargetParam(
117445
- sig,
117446
- idx,
117447
- funcExpr,
117448
- input.symbolTable
117449
- );
117450
- const targetParam = resolved.param;
117451
- if (!isCNextFunc) {
117452
- return _generateCFunctionArg(e, targetParam, input, orchestrator);
117453
- }
117454
- if (_shouldPassByValue(
117455
- funcExpr,
117456
- idx,
117457
- targetParam,
117458
- resolved.isCrossFile,
117459
- orchestrator
117460
- )) {
117461
- const argCode = CodeGenState.withExpectedType(
117462
- targetParam?.baseType,
117463
- () => orchestrator.generateExpression(e),
117464
- true
117465
- // suppressEnumResolution
117905
+ const args = CodeGenState.withoutDeclarationInit(
117906
+ () => argExprs.map((e, idx) => {
117907
+ const resolved = CallExprUtils_default.resolveTargetParam(
117908
+ sig,
117909
+ idx,
117910
+ funcExpr,
117911
+ input.symbolTable
117466
117912
  );
117467
- return wrapWithCppEnumCast(
117468
- argCode,
117469
- e,
117470
- targetParam?.baseType,
117913
+ const targetParam = resolved.param;
117914
+ if (!isCNextFunc) {
117915
+ return _generateCFunctionArg(e, targetParam, input, orchestrator);
117916
+ }
117917
+ if (_shouldPassByValue(
117918
+ funcExpr,
117919
+ idx,
117920
+ targetParam,
117921
+ resolved.isCrossFile,
117471
117922
  orchestrator
117472
- );
117473
- }
117474
- return orchestrator.generateFunctionArg(e, targetParam?.baseType);
117475
- }).join(", ");
117923
+ )) {
117924
+ const argCode = CodeGenState.withExpectedType(
117925
+ targetParam?.baseType,
117926
+ () => orchestrator.generateExpression(e),
117927
+ true
117928
+ // suppressEnumResolution
117929
+ );
117930
+ return wrapWithCppEnumCast(
117931
+ argCode,
117932
+ e,
117933
+ targetParam?.baseType,
117934
+ orchestrator
117935
+ );
117936
+ }
117937
+ return orchestrator.generateFunctionArg(e, targetParam?.baseType);
117938
+ }).join(", ")
117939
+ );
117476
117940
  return { code: `${funcExpr}(${args})`, effects };
117477
117941
  };
117478
117942
  var generateSafeDivMod = (funcName, argExprs, input, orchestrator, effects) => {
@@ -119915,7 +120379,9 @@ function generateInitializer(varDecl, isArray, orchestrator) {
119915
120379
  const typeName = orchestrator.generateType(varDecl.type());
119916
120380
  return CodeGenState.withExpectedType(
119917
120381
  typeName,
119918
- () => ` = ${orchestrator.generateExpression(varDecl.expression())}`
120382
+ () => CodeGenState.withDeclarationInit(
120383
+ () => ` = ${orchestrator.generateExpression(varDecl.expression())}`
120384
+ )
119919
120385
  );
119920
120386
  }
119921
120387
  return ` = ${orchestrator.getZeroInitializer(varDecl.type(), isArray)}`;
@@ -119993,9 +120459,19 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
119993
120459
  type = `${type}*`;
119994
120460
  orchestrator.markOpaqueScopeVariable(fullName);
119995
120461
  }
120462
+ const modifiers = VariableModifierBuilder_default.build(
120463
+ varDecl,
120464
+ false,
120465
+ // inFunctionBody - scope vars are file scope
120466
+ false,
120467
+ // hasInitializer - doesn't affect volatile/atomic handling
120468
+ false
120469
+ // cppMode - doesn't affect volatile/atomic handling
120470
+ );
120471
+ const staticPrefix = isPrivate ? "static " : "";
120472
+ const volatilePrefix = modifiers.atomic || modifiers.volatile;
119996
120473
  const constPrefix = isConst ? "const " : "";
119997
- const prefix = isPrivate ? "static " : "";
119998
- let decl = `${prefix}${constPrefix}${type} ${fullName}`;
120474
+ let decl = `${staticPrefix}${volatilePrefix}${constPrefix}${type} ${fullName}`;
119999
120475
  decl += ArrayDimensionUtils_default.generateArrayTypeDimension(
120000
120476
  arrayTypeCtx,
120001
120477
  orchestrator
@@ -120004,7 +120480,7 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
120004
120480
  decl += orchestrator.generateArrayDimensions(arrayDims);
120005
120481
  }
120006
120482
  decl += ArrayDimensionUtils_default.generateStringCapacityDim(varDecl.type());
120007
- if (isOpaque || isExternalStruct) {
120483
+ if ((isOpaque || isExternalStruct) && !isArray) {
120008
120484
  decl += " = NULL";
120009
120485
  } else {
120010
120486
  decl += generateInitializer(varDecl, isArray, orchestrator);
@@ -120061,7 +120537,9 @@ function generateEnumMembersFromAST(members, fullName, orchestrator) {
120061
120537
  return lines;
120062
120538
  }
120063
120539
  function processScopeMember(member, scopeName, input, state, orchestrator) {
120064
- const visibility = member.visibilityModifier()?.getText() || "private";
120540
+ const explicitVisibility = member.visibilityModifier()?.getText();
120541
+ const isFunction = member.functionDeclaration() !== null;
120542
+ const visibility = explicitVisibility ?? ScopeUtils_default.getDefaultVisibility(isFunction);
120065
120543
  const isPrivate = visibility === "private";
120066
120544
  if (member.variableDeclaration()) {
120067
120545
  const varDecl = member.variableDeclaration();
@@ -125837,19 +126315,6 @@ var SymbolLookupHelper = class _SymbolLookupHelper {
125837
126315
  const symbols = symbolTable.getOverloads(name);
125838
126316
  return symbols.some((sym) => sym.kind === "namespace");
125839
126317
  }
125840
- /**
125841
- * Check if a type name is from a C++ header.
125842
- * Issue #304: Used to determine whether to use {} or {0} for initialization.
125843
- * C++ types with constructors may fail with {0} but work with {}.
125844
- */
125845
- static isCppType(symbolTable, typeName) {
125846
- if (!symbolTable) return false;
125847
- const symbols = symbolTable.getOverloads(typeName);
125848
- const cppTypeKinds = /* @__PURE__ */ new Set(["struct", "class", "type"]);
125849
- return symbols.some(
125850
- (sym) => sym.sourceLanguage === ESourceLanguage_default.Cpp && cppTypeKinds.has(sym.kind)
125851
- );
125852
- }
125853
126318
  /**
125854
126319
  * Check if a function is a C-Next function (uses pass-by-reference semantics).
125855
126320
  * Returns true if the function is found in symbol table as C-Next.
@@ -126189,6 +126654,18 @@ var StringDeclHelper = class _StringDeclHelper {
126189
126654
  * Returns { handled: false } if not a string type.
126190
126655
  */
126191
126656
  static generateStringDecl(typeCtx, name, expression, arrayDims, modifiers, isConst, callbacks) {
126657
+ const arrayTypeCtx = typeCtx.arrayType?.();
126658
+ if (arrayTypeCtx?.stringType?.()) {
126659
+ return _StringDeclHelper._generateStringArrayFromArrayType(
126660
+ name,
126661
+ arrayTypeCtx,
126662
+ expression,
126663
+ arrayDims,
126664
+ modifiers,
126665
+ isConst,
126666
+ callbacks
126667
+ );
126668
+ }
126192
126669
  const stringCtx = typeCtx.stringType();
126193
126670
  if (!stringCtx) {
126194
126671
  return { code: "", handled: false };
@@ -126215,6 +126692,122 @@ var StringDeclHelper = class _StringDeclHelper {
126215
126692
  );
126216
126693
  }
126217
126694
  }
126695
+ /**
126696
+ * Issue #1029: Generate string array declaration from arrayType syntax.
126697
+ * Handles: string<32>[4] items -> char items[4][33] = {0};
126698
+ */
126699
+ static _generateStringArrayFromArrayType(name, arrayTypeCtx, expression, trailingArrayDims, modifiers, isConst, callbacks) {
126700
+ const stringCtx = arrayTypeCtx.stringType();
126701
+ const intLiteral = stringCtx.INTEGER_LITERAL();
126702
+ if (!intLiteral) {
126703
+ throw new Error(
126704
+ "Error: String arrays require explicit capacity, e.g., string<64>[4]"
126705
+ );
126706
+ }
126707
+ const capacity = Number.parseInt(intLiteral.getText(), 10);
126708
+ callbacks.requireStringInclude();
126709
+ const {
126710
+ extern,
126711
+ const: constMod,
126712
+ atomic,
126713
+ volatile: volatileMod
126714
+ } = modifiers;
126715
+ let arrayDimStr = "";
126716
+ for (const dim of arrayTypeCtx.arrayTypeDimension()) {
126717
+ const sizeExpr = dim.expression();
126718
+ if (sizeExpr) {
126719
+ arrayDimStr += `[${sizeExpr.getText()}]`;
126720
+ } else {
126721
+ arrayDimStr += "[]";
126722
+ }
126723
+ }
126724
+ arrayDimStr += callbacks.generateArrayDimensions(trailingArrayDims);
126725
+ arrayDimStr += `[${capacity + 1}]`;
126726
+ let decl = `${extern}${constMod}${atomic}${volatileMod}char ${name}${arrayDimStr}`;
126727
+ CodeGenState.localArrays.add(name);
126728
+ if (!expression) {
126729
+ return { code: `${decl} = {0};`, handled: true };
126730
+ }
126731
+ CodeGenState.lastArrayInitCount = 0;
126732
+ CodeGenState.lastArrayFillValue = void 0;
126733
+ const initValue = callbacks.generateExpression(expression);
126734
+ const isArrayInit = CodeGenState.lastArrayInitCount > 0 || CodeGenState.lastArrayFillValue !== void 0;
126735
+ if (!isArrayInit) {
126736
+ throw new Error(
126737
+ `Error: String array initialization from variables not supported`
126738
+ );
126739
+ }
126740
+ const declaredSize = _StringDeclHelper._getArrayTypeDeclaredSize(arrayTypeCtx);
126741
+ if (declaredSize !== null) {
126742
+ const isFillAll = CodeGenState.lastArrayFillValue !== void 0;
126743
+ const elementCount = CodeGenState.lastArrayInitCount;
126744
+ if (!isFillAll && elementCount !== declaredSize) {
126745
+ throw new Error(
126746
+ `Error: Array size mismatch - declared [${declaredSize}] but got ${elementCount} elements`
126747
+ );
126748
+ }
126749
+ }
126750
+ const finalInitValue = _StringDeclHelper._expandFillAllForArrayType(
126751
+ initValue,
126752
+ arrayTypeCtx
126753
+ );
126754
+ const suppression = "// cppcheck-suppress misra-c2012-9.3\n// cppcheck-suppress misra-c2012-9.4\n";
126755
+ return {
126756
+ code: `${suppression}${decl} = ${finalInitValue};`,
126757
+ handled: true
126758
+ };
126759
+ }
126760
+ /**
126761
+ * Get the numeric size from the first arrayTypeDimension, or null if not numeric.
126762
+ * Used by arrayType-based string arrays (string<N>[M]).
126763
+ */
126764
+ static _getArrayTypeDeclaredSize(arrayTypeCtx) {
126765
+ const dims = arrayTypeCtx.arrayTypeDimension();
126766
+ if (dims.length === 0) {
126767
+ return null;
126768
+ }
126769
+ const firstDimExpr = dims[0].expression();
126770
+ return _StringDeclHelper._parseNumericSize(firstDimExpr);
126771
+ }
126772
+ /**
126773
+ * Expand fill-all syntax for arrayType-based string arrays.
126774
+ * Delegates to the common fill-all expansion logic with size from arrayType.
126775
+ */
126776
+ static _expandFillAllForArrayType(initValue, arrayTypeCtx) {
126777
+ const declaredSize = _StringDeclHelper._getArrayTypeDeclaredSize(arrayTypeCtx);
126778
+ return _StringDeclHelper._expandFillAll(initValue, declaredSize);
126779
+ }
126780
+ /**
126781
+ * Common fill-all expansion logic shared between arrayType and arrayDimension paths.
126782
+ */
126783
+ static _expandFillAll(initValue, declaredSize) {
126784
+ const fillVal = CodeGenState.lastArrayFillValue;
126785
+ if (fillVal === void 0) {
126786
+ return initValue;
126787
+ }
126788
+ if (fillVal === '""') {
126789
+ return initValue;
126790
+ }
126791
+ if (declaredSize === null) {
126792
+ return initValue;
126793
+ }
126794
+ const elements = new Array(declaredSize).fill(fillVal);
126795
+ return `{${elements.join(", ")}}`;
126796
+ }
126797
+ /**
126798
+ * Parse a numeric size from an expression, or return null if not numeric.
126799
+ * Shared helper to eliminate duplicate parsing logic.
126800
+ */
126801
+ static _parseNumericSize(expr) {
126802
+ if (!expr) {
126803
+ return null;
126804
+ }
126805
+ const sizeText = expr.getText();
126806
+ if (!/^\d+$/.exec(sizeText)) {
126807
+ return null;
126808
+ }
126809
+ return Number.parseInt(sizeText, 10);
126810
+ }
126218
126811
  /**
126219
126812
  * Generate bounded string declaration (string<N>).
126220
126813
  */
@@ -126268,16 +126861,33 @@ var StringDeclHelper = class _StringDeclHelper {
126268
126861
  constMod
126269
126862
  );
126270
126863
  }
126271
- _StringDeclHelper._validateStringInit(
126272
- expression.getText(),
126864
+ const exprText = expression.getText();
126865
+ const isLiteral = _StringDeclHelper._validateStringInit(
126866
+ exprText,
126273
126867
  capacity,
126274
126868
  callbacks
126275
126869
  );
126276
- const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${callbacks.generateExpression(expression)};`;
126277
- return { code, handled: true };
126870
+ if (isLiteral) {
126871
+ const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${callbacks.generateExpression(expression)};`;
126872
+ return { code, handled: true };
126873
+ }
126874
+ if (!CodeGenState.inFunctionBody) {
126875
+ throw new Error(
126876
+ `Error: String initialization from variable cannot be used at global scope. Move the declaration inside a function, or use an empty initializer and assign later.`
126877
+ );
126878
+ }
126879
+ const srcExpr = callbacks.generateExpression(expression);
126880
+ const indent = FormatUtils_default.indent(CodeGenState.indentLevel);
126881
+ const lines = [];
126882
+ lines.push(
126883
+ `${constMod}char ${name}[${capacity + 1}] = "";`,
126884
+ `${indent}strcpy(${name}, ${srcExpr});`
126885
+ );
126886
+ return { code: lines.join("\n"), handled: true };
126278
126887
  }
126279
126888
  /**
126280
126889
  * Validate string initialization (literal length and variable capacity)
126890
+ * Returns true if the expression is a string literal, false if it's a variable.
126281
126891
  */
126282
126892
  static _validateStringInit(exprText, capacity, callbacks) {
126283
126893
  if (exprText.startsWith('"') && exprText.endsWith('"')) {
@@ -126287,6 +126897,7 @@ var StringDeclHelper = class _StringDeclHelper {
126287
126897
  `Error: String literal (${content} chars) exceeds string<${capacity}> capacity`
126288
126898
  );
126289
126899
  }
126900
+ return true;
126290
126901
  }
126291
126902
  const srcCapacity = callbacks.getStringExprCapacity(exprText);
126292
126903
  if (srcCapacity !== null && srcCapacity > capacity) {
@@ -126294,6 +126905,7 @@ var StringDeclHelper = class _StringDeclHelper {
126294
126905
  `Error: Cannot assign string<${srcCapacity}> to string<${capacity}> (potential truncation)`
126295
126906
  );
126296
126907
  }
126908
+ return false;
126297
126909
  }
126298
126910
  /**
126299
126911
  * Generate string array declaration.
@@ -126381,35 +126993,19 @@ var StringDeclHelper = class _StringDeclHelper {
126381
126993
  /**
126382
126994
  * Expand fill-all syntax if needed.
126383
126995
  * ["Hello"*] with size 3 -> {"Hello", "Hello", "Hello"}
126996
+ * Delegates to the common fill-all expansion logic with size from arrayDimension.
126384
126997
  */
126385
126998
  static _expandFillAllIfNeeded(initValue, arrayDims) {
126386
- const fillVal = CodeGenState.lastArrayFillValue;
126387
- if (fillVal === void 0) {
126388
- return initValue;
126389
- }
126390
- if (fillVal === '""') {
126391
- return initValue;
126392
- }
126393
126999
  const declaredSize = _StringDeclHelper._getFirstDimNumericSize(arrayDims);
126394
- if (declaredSize === null) {
126395
- return initValue;
126396
- }
126397
- const elements = new Array(declaredSize).fill(fillVal);
126398
- return `{${elements.join(", ")}}`;
127000
+ return _StringDeclHelper._expandFillAll(initValue, declaredSize);
126399
127001
  }
126400
127002
  /**
126401
127003
  * Get the numeric size from the first array dimension, or null if not numeric.
127004
+ * Used by arrayDimension-based string arrays (string<N> arr[M]).
126402
127005
  */
126403
127006
  static _getFirstDimNumericSize(arrayDims) {
126404
127007
  const firstDimExpr = arrayDims[0]?.expression();
126405
- if (!firstDimExpr) {
126406
- return null;
126407
- }
126408
- const sizeText = firstDimExpr.getText();
126409
- if (!/^\d+$/.exec(sizeText)) {
126410
- return null;
126411
- }
126412
- return Number.parseInt(sizeText, 10);
127008
+ return _StringDeclHelper._parseNumericSize(firstDimExpr);
126413
127009
  }
126414
127010
  /**
126415
127011
  * Generate string concatenation declaration.
@@ -126603,24 +127199,14 @@ var VariableDeclHelper = class _VariableDeclHelper {
126603
127199
  if (arrayDims.length === 0) {
126604
127200
  return;
126605
127201
  }
126606
- if (typeCtx.arrayType()) {
126607
- return;
126608
- }
126609
- if (arrayDims.length === 1 && !arrayDims[0].expression()) {
126610
- return;
126611
- }
126612
- if (arrayDims.length > 1) {
126613
- return;
126614
- }
126615
- if (typeCtx.qualifiedType() || typeCtx.scopedType() || typeCtx.globalType() || typeCtx.stringType()) {
126616
- return;
126617
- }
126618
127202
  const baseType = _VariableDeclHelper.extractBaseTypeName(typeCtx);
126619
- const dimensions = arrayDims.map((dim) => `[${dim.expression()?.getText() ?? ""}]`).join("");
127203
+ const existingDims = typeCtx.arrayType() ? typeCtx.arrayType().arrayTypeDimension().map((d) => `[${d.expression()?.getText() ?? ""}]`).join("") : "";
127204
+ const trailingDims = arrayDims.map((dim) => `[${dim.expression()?.getText() ?? ""}]`).join("");
127205
+ const allDims = existingDims + trailingDims;
126620
127206
  const line = ctx.start?.line ?? 0;
126621
127207
  const col = ctx.start?.column ?? 0;
126622
127208
  throw new Error(
126623
- `${line}:${col} C-style array declaration is not allowed. Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`
127209
+ `${line}:${col} C-style array declaration is not allowed. Use '${baseType}${allDims} ${name}' instead of '${baseType}${existingDims} ${name}${trailingDims}'`
126624
127210
  );
126625
127211
  }
126626
127212
  /**
@@ -126727,7 +127313,8 @@ ${assignments}`;
126727
127313
  typeCtx,
126728
127314
  callbacks
126729
127315
  );
126730
- const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
127316
+ const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression()) || (typeCtx.arrayType()?.arrayTypeDimension().some((dim) => !dim.expression()) ?? false);
127317
+ const hasEmptyArrayTypeDim = typeCtx.arrayType()?.arrayTypeDimension().some((dim) => !dim.expression()) ?? false;
126731
127318
  const declaredSize = _VariableDeclHelper.parseArrayTypeDimension(typeCtx) ?? _VariableDeclHelper.parseFirstArrayDimension(arrayDims);
126732
127319
  if (ctx.expression()) {
126733
127320
  const arrayInitResult = ArrayInitHelper_default.processArrayInit(
@@ -126745,7 +127332,7 @@ ${assignments}`;
126745
127332
  );
126746
127333
  if (arrayInitResult) {
126747
127334
  CodeGenState.localArrays.add(name);
126748
- const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
127335
+ const fullDimSuffix = hasEmptyArrayTypeDim ? arrayInitResult.dimensionSuffix : arrayTypeDimStr + arrayInitResult.dimensionSuffix;
126749
127336
  return {
126750
127337
  handled: true,
126751
127338
  code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
@@ -126780,7 +127367,9 @@ ${assignments}`;
126780
127367
  getExpressionType: callbacks.getExpressionType
126781
127368
  });
126782
127369
  return CodeGenState.withExpectedType(typeName, () => {
126783
- let exprCode = callbacks.generateExpression(ctx.expression());
127370
+ let exprCode = CodeGenState.withDeclarationInit(
127371
+ () => callbacks.generateExpression(ctx.expression())
127372
+ );
126784
127373
  const exprType = callbacks.getExpressionType(ctx.expression());
126785
127374
  if (exprType && NarrowingCastHelper_default.isCrossTypeCategoryConversion(exprType, typeName)) {
126786
127375
  if (NarrowingCastHelper_default.isIntegerType(exprType) && NarrowingCastHelper_default.isFloatType(typeName)) {
@@ -127568,31 +128157,29 @@ var TypeGenerationHelper = class _TypeGenerationHelper {
127568
128157
  return "char";
127569
128158
  }
127570
128159
  /**
127571
- * Full type generation using all dependencies.
127572
- * This is the main entry point that handles all type contexts.
128160
+ * Dispatch type generation for contexts that share common type accessors.
128161
+ * Handles scoped, qualified, global, primitive, string, and user types.
128162
+ * Used by both bare type contexts and array element type contexts.
128163
+ *
128164
+ * @returns The resolved C type string, or null if no matching type accessor found
127573
128165
  */
127574
- static generate(ctx, deps) {
127575
- if (ctx.primitiveType()) {
127576
- const type = ctx.primitiveType().getText();
127577
- const result = _TypeGenerationHelper.generatePrimitiveType(type);
127578
- return result.cType;
127579
- }
127580
- if (ctx.stringType()) {
128166
+ static dispatchTypeGeneration(accessors, deps) {
128167
+ if (accessors.stringType()) {
127581
128168
  return _TypeGenerationHelper.generateStringType();
127582
128169
  }
127583
- if (ctx.scopedType()) {
127584
- const typeName = ctx.scopedType().IDENTIFIER().getText();
128170
+ if (accessors.scopedType()) {
128171
+ const typeName = accessors.scopedType().IDENTIFIER().getText();
127585
128172
  return _TypeGenerationHelper.generateScopedType(
127586
128173
  typeName,
127587
128174
  deps.currentScope
127588
128175
  );
127589
128176
  }
127590
- if (ctx.globalType()) {
127591
- const typeName = ctx.globalType().IDENTIFIER().getText();
128177
+ if (accessors.globalType()) {
128178
+ const typeName = accessors.globalType().IDENTIFIER().getText();
127592
128179
  return _TypeGenerationHelper.generateGlobalType(typeName);
127593
128180
  }
127594
- if (ctx.qualifiedType()) {
127595
- const identifiers = ctx.qualifiedType().IDENTIFIER();
128181
+ if (accessors.qualifiedType()) {
128182
+ const identifiers = accessors.qualifiedType().IDENTIFIER();
127596
128183
  const identifierNames = identifiers.map((id) => id.getText());
127597
128184
  const isCpp = deps.isCppScopeSymbol(identifierNames[0]);
127598
128185
  return _TypeGenerationHelper.generateQualifiedType(
@@ -127601,24 +128188,36 @@ var TypeGenerationHelper = class _TypeGenerationHelper {
127601
128188
  deps.validateCrossScopeVisibility
127602
128189
  );
127603
128190
  }
127604
- if (ctx.userType()) {
127605
- const typeName = ctx.userType().getText();
128191
+ if (accessors.primitiveType()) {
128192
+ const type = accessors.primitiveType().getText();
128193
+ return TYPE_MAP_default[type] || type;
128194
+ }
128195
+ if (accessors.userType()) {
128196
+ const typeName = accessors.userType().getText();
128197
+ if (typeName === "cstring") {
128198
+ return "char*";
128199
+ }
127606
128200
  const needsStruct = deps.checkNeedsStructKeyword(typeName);
127607
128201
  return _TypeGenerationHelper.generateUserType(typeName, needsStruct);
127608
128202
  }
128203
+ return null;
128204
+ }
128205
+ /**
128206
+ * Full type generation using all dependencies.
128207
+ * This is the main entry point that handles all type contexts.
128208
+ */
128209
+ static generate(ctx, deps) {
127609
128210
  if (ctx.arrayType()) {
127610
128211
  const arrCtx = ctx.arrayType();
127611
- if (arrCtx.stringType()) {
127612
- return "char";
127613
- }
127614
- const primitiveText = arrCtx.primitiveType()?.getText() ?? null;
127615
- const userTypeName = arrCtx.userType()?.getText() ?? null;
127616
- const needsStruct = userTypeName ? deps.checkNeedsStructKeyword(userTypeName) : false;
127617
- return _TypeGenerationHelper.generateArrayBaseType(
127618
- primitiveText,
127619
- userTypeName,
127620
- needsStruct
127621
- );
128212
+ const result2 = _TypeGenerationHelper.dispatchTypeGeneration(arrCtx, deps);
128213
+ if (result2 !== null) {
128214
+ return result2;
128215
+ }
128216
+ return ctx.getText();
128217
+ }
128218
+ const result = _TypeGenerationHelper.dispatchTypeGeneration(ctx, deps);
128219
+ if (result !== null) {
128220
+ return result;
127622
128221
  }
127623
128222
  if (ctx.getText() === "void") {
127624
128223
  return "void";
@@ -128979,6 +129578,7 @@ var ParameterInputAdapter = class {
128979
129578
  const isKnownStruct = deps.isKnownStruct(typeName);
128980
129579
  const isKnownPrimitive = !!deps.typeMap[typeName];
128981
129580
  const isTypedefStruct = deps.isTypedefStructType(typeName);
129581
+ const isOpaque = deps.isOpaqueType?.(typeName) ?? false;
128982
129582
  const isAutoConst = !deps.isCallbackCompatible && !deps.isModified && !isConst;
128983
129583
  const isPassByReference = deps.forcePassByReference || isKnownStruct || isKnownPrimitive || isTypedefStruct;
128984
129584
  return {
@@ -128996,7 +129596,9 @@ var ParameterInputAdapter = class {
128996
129596
  // and typedef struct params (C types expect pointers, not C++ references)
128997
129597
  forcePointerSyntax: deps.forcePassByReference || isTypedefStruct || void 0,
128998
129598
  // Issue #895: Preserve const from callback typedef signature
128999
- forceConst: deps.forceConst
129599
+ forceConst: deps.forceConst,
129600
+ // Issue #995: Pass through opaque handle detection — rule applied in builder
129601
+ isOpaqueHandle: isOpaque || void 0
129000
129602
  };
129001
129603
  }
129002
129604
  /**
@@ -129043,7 +129645,9 @@ var ParameterInputAdapter = class {
129043
129645
  isPassByValue: isCallbackPointer ? false : deps.isPassByValue,
129044
129646
  isPassByReference: isCallbackPointer ? true : !deps.isPassByValue,
129045
129647
  forcePointerSyntax: isCallbackPointer || void 0,
129046
- forceConst: param.isCallbackConst || void 0
129648
+ forceConst: param.isCallbackConst || void 0,
129649
+ // Issue #995: Pass through opaque handle detection — rule applied in builder
129650
+ isOpaqueHandle: param.isOpaqueHandle || void 0
129047
129651
  };
129048
129652
  }
129049
129653
  /**
@@ -129085,13 +129689,12 @@ var ParameterInputAdapter = class {
129085
129689
  dims.push(String(capacity + 1));
129086
129690
  }
129087
129691
  }
129088
- const isAutoConst = !deps.isModified && !isConst;
129089
129692
  return {
129090
129693
  name,
129091
129694
  baseType: typeName,
129092
129695
  mappedType,
129093
129696
  isConst,
129094
- isAutoConst,
129697
+ isAutoConst: false,
129095
129698
  isArray: true,
129096
129699
  arrayDimensions: dims,
129097
129700
  isCallback: false,
@@ -129169,6 +129772,9 @@ var ParameterSignatureBuilder = class {
129169
129772
  if (param.isString && !param.isArray) {
129170
129773
  return this._buildStringParam(param);
129171
129774
  }
129775
+ if (param.isOpaqueHandle) {
129776
+ return this._buildRefParam(param, refSuffix);
129777
+ }
129172
129778
  if (param.isPassByReference) {
129173
129779
  return this._buildRefParam(param, refSuffix);
129174
129780
  }
@@ -129213,14 +129819,16 @@ var ParameterSignatureBuilder = class {
129213
129819
  /**
129214
129820
  * Build pass-by-reference parameter signature.
129215
129821
  * C mode: const Point* p
129216
- * C++ mode: const Point& p (unless forcePointerSyntax)
129822
+ * C++ mode: const Point& p (unless forcePointerSyntax or isOpaqueHandle)
129217
129823
  *
129218
129824
  * Issue #895: When forcePointerSyntax is set, always use pointer syntax
129219
129825
  * because C callback typedefs expect pointers, not C++ references.
129826
+ * Issue #995: Opaque handles must use pointer syntax because C APIs
129827
+ * expect pointers to incomplete struct types (e.g., widget_t*).
129220
129828
  */
129221
129829
  static _buildRefParam(param, refSuffix) {
129222
129830
  const constPrefix = this._getConstPrefix(param);
129223
- const actualSuffix = param.forcePointerSyntax ? "*" : refSuffix;
129831
+ const actualSuffix = param.forcePointerSyntax || param.isOpaqueHandle ? "*" : refSuffix;
129224
129832
  return `${constPrefix}${param.mappedType}${actualSuffix} ${param.name}`;
129225
129833
  }
129226
129834
  /**
@@ -129234,9 +129842,12 @@ var ParameterSignatureBuilder = class {
129234
129842
  * Get const prefix combining explicit const, auto-const, and forced const.
129235
129843
  * Priority: forceConst > isConst > isAutoConst
129236
129844
  * Issue #895: forceConst preserves const from callback typedef signature.
129845
+ * Issue #995: Opaque handles suppress auto-const (they must be passed to
129846
+ * C APIs that expect non-const pointers).
129237
129847
  */
129238
129848
  static _getConstPrefix(param) {
129239
- if (param.forceConst || param.isConst || param.isAutoConst) {
129849
+ const effectiveAutoConst = param.isOpaqueHandle ? false : param.isAutoConst;
129850
+ if (param.forceConst || param.isConst || effectiveAutoConst) {
129240
129851
  return "const ";
129241
129852
  }
129242
129853
  return "";
@@ -129833,6 +130444,7 @@ var CodeGenerator = class _CodeGenerator {
129833
130444
  * Part of IOrchestrator interface.
129834
130445
  * ADR-045: Used to detect string comparisons and generate strcmp().
129835
130446
  * Issue #137: Extended to handle array element access (e.g., names[0])
130447
+ * Issue #1030: Extended to handle struct member access (e.g., person.name)
129836
130448
  */
129837
130449
  isStringExpression(ctx) {
129838
130450
  const text = ctx.getText();
@@ -129845,6 +130457,9 @@ var CodeGenerator = class _CodeGenerator {
129845
130457
  return true;
129846
130458
  }
129847
130459
  }
130460
+ if (this._isStructMemberStringExpression(text)) {
130461
+ return true;
130462
+ }
129848
130463
  return this._isArrayAccessStringExpression(text);
129849
130464
  }
129850
130465
  /**
@@ -129872,6 +130487,36 @@ var CodeGenerator = class _CodeGenerator {
129872
130487
  typeInfo.isArray && typeInfo.baseType && TypeCheckUtils_default.isString(typeInfo.baseType)
129873
130488
  );
129874
130489
  }
130490
+ /**
130491
+ * Check if struct member access expression evaluates to a string.
130492
+ * Issue #1030: Handles patterns like person.name, config.key
130493
+ */
130494
+ _isStructMemberStringExpression(text) {
130495
+ if (text.endsWith(".char_count") || text.endsWith(".capacity") || text.endsWith(".size") || text.endsWith(".length") || text.endsWith(".bit_length") || text.endsWith(".byte_length") || text.endsWith(".element_count")) {
130496
+ return false;
130497
+ }
130498
+ const memberMatch = /^([a-zA-Z_]\w*)\.([a-zA-Z_]\w*)$/.exec(text);
130499
+ if (!memberMatch) {
130500
+ return false;
130501
+ }
130502
+ const [, varName, fieldName] = memberMatch;
130503
+ const typeInfo = CodeGenState.getVariableTypeInfo(varName);
130504
+ if (!typeInfo) {
130505
+ return false;
130506
+ }
130507
+ const structTypeName = typeInfo.baseType;
130508
+ if (!structTypeName) {
130509
+ return false;
130510
+ }
130511
+ const fieldType = CodeGenState.getStructFieldType(
130512
+ structTypeName,
130513
+ fieldName
130514
+ );
130515
+ if (!fieldType) {
130516
+ return false;
130517
+ }
130518
+ return fieldType.startsWith("string");
130519
+ }
129875
130520
  /**
129876
130521
  * Get type of additive expression.
129877
130522
  * Part of IOrchestrator interface - delegates to private implementation.
@@ -130269,21 +130914,21 @@ var CodeGenerator = class _CodeGenerator {
130269
130914
  */
130270
130915
  getZeroInitializer(typeCtx, isArray) {
130271
130916
  if (isArray) {
130272
- return this._getArrayZeroInitializer(typeCtx);
130917
+ return this._getAggregateZeroInitBrace();
130273
130918
  }
130274
130919
  const resolved = this._resolveTypeNameFromContext(typeCtx);
130275
130920
  if (resolved) {
130276
130921
  if (CodeGenState.symbols.knownEnums.has(resolved.name)) {
130277
130922
  return this._getEnumZeroValue(resolved.name, resolved.separator);
130278
130923
  }
130279
- if (resolved.checkCppType && this._needsEmptyBraceInit(resolved.name)) {
130280
- return "{}";
130281
- }
130282
- return "{0}";
130924
+ return this._getAggregateZeroInitBrace();
130283
130925
  }
130284
130926
  if (typeCtx.templateType()) {
130285
130927
  return "{}";
130286
130928
  }
130929
+ if (typeCtx.stringType()) {
130930
+ return '""';
130931
+ }
130287
130932
  if (typeCtx.primitiveType()) {
130288
130933
  const primType = typeCtx.primitiveType().getText();
130289
130934
  return _CodeGenerator.PRIMITIVE_ZERO_VALUES.get(primType) ?? "0";
@@ -130395,7 +131040,7 @@ var CodeGenerator = class _CodeGenerator {
130395
131040
  const constMod = p.isConst ? "const " : "";
130396
131041
  if (p.isArray) {
130397
131042
  return `${constMod}${p.type} ${p.name}${p.arrayDims}`;
130398
- } else if (p.isPointer) {
131043
+ } else if (p.isStruct) {
130399
131044
  const ptrOrRef = this.isCppMode() ? "&" : "*";
130400
131045
  return `${constMod}${p.type}${ptrOrRef}`;
130401
131046
  } else {
@@ -130595,7 +131240,15 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
130595
131240
  return "__GLOBAL_PREFIX__";
130596
131241
  }
130597
131242
  if (ctx.IDENTIFIER()) {
130598
- return this._resolveIdentifierExpression(ctx.IDENTIFIER().getText());
131243
+ const id = ctx.IDENTIFIER().getText();
131244
+ if (id === "break" || id === "continue") {
131245
+ const line = ctx.start?.line ?? 0;
131246
+ const col = ctx.start?.column ?? 0;
131247
+ throw new Error(
131248
+ `${line}:${col} error[E0703]: '${id}' is not supported in C-Next - use structured conditions instead`
131249
+ );
131250
+ }
131251
+ return this._resolveIdentifierExpression(id);
130599
131252
  }
130600
131253
  if (ctx.literal()) {
130601
131254
  return this._generateLiteralExpression(ctx.literal());
@@ -130840,14 +131493,6 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
130840
131493
  }
130841
131494
  return identifiers.join("_");
130842
131495
  }
130843
- /**
130844
- * Issue #304: Check if a type name is from a C++ header
130845
- * Used to determine whether to use {} or {0} for initialization.
130846
- * C++ types with constructors may fail with {0} but work with {}.
130847
- */
130848
- isCppType(typeName) {
130849
- return SymbolLookupHelper_default.isCppType(CodeGenState.symbolTable, typeName);
130850
- }
130851
131496
  /**
130852
131497
  * Generate C code from a C-Next program
130853
131498
  * @param tree The parsed C-Next program
@@ -131278,6 +131923,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131278
131923
  const arrayTypeCtx = param.type().arrayType();
131279
131924
  const isArray = dims.length > 0 || arrayTypeCtx !== null;
131280
131925
  const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
131926
+ const isStruct = this.isStructType(typeName);
131281
131927
  let paramType;
131282
131928
  let isPointer;
131283
131929
  if (isCallbackParam) {
@@ -131286,7 +131932,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131286
131932
  isPointer = false;
131287
131933
  } else {
131288
131934
  paramType = this.generateType(param.type());
131289
- isPointer = !isArray;
131935
+ isPointer = !isArray && isStruct;
131290
131936
  }
131291
131937
  let arrayDims;
131292
131938
  if (dims.length > 0) {
@@ -131304,6 +131950,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131304
131950
  type: paramType,
131305
131951
  isConst,
131306
131952
  isPointer,
131953
+ isStruct,
131307
131954
  isArray,
131308
131955
  arrayDims
131309
131956
  });
@@ -131649,7 +132296,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131649
132296
  }
131650
132297
  decl += this._getStringCapacityDimension(varDecl.type());
131651
132298
  if (varDecl.expression()) {
131652
- decl += ` = ${this.generateExpression(varDecl.expression())}`;
132299
+ decl += ` = ${CodeGenState.withDeclarationInit(() => this.generateExpression(varDecl.expression()))}`;
131653
132300
  } else {
131654
132301
  decl += ` = ${this.getZeroInitializer(varDecl.type(), isArray)}`;
131655
132302
  }
@@ -131842,21 +132489,13 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131842
132489
  needsStructKeyword
131843
132490
  );
131844
132491
  if (!fieldList) {
131845
- return isCppClass ? "{}" : `(${castType}){ 0 }`;
132492
+ if (isCppClass) return "{}";
132493
+ return CodeGenState.inDeclarationInit ? "{ 0 }" : `(${castType}){ 0 }`;
131846
132494
  }
131847
132495
  const structFieldTypes = CodeGenState.symbolTable?.getStructFieldTypes(typeName);
131848
132496
  const fields = fieldList.fieldInitializer().map((field) => {
131849
132497
  const fieldName = field.IDENTIFIER().getText();
131850
- let fieldType;
131851
- if (structFieldTypes?.has(fieldName)) {
131852
- fieldType = structFieldTypes.get(fieldName);
131853
- if (fieldType.includes("_")) {
131854
- const parts = fieldType.split("_");
131855
- if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
131856
- fieldType = parts.join("::");
131857
- }
131858
- }
131859
- }
132498
+ const fieldType = this._resolveFieldType(fieldName, structFieldTypes);
131860
132499
  const value = CodeGenState.withExpectedType(
131861
132500
  fieldType,
131862
132501
  () => this.generateExpression(field.expression())
@@ -131872,10 +132511,35 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
131872
132511
  return "{}";
131873
132512
  }
131874
132513
  const fieldInits = fields.map((f) => `.${f.fieldName} = ${f.value}`);
132514
+ return this.formatStructInitializer(typeName, castType, fieldInits);
132515
+ }
132516
+ formatStructInitializer(typeName, castType, fieldInits) {
132517
+ const initializer = `{ ${fieldInits.join(", ")} }`;
132518
+ if (CodeGenState.inDeclarationInit) {
132519
+ return initializer;
132520
+ }
131875
132521
  if (CodeGenState.cppMode && (typeName.startsWith("struct {") || typeName.startsWith("union {"))) {
131876
- return `{ ${fieldInits.join(", ")} }`;
132522
+ return initializer;
132523
+ }
132524
+ if (!CodeGenState.inFunctionBody) {
132525
+ return initializer;
131877
132526
  }
131878
- return `(${castType}){ ${fieldInits.join(", ")} }`;
132527
+ return `(${castType})${initializer}`;
132528
+ }
132529
+ /**
132530
+ * Resolve the C type string for a named struct field, converting C++ underscore-separated
132531
+ * names to :: notation. Returns undefined if the field is not in the type map.
132532
+ * Issue #502: C-Next stores C++ types with _ separator; codegen needs ::.
132533
+ */
132534
+ _resolveFieldType(fieldName, structFieldTypes) {
132535
+ if (!structFieldTypes?.has(fieldName)) return void 0;
132536
+ const fieldType = structFieldTypes.get(fieldName);
132537
+ if (!fieldType.includes("_")) return fieldType;
132538
+ const parts = fieldType.split("_");
132539
+ if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
132540
+ return parts.join("::");
132541
+ }
132542
+ return fieldType;
131879
132543
  }
131880
132544
  /**
131881
132545
  * ADR-035: Generate array initializer
@@ -132018,7 +132682,9 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
132018
132682
  isCallbackCompatible,
132019
132683
  forcePassByReference,
132020
132684
  forceConst,
132021
- isTypedefStructType: (t) => CodeGenState.symbolTable?.isTypedefStructType(t) ?? false
132685
+ isTypedefStructType: (t) => CodeGenState.symbolTable?.isTypedefStructType(t) ?? false,
132686
+ // Issue #995: Opaque handles should not get auto-const
132687
+ isOpaqueType: (t) => CodeGenState.isOpaqueType(t)
132022
132688
  });
132023
132689
  return ParameterSignatureBuilder_default.build(input, CppModeHelper_default.refOrPtr());
132024
132690
  }
@@ -132249,26 +132915,13 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
132249
132915
  // _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
132250
132916
  // and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
132251
132917
  /**
132252
- * Get zero initializer for array types.
132253
- * Issue #379: C++ class arrays must use {} instead of {0}
132918
+ * Brace initializer that zero-initializes an aggregate (struct or array).
132919
+ * Issue #379 / #1004: C++ uses value-initialization ({}), which is valid for
132920
+ * any aggregate element type (POD, struct, class) including enum-first
132921
+ * structs where {0} is an invalid int->enum narrowing; C uses {0}.
132254
132922
  */
132255
- _getArrayZeroInitializer(typeCtx) {
132256
- if (typeCtx.userType()) {
132257
- const typeName = typeCtx.userType().getText();
132258
- if (this._needsEmptyBraceInit(typeName)) {
132259
- return "{}";
132260
- }
132261
- }
132262
- if (typeCtx.arrayType()?.userType()) {
132263
- const typeName = typeCtx.arrayType().userType().getText();
132264
- if (this._needsEmptyBraceInit(typeName)) {
132265
- return "{}";
132266
- }
132267
- }
132268
- if (typeCtx.templateType()) {
132269
- return "{}";
132270
- }
132271
- return "{0}";
132923
+ _getAggregateZeroInitBrace() {
132924
+ return CodeGenState.cppMode ? "{}" : "{0}";
132272
132925
  }
132273
132926
  /**
132274
132927
  * Get zero initializer for an enum type.
@@ -132293,49 +132946,35 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
132293
132946
  }
132294
132947
  /**
132295
132948
  * Resolve full type name from any TypeContext variant.
132296
- * Returns { name, separator, checkCppType } or null if not a named type.
132949
+ * Returns { name, separator } or null if not a named type.
132297
132950
  * ADR-016: Handles scoped, global, qualified, and user types
132298
- * checkCppType: only true for userType (original behavior preserved)
132299
132951
  */
132300
132952
  _resolveTypeNameFromContext(typeCtx) {
132301
132953
  if (typeCtx.scopedType()) {
132302
132954
  const localName = typeCtx.scopedType().IDENTIFIER().getText();
132303
132955
  const name = CodeGenState.currentScope ? `${CodeGenState.currentScope}_${localName}` : localName;
132304
- return { name, separator: "_", checkCppType: false };
132956
+ return { name, separator: "_" };
132305
132957
  }
132306
132958
  if (typeCtx.globalType()) {
132307
132959
  return {
132308
132960
  name: typeCtx.globalType().IDENTIFIER().getText(),
132309
- separator: "_",
132310
- checkCppType: false
132961
+ separator: "_"
132311
132962
  };
132312
132963
  }
132313
132964
  if (typeCtx.qualifiedType()) {
132314
132965
  const parts = typeCtx.qualifiedType().IDENTIFIER();
132315
132966
  const name = this.resolveQualifiedType(parts.map((id) => id.getText()));
132316
132967
  const separator = name.includes("::") ? "::" : "_";
132317
- return { name, separator, checkCppType: false };
132968
+ return { name, separator };
132318
132969
  }
132319
132970
  if (typeCtx.userType()) {
132320
132971
  return {
132321
132972
  name: typeCtx.userType().getText(),
132322
- separator: "_",
132323
- checkCppType: true
132973
+ separator: "_"
132324
132974
  };
132325
132975
  }
132326
132976
  return null;
132327
132977
  }
132328
- /**
132329
- * Check if a type needs empty brace initialization {}.
132330
- * Issue #304: C++ types with constructors may fail with {0}
132331
- * Issue #309: Unknown user types in C++ mode may have non-trivial constructors
132332
- */
132333
- _needsEmptyBraceInit(typeName) {
132334
- if (this.isCppType(typeName)) {
132335
- return true;
132336
- }
132337
- return CodeGenState.cppMode && !this.isKnownStruct(typeName);
132338
- }
132339
132978
  /**
132340
132979
  * Generate a safe bit mask expression.
132341
132980
  * Avoids undefined behavior when width >= 32 for 32-bit integers.
@@ -132715,7 +133354,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
132715
133354
  const maxComparison = `((${floatCastType})${maxValue})`;
132716
133355
  const finalCast = CppModeHelper_default.cast(targetType, `(${expr})`);
132717
133356
  const castMax = CppModeHelper_default.cast(targetType, maxValue);
132718
- const castMin = minValue === "0" ? "0" : CppModeHelper_default.cast(targetType, minValue);
133357
+ const castMin = CppModeHelper_default.cast(targetType, minValue);
132719
133358
  return `((${expr}) > ${maxComparison} ? ${castMax} : (${expr}) < ${minComparison} ? ${castMin} : ${finalCast})`;
132720
133359
  }
132721
133360
  /**
@@ -133091,6 +133730,30 @@ var generateEnumHeader_default = generateEnumHeader;
133091
133730
 
133092
133731
  // src/transpiler/output/headers/generators/generateStructHeader.ts
133093
133732
  var { mapType: mapType2 } = mapType_default;
133733
+ function resolveFieldCType(fieldType, input) {
133734
+ const callbackInfo = input.callbackTypes?.get(fieldType);
133735
+ if (callbackInfo) {
133736
+ return callbackInfo.typedefName;
133737
+ }
133738
+ const convertedType = CppNamespaceUtils_default.convertToCppNamespace(
133739
+ fieldType,
133740
+ input.symbolTable
133741
+ );
133742
+ return mapType2(convertedType);
133743
+ }
133744
+ function generateFieldLine(fieldName, cType, dims) {
133745
+ const dimSuffix = dims && dims.length > 0 ? dims.map((d) => `[${d}]`).join("") : "";
133746
+ const embeddedMatch = /^(\w+)\[(\d+)\]$/.exec(cType);
133747
+ if (!embeddedMatch) {
133748
+ return ` ${cType} ${fieldName}${dimSuffix};`;
133749
+ }
133750
+ const baseType = embeddedMatch[1];
133751
+ const embeddedDim = embeddedMatch[2];
133752
+ if (dims && dims.length > 0) {
133753
+ return ` ${baseType} ${fieldName}${dimSuffix};`;
133754
+ }
133755
+ return ` ${baseType} ${fieldName}[${embeddedDim}];`;
133756
+ }
133094
133757
  function generateStructHeader(name, input) {
133095
133758
  const fields = input.structFields.get(name);
133096
133759
  if (!fields || fields.size === 0) {
@@ -133100,25 +133763,9 @@ function generateStructHeader(name, input) {
133100
133763
  const lines = [];
133101
133764
  lines.push(`typedef struct ${name} {`);
133102
133765
  for (const [fieldName, fieldType] of fields) {
133103
- const convertedType = CppNamespaceUtils_default.convertToCppNamespace(
133104
- fieldType,
133105
- input.symbolTable
133106
- );
133107
- const cType = mapType2(convertedType);
133766
+ const cType = resolveFieldCType(fieldType, input);
133108
133767
  const dims = dimensions?.get(fieldName);
133109
- const dimSuffix = dims && dims.length > 0 ? dims.map((d) => `[${d}]`).join("") : "";
133110
- const embeddedMatch = /^(\w+)\[(\d+)\]$/.exec(cType);
133111
- if (embeddedMatch) {
133112
- const baseType = embeddedMatch[1];
133113
- const embeddedDim = embeddedMatch[2];
133114
- if (dims && dims.length > 0) {
133115
- lines.push(` ${baseType} ${fieldName}${dimSuffix};`);
133116
- } else {
133117
- lines.push(` ${baseType} ${fieldName}[${embeddedDim}];`);
133118
- }
133119
- } else {
133120
- lines.push(` ${cType} ${fieldName}${dimSuffix};`);
133121
- }
133768
+ lines.push(generateFieldLine(fieldName, cType, dims));
133122
133769
  }
133123
133770
  lines.push(`} ${name};`);
133124
133771
  return lines.join("\n");
@@ -133511,6 +134158,59 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
133511
134158
  lines.push("");
133512
134159
  return lines;
133513
134160
  }
134161
+ /**
134162
+ * ADR-029: Generate forward declarations for structs used in callback typedefs.
134163
+ * This ensures struct types can be used in callback parameter types before
134164
+ * the full struct definition.
134165
+ */
134166
+ static generateCallbackStructForwardDecls(structs, typeInput) {
134167
+ if (!typeInput?.callbackTypes || typeInput.callbackTypes.size === 0) {
134168
+ return [];
134169
+ }
134170
+ const usedStructTypes = /* @__PURE__ */ new Set();
134171
+ for (const [, cbInfo] of typeInput.callbackTypes) {
134172
+ for (const p of cbInfo.parameters) {
134173
+ if (p.isStruct) {
134174
+ usedStructTypes.add(p.type);
134175
+ }
134176
+ }
134177
+ }
134178
+ if (usedStructTypes.size === 0) {
134179
+ return [];
134180
+ }
134181
+ const localStructNames = new Set(structs.map((s) => s.name));
134182
+ const lines = [];
134183
+ for (const structType of usedStructTypes) {
134184
+ if (localStructNames.has(structType)) {
134185
+ lines.push(`typedef struct ${structType} ${structType};`);
134186
+ }
134187
+ }
134188
+ return lines.length > 0 ? [...lines, ""] : [];
134189
+ }
134190
+ /**
134191
+ * ADR-029: Generate callback typedef section
134192
+ * Generates function pointer typedefs for callbacks used as struct field types
134193
+ */
134194
+ static generateCallbackTypedefSection(typeInput, isCppMode) {
134195
+ if (!typeInput?.callbackTypes || typeInput.callbackTypes.size === 0) {
134196
+ return [];
134197
+ }
134198
+ const lines = ["/* Callback typedefs */"];
134199
+ for (const [, cbInfo] of typeInput.callbackTypes) {
134200
+ const params = cbInfo.parameters.length > 0 ? cbInfo.parameters.map((p) => {
134201
+ if (p.isStruct) {
134202
+ const ptrOrRef = isCppMode ? "&" : "*";
134203
+ return `${p.type}${ptrOrRef}`;
134204
+ }
134205
+ return p.type;
134206
+ }).join(", ") : "void";
134207
+ lines.push(
134208
+ `typedef ${cbInfo.returnType} (*${cbInfo.typedefName})(${params});`
134209
+ );
134210
+ }
134211
+ lines.push("");
134212
+ return lines;
134213
+ }
133514
134214
  /**
133515
134215
  * Generate struct and class definitions section
133516
134216
  */
@@ -133638,6 +134338,14 @@ var BaseHeaderGenerator = class {
133638
134338
  ...HeaderGeneratorUtils_default.generateEnumSection(groups.enums, typeInput),
133639
134339
  ...HeaderGeneratorUtils_default.generateBitmapSection(groups.bitmaps, typeInput),
133640
134340
  ...HeaderGeneratorUtils_default.generateTypeAliasSection(groups.types),
134341
+ ...HeaderGeneratorUtils_default.generateCallbackStructForwardDecls(
134342
+ groups.structs,
134343
+ typeInput
134344
+ ),
134345
+ ...HeaderGeneratorUtils_default.generateCallbackTypedefSection(
134346
+ typeInput,
134347
+ options.cppMode
134348
+ ),
133641
134349
  ...HeaderGeneratorUtils_default.generateStructSection(
133642
134350
  groups.structs,
133643
134351
  groups.classes,
@@ -133976,24 +134684,32 @@ var EnumCollector = class {
133976
134684
  var EnumCollector_default = EnumCollector;
133977
134685
 
133978
134686
  // src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts
133979
- function resolveScopedType(scopedTypeCtx, scopeName) {
133980
- const typeName = scopedTypeCtx.IDENTIFIER().getText();
133981
- return scopeName ? `${scopeName}_${typeName}` : typeName;
133982
- }
133983
134687
  function resolveStringType(stringCtx) {
133984
134688
  const intLiteral = stringCtx.INTEGER_LITERAL();
133985
134689
  return intLiteral ? `string<${intLiteral.getText()}>` : "string";
133986
134690
  }
133987
- function resolveArrayInnerType(arrayTypeCtx) {
133988
- if (arrayTypeCtx.primitiveType()) {
133989
- return arrayTypeCtx.primitiveType().getText();
134691
+ function dispatchTypeResolution(accessors, scopeName) {
134692
+ if (accessors.scopedType()) {
134693
+ const typeName = accessors.scopedType().IDENTIFIER().getText();
134694
+ return scopeName ? `${scopeName}_${typeName}` : typeName;
134695
+ }
134696
+ if (accessors.globalType()) {
134697
+ return accessors.globalType().IDENTIFIER().getText();
133990
134698
  }
133991
- if (arrayTypeCtx.userType()) {
133992
- return arrayTypeCtx.userType().getText();
134699
+ if (accessors.qualifiedType()) {
134700
+ const identifiers = accessors.qualifiedType().IDENTIFIER();
134701
+ return identifiers.map((id) => id.getText()).join("_");
133993
134702
  }
133994
- const text = arrayTypeCtx.getText();
133995
- const bracketIdx = text.indexOf("[");
133996
- return bracketIdx > 0 ? text.substring(0, bracketIdx) : text;
134703
+ if (accessors.userType()) {
134704
+ return accessors.userType().getText();
134705
+ }
134706
+ if (accessors.primitiveType()) {
134707
+ return accessors.primitiveType().getText();
134708
+ }
134709
+ if (accessors.stringType()) {
134710
+ return resolveStringType(accessors.stringType());
134711
+ }
134712
+ return null;
133997
134713
  }
133998
134714
  var TypeUtils = class {
133999
134715
  /**
@@ -134007,27 +134723,18 @@ var TypeUtils = class {
134007
134723
  */
134008
134724
  static getTypeName(ctx, scopeName) {
134009
134725
  if (!ctx) return "void";
134010
- if (ctx.scopedType()) {
134011
- return resolveScopedType(ctx.scopedType(), scopeName);
134012
- }
134013
- if (ctx.globalType()) {
134014
- return ctx.globalType().IDENTIFIER().getText();
134015
- }
134016
- if (ctx.qualifiedType()) {
134017
- const identifiers = ctx.qualifiedType().IDENTIFIER();
134018
- return identifiers.map((id) => id.getText()).join("_");
134019
- }
134020
- if (ctx.userType()) {
134021
- return ctx.userType().getText();
134022
- }
134023
- if (ctx.primitiveType()) {
134024
- return ctx.primitiveType().getText();
134025
- }
134026
- if (ctx.stringType()) {
134027
- return resolveStringType(ctx.stringType());
134028
- }
134029
134726
  if (ctx.arrayType()) {
134030
- return resolveArrayInnerType(ctx.arrayType());
134727
+ const result2 = dispatchTypeResolution(ctx.arrayType(), scopeName);
134728
+ if (result2 !== null) {
134729
+ return result2;
134730
+ }
134731
+ const text = ctx.arrayType().getText();
134732
+ const bracketIdx = text.indexOf("[");
134733
+ return bracketIdx > 0 ? text.substring(0, bracketIdx) : text;
134734
+ }
134735
+ const result = dispatchTypeResolution(ctx, scopeName);
134736
+ if (result !== null) {
134737
+ return result;
134031
134738
  }
134032
134739
  return ctx.getText();
134033
134740
  }
@@ -134393,13 +135100,22 @@ var VariableCollector = class _VariableCollector {
134393
135100
  return dimensions;
134394
135101
  }
134395
135102
  /**
134396
- * Collect dimensions from C-Next style arrayType syntax (u16[8] arr, u16[4][4] arr).
135103
+ * Collect dimensions from C-Next style arrayType syntax (u16[8] arr, u16[4][4] arr, u16[] arr).
135104
+ * Handles size inference from initializer when dimension is empty.
134397
135105
  */
134398
- static collectArrayTypeDimensions(arrayTypeCtx, constValues) {
135106
+ static collectArrayTypeDimensions(arrayTypeCtx, constValues, initExpr) {
134399
135107
  const dimensions = [];
134400
135108
  for (const dim of arrayTypeCtx.arrayTypeDimension()) {
134401
135109
  const sizeExpr = dim.expression();
134402
- if (!sizeExpr) continue;
135110
+ if (!sizeExpr) {
135111
+ if (initExpr) {
135112
+ const inferredSize = ArrayInitializerUtils_default.getInferredSize(initExpr);
135113
+ if (inferredSize !== void 0) {
135114
+ dimensions.push(inferredSize);
135115
+ }
135116
+ }
135117
+ continue;
135118
+ }
134403
135119
  const dimText = sizeExpr.getText();
134404
135120
  const literalSize = LiteralUtils_default.parseIntegerLiteral(dimText);
134405
135121
  if (literalSize !== void 0) {
@@ -134441,7 +135157,8 @@ var VariableCollector = class _VariableCollector {
134441
135157
  arrayDimensions.push(
134442
135158
  ..._VariableCollector.collectArrayTypeDimensions(
134443
135159
  arrayTypeCtx,
134444
- constValues
135160
+ constValues,
135161
+ initExpr
134445
135162
  )
134446
135163
  );
134447
135164
  }
@@ -134560,7 +135277,9 @@ var ScopeCollector = class {
134560
135277
  const memberSymbols = [];
134561
135278
  for (const member of ctx.scopeMember()) {
134562
135279
  const visibilityMod = member.visibilityModifier();
134563
- const visibility = visibilityMod?.getText() ?? "private";
135280
+ const explicitVisibility = visibilityMod?.getText();
135281
+ const isFunction = member.functionDeclaration() !== null;
135282
+ const visibility = explicitVisibility ?? ScopeUtils_default.getDefaultVisibility(isFunction);
134564
135283
  const isPublic = visibility === "public";
134565
135284
  if (member.variableDeclaration()) {
134566
135285
  const varDecl = member.variableDeclaration();
@@ -135250,12 +135969,15 @@ var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
135250
135969
  var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set([]);
135251
135970
  function parseArrayDimensions2(text) {
135252
135971
  const dimensions = [];
135253
- const arrayMatches = text.match(/\[(\d+)\]/g);
135972
+ const arrayMatches = text.match(/\[([^\]]+)\]/g);
135254
135973
  if (arrayMatches) {
135255
135974
  for (const match of arrayMatches) {
135256
- const size = Number.parseInt(match.slice(1, -1), 10);
135257
- if (!Number.isNaN(size)) {
135258
- dimensions.push(size);
135975
+ const content = match.slice(1, -1).trim();
135976
+ const numericValue = Number.parseInt(content, 10);
135977
+ if (!Number.isNaN(numericValue) && String(numericValue) === content) {
135978
+ dimensions.push(numericValue);
135979
+ } else {
135980
+ dimensions.push(content);
135259
135981
  }
135260
135982
  }
135261
135983
  }
@@ -135453,6 +136175,7 @@ var DeclaratorUtils = class _DeclaratorUtils {
135453
136175
  }
135454
136176
  /**
135455
136177
  * Extract array dimensions from a declarator.
136178
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
135456
136179
  */
135457
136180
  static extractArrayDimensions(declarator) {
135458
136181
  const directDecl = declarator.directDeclarator?.();
@@ -136607,6 +137330,7 @@ var DeclaratorUtils2 = class _DeclaratorUtils {
136607
137330
  }
136608
137331
  /**
136609
137332
  * Extract array dimensions from a declarator.
137333
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
136610
137334
  */
136611
137335
  static extractArrayDimensions(declarator) {
136612
137336
  const ptrDecl = declarator.pointerDeclarator?.();
@@ -136624,6 +137348,7 @@ var DeclaratorUtils2 = class _DeclaratorUtils {
136624
137348
  }
136625
137349
  /**
136626
137350
  * Extract array dimensions from a noPointerDeclarator.
137351
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
136627
137352
  */
136628
137353
  static extractArrayDimensionsFromNoPtr(noPtr) {
136629
137354
  return SymbolUtils_default.parseArrayDimensions(noPtr.getText());
@@ -138795,19 +139520,28 @@ var InitializationListener = class extends CNextListener {
138795
139520
  if (!baseId) {
138796
139521
  return;
138797
139522
  }
139523
+ const target = this._resolveAssignmentTarget(baseId, postfixOps);
139524
+ const isCompoundAssignment = ctx.assignmentOperator().ASSIGN() === null;
139525
+ if (isCompoundAssignment) {
139526
+ const { line, column } = ParserUtils_default.getPosition(ctx);
139527
+ this.analyzer.checkRead(target.varName, line, column, target.fieldName);
139528
+ }
139529
+ this.analyzer.recordAssignment(target.varName, target.fieldName);
139530
+ };
139531
+ /**
139532
+ * Resolve an assignment target to its variable name and optional field name.
139533
+ * Single classification path used by both read checks and assignment recording.
139534
+ */
139535
+ _resolveAssignmentTarget(baseId, postfixOps) {
138798
139536
  if (postfixOps.length === 0) {
138799
- this.analyzer.recordAssignment(baseId);
138800
- return;
139537
+ return { varName: baseId };
138801
139538
  }
138802
139539
  const { identifiers, hasSubscript } = PostfixAnalysisUtils_default(baseId, postfixOps);
138803
139540
  if (identifiers.length >= 2 && !hasSubscript) {
138804
- const varName = identifiers[0];
138805
- const fieldName = identifiers[1];
138806
- this.analyzer.recordAssignment(varName, fieldName);
138807
- } else {
138808
- this.analyzer.recordAssignment(baseId);
139541
+ return { varName: identifiers[0], fieldName: identifiers[1] };
138809
139542
  }
138810
- };
139543
+ return { varName: baseId };
139544
+ }
138811
139545
  // ========================================================================
138812
139546
  // Function Call Arguments (ADR-006: pass-by-reference may initialize)
138813
139547
  // ========================================================================
@@ -139045,27 +139779,128 @@ var InitializationAnalyzer = class {
139045
139779
  }
139046
139780
  /**
139047
139781
  * Process scope member variable declarations (ADR-016)
139782
+ * Issue #1019: Scope members require explicit initialization like locals
139048
139783
  */
139049
139784
  _processScopeMembers(decl) {
139050
139785
  const scopeDecl = decl.scopeDeclaration();
139051
139786
  if (!scopeDecl) return;
139052
139787
  const scopeName = scopeDecl.IDENTIFIER().getText();
139788
+ const assignedMembers = this._findAssignedScopeMembers(scopeDecl);
139053
139789
  for (const member of scopeDecl.scopeMember()) {
139054
- this._processScopeMemberVariable(member, scopeName);
139790
+ this._processScopeMemberVariable(member, scopeName, assignedMembers);
139791
+ }
139792
+ }
139793
+ /**
139794
+ * Scan all functions in a scope to find which members are assigned.
139795
+ * Issue #1019: A member assigned in ANY function is considered initialized
139796
+ * for reads in other functions within the same scope.
139797
+ */
139798
+ _findAssignedScopeMembers(scopeDecl) {
139799
+ const assigned = /* @__PURE__ */ new Set();
139800
+ for (const member of scopeDecl.scopeMember()) {
139801
+ const funcDecl = member.functionDeclaration();
139802
+ if (!funcDecl) continue;
139803
+ const body = funcDecl.block();
139804
+ if (!body) continue;
139805
+ this._collectAssignmentsInBlock(body, assigned);
139806
+ }
139807
+ return assigned;
139808
+ }
139809
+ /**
139810
+ * Recursively collect variable names that are assigned in a block.
139811
+ * Looks for assignment statements targeting bare identifiers or this.member.
139812
+ */
139813
+ _collectAssignmentsInBlock(block, assigned) {
139814
+ for (const stmt of block.statement()) {
139815
+ this._collectAssignmentsInStatement(stmt, assigned);
139816
+ }
139817
+ }
139818
+ /**
139819
+ * Collect assignments from a single statement, recursing into nested blocks.
139820
+ */
139821
+ _collectAssignmentsInStatement(stmt, assigned) {
139822
+ this._collectDirectAssignment(stmt, assigned);
139823
+ this._collectFromControlFlow(stmt, assigned);
139824
+ this._collectFromSwitch(stmt, assigned);
139825
+ this._collectFromBlock(stmt, assigned);
139826
+ }
139827
+ /**
139828
+ * Collect assignment from the statement itself (if it's an assignment).
139829
+ */
139830
+ _collectDirectAssignment(stmt, assigned) {
139831
+ const assignStmt = stmt.assignmentStatement();
139832
+ if (!assignStmt) return;
139833
+ const target = assignStmt.assignmentTarget();
139834
+ if (!target) return;
139835
+ const id = target.IDENTIFIER()?.getText();
139836
+ if (id) {
139837
+ assigned.add(id);
139838
+ }
139839
+ }
139840
+ /**
139841
+ * Recurse into control flow statements (if, while, do-while, for).
139842
+ */
139843
+ _collectFromControlFlow(stmt, assigned) {
139844
+ const ifStmt = stmt.ifStatement();
139845
+ if (ifStmt) {
139846
+ for (const childStmt of ifStmt.statement()) {
139847
+ this._collectAssignmentsInStatement(childStmt, assigned);
139848
+ }
139849
+ }
139850
+ const whileBody = stmt.whileStatement()?.statement();
139851
+ if (whileBody) {
139852
+ this._collectAssignmentsInStatement(whileBody, assigned);
139853
+ }
139854
+ const doWhileBody = stmt.doWhileStatement()?.block();
139855
+ if (doWhileBody) {
139856
+ this._collectAssignmentsInBlock(doWhileBody, assigned);
139857
+ }
139858
+ const forBody = stmt.forStatement()?.statement();
139859
+ if (forBody) {
139860
+ this._collectAssignmentsInStatement(forBody, assigned);
139861
+ }
139862
+ }
139863
+ /**
139864
+ * Recurse into switch statement cases.
139865
+ */
139866
+ _collectFromSwitch(stmt, assigned) {
139867
+ const switchStmt = stmt.switchStatement();
139868
+ if (!switchStmt) return;
139869
+ for (const switchCase of switchStmt.switchCase()) {
139870
+ const caseBlock = switchCase.block();
139871
+ if (caseBlock) {
139872
+ this._collectAssignmentsInBlock(caseBlock, assigned);
139873
+ }
139874
+ }
139875
+ const defaultBlock = switchStmt.defaultCase()?.block();
139876
+ if (defaultBlock) {
139877
+ this._collectAssignmentsInBlock(defaultBlock, assigned);
139878
+ }
139879
+ }
139880
+ /**
139881
+ * Recurse into standalone block statement.
139882
+ */
139883
+ _collectFromBlock(stmt, assigned) {
139884
+ const block = stmt.block();
139885
+ if (block) {
139886
+ this._collectAssignmentsInBlock(block, assigned);
139055
139887
  }
139056
139888
  }
139057
139889
  /**
139058
139890
  * Process a single scope member variable
139059
139891
  */
139060
- _processScopeMemberVariable(member, scopeName) {
139892
+ _processScopeMemberVariable(member, scopeName, assignedMembers) {
139061
139893
  const memberVar = member.variableDeclaration();
139062
139894
  if (!memberVar) return;
139063
139895
  const varName = memberVar.IDENTIFIER().getText();
139064
139896
  const fullName = `${scopeName}_${varName}`;
139065
139897
  const { line, column } = ParserUtils_default.getPosition(memberVar);
139066
139898
  const typeName = this._extractUserTypeName(memberVar.type());
139067
- this.declareVariable(varName, line, column, true, typeName);
139068
- this.declareVariable(fullName, line, column, true, typeName);
139899
+ const hasInlineInit = memberVar.expression() !== null;
139900
+ const isAssignedInScope = assignedMembers.has(varName);
139901
+ const hasInitializer = hasInlineInit || isAssignedInScope;
139902
+ this.declareVariable(varName, line, column, hasInitializer, typeName);
139903
+ this.declareVariable(fullName, line, column, hasInitializer, typeName);
139069
139904
  }
139070
139905
  /**
139071
139906
  * Extract user type name from a type context
@@ -139564,14 +140399,18 @@ var FunctionCallListener = class extends CNextListener {
139564
140399
  const primary = ctx.primaryExpression();
139565
140400
  const baseName = this.extractBaseName(primary);
139566
140401
  if (!baseName) return;
139567
- const { resolvedName, foundCall } = this.resolveCallTarget(ops, baseName);
140402
+ const { resolvedName, foundCall, isGlobalCall } = this.resolveCallTarget(
140403
+ ops,
140404
+ baseName
140405
+ );
139568
140406
  if (!foundCall) return;
139569
140407
  const { line, column } = ParserUtils_default.getPosition(ctx);
139570
140408
  this.analyzer.checkFunctionCall(
139571
140409
  resolvedName,
139572
140410
  line,
139573
140411
  column,
139574
- this.currentScope
140412
+ this.currentScope,
140413
+ isGlobalCall
139575
140414
  );
139576
140415
  };
139577
140416
  /**
@@ -139584,6 +140423,9 @@ var FunctionCallListener = class extends CNextListener {
139584
140423
  if (primary.THIS()) {
139585
140424
  return "this";
139586
140425
  }
140426
+ if (primary.GLOBAL()) {
140427
+ return "global";
140428
+ }
139587
140429
  return null;
139588
140430
  }
139589
140431
  /**
@@ -139593,11 +140435,15 @@ var FunctionCallListener = class extends CNextListener {
139593
140435
  */
139594
140436
  resolveCallTarget(ops, baseName) {
139595
140437
  let resolvedName = baseName;
140438
+ let isGlobalCall = baseName === "global";
139596
140439
  for (const op of ops) {
139597
140440
  if (op.IDENTIFIER()) {
139598
140441
  const resolved = this.resolveMemberAccess(resolvedName, op);
139599
140442
  if (resolved === null) {
139600
- return { resolvedName, foundCall: false };
140443
+ return { resolvedName, foundCall: false, isGlobalCall };
140444
+ }
140445
+ if (isGlobalCall && this.analyzer.isScope(resolvedName)) {
140446
+ isGlobalCall = false;
139601
140447
  }
139602
140448
  resolvedName = resolved;
139603
140449
  continue;
@@ -139605,11 +140451,11 @@ var FunctionCallListener = class extends CNextListener {
139605
140451
  if (op.argumentList() || op.getChildCount() === 2) {
139606
140452
  const text = op.getText();
139607
140453
  if (text.startsWith("(")) {
139608
- return { resolvedName, foundCall: true };
140454
+ return { resolvedName, foundCall: true, isGlobalCall };
139609
140455
  }
139610
140456
  }
139611
140457
  }
139612
- return { resolvedName, foundCall: false };
140458
+ return { resolvedName, foundCall: false, isGlobalCall };
139613
140459
  }
139614
140460
  /**
139615
140461
  * Resolve member access pattern. Returns new name or null if not a C-Next function.
@@ -139619,6 +140465,9 @@ var FunctionCallListener = class extends CNextListener {
139619
140465
  if (resolvedName === "this" && this.currentScope) {
139620
140466
  return `${this.currentScope}_${memberName}`;
139621
140467
  }
140468
+ if (resolvedName === "global") {
140469
+ return memberName;
140470
+ }
139622
140471
  if (this.analyzer.isScope(resolvedName)) {
139623
140472
  return `${resolvedName}_${memberName}`;
139624
140473
  }
@@ -140017,8 +140866,9 @@ var FunctionCallAnalyzer = class {
140017
140866
  * @param line Source line number
140018
140867
  * @param column Source column number
140019
140868
  * @param currentScope The current scope name (if inside a scope)
140869
+ * @param isGlobalCall Whether the call used global. prefix
140020
140870
  */
140021
- checkFunctionCall(name, line, column, currentScope) {
140871
+ checkFunctionCall(name, line, column, currentScope, isGlobalCall = false) {
140022
140872
  if (this.currentFunctionName && name === this.currentFunctionName) {
140023
140873
  this.errors.push({
140024
140874
  code: "E0423",
@@ -140044,17 +140894,19 @@ var FunctionCallAnalyzer = class {
140044
140894
  if (this.callableVariables.has(name)) {
140045
140895
  return;
140046
140896
  }
140047
- if (currentScope) {
140897
+ if (currentScope && !isGlobalCall) {
140048
140898
  const qualifiedName = `${currentScope}_${name}`;
140049
140899
  if (this.definedFunctions.has(qualifiedName)) {
140050
140900
  return;
140051
140901
  }
140052
140902
  }
140903
+ const isLocalFunction = this.allLocalFunctions.has(name);
140053
140904
  const header = this.findStdlibHeader(name);
140054
- let message = `function '${name}' called before definition`;
140055
- if (header) {
140056
- message += `; hint: '${name}' is available from ${header} \u2014 try global.${name}()`;
140057
- }
140905
+ const message = this.buildUndefinedFunctionMessage(
140906
+ name,
140907
+ header,
140908
+ isGlobalCall && !isLocalFunction
140909
+ );
140058
140910
  this.errors.push({
140059
140911
  code: "E0422",
140060
140912
  functionName: name,
@@ -140063,6 +140915,23 @@ var FunctionCallAnalyzer = class {
140063
140915
  message
140064
140916
  });
140065
140917
  }
140918
+ /**
140919
+ * Issue #985: Build error message for undefined function calls.
140920
+ * Adjusts hint based on whether the call used global. prefix.
140921
+ */
140922
+ buildUndefinedFunctionMessage(name, header, isGlobalCall) {
140923
+ if (isGlobalCall && header) {
140924
+ return `'${name}' is not declared in any included header; add #include <${header}>`;
140925
+ }
140926
+ if (isGlobalCall) {
140927
+ return `'${name}' is not declared in any included header`;
140928
+ }
140929
+ let message = `function '${name}' called before definition`;
140930
+ if (header) {
140931
+ message += `; hint: '${name}' is available from ${header} \u2014 try global.${name}()`;
140932
+ }
140933
+ return message;
140934
+ }
140066
140935
  /**
140067
140936
  * Check if a function is defined externally (from included files)
140068
140937
  * This includes C/C++ headers AND C-Next includes.
@@ -140588,46 +141457,56 @@ var ArrayIndexTypeAnalyzer_default = ArrayIndexTypeAnalyzer;
140588
141457
  import { ParseTreeWalker as ParseTreeWalker9 } from "antlr4ng";
140589
141458
  var SignedVariableCollector = class extends CNextListener {
140590
141459
  signedVars = /* @__PURE__ */ new Set();
141460
+ // Track all variable types (for resolving struct member chains)
141461
+ varTypes = /* @__PURE__ */ new Map();
140591
141462
  getSignedVars() {
140592
141463
  return this.signedVars;
140593
141464
  }
141465
+ getVarTypes() {
141466
+ return this.varTypes;
141467
+ }
140594
141468
  /**
140595
- * Track a typed identifier if it has a signed type
141469
+ * Track a typed identifier - add to signedVars if signed, always track type
140596
141470
  */
140597
- trackIfSigned(typeCtx, identifier) {
140598
- if (!typeCtx) return;
141471
+ trackType(typeCtx, identifier) {
141472
+ if (!typeCtx || !identifier) return;
140599
141473
  const typeName = typeCtx.getText();
140600
- if (!TypeConstants_default.SIGNED_TYPES.includes(typeName)) return;
140601
- if (!identifier) return;
140602
- this.signedVars.add(identifier.getText());
141474
+ const varName = identifier.getText();
141475
+ this.varTypes.set(varName, typeName);
141476
+ if (TypeConstants_default.SIGNED_TYPES.includes(typeName)) {
141477
+ this.signedVars.add(varName);
141478
+ }
140603
141479
  }
140604
141480
  /**
140605
141481
  * Track variable declarations with signed types
140606
141482
  */
140607
141483
  enterVariableDeclaration = (ctx) => {
140608
- this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
141484
+ this.trackType(ctx.type(), ctx.IDENTIFIER());
140609
141485
  };
140610
141486
  /**
140611
141487
  * Track function parameters with signed types
140612
141488
  */
140613
141489
  enterParameter = (ctx) => {
140614
- this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
141490
+ this.trackType(ctx.type(), ctx.IDENTIFIER());
140615
141491
  };
140616
141492
  /**
140617
141493
  * Track for-loop variable declarations with signed types
140618
141494
  */
140619
141495
  enterForVarDecl = (ctx) => {
140620
- this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
141496
+ this.trackType(ctx.type(), ctx.IDENTIFIER());
140621
141497
  };
140622
141498
  };
140623
141499
  var SignedShiftListener = class extends CNextListener {
140624
141500
  analyzer;
140625
141501
  // eslint-disable-next-line @typescript-eslint/lines-between-class-members
140626
141502
  signedVars;
140627
- constructor(analyzer, signedVars) {
141503
+ // eslint-disable-next-line @typescript-eslint/lines-between-class-members
141504
+ varTypes;
141505
+ constructor(analyzer, signedVars, varTypes) {
140628
141506
  super();
140629
141507
  this.analyzer = analyzer;
140630
141508
  this.signedVars = signedVars;
141509
+ this.varTypes = varTypes;
140631
141510
  }
140632
141511
  /**
140633
141512
  * Check shift expressions for signed operands
@@ -140648,6 +141527,69 @@ var SignedShiftListener = class extends CNextListener {
140648
141527
  }
140649
141528
  }
140650
141529
  };
141530
+ /**
141531
+ * Check compound shift-assign statements for signed targets
141532
+ * assignmentStatement: assignmentTarget assignmentOperator expression ';'
141533
+ * Issue #1008: <<<- and >><- must also be rejected on signed types
141534
+ *
141535
+ * Handles both simple identifiers (x <<<- 2) and member chains (s.x <<<- 2)
141536
+ */
141537
+ enterAssignmentStatement = (ctx) => {
141538
+ const opCtx = ctx.assignmentOperator();
141539
+ if (!opCtx) return;
141540
+ const isLeftShiftAssign = opCtx.LSHIFT_ASSIGN() !== null;
141541
+ const isRightShiftAssign = opCtx.RSHIFT_ASSIGN() !== null;
141542
+ if (!isLeftShiftAssign && !isRightShiftAssign) return;
141543
+ const target = ctx.assignmentTarget();
141544
+ if (!target) return;
141545
+ const identifier = target.IDENTIFIER();
141546
+ if (!identifier) return;
141547
+ const baseName = identifier.getText();
141548
+ const postfixOps = target.postfixTargetOp();
141549
+ if (this.isSignedTarget(baseName, postfixOps)) {
141550
+ const operator = isLeftShiftAssign ? "<<<-" : ">><-";
141551
+ const { line, column } = ParserUtils_default.getPosition(target);
141552
+ this.analyzer.addError(line, column, operator);
141553
+ }
141554
+ };
141555
+ /**
141556
+ * Resolve the final type of an assignment target, handling member chains.
141557
+ * Returns true if the final target is a signed type.
141558
+ *
141559
+ * Examples:
141560
+ * - "x" with no postfix ops → check if x is signed
141561
+ * - "s" with postfixOps [".x"] → check if s.x field is signed
141562
+ * - "arr" with postfixOps ["[0]", ".field"] → check if field is signed
141563
+ */
141564
+ isSignedTarget(baseName, postfixOps) {
141565
+ if (postfixOps.length === 0) {
141566
+ return this.signedVars.has(baseName);
141567
+ }
141568
+ let currentType = this.varTypes.get(baseName);
141569
+ if (!currentType) {
141570
+ return false;
141571
+ }
141572
+ for (const op of postfixOps) {
141573
+ const memberIdent = op.IDENTIFIER();
141574
+ if (memberIdent) {
141575
+ const fieldName = memberIdent.getText();
141576
+ const fieldType = CodeGenState.getStructFieldType(
141577
+ currentType,
141578
+ fieldName
141579
+ );
141580
+ if (!fieldType) {
141581
+ return false;
141582
+ }
141583
+ currentType = fieldType;
141584
+ } else {
141585
+ const bracketIndex = currentType.indexOf("[");
141586
+ if (bracketIndex !== -1) {
141587
+ currentType = currentType.substring(0, bracketIndex);
141588
+ }
141589
+ }
141590
+ }
141591
+ return TypeConstants_default.SIGNED_TYPES.includes(currentType);
141592
+ }
140651
141593
  /**
140652
141594
  * Check if an additive expression contains a signed type operand
140653
141595
  */
@@ -140715,7 +141657,8 @@ var SignedShiftAnalyzer = class {
140715
141657
  const collector = new SignedVariableCollector();
140716
141658
  ParseTreeWalker9.DEFAULT.walk(collector, tree);
140717
141659
  const signedVars = collector.getSignedVars();
140718
- const listener = new SignedShiftListener(this, signedVars);
141660
+ const varTypes = collector.getVarTypes();
141661
+ const listener = new SignedShiftListener(this, signedVars, varTypes);
140719
141662
  ParseTreeWalker9.DEFAULT.walk(listener, tree);
140720
141663
  return this.errors;
140721
141664
  }
@@ -142423,7 +143366,12 @@ var Transpiler = class {
142423
143366
  this.state.getAllHeaderDirectives(),
142424
143367
  CodeGenState.symbolTable
142425
143368
  );
142426
- const typeInputWithSymbolTable = typeInput ? { ...typeInput, symbolTable: CodeGenState.symbolTable } : void 0;
143369
+ const callbackTypesForHeader = this._buildCallbackTypesForHeader();
143370
+ const typeInputWithSymbolTable = typeInput ? {
143371
+ ...typeInput,
143372
+ symbolTable: CodeGenState.symbolTable,
143373
+ callbackTypes: callbackTypesForHeader
143374
+ } : void 0;
142427
143375
  const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
142428
143376
  const headerSymbols = this.convertToHeaderSymbols(
142429
143377
  exportedSymbols,
@@ -142445,6 +143393,32 @@ var Transpiler = class {
142445
143393
  basename6(sourcePath)
142446
143394
  );
142447
143395
  }
143396
+ /**
143397
+ * ADR-029: Build callback types for header generation.
143398
+ * Only includes callbacks that are actually used as struct field types.
143399
+ * Converts CodeGenState.callbackTypes to the format expected by IHeaderTypeInput.
143400
+ */
143401
+ _buildCallbackTypesForHeader() {
143402
+ const result = /* @__PURE__ */ new Map();
143403
+ const usedCallbackTypes = /* @__PURE__ */ new Set();
143404
+ for (const [, funcName] of CodeGenState.callbackFieldTypes) {
143405
+ usedCallbackTypes.add(funcName);
143406
+ }
143407
+ for (const funcName of usedCallbackTypes) {
143408
+ const cbInfo = CodeGenState.callbackTypes.get(funcName);
143409
+ if (cbInfo) {
143410
+ result.set(funcName, {
143411
+ typedefName: cbInfo.typedefName,
143412
+ returnType: cbInfo.returnType,
143413
+ parameters: cbInfo.parameters.map((p) => ({
143414
+ type: p.type,
143415
+ isStruct: p.isStruct
143416
+ }))
143417
+ });
143418
+ }
143419
+ }
143420
+ return result;
143421
+ }
142448
143422
  /**
142449
143423
  * Collect external enum sources from included C-Next files.
142450
143424
  */
@@ -142491,25 +143465,27 @@ var Transpiler = class {
142491
143465
  );
142492
143466
  const callbackTypedefType = typedefName ? CodeGenState.getTypedefType(typedefName) : void 0;
142493
143467
  if (callbackTypedefType) {
142494
- const updatedParams = TypedefParamParser_default.resolveCallbackParams(
143468
+ const updatedParams2 = TypedefParamParser_default.resolveCallbackParams(
142495
143469
  headerSymbol.parameters,
142496
143470
  callbackTypedefType
142497
143471
  );
142498
- return { ...headerSymbol, parameters: updatedParams };
143472
+ return { ...headerSymbol, parameters: updatedParams2 };
142499
143473
  }
142500
143474
  const unmodified = unmodifiedParams.get(headerSymbol.name);
142501
- if (unmodified) {
142502
- const updatedParams = headerSymbol.parameters.map((param) => {
142503
- const isPointerParam = !param.isConst && !param.isArray && param.type !== "f32" && param.type !== "f64" && param.type !== "ISR" && !knownEnums.has(param.type ?? "");
142504
- const isArrayParam = param.isArray && !param.isConst;
142505
- if ((isPointerParam || isArrayParam) && unmodified.has(param.name)) {
142506
- return { ...param, isAutoConst: true };
142507
- }
142508
- return param;
142509
- });
142510
- return { ...headerSymbol, parameters: updatedParams };
142511
- }
142512
- return headerSymbol;
143475
+ const updatedParams = headerSymbol.parameters.map((param) => {
143476
+ const isOpaque = CodeGenState.isOpaqueType(param.type ?? "");
143477
+ const isPointerParam = !param.isConst && !param.isArray && param.type !== "f32" && param.type !== "f64" && param.type !== "ISR" && !knownEnums.has(param.type ?? "");
143478
+ const shouldAutoConst = unmodified && isPointerParam && unmodified.has(param.name);
143479
+ if (shouldAutoConst || isOpaque) {
143480
+ return {
143481
+ ...param,
143482
+ isAutoConst: shouldAutoConst || void 0,
143483
+ isOpaqueHandle: isOpaque || void 0
143484
+ };
143485
+ }
143486
+ return param;
143487
+ });
143488
+ return { ...headerSymbol, parameters: updatedParams };
142513
143489
  });
142514
143490
  }
142515
143491
  // ===========================================================================