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,240 @@
1
+ import { CommonTokenStream, Token } from "antlr4ng";
2
+ import { CNextLexer } from "../parser/grammar/CNextLexer";
3
+ import ECommentType from "./types/ECommentType";
4
+ import IComment from "./types/IComment";
5
+ import ICommentError from "./types/ICommentError";
6
+
7
+ /**
8
+ * Extracts and validates comments from the HIDDEN channel (ADR-043)
9
+ *
10
+ * - Extracts LINE_COMMENT, BLOCK_COMMENT, DOC_COMMENT tokens
11
+ * - Validates MISRA C:2012 Rule 3.1 (no nested comment markers)
12
+ * - Validates MISRA C:2012 Rule 3.2 (no line-splice in line comments)
13
+ */
14
+ class CommentExtractor {
15
+ private tokenStream: CommonTokenStream;
16
+
17
+ private comments: IComment[] | null = null;
18
+
19
+ private errors: ICommentError[] = [];
20
+
21
+ constructor(tokenStream: CommonTokenStream) {
22
+ this.tokenStream = tokenStream;
23
+ }
24
+
25
+ /**
26
+ * Extract all comments from the token stream
27
+ */
28
+ extractAll(): IComment[] {
29
+ if (this.comments !== null) {
30
+ return this.comments;
31
+ }
32
+
33
+ this.tokenStream.fill();
34
+ this.comments = [];
35
+
36
+ // Get all tokens and filter for comments on HIDDEN channel
37
+ const size = this.tokenStream.size;
38
+ for (let i = 0; i < size; i++) {
39
+ const token = this.tokenStream.get(i);
40
+ if (token.channel === Token.HIDDEN_CHANNEL) {
41
+ const comment = this.tokenToComment(token);
42
+ if (comment) {
43
+ this.comments.push(comment);
44
+ }
45
+ }
46
+ }
47
+
48
+ return this.comments;
49
+ }
50
+
51
+ /**
52
+ * Get comments that appear before a given token index
53
+ */
54
+ getCommentsBefore(tokenIndex: number): IComment[] {
55
+ const hiddenTokens = this.tokenStream.getHiddenTokensToLeft(
56
+ tokenIndex,
57
+ Token.HIDDEN_CHANNEL,
58
+ );
59
+ if (!hiddenTokens) return [];
60
+
61
+ const comments: IComment[] = [];
62
+ for (const token of hiddenTokens) {
63
+ const comment = this.tokenToComment(token);
64
+ if (comment) {
65
+ comments.push(comment);
66
+ }
67
+ }
68
+ return comments;
69
+ }
70
+
71
+ /**
72
+ * Get inline comments that appear after a given token index (same line)
73
+ */
74
+ getCommentsAfter(tokenIndex: number): IComment[] {
75
+ const hiddenTokens = this.tokenStream.getHiddenTokensToRight(
76
+ tokenIndex,
77
+ Token.HIDDEN_CHANNEL,
78
+ );
79
+ if (!hiddenTokens) return [];
80
+
81
+ const comments: IComment[] = [];
82
+ const sourceToken = this.tokenStream.get(tokenIndex);
83
+ const sourceLine = sourceToken.line;
84
+
85
+ for (const token of hiddenTokens) {
86
+ // Only include comments on the same line (inline comments)
87
+ if (token.line !== sourceLine) break;
88
+
89
+ const comment = this.tokenToComment(token);
90
+ if (comment) {
91
+ comments.push(comment);
92
+ }
93
+ }
94
+ return comments;
95
+ }
96
+
97
+ /**
98
+ * Validate all comments against MISRA C:2012 Rules 3.1 and 3.2
99
+ */
100
+ validate(): ICommentError[] {
101
+ this.errors = [];
102
+ const comments = this.extractAll();
103
+
104
+ for (const comment of comments) {
105
+ this.validateMisra31(comment);
106
+ this.validateMisra32(comment);
107
+ }
108
+
109
+ return this.errors;
110
+ }
111
+
112
+ /**
113
+ * Get validation errors
114
+ */
115
+ getErrors(): ICommentError[] {
116
+ return this.errors;
117
+ }
118
+
119
+ /**
120
+ * Convert a token to an IComment, or null if not a comment token
121
+ */
122
+ private tokenToComment(token: Token): IComment | null {
123
+ const text = token.text;
124
+ if (!text) return null;
125
+
126
+ let type: ECommentType;
127
+ let content: string;
128
+
129
+ switch (token.type) {
130
+ case CNextLexer.DOC_COMMENT:
131
+ type = ECommentType.Doc;
132
+ content = text.slice(3).trim(); // Remove ///
133
+ break;
134
+ case CNextLexer.LINE_COMMENT:
135
+ type = ECommentType.Line;
136
+ content = text.slice(2); // Remove //
137
+ break;
138
+ case CNextLexer.BLOCK_COMMENT:
139
+ type = ECommentType.Block;
140
+ content = text.slice(2, -2); // Remove /* and */
141
+ break;
142
+ default:
143
+ return null; // Not a comment token (e.g., whitespace)
144
+ }
145
+
146
+ return {
147
+ type,
148
+ raw: text,
149
+ content,
150
+ line: token.line,
151
+ column: token.column,
152
+ tokenIndex: token.tokenIndex,
153
+ };
154
+ }
155
+
156
+ /**
157
+ * MISRA C:2012 Rule 3.1: No nested comment markers
158
+ * The character sequences /* and // shall not appear within a comment.
159
+ * Exception: :// (URI pattern) is allowed per Amendment 4
160
+ */
161
+ private validateMisra31(comment: IComment): void {
162
+ const content = comment.content;
163
+
164
+ // Check for nested /* (not part of a URI)
165
+ const nestedBlockStart = content.indexOf("/*");
166
+ if (nestedBlockStart !== -1) {
167
+ this.errors.push({
168
+ rule: "3.1",
169
+ message:
170
+ "Nested comment marker '/*' found inside comment (MISRA C:2012 Rule 3.1)",
171
+ line: comment.line,
172
+ column:
173
+ comment.column +
174
+ this.getMarkerLength(comment.type) +
175
+ nestedBlockStart,
176
+ });
177
+ }
178
+
179
+ // Check for nested // (not part of a URI like ://)
180
+ // Find all // occurrences and check if preceded by :
181
+ let searchStart = 0;
182
+ while (true) {
183
+ const slashSlash = content.indexOf("//", searchStart);
184
+ if (slashSlash === -1) break;
185
+
186
+ // Check if this is part of a URI (preceded by :)
187
+ const isUri = slashSlash > 0 && content[slashSlash - 1] === ":";
188
+
189
+ if (!isUri) {
190
+ this.errors.push({
191
+ rule: "3.1",
192
+ message:
193
+ "Nested comment marker '//' found inside comment (MISRA C:2012 Rule 3.1)",
194
+ line: comment.line,
195
+ column:
196
+ comment.column + this.getMarkerLength(comment.type) + slashSlash,
197
+ });
198
+ break; // Only report first occurrence
199
+ }
200
+
201
+ searchStart = slashSlash + 2;
202
+ }
203
+ }
204
+
205
+ /**
206
+ * MISRA C:2012 Rule 3.2: No line-splice in line comments
207
+ * Line comments ending with \ cause undefined behavior
208
+ */
209
+ private validateMisra32(comment: IComment): void {
210
+ // Only applies to line comments (// and ///)
211
+ if (comment.type === ECommentType.Block) return;
212
+
213
+ const content = comment.content;
214
+ if (content.endsWith("\\")) {
215
+ this.errors.push({
216
+ rule: "3.2",
217
+ message:
218
+ "Line comment ends with '\\' which causes line-splice (MISRA C:2012 Rule 3.2)",
219
+ line: comment.line,
220
+ column: comment.column,
221
+ });
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Get the length of the comment marker for column calculation
227
+ */
228
+ private getMarkerLength(type: ECommentType): number {
229
+ switch (type) {
230
+ case ECommentType.Doc:
231
+ return 3; // ///
232
+ case ECommentType.Line:
233
+ return 2; // //
234
+ case ECommentType.Block:
235
+ return 2; // /*
236
+ }
237
+ }
238
+ }
239
+
240
+ export default CommentExtractor;
@@ -0,0 +1,155 @@
1
+ import ECommentType from "./types/ECommentType";
2
+ import IComment from "./types/IComment";
3
+
4
+ /**
5
+ * Formats comments for C output (ADR-043)
6
+ *
7
+ * - Line comments: Keep as // (C99+ mode)
8
+ * - Block comments: Keep as block comments
9
+ * - Doc comments: Convert /// to Doxygen format
10
+ */
11
+ class CommentFormatter {
12
+ /**
13
+ * Format a single comment for C output
14
+ * @param comment The comment to format
15
+ * @param indent Indentation string (spaces)
16
+ * @returns Formatted comment string
17
+ */
18
+ format(comment: IComment, indent: string = ""): string {
19
+ switch (comment.type) {
20
+ case ECommentType.Line:
21
+ return `${indent}//${comment.content}`;
22
+
23
+ case ECommentType.Block:
24
+ return this.formatBlockComment(comment, indent);
25
+
26
+ case ECommentType.Doc:
27
+ return this.formatDocComment(comment, indent);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Format consecutive doc comments as a single Doxygen block
33
+ * @param comments Array of consecutive doc comments
34
+ * @param indent Indentation string
35
+ * @returns Formatted Doxygen comment block
36
+ */
37
+ formatDocCommentGroup(comments: IComment[], indent: string = ""): string {
38
+ if (comments.length === 0) return "";
39
+
40
+ if (comments.length === 1) {
41
+ return this.formatDocComment(comments[0], indent);
42
+ }
43
+
44
+ // Multiple doc comments -> single /** ... */ block
45
+ const lines: string[] = [];
46
+ lines.push(`${indent}/**`);
47
+
48
+ for (const comment of comments) {
49
+ const content = comment.content.trim();
50
+ if (content) {
51
+ lines.push(`${indent} * ${content}`);
52
+ } else {
53
+ lines.push(`${indent} *`);
54
+ }
55
+ }
56
+
57
+ lines.push(`${indent} */`);
58
+ return lines.join("\n");
59
+ }
60
+
61
+ /**
62
+ * Format leading comments (comments that appear before code)
63
+ * Groups consecutive doc comments into Doxygen blocks
64
+ * @param comments Array of comments
65
+ * @param indent Indentation string
66
+ * @returns Array of formatted comment strings
67
+ */
68
+ formatLeadingComments(comments: IComment[], indent: string = ""): string[] {
69
+ if (comments.length === 0) return [];
70
+
71
+ const result: string[] = [];
72
+ let docGroup: IComment[] = [];
73
+
74
+ for (const comment of comments) {
75
+ if (comment.type === ECommentType.Doc) {
76
+ docGroup.push(comment);
77
+ } else {
78
+ // Flush any accumulated doc comments
79
+ if (docGroup.length > 0) {
80
+ result.push(this.formatDocCommentGroup(docGroup, indent));
81
+ docGroup = [];
82
+ }
83
+ result.push(this.format(comment, indent));
84
+ }
85
+ }
86
+
87
+ // Flush remaining doc comments
88
+ if (docGroup.length > 0) {
89
+ result.push(this.formatDocCommentGroup(docGroup, indent));
90
+ }
91
+
92
+ return result;
93
+ }
94
+
95
+ /**
96
+ * Format a trailing/inline comment
97
+ * @param comment The comment
98
+ * @returns Formatted inline comment (with leading spaces)
99
+ */
100
+ formatTrailingComment(comment: IComment): string {
101
+ switch (comment.type) {
102
+ case ECommentType.Line:
103
+ case ECommentType.Doc:
104
+ return ` //${comment.content}`;
105
+
106
+ case ECommentType.Block:
107
+ // For inline block comments, keep on single line if possible
108
+ if (!comment.content.includes("\n")) {
109
+ return ` /*${comment.content}*/`;
110
+ }
111
+ // Multi-line block comment shouldn't be inline
112
+ return ` /*${comment.content}*/`;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Format a block comment preserving internal structure
118
+ */
119
+ private formatBlockComment(comment: IComment, indent: string): string {
120
+ const content = comment.content;
121
+
122
+ // Single-line block comment
123
+ if (!content.includes("\n")) {
124
+ return `${indent}/*${content}*/`;
125
+ }
126
+
127
+ // Multi-line block comment - preserve structure
128
+ const lines = content.split("\n");
129
+ const result: string[] = [];
130
+ result.push(`${indent}/*${lines[0]}`);
131
+
132
+ for (let i = 1; i < lines.length - 1; i++) {
133
+ result.push(`${indent}${lines[i]}`);
134
+ }
135
+
136
+ if (lines.length > 1) {
137
+ result.push(`${indent}${lines[lines.length - 1]}*/`);
138
+ }
139
+
140
+ return result.join("\n");
141
+ }
142
+
143
+ /**
144
+ * Format a single doc comment as Doxygen
145
+ */
146
+ private formatDocComment(comment: IComment, indent: string): string {
147
+ const content = comment.content.trim();
148
+ if (!content) {
149
+ return `${indent}/** */`;
150
+ }
151
+ return `${indent}/** ${content} */`;
152
+ }
153
+ }
154
+
155
+ export default CommentFormatter;
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Header Generator
3
+ * Generates C header (.h) files from C-Next source
4
+ */
5
+
6
+ import ISymbol from "../types/ISymbol";
7
+ import ESymbolKind from "../types/ESymbolKind";
8
+ import ESourceLanguage from "../types/ESourceLanguage";
9
+ import SymbolTable from "../symbols/SymbolTable";
10
+
11
+ /**
12
+ * Maps C-Next types to C types
13
+ */
14
+ const TYPE_MAP: Record<string, string> = {
15
+ u8: "uint8_t",
16
+ u16: "uint16_t",
17
+ u32: "uint32_t",
18
+ u64: "uint64_t",
19
+ i8: "int8_t",
20
+ i16: "int16_t",
21
+ i32: "int32_t",
22
+ i64: "int64_t",
23
+ f32: "float",
24
+ f64: "double",
25
+ bool: "bool",
26
+ void: "void",
27
+ ISR: "ISR", // ADR-040: Interrupt Service Routine function pointer
28
+ };
29
+
30
+ /**
31
+ * Options for header generation
32
+ */
33
+ interface IHeaderOptions {
34
+ /** Guard prefix (default: derived from filename) */
35
+ guardPrefix?: string;
36
+
37
+ /** Include system headers in the output */
38
+ includeSystemHeaders?: boolean;
39
+
40
+ /** Only generate declarations for exported symbols */
41
+ exportedOnly?: boolean;
42
+ }
43
+
44
+ /**
45
+ * Generates C header files from symbol information
46
+ */
47
+ class HeaderGenerator {
48
+ /**
49
+ * Generate a header file from symbols
50
+ */
51
+ generate(
52
+ symbols: ISymbol[],
53
+ filename: string,
54
+ options: IHeaderOptions = {},
55
+ ): string {
56
+ const lines: string[] = [];
57
+ const guard = this.makeGuard(filename, options.guardPrefix);
58
+
59
+ // Header guard
60
+ lines.push(`#ifndef ${guard}`);
61
+ lines.push(`#define ${guard}`);
62
+ lines.push("");
63
+
64
+ // Header comment
65
+ lines.push("/**");
66
+ lines.push(" * Generated by C-Next Transpiler");
67
+ lines.push(" * Header file for cross-language interoperability");
68
+ lines.push(" */");
69
+ lines.push("");
70
+
71
+ // System includes
72
+ if (options.includeSystemHeaders !== false) {
73
+ lines.push("#include <stdint.h>");
74
+ lines.push("#include <stdbool.h>");
75
+ lines.push("");
76
+ }
77
+
78
+ // C++ compatibility
79
+ lines.push("#ifdef __cplusplus");
80
+ lines.push('extern "C" {');
81
+ lines.push("#endif");
82
+ lines.push("");
83
+
84
+ // Filter symbols
85
+ const exportedSymbols = options.exportedOnly
86
+ ? symbols.filter((s) => s.isExported)
87
+ : symbols;
88
+
89
+ // Group symbols by kind
90
+ const structs = exportedSymbols.filter(
91
+ (s) => s.kind === ESymbolKind.Struct,
92
+ );
93
+ const classes = exportedSymbols.filter((s) => s.kind === ESymbolKind.Class);
94
+ const functions = exportedSymbols.filter(
95
+ (s) => s.kind === ESymbolKind.Function,
96
+ );
97
+ const variables = exportedSymbols.filter(
98
+ (s) => s.kind === ESymbolKind.Variable,
99
+ );
100
+ const enums = exportedSymbols.filter((s) => s.kind === ESymbolKind.Enum);
101
+ const types = exportedSymbols.filter((s) => s.kind === ESymbolKind.Type);
102
+
103
+ // Forward declarations for structs
104
+ if (structs.length > 0 || classes.length > 0) {
105
+ lines.push("/* Forward declarations */");
106
+ for (const sym of structs) {
107
+ lines.push(`typedef struct ${sym.name} ${sym.name};`);
108
+ }
109
+ for (const sym of classes) {
110
+ // Classes become typedefs to structs
111
+ lines.push(`typedef struct ${sym.name} ${sym.name};`);
112
+ }
113
+ lines.push("");
114
+ }
115
+
116
+ // Enum declarations
117
+ if (enums.length > 0) {
118
+ lines.push("/* Enumerations */");
119
+ for (const sym of enums) {
120
+ // For now, just forward declare - full definition would require enum values
121
+ lines.push(`/* Enum: ${sym.name} (see implementation for values) */`);
122
+ }
123
+ lines.push("");
124
+ }
125
+
126
+ // Type aliases
127
+ if (types.length > 0) {
128
+ lines.push("/* Type aliases */");
129
+ for (const sym of types) {
130
+ if (sym.type) {
131
+ const cType = this.mapType(sym.type);
132
+ lines.push(`typedef ${cType} ${sym.name};`);
133
+ }
134
+ }
135
+ lines.push("");
136
+ }
137
+
138
+ // Extern variable declarations
139
+ if (variables.length > 0) {
140
+ lines.push("/* External variables */");
141
+ for (const sym of variables) {
142
+ const cType = sym.type ? this.mapType(sym.type) : "int";
143
+ lines.push(`extern ${cType} ${sym.name};`);
144
+ }
145
+ lines.push("");
146
+ }
147
+
148
+ // Function prototypes
149
+ if (functions.length > 0) {
150
+ lines.push("/* Function prototypes */");
151
+ for (const sym of functions) {
152
+ const proto = this.generateFunctionPrototype(sym);
153
+ if (proto) {
154
+ lines.push(proto);
155
+ }
156
+ }
157
+ lines.push("");
158
+ }
159
+
160
+ // C++ compatibility end
161
+ lines.push("#ifdef __cplusplus");
162
+ lines.push("}");
163
+ lines.push("#endif");
164
+ lines.push("");
165
+
166
+ // End header guard
167
+ lines.push(`#endif /* ${guard} */`);
168
+ lines.push("");
169
+
170
+ return lines.join("\n");
171
+ }
172
+
173
+ /**
174
+ * Generate header from a symbol table, filtering by source file
175
+ */
176
+ generateFromSymbolTable(
177
+ symbolTable: SymbolTable,
178
+ sourceFile: string,
179
+ options: IHeaderOptions = {},
180
+ ): string {
181
+ const symbols = symbolTable.getSymbolsByFile(sourceFile);
182
+ const basename = sourceFile.replace(/\.[^.]+$/, "");
183
+ const headerName = `${basename}.h`;
184
+
185
+ return this.generate(symbols, headerName, options);
186
+ }
187
+
188
+ /**
189
+ * Generate header for all C-Next symbols in the symbol table
190
+ */
191
+ generateCNextHeader(
192
+ symbolTable: SymbolTable,
193
+ filename: string,
194
+ options: IHeaderOptions = {},
195
+ ): string {
196
+ const symbols = symbolTable.getSymbolsByLanguage(ESourceLanguage.CNext);
197
+ return this.generate(symbols, filename, options);
198
+ }
199
+
200
+ /**
201
+ * Create an include guard macro from filename
202
+ */
203
+ private makeGuard(filename: string, prefix?: string): string {
204
+ // Remove path and extension
205
+ const base = filename.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, "");
206
+
207
+ // Convert to uppercase and replace non-alphanumeric with underscore
208
+ const sanitized = base.toUpperCase().replace(/[^A-Z0-9]/g, "_");
209
+
210
+ if (prefix) {
211
+ return `${prefix.toUpperCase()}_${sanitized}_H`;
212
+ }
213
+
214
+ return `${sanitized}_H`;
215
+ }
216
+
217
+ /**
218
+ * Map a C-Next type to C type
219
+ */
220
+ private mapType(type: string): string {
221
+ // Check direct mapping first
222
+ if (TYPE_MAP[type]) {
223
+ return TYPE_MAP[type];
224
+ }
225
+
226
+ // Handle pointer types
227
+ if (type.endsWith("*")) {
228
+ const baseType = type.slice(0, -1).trim();
229
+ return `${this.mapType(baseType)}*`;
230
+ }
231
+
232
+ // Handle array types (simplified)
233
+ const arrayMatch = type.match(/^(\w+)\[(\d*)\]$/);
234
+ if (arrayMatch) {
235
+ const baseType = this.mapType(arrayMatch[1]);
236
+ const size = arrayMatch[2] || "";
237
+ return `${baseType}[${size}]`;
238
+ }
239
+
240
+ // User-defined types pass through
241
+ return type;
242
+ }
243
+
244
+ /**
245
+ * Generate a function prototype from symbol info
246
+ */
247
+ private generateFunctionPrototype(sym: ISymbol): string | null {
248
+ // Use signature if available
249
+ if (sym.signature) {
250
+ // Parse signature to extract return type and params
251
+ // Signature format is typically: "return_type(param1_type, param2_type, ...)"
252
+ return `${sym.signature};`;
253
+ }
254
+
255
+ // Generate from type info
256
+ const returnType = sym.type ? this.mapType(sym.type) : "void";
257
+
258
+ // For C-Next functions, all non-array parameters become pointers
259
+ // This is a simplified version - full implementation would need param info
260
+ return `${returnType} ${sym.name}(void);`;
261
+ }
262
+ }
263
+
264
+ export default HeaderGenerator;
265
+ export type { IHeaderOptions };