c-next 0.1.69 → 0.1.70

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 (54) hide show
  1. package/package.json +1 -1
  2. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -204
  3. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +693 -0
  4. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +86 -5
  5. package/src/transpiler/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
  6. package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
  7. package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
  8. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
  9. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
  10. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +35 -607
  12. package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
  13. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  14. package/src/transpiler/output/codegen/TypeValidator.ts +5 -5
  15. package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
  16. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
  17. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +3 -3
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
  19. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  20. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  21. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
  22. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
  23. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +11 -11
  24. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +23 -17
  25. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +2 -2
  26. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +3 -3
  27. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +3 -3
  28. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
  29. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
  30. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +23 -25
  31. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +20 -36
  32. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +18 -18
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +42 -32
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
  35. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
  36. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
  37. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +21 -4
  38. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
  39. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
  40. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
  41. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
  42. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  43. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
  44. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  45. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
  46. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
  47. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +2 -2
  50. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
  51. package/src/transpiler/state/CodeGenState.ts +122 -4
  52. package/src/transpiler/state/__tests__/CodeGenState.test.ts +269 -1
  53. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
  54. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c-next",
3
- "version": "0.1.69",
3
+ "version": "0.1.70",
4
4
  "description": "A safer C for embedded systems development. Transpiles to clean, readable C.",
5
5
  "packageManager": "npm@11.9.0",
6
6
  "type": "module",
@@ -11,7 +11,6 @@ import { ParseTreeWalker } from "antlr4ng";
11
11
  import { CNextListener } from "../parser/grammar/CNextListener";
12
12
  import * as Parser from "../parser/grammar/CNextParser";
13
13
  import SymbolTable from "../symbols/SymbolTable";
14
- import ESourceLanguage from "../../../utils/types/ESourceLanguage";
15
14
  import ESymbolKind from "../../../utils/types/ESymbolKind";
16
15
  import IFunctionCallError from "./types/IFunctionCallError";
17
16
  import ParserUtils from "../../../utils/ParserUtils";
@@ -26,195 +25,178 @@ const CNEXT_BUILTINS: Set<string> = new Set([
26
25
  ]);
27
26
 
28
27
  /**
29
- * Standard library functions from common C headers
30
- * These are considered "external" and don't need to be defined in C-Next
28
+ * Standard library functions mapped to their header files.
29
+ * Flat structure: function name header file.
30
+ * These are considered "external" and don't need to be defined in C-Next.
31
31
  */
