c-next 0.1.0

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 (72) hide show
  1. package/README.md +726 -0
  2. package/bin/cnext.js +5 -0
  3. package/grammar/C.g4 +1112 -0
  4. package/grammar/CNext.g4 +817 -0
  5. package/grammar/CPP14Lexer.g4 +282 -0
  6. package/grammar/CPP14Parser.g4 +1072 -0
  7. package/package.json +85 -0
  8. package/src/analysis/DivisionByZeroAnalyzer.ts +378 -0
  9. package/src/analysis/FunctionCallAnalyzer.ts +526 -0
  10. package/src/analysis/InitializationAnalyzer.ts +725 -0
  11. package/src/analysis/NullCheckAnalyzer.ts +427 -0
  12. package/src/analysis/types/IDivisionByZeroError.ts +25 -0
  13. package/src/analysis/types/IFunctionCallError.ts +17 -0
  14. package/src/analysis/types/IInitializationError.ts +55 -0
  15. package/src/analysis/types/INullCheckError.ts +25 -0
  16. package/src/codegen/CodeGenerator.ts +7945 -0
  17. package/src/codegen/CommentExtractor.ts +240 -0
  18. package/src/codegen/CommentFormatter.ts +155 -0
  19. package/src/codegen/HeaderGenerator.ts +265 -0
  20. package/src/codegen/TypeResolver.ts +365 -0
  21. package/src/codegen/types/ECommentType.ts +10 -0
  22. package/src/codegen/types/IComment.ts +21 -0
  23. package/src/codegen/types/ICommentError.ts +15 -0
  24. package/src/codegen/types/TOverflowBehavior.ts +6 -0
  25. package/src/codegen/types/TParameterInfo.ts +13 -0
  26. package/src/codegen/types/TTypeConstants.ts +94 -0
  27. package/src/codegen/types/TTypeInfo.ts +22 -0
  28. package/src/index.ts +518 -0
  29. package/src/lib/IncludeDiscovery.ts +131 -0
  30. package/src/lib/InputExpansion.ts +121 -0
  31. package/src/lib/PlatformIODetector.ts +162 -0
  32. package/src/lib/transpiler.ts +439 -0
  33. package/src/lib/types/ITranspileResult.ts +80 -0
  34. package/src/parser/c/grammar/C.interp +338 -0
  35. package/src/parser/c/grammar/C.tokens +229 -0
  36. package/src/parser/c/grammar/CLexer.interp +415 -0
  37. package/src/parser/c/grammar/CLexer.tokens +229 -0
  38. package/src/parser/c/grammar/CLexer.ts +750 -0
  39. package/src/parser/c/grammar/CListener.ts +976 -0
  40. package/src/parser/c/grammar/CParser.ts +9663 -0
  41. package/src/parser/c/grammar/CVisitor.ts +626 -0
  42. package/src/parser/cpp/grammar/CPP14Lexer.interp +478 -0
  43. package/src/parser/cpp/grammar/CPP14Lexer.tokens +264 -0
  44. package/src/parser/cpp/grammar/CPP14Lexer.ts +848 -0
  45. package/src/parser/cpp/grammar/CPP14Parser.interp +492 -0
  46. package/src/parser/cpp/grammar/CPP14Parser.tokens +264 -0
  47. package/src/parser/cpp/grammar/CPP14Parser.ts +19961 -0
  48. package/src/parser/cpp/grammar/CPP14ParserListener.ts +2120 -0
  49. package/src/parser/cpp/grammar/CPP14ParserVisitor.ts +1354 -0
  50. package/src/parser/grammar/CNext.interp +340 -0
  51. package/src/parser/grammar/CNext.tokens +214 -0
  52. package/src/parser/grammar/CNextLexer.interp +374 -0
  53. package/src/parser/grammar/CNextLexer.tokens +214 -0
  54. package/src/parser/grammar/CNextLexer.ts +668 -0
  55. package/src/parser/grammar/CNextListener.ts +1020 -0
  56. package/src/parser/grammar/CNextParser.ts +9239 -0
  57. package/src/parser/grammar/CNextVisitor.ts +654 -0
  58. package/src/preprocessor/Preprocessor.ts +301 -0
  59. package/src/preprocessor/ToolchainDetector.ts +225 -0
  60. package/src/preprocessor/types/IPreprocessResult.ts +39 -0
  61. package/src/preprocessor/types/IToolchain.ts +27 -0
  62. package/src/project/FileDiscovery.ts +236 -0
  63. package/src/project/Project.ts +425 -0
  64. package/src/project/types/IProjectConfig.ts +64 -0
  65. package/src/symbols/CNextSymbolCollector.ts +326 -0
  66. package/src/symbols/CSymbolCollector.ts +457 -0
  67. package/src/symbols/CppSymbolCollector.ts +362 -0
  68. package/src/symbols/SymbolTable.ts +312 -0
  69. package/src/symbols/types/IConflict.ts +20 -0
  70. package/src/types/ESourceLanguage.ts +10 -0
  71. package/src/types/ESymbolKind.ts +20 -0
  72. package/src/types/ISymbol.ts +45 -0