32
- const STDLIB_FUNCTIONS: Map<string, Set<string>> = new Map([
33
- [
34
- "stdio.h",
35
- new Set([
36
- "printf",
37
- "fprintf",
38
- "sprintf",
39
- "snprintf",
40
- "scanf",
41
- "fscanf",
42
- "sscanf",
43
- "fopen",
44
- "fclose",
45
- "fread",
46
- "fwrite",
47
- "fgets",
48
- "fputs",
49
- "fgetc",
50
- "fputc",
51
- "puts",
52
- "putchar",
53
- "getchar",
54
- "gets",
55
- "perror",
56
- "fflush",
57
- "fseek",
58
- "ftell",
59
- "rewind",
60
- "feof",
61
- "ferror",
62
- "clearerr",
63
- "remove",
64
- "rename",
65
- "tmpfile",
66
- "tmpnam",
67
- "setbuf",
68
- "setvbuf",
69
- ]),
70
- ],
71
- [
72
- "stdlib.h",
73
- new Set([
74
- "malloc",
75
- "calloc",
76
- "realloc",
77
- "free",
78
- "atoi",
79
- "atof",
80
- "atol",
81
- "atoll",
82
- "strtol",
83
- "strtoul",
84
- "strtoll",
85
- "strtoull",
86
- "strtof",
87
- "strtod",
88
- "strtold",
89
- "rand",
90
- "srand",
91
- "exit",
92
- "abort",
93
- "atexit",
94
- "system",
95
- "getenv",
96
- "abs",
97
- "labs",
98
- "llabs",
99
- "div",
100
- "ldiv",
101
- "lldiv",
102
- "qsort",
103
- "bsearch",
104
- ]),
105
- ],
106
- [
107
- "string.h",
108
- new Set([
109
- "strlen",
110
- "strcpy",
111
- "strncpy",
112
- "strcat",
113
- "strncat",
114
- "strcmp",
115
- "strncmp",
116
- "strchr",
117
- "strrchr",
118
- "strstr",
119
- "strtok",
120
- "memcpy",
121
- "memmove",
122
- "memset",
123
- "memcmp",
124
- "memchr",
125
- ]),
126
- ],
127
- [
128
- "math.h",
129
- new Set([
130
- "sin",
131
- "cos",
132
- "tan",
133
- "asin",
134
- "acos",
135
- "atan",
136
- "atan2",
137
- "sinh",
138
- "cosh",
139
- "tanh",
140
- "exp",
141
- "log",
142
- "log10",
143
- "log2",
144
- "pow",
145
- "sqrt",
146
- "cbrt",
147
- "ceil",
148
- "floor",
149
- "round",
150
- "trunc",
151
- "fabs",
152
- "fmod",
153
- "remainder",
154
- "fmax",
155
- "fmin",
156
- "hypot",
157
- "ldexp",
158
- "frexp",
159
- "modf",
160
- ]),
161
- ],
162
- [
163
- "ctype.h",
164
- new Set([
165
- "isalnum",
166
- "isalpha",
167
- "isdigit",
168
- "isxdigit",
169
- "islower",
170
- "isupper",
171
- "isspace",
172
- "ispunct",
173
- "isprint",
174
- "isgraph",
175
- "iscntrl",
176
- "tolower",
177
- "toupper",
178
- ]),
179
- ],
180
- [
181
- "time.h",
182
- new Set([
183
- "time",
184
- "clock",
185
- "difftime",
186
- "mktime",
187
- "strftime",
188
- "localtime",
189
- "gmtime",
190
- "asctime",
191
- "ctime",
192
- ]),
193
- ],
194
- ["assert.h", new Set(["assert"])],
32
+ const STDLIB_FUNCTION_HEADERS: Record<string, string> = {
33
+ // stdio.h
34
+ printf: "stdio.h",
35
+ fprintf: "stdio.h",
36
+ sprintf: "stdio.h",
37
+ snprintf: "stdio.h",
38
+ scanf: "stdio.h",
39
+ fscanf: "stdio.h",
40
+ sscanf: "stdio.h",
41
+ fopen: "stdio.h",
42
+ fclose: "stdio.h",
43
+ fread: "stdio.h",
44
+ fwrite: "stdio.h",
45
+ fgets: "stdio.h",
46
+ fputs: "stdio.h",
47
+ fgetc: "stdio.h",
48
+ fputc: "stdio.h",
49
+ puts: "stdio.h",
50
+ putchar: "stdio.h",
51
+ getchar: "stdio.h",
52
+ gets: "stdio.h",
53
+ perror: "stdio.h",
54
+ fflush: "stdio.h",
55
+ fseek: "stdio.h",
56
+ ftell: "stdio.h",
57
+ rewind: "stdio.h",
58
+ feof: "stdio.h",
59
+ ferror: "stdio.h",
60
+ clearerr: "stdio.h",
61
+ remove: "stdio.h",
62
+ rename: "stdio.h",
63
+ tmpfile: "stdio.h",
64
+ tmpnam: "stdio.h",
65
+ setbuf: "stdio.h",
66
+ setvbuf: "stdio.h",
67
+ // stdlib.h
68
+ malloc: "stdlib.h",
69
+ calloc: "stdlib.h",
70
+ realloc: "stdlib.h",
71
+ free: "stdlib.h",
72
+ atoi: "stdlib.h",
73
+ atof: "stdlib.h",
74
+ atol: "stdlib.h",
75
+ atoll: "stdlib.h",
76
+ strtol: "stdlib.h",
77
+ strtoul: "stdlib.h",
78
+ strtoll: "stdlib.h",
79
+ strtoull: "stdlib.h",
80
+ strtof: "stdlib.h",
81
+ strtod: "stdlib.h",
82
+ strtold: "stdlib.h",
83
+ rand: "stdlib.h",
84
+ srand: "stdlib.h",
85
+ exit: "stdlib.h",
86
+ abort: "stdlib.h",
87
+ atexit: "stdlib.h",
88
+ system: "stdlib.h",
89
+ getenv: "stdlib.h",
90
+ abs: "stdlib.h",
91
+ labs: "stdlib.h",
92
+ llabs: "stdlib.h",
93
+ div: "stdlib.h",
94
+ ldiv: "stdlib.h",
95
+ lldiv: "stdlib.h",
96
+ qsort: "stdlib.h",
97
+ bsearch: "stdlib.h",
98
+ // string.h
99
+ strlen: "string.h",
100
+ strcpy: "string.h",
101
+ strncpy: "string.h",
102
+ strcat: "string.h",
103
+ strncat: "string.h",
104
+ strcmp: "string.h",
105
+ strncmp: "string.h",
106
+ strchr: "string.h",
107
+ strrchr: "string.h",
108
+ strstr: "string.h",
109
+ strtok: "string.h",
110
+ memcpy: "string.h",
111
+ memmove: "string.h",
112
+ memset: "string.h",
113
+ memcmp: "string.h",
114
+ memchr: "string.h",
115
+ // math.h
116
+ sin: "math.h",
117
+ cos: "math.h",
118
+ tan: "math.h",
119
+ asin: "math.h",
120
+ acos: "math.h",
121
+ atan: "math.h",
122
+ atan2: "math.h",
123
+ sinh: "math.h",
124
+ cosh: "math.h",
125
+ tanh: "math.h",
126
+ exp: "math.h",
127
+ log: "math.h",
128
+ log10: "math.h",
129
+ log2: "math.h",
130
+ pow: "math.h",
131
+ sqrt: "math.h",
132
+ cbrt: "math.h",
133
+ ceil: "math.h",
134
+ floor: "math.h",
135
+ round: "math.h",
136
+ trunc: "math.h",
137
+ fabs: "math.h",
138
+ fmod: "math.h",
139
+ remainder: "math.h",
140
+ fmax: "math.h",
141
+ fmin: "math.h",
142
+ hypot: "math.h",
143
+ ldexp: "math.h",
144
+ frexp: "math.h",
145
+ modf: "math.h",
146
+ // C99 classification macros (also functions in C++)
147
+ isnan: "math.h",
148
+ isinf: "math.h",
149
+ isfinite: "math.h",
150
+ isnormal: "math.h",
151
+ signbit: "math.h",
152
+ fpclassify: "math.h",
153
+ nan: "math.h",
154
+ nanf: "math.h",
155
+ nanl: "math.h",
156
+ // ctype.h
157
+ isalnum: "ctype.h",
158
+ isalpha: "ctype.h",
159
+ isdigit: "ctype.h",
160
+ isxdigit: "ctype.h",
161
+ islower: "ctype.h",
162
+ isupper: "ctype.h",
163
+ isspace: "ctype.h",
164
+ ispunct: "ctype.h",
165
+ isprint: "ctype.h",
166
+ isgraph: "ctype.h",
167
+ iscntrl: "ctype.h",
168
+ tolower: "ctype.h",
169
+ toupper: "ctype.h",
170
+ // time.h
171
+ time: "time.h",
172
+ clock: "time.h",
173
+ difftime: "time.h",
174
+ mktime: "time.h",
175
+ strftime: "time.h",
176
+ localtime: "time.h",
177
+ gmtime: "time.h",
178
+ asctime: "time.h",
179
+ ctime: "time.h",
180
+ // assert.h
181
+ assert: "assert.h",
195
182
  // Arduino framework
196
- [
197
- "Arduino.h",
198
- new Set([
199
- "pinMode",
200
- "digitalWrite",
201
- "digitalRead",
202
- "analogRead",
203
- "analogWrite",
204
- "delay",
205
- "delayMicroseconds",
206
- "millis",
207
- "micros",
208
- "attachInterrupt",
209
- "detachInterrupt",
210
- "noInterrupts",
211
- "interrupts",
212
- "Serial",
213
- "Wire",
214
- "SPI",
215
- ]),
216
- ],
217
- ]);
183
+ pinMode: "Arduino.h",
184
+ digitalWrite: "Arduino.h",
185
+ digitalRead: "Arduino.h",
186
+ analogRead: "Arduino.h",
187
+ analogWrite: "Arduino.h",
188
+ delay: "Arduino.h",
189
+ delayMicroseconds: "Arduino.h",
190
+ millis: "Arduino.h",
191
+ micros: "Arduino.h",
192
+ attachInterrupt: "Arduino.h",
193
+ detachInterrupt: "Arduino.h",
194
+ noInterrupts: "Arduino.h",
195
+ interrupts: "Arduino.h",
196
+ Serial: "Arduino.h",
197
+ Wire: "Arduino.h",
198
+ SPI: "Arduino.h",
199
+ };
218
200
 