@@ -0,0 +1,362 @@
1
+ /**
2
+ * C++ Symbol Collector
3
+ * Extracts symbols from C++ parse trees for the unified symbol table
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-explicit-any */
7
+
8
+ import { CPP14Parser } from "../parser/cpp/grammar/CPP14Parser";
9
+ import ISymbol from "../types/ISymbol";
10
+ import ESymbolKind from "../types/ESymbolKind";
11
+ import ESourceLanguage from "../types/ESourceLanguage";
12
+
13
+ // Import context types
14
+ type TranslationUnitContext = ReturnType<CPP14Parser["translationUnit"]>;
15
+
16
+ /**
17
+ * Collects symbols from a C++ parse tree
18
+ */
19
+ class CppSymbolCollector {
20
+ private sourceFile: string;
21
+
22
+ private symbols: ISymbol[] = [];
23
+
24
+ private currentNamespace: string | undefined;
25
+
26
+ constructor(sourceFile: string) {
27
+ this.sourceFile = sourceFile;
28
+ }
29
+
30
+ /**
31
+ * Collect all symbols from a C++ translation unit
32
+ */
33
+ collect(tree: TranslationUnitContext): ISymbol[] {
34
+ this.symbols = [];
35
+ this.currentNamespace = undefined;
36
+
37
+ if (!tree) {
38
+ return this.symbols;
39
+ }
40
+
41
+ const declSeq = tree.declarationseq?.();
42
+ if (!declSeq) {
43
+ return this.symbols;
44
+ }
45
+
46
+ for (const decl of declSeq.declaration()) {
47
+ this.collectDeclaration(decl);
48
+ }
49
+
50
+ return this.symbols;
51
+ }
52
+
53
+ private collectDeclaration(decl: any): void {
54
+ const line = decl.start?.line ?? 0;
55
+
56
+ // Function definition
57
+ const funcDef = decl.functionDefinition?.();
58
+ if (funcDef) {
59
+ this.collectFunctionDefinition(funcDef, line);
60
+ return;
61
+ }
62
+
63
+ // Namespace definition
64
+ const nsDef = decl.namespaceDefinition?.();
65
+ if (nsDef) {
66
+ this.collectNamespaceDefinition(nsDef, line);
67
+ return;
68
+ }
69
+
70
+ // Template declaration
71
+ const templDecl = decl.templateDeclaration?.();
72
+ if (templDecl) {
73
+ // Skip template declarations for now - complex to handle
74
+ return;
75
+ }
76
+
77
+ // Block declaration (simpleDeclaration, etc.)
78
+ const blockDecl = decl.blockDeclaration?.();
79
+ if (blockDecl) {
80
+ this.collectBlockDeclaration(blockDecl, line);
81
+ }
82
+ }
83
+
84
+ private collectFunctionDefinition(funcDef: any, line: number): void {
85
+ const declarator = funcDef.declarator?.();
86
+ if (!declarator) return;
87
+
88
+ const name = this.extractDeclaratorName(declarator);
89
+ if (!name) return;
90
+
91
+ // Get return type
92
+ const declSpecSeq = funcDef.declSpecifierSeq?.();
93
+ const returnType = declSpecSeq
94
+ ? this.extractTypeFromDeclSpecSeq(declSpecSeq)
95
+ : "void";
96
+
97
+ const fullName = this.currentNamespace
98
+ ? `${this.currentNamespace}::${name}`
99
+ : name;
100
+
101
+ this.symbols.push({
102
+ name: fullName,
103
+ kind: ESymbolKind.Function,
104
+ type: returnType,
105
+ sourceFile: this.sourceFile,
106
+ sourceLine: line,
107
+ sourceLanguage: ESourceLanguage.Cpp,
108
+ isExported: true,
109
+ parent: this.currentNamespace,
110
+ });
111
+ }
112
+
113
+ private collectNamespaceDefinition(nsDef: any, line: number): void {
114
+ const identifier = nsDef.Identifier?.();
115
+ const originalNs = nsDef.originalNamespaceName?.();
116
+
117
+ const name = identifier?.getText() ?? originalNs?.getText();
118
+ if (!name) return;
119
+
120
+ this.symbols.push({
121
+ name,
122
+ kind: ESymbolKind.Namespace,
123
+ sourceFile: this.sourceFile,
124
+ sourceLine: line,
125
+ sourceLanguage: ESourceLanguage.Cpp,
126
+ isExported: true,
127
+ });
128
+
129
+ // Process namespace body
130
+ const savedNamespace = this.currentNamespace;
131
+ this.currentNamespace = this.currentNamespace
132
+ ? `${this.currentNamespace}::${name}`
133
+ : name;
134
+
135
+ const body = nsDef.declarationseq?.();
136
+ if (body) {
137
+ for (const decl of body.declaration()) {
138
+ this.collectDeclaration(decl);
139
+ }
140
+ }
141
+
142
+ this.currentNamespace = savedNamespace;
143
+ }
144
+
145
+ private collectBlockDeclaration(blockDecl: any, line: number): void {
146
+ // Simple declaration (variables, typedefs, class declarations)
147
+ const simpleDecl = blockDecl.simpleDeclaration?.();
148
+ if (simpleDecl) {
149
+ this.collectSimpleDeclaration(simpleDecl, line);
150
+ }
151
+
152
+ // Using declaration
153
+ const usingDecl = blockDecl.usingDeclaration?.();
154
+ if (usingDecl) {
155
+ // Skip using declarations for now
156
+ }
157
+
158
+ // Alias declaration (using X = Y)
159
+ const aliasDecl = blockDecl.aliasDeclaration?.();
160
+ if (aliasDecl) {
161
+ const identifier = aliasDecl.Identifier?.();
162
+ if (identifier) {
163
+ this.symbols.push({
164
+ name: identifier.getText(),
165
+ kind: ESymbolKind.Type,
166
+ sourceFile: this.sourceFile,
167
+ sourceLine: line,
168
+ sourceLanguage: ESourceLanguage.Cpp,
169
+ isExported: true,
170
+ parent: this.currentNamespace,
171
+ });
172
+ }
173
+ }
174
+ }
175
+
176
+ private collectSimpleDeclaration(simpleDecl: any, line: number): void {
177
+ const declSpecSeq = simpleDecl.declSpecifierSeq?.();
178
+ if (!declSpecSeq) return;
179
+
180
+ const baseType = this.extractTypeFromDeclSpecSeq(declSpecSeq);
181
+
182
+ // Check for class specifier
183
+ for (const spec of declSpecSeq.declSpecifier?.() ?? []) {
184
+ const typeSpec = spec.typeSpecifier?.();
185
+ if (typeSpec) {
186
+ const classSpec = typeSpec.classSpecifier?.();
187
+ if (classSpec) {
188
+ this.collectClassSpecifier(classSpec, line);
189
+ }
190
+
191
+ const enumSpec = typeSpec.enumSpecifier?.();
192
+ if (enumSpec) {
193
+ this.collectEnumSpecifier(enumSpec, line);
194
+ }
195
+ }
196
+ }
197
+
198
+ // Collect declarators (variables, function prototypes)
199
+ const initDeclList = simpleDecl.initDeclaratorList?.();
200
+ if (initDeclList) {
201
+ for (const initDecl of initDeclList.initDeclarator()) {
202
+ const declarator = initDecl.declarator?.();
203
+ if (!declarator) continue;
204
+
205
+ const name = this.extractDeclaratorName(declarator);
206
+ if (!name) continue;
207
+
208
+ const isFunction = this.declaratorIsFunction(declarator);
209
+ const fullName = this.currentNamespace
210
+ ? `${this.currentNamespace}::${name}`
211
+ : name;
212
+
213
+ this.symbols.push({
214
+ name: fullName,
215
+ kind: isFunction ? ESymbolKind.Function : ESymbolKind.Variable,
216
+ type: baseType,
217
+ sourceFile: this.sourceFile,
218
+ sourceLine: line,
219
+ sourceLanguage: ESourceLanguage.Cpp,
220
+ isExported: true,
221
+ isDeclaration: isFunction,
222
+ parent: this.currentNamespace,
223
+ });
224
+ }
225
+ }
226
+ }
227
+
228
+ private collectClassSpecifier(classSpec: any, line: number): void {
229
+ const classHead = classSpec.classHead?.();
230
+ if (!classHead) return;
231
+
232
+ const classHeadName = classHead.classHeadName?.();
233
+ if (!classHeadName) return;
234
+
235
+ const className = classHeadName.className?.();
236
+ if (!className) return;
237
+
238
+ const identifier = className.Identifier?.();
239
+ const name = identifier?.getText();
240
+ if (!name) return;
241
+
242
+ const fullName = this.currentNamespace
243
+ ? `${this.currentNamespace}::${name}`
244
+ : name;
245
+
246
+ this.symbols.push({
247
+ name: fullName,
248
+ kind: ESymbolKind.Class,
249
+ sourceFile: this.sourceFile,
250
+ sourceLine: line,
251
+ sourceLanguage: ESourceLanguage.Cpp,
252
+ isExported: true,
253
+ parent: this.currentNamespace,
254
+ });
255
+ }
256
+
257
+ private collectEnumSpecifier(enumSpec: any, line: number): void {
258
+ const enumHead = enumSpec.enumHead?.();
259
+ if (!enumHead) return;
260
+
261
+ const identifier = enumHead.Identifier?.();
262
+ if (!identifier) return;
263
+
264
+ const name = identifier.getText();
265
+ const fullName = this.currentNamespace
266
+ ? `${this.currentNamespace}::${name}`
267
+ : name;
268
+
269
+ this.symbols.push({
270
+ name: fullName,
271
+ kind: ESymbolKind.Enum,
272
+ sourceFile: this.sourceFile,
273
+ sourceLine: line,
274
+ sourceLanguage: ESourceLanguage.Cpp,
275
+ isExported: true,
276
+ parent: this.currentNamespace,
277
+ });
278
+ }
279
+
280
+ // Helper methods
281
+
282
+ private extractDeclaratorName(declarator: any): string | null {
283
+ // Pointer declarator -> noPointerDeclarator
284
+ const ptrDecl = declarator.pointerDeclarator?.();
285
+ if (ptrDecl) {
286
+ const noPtr = ptrDecl.noPointerDeclarator?.();
287
+ if (noPtr) {
288
+ return this.extractNoPointerDeclaratorName(noPtr);
289
+ }
290
+ }
291
+
292
+ // No pointer declarator
293
+ const noPtr = declarator.noPointerDeclarator?.();
294
+ if (noPtr) {
295
+ return this.extractNoPointerDeclaratorName(noPtr);
296
+ }
297
+
298
+ return null;
299
+ }
300
+
301
+ private extractNoPointerDeclaratorName(noPtr: any): string | null {
302
+ const declId = noPtr.declaratorid?.();
303
+ if (declId) {
304
+ const idExpr = declId.idExpression?.();
305
+ if (idExpr) {
306
+ const unqualId = idExpr.unqualifiedId?.();
307
+ if (unqualId) {
308
+ const identifier = unqualId.Identifier?.();
309
+ if (identifier) {
310
+ return identifier.getText();
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ // Recursive case
317
+ const innerNoPtr = noPtr.noPointerDeclarator?.();
318
+ if (innerNoPtr) {
319
+ return this.extractNoPointerDeclaratorName(innerNoPtr);
320
+ }
321
+
322
+ return null;
323
+ }
324
+
325
+ private declaratorIsFunction(declarator: any): boolean {
326
+ const ptrDecl = declarator.pointerDeclarator?.();
327
+ if (ptrDecl) {
328
+ const noPtr = ptrDecl.noPointerDeclarator?.();
329
+ if (noPtr?.parametersAndQualifiers?.()) {
330
+ return true;
331
+ }
332
+ }
333
+
334
+ const noPtr = declarator.noPointerDeclarator?.();
335
+ if (noPtr?.parametersAndQualifiers?.()) {
336
+ return true;
337
+ }
338
+
339
+ return false;
340
+ }
341
+
342
+ private extractTypeFromDeclSpecSeq(declSpecSeq: any): string {
343
+ const parts: string[] = [];
344
+
345
+ for (const spec of declSpecSeq.declSpecifier?.() ?? []) {
346
+ const typeSpec = spec.typeSpecifier?.();
347
+ if (typeSpec) {
348
+ const trailingType = typeSpec.trailingTypeSpecifier?.();
349
+ if (trailingType) {
350
+ const simpleType = trailingType.simpleTypeSpecifier?.();
351
+ if (simpleType) {
352
+ parts.push(simpleType.getText());
353
+ }
354
+ }
355
+ }
356
+ }
357
+
358
+ return parts.join(" ") || "int";
359
+ }
360
+ }
361
+
362
+ export default CppSymbolCollector;
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Unified Symbol Table
3
+ * Stores symbols from all source languages and detects conflicts
4
+ */
5
+
6
+ import ISymbol from "../types/ISymbol";
7
+ import ESourceLanguage from "../types/ESourceLanguage";
8
+ import IConflict from "./types/IConflict";
9
+
10
+ /**
11
+ * Struct field information
12
+ */
13
+ interface IStructFieldInfo {
14
+ /** Field type (e.g., "uint32_t", "uint16_t") */
15
+ type: string;
16
+ /** Array dimensions if field is an array */
17
+ arrayDimensions?: number[];
18
+ }
19
+
20
+ /**
21
+ * Central symbol table for cross-language interoperability
22
+ *
23
+ * Per user requirement: Symbol conflicts between C-Next and C/C++ are ERRORS.
24
+ * - ERROR: Same symbol defined in C-Next and C/C++
25
+ * - OK: Multiple `extern` declarations in C (declaration, not definition)
26
+ * - OK: Function overloads in C++ (different signatures)
27
+ */
28
+ class SymbolTable {
29
+ /** All symbols indexed by name */
30
+ private symbols: Map<string, ISymbol[]> = new Map();
31
+
32
+ /** Symbols indexed by source file */
33
+ private byFile: Map<string, ISymbol[]> = new Map();
34
+
35
+ /** Struct field information: struct name -> (field name -> field info) */
36
+ private structFields: Map<string, Map<string, IStructFieldInfo>> = new Map();
37
+
38
+ /**
39
+ * Add a symbol to the table
40
+ */
41
+ addSymbol(symbol: ISymbol): void {
42
+ // Add to name index
43
+ const existing = this.symbols.get(symbol.name);
44
+ if (existing) {
45
+ existing.push(symbol);
46
+ } else {
47
+ this.symbols.set(symbol.name, [symbol]);
48
+ }
49
+
50
+ // Add to file index
51
+ const fileSymbols = this.byFile.get(symbol.sourceFile);
52
+ if (fileSymbols) {
53
+ fileSymbols.push(symbol);
54
+ } else {
55
+ this.byFile.set(symbol.sourceFile, [symbol]);
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Add multiple symbols at once
61
+ */
62
+ addSymbols(symbols: ISymbol[]): void {
63
+ for (const symbol of symbols) {
64
+ this.addSymbol(symbol);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get a symbol by name (returns first match, or undefined)
70
+ */
71
+ getSymbol(name: string): ISymbol | undefined {
72
+ const symbols = this.symbols.get(name);
73
+ return symbols?.[0];
74
+ }
75
+
76
+ /**
77
+ * Get all symbols with a given name (for overload detection)
78
+ */
79
+ getOverloads(name: string): ISymbol[] {
80
+ return this.symbols.get(name) ?? [];
81
+ }
82
+
83
+ /**
84
+ * Check if a symbol exists
85
+ */
86
+ hasSymbol(name: string): boolean {
87
+ return this.symbols.has(name);
88
+ }
89
+
90
+ /**
91
+ * Check if a symbol has conflicts
92
+ */
93
+ hasConflict(name: string): boolean {
94
+ const symbols = this.symbols.get(name);
95
+ if (!symbols || symbols.length <= 1) {
96
+ return false;
97
+ }
98
+
99
+ return this.detectConflict(symbols) !== null;
100
+ }
101
+
102
+ /**
103
+ * Get all conflicts in the symbol table
104
+ * Per user requirement: Strict errors for cross-language conflicts
105
+ */
106
+ getConflicts(): IConflict[] {
107
+ const conflicts: IConflict[] = [];
108
+
109
+ for (const [, symbols] of this.symbols) {
110
+ if (symbols.length <= 1) continue;
111
+
112
+ const conflict = this.detectConflict(symbols);
113
+ if (conflict) {
114
+ conflicts.push(conflict);
115
+ }
116
+ }
117
+
118
+ return conflicts;
119
+ }
120
+
121
+ /**
122
+ * Get symbols by source file
123
+ */
124
+ getSymbolsByFile(file: string): ISymbol[] {
125
+ return this.byFile.get(file) ?? [];
126
+ }
127
+
128
+ /**
129
+ * Get symbols by source language
130
+ */
131
+ getSymbolsByLanguage(lang: ESourceLanguage): ISymbol[] {
132
+ const result: ISymbol[] = [];
133
+ for (const symbols of this.symbols.values()) {
134
+ for (const symbol of symbols) {
135
+ if (symbol.sourceLanguage === lang) {
136
+ result.push(symbol);
137
+ }
138
+ }
139
+ }
140
+ return result;
141
+ }
142
+
143
+ /**
144
+ * Get all symbols
145
+ */
146
+ getAllSymbols(): ISymbol[] {
147
+ const result: ISymbol[] = [];
148
+ for (const symbols of this.symbols.values()) {
149
+ result.push(...symbols);
150
+ }
151
+ return result;
152
+ }
153
+
154
+ /**
155
+ * Add struct field information
156
+ * @param structName Name of the struct
157
+ * @param fieldName Name of the field
158
+ * @param fieldType Type of the field (e.g., "uint32_t")
159
+ * @param arrayDimensions Optional array dimensions if field is an array
160
+ */
161
+ addStructField(
162
+ structName: string,
163
+ fieldName: string,
164
+ fieldType: string,
165
+ arrayDimensions?: number[],
166
+ ): void {
167
+ let fields = this.structFields.get(structName);
168
+ if (!fields) {
169
+ fields = new Map();
170
+ this.structFields.set(structName, fields);
171
+ }
172
+
173
+ fields.set(fieldName, {
174
+ type: fieldType,
175
+ arrayDimensions,
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Get struct field type
181
+ * @param structName Name of the struct
182
+ * @param fieldName Name of the field
183
+ * @returns Field type or undefined if not found
184
+ */
185
+ getStructFieldType(
186
+ structName: string,
187
+ fieldName: string,
188
+ ): string | undefined {
189
+ const fields = this.structFields.get(structName);
190
+ return fields?.get(fieldName)?.type;
191
+ }
192
+
193
+ /**
194
+ * Get struct field info (type and array dimensions)
195
+ * @param structName Name of the struct
196
+ * @param fieldName Name of the field
197
+ * @returns Field info or undefined if not found
198
+ */
199
+ getStructFieldInfo(
200
+ structName: string,
201
+ fieldName: string,
202
+ ): IStructFieldInfo | undefined {
203
+ const fields = this.structFields.get(structName);
204
+ return fields?.get(fieldName);
205
+ }
206
+
207
+ /**
208
+ * Get all fields for a struct
209
+ * @param structName Name of the struct
210
+ * @returns Map of field names to field info, or undefined if struct not found
211
+ */
212
+ getStructFields(
213
+ structName: string,
214
+ ): Map<string, IStructFieldInfo> | undefined {
215
+ return this.structFields.get(structName);
216
+ }
217
+
218
+ /**
219
+ * Clear all symbols
220
+ */
221
+ clear(): void {
222
+ this.symbols.clear();
223
+ this.byFile.clear();
224
+ this.structFields.clear();
225
+ }
226
+
227
+ /**
228
+ * Get symbol count
229
+ */
230
+ get size(): number {
231
+ let count = 0;
232
+ for (const symbols of this.symbols.values()) {
233
+ count += symbols.length;
234
+ }
235
+ return count;
236
+ }
237
+
238
+ /**
239
+ * Detect if a set of symbols with the same name represents a conflict
240
+ */
241
+ private detectConflict(symbols: ISymbol[]): IConflict | null {
242
+ // Filter out pure declarations (extern in C) - they don't count as definitions
243
+ const definitions = symbols.filter((s) => !s.isDeclaration);
244
+
245
+ if (definitions.length <= 1) {
246
+ // 0 or 1 definitions = no conflict
247
+ return null;
248
+ }
249
+
250
+ // Check for C++ function overloads (different signatures are OK)
251
+ const cppFunctions = definitions.filter(
252
+ (s) => s.sourceLanguage === ESourceLanguage.Cpp && s.signature,
253
+ );
254
+ if (cppFunctions.length === definitions.length) {
255
+ // All are C++ functions with signatures
256
+ const uniqueSignatures = new Set(cppFunctions.map((s) => s.signature));
257
+ if (uniqueSignatures.size === cppFunctions.length) {
258
+ // All signatures are unique = valid overload, no conflict
259
+ return null;
260
+ }
261
+ }
262
+
263
+ // Check for cross-language conflict (C-Next vs C or C++)
264
+ const cnextDefs = definitions.filter(
265
+ (s) => s.sourceLanguage === ESourceLanguage.CNext,
266
+ );
267
+ const cDefs = definitions.filter(
268
+ (s) => s.sourceLanguage === ESourceLanguage.C,
269
+ );
270
+ const cppDefs = definitions.filter(
271
+ (s) => s.sourceLanguage === ESourceLanguage.Cpp,
272
+ );
273
+
274
+ if (cnextDefs.length > 0 && (cDefs.length > 0 || cppDefs.length > 0)) {
275
+ // C-Next + C/C++ conflict = ERROR
276
+ const locations = definitions.map(
277
+ (s) =>
278
+ `${s.sourceLanguage.toUpperCase()} (${s.sourceFile}:${s.sourceLine})`,
279
+ );
280
+
281
+ return {
282
+ symbolName: definitions[0].name,
283
+ definitions,
284
+ severity: "error",
285
+ message: `Symbol conflict: '${definitions[0].name}' is defined in multiple languages:\n ${locations.join("\n ")}\nRename the C-Next symbol to resolve.`,
286
+ };
287
+ }
288
+
289
+ // Multiple definitions in same language (excluding overloads) = ERROR
290
+ if (cnextDefs.length > 1) {
291
+ const locations = cnextDefs.map((s) => `${s.sourceFile}:${s.sourceLine}`);
292
+ return {
293
+ symbolName: definitions[0].name,
294
+ definitions: cnextDefs,
295
+ severity: "error",
296
+ message: `Symbol conflict: '${definitions[0].name}' is defined multiple times in C-Next:\n ${locations.join("\n ")}`,
297
+ };
298
+ }
299
+
300
+ // Same symbol in C and C++ - typically OK (same symbol)
301
+ // But if they have different types, might be a warning
302
+ if (cDefs.length > 0 && cppDefs.length > 0) {
303
+ // For now, allow C/C++ to share symbols (common pattern)
304
+ return null;
305
+ }
306
+
307
+ return null;
308
+ }
309
+ }
310
+
311
+ export default SymbolTable;
312
+ export type { IStructFieldInfo };
@@ -0,0 +1,20 @@
1
+ import ISymbol from "../../types/ISymbol";
2
+
3
+ /**
4
+ * Represents a symbol conflict between languages
5
+ */
6
+ interface IConflict {
7
+ /** The conflicting symbol name */
8
+ symbolName: string;
9
+
10
+ /** All definitions of this symbol */
11
+ definitions: ISymbol[];
12
+
13
+ /** Conflict severity */
14
+ severity: "error" | "warning";
15
+
16
+ /** Human-readable message */
17
+ message: string;
18
+ }
19
+
20
+ export default IConflict;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Source language of a symbol
3
+ */
4
+ enum ESourceLanguage {
5
+ CNext = "cnext",
6
+ C = "c",
7
+ Cpp = "cpp",
8
+ }
9
+
10
+ export default ESourceLanguage;