219
201
  /**
220
202
  * Listener that walks the parse tree and checks function calls
@@ -424,6 +406,9 @@ class FunctionCallAnalyzer {
424
406
  /** Functions that have been defined (in order of appearance) */
425
407
  private definedFunctions: Set<string> = new Set();
426
408
 
409
+ /** All functions that will be defined in this file (for distinguishing local vs cross-file) */
410
+ private allLocalFunctions: Set<string> = new Set();
411
+
427
412
  /** Known scopes (for Scope.member -> Scope_member resolution) */
428
413
  private knownScopes: Set<string> = new Set();
429
414
 
@@ -454,6 +439,7 @@ class FunctionCallAnalyzer {
454
439
  ): IFunctionCallError[] {
455
440
  this.errors = [];
456
441
  this.definedFunctions = new Set();
442
+ this.allLocalFunctions = new Set();
457
443
  this.knownScopes = new Set();
458
444
  this.includedHeaders = new Set();
459
445
  this.symbolTable = symbolTable ?? null;
@@ -461,10 +447,11 @@ class FunctionCallAnalyzer {
461
447
  this.callableVariables = new Set();
462
448
  this.callbackTypes = new Set();
463
449
 
464
- // First pass: collect scope names, includes, and callback types
450
+ // First pass: collect scope names, includes, callback types, and all local functions
465
451
  this.collectScopes(tree);
466
452
  this.collectIncludes(tree);
467
453
  this.collectCallbackTypes(tree);
454
+ this.collectAllLocalFunctions(tree);
468
455
 
469
456
  // Second pass: walk tree in order, tracking definitions and checking calls
470
457
  const listener = new FunctionCallListener(this);
@@ -503,13 +490,17 @@ class FunctionCallAnalyzer {
503
490
  * Check if a function is from an included standard library header
504
491
  */
505
492
  private isStdlibFunction(name: string): boolean {
506
- for (const header of this.includedHeaders) {
507
- const funcs = STDLIB_FUNCTIONS.get(header);
508
- if (funcs?.has(name)) {
509
- return true;
510
- }
511
- }
512
- return false;
493
+ const header = STDLIB_FUNCTION_HEADERS[name];
494
+ return header !== undefined && this.includedHeaders.has(header);
495
+ }
496
+
497
+ /**
498
+ * Issue #787: Find which header a stdlib function belongs to (if any).
499
+ * Returns the header name if found, or null if not a known stdlib function.
500
+ * Checks ALL stdlib functions, not just from included headers.
501
+ */
502
+ private findStdlibHeader(name: string): string | null {
503
+ return STDLIB_FUNCTION_HEADERS[name] ?? null;
513
504
  }
514
505
 
515
506
  /**
@@ -525,6 +516,35 @@ class FunctionCallAnalyzer {
525
516
  }
526
517
  }
527
518
 
519
+ /**
520
+ * Issue #786: Pre-collect all function names defined in this file.
521
+ * Used to distinguish between local functions (subject to define-before-use)
522
+ * and cross-file functions from includes (allowed without local definition).
523
+ */
524
+ private collectAllLocalFunctions(tree: Parser.ProgramContext): void {
525
+ for (const decl of tree.declaration()) {
526
+ // Standalone functions
527
+ if (decl.functionDeclaration()) {
528
+ const name = decl.functionDeclaration()!.IDENTIFIER().getText();
529
+ this.allLocalFunctions.add(name);
530
+ }
531
+ // Scope member functions
532
+ if (decl.scopeDeclaration()) {
533
+ const scopeDecl = decl.scopeDeclaration()!;
534
+ const scopeName = scopeDecl.IDENTIFIER().getText();
535
+ for (const member of scopeDecl.scopeMember()) {
536
+ if (member.functionDeclaration()) {
537
+ const funcName = member
538
+ .functionDeclaration()!
539
+ .IDENTIFIER()
540
+ .getText();
541
+ this.allLocalFunctions.add(`${scopeName}_${funcName}`);
542
+ }
543
+ }
544
+ }
545
+ }
546
+ }
547
+
528
548
  /**
529
549
  * ADR-029: Check if a type name is a callback type (function-as-type)
530
550
  */
@@ -627,31 +647,47 @@ class FunctionCallAnalyzer {
627
647
  }
628
648
  }
629
649
 
630
- // Not defined - report error
650
+ // Not defined - report error with optional hint
651
+ const header = this.findStdlibHeader(name);
652
+ let message = `function '${name}' called before definition`;
653
+ if (header) {
654
+ message += `; hint: '${name}' is available from ${header} — try global.${name}()`;
655
+ }
656
+
631
657
  this.errors.push({
632
658
  code: "E0422",
633
659
  functionName: name,
634
660
  line,
635
661
  column,
636
- message: `function '${name}' called before definition`,
662
+ message,
637
663
  });
638
664
  }
639
665
 
640
666
  /**
641
- * Check if a function is defined externally (C/C++ interop)
667
+ * Check if a function is defined externally (from included files)
668
+ * This includes C/C++ headers AND C-Next includes.
669
+ *
670
+ * Issue #786: Only considers a function "external" if it's NOT defined
671
+ * in the current file. Functions defined locally are subject to
672
+ * define-before-use checking, even if they exist in the SymbolTable.
642
673
  */
643
674
  private isExternalFunction(name: string): boolean {
675
+ // If the function is defined in this file, it's not external
676
+ // (even if it's also in the SymbolTable from symbol collection)
677
+ if (this.allLocalFunctions.has(name)) {
678
+ return false;
679
+ }
680
+
644
681
  if (!this.symbolTable) {
645
682
  return false;
646
683
  }
647
684
 
648
685
  const symbols = this.symbolTable.getOverloads(name);
649
686
  for (const sym of symbols) {
650
- if (
651
- (sym.sourceLanguage === ESourceLanguage.C ||
652
- sym.sourceLanguage === ESourceLanguage.Cpp) &&
653
- sym.kind === ESymbolKind.Function
654
- ) {
687
+ // Accept functions from any source language:
688
+ // - C/C++ functions from header includes
689
+ // - C-Next functions from .cnx file includes
690
+ if (sym.kind === ESymbolKind.Function) {
655
691
  return true;
656
692
  }
657
693
  }