c-next 0.1.33 → 0.1.34

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 (161) hide show
  1. package/README.md +7 -0
  2. package/package.json +7 -6
  3. package/src/analysis/DivisionByZeroAnalyzer.test.ts +2 -2
  4. package/src/analysis/DivisionByZeroAnalyzer.ts +9 -190
  5. package/src/analysis/FloatModuloAnalyzer.test.ts +2 -2
  6. package/src/analysis/FloatModuloAnalyzer.ts +9 -21
  7. package/src/analysis/FunctionCallAnalyzer.test.ts +105 -3
  8. package/src/analysis/FunctionCallAnalyzer.ts +53 -13
  9. package/src/analysis/InitializationAnalyzer.ts +18 -54
  10. package/src/analysis/NullCheckAnalyzer.test.ts +1347 -0
  11. package/src/analysis/NullCheckAnalyzer.ts +16 -20
  12. package/src/analysis/ParameterNamingAnalyzer.test.ts +2 -2
  13. package/src/analysis/ParameterNamingAnalyzer.ts +2 -2
  14. package/src/analysis/StructFieldAnalyzer.ts +3 -3
  15. package/src/codegen/CodeGenerator.ts +98 -95
  16. package/src/codegen/CommentExtractor.test.ts +1 -1
  17. package/src/codegen/CommentExtractor.ts +1 -1
  18. package/src/codegen/CommentFormatter.ts +1 -1
  19. package/src/codegen/HeaderGenerator.test.ts +131 -0
  20. package/src/codegen/HeaderGenerator.ts +90 -6
  21. package/src/codegen/TypeResolver.test.ts +1 -1
  22. package/src/codegen/TypeResolver.ts +9 -9
  23. package/src/codegen/TypeValidator.test.ts +1 -1
  24. package/src/codegen/TypeValidator.ts +23 -23
  25. package/src/codegen/generators/IGeneratorInput.ts +1 -1
  26. package/src/codegen/generators/IOrchestrator.ts +1 -1
  27. package/src/codegen/generators/ISymbolInfo.ts +14 -0
  28. package/src/codegen/generators/declarationGenerators/BitmapGenerator.ts +1 -1
  29. package/src/codegen/generators/declarationGenerators/EnumGenerator.ts +1 -1
  30. package/src/codegen/generators/declarationGenerators/FunctionGenerator.ts +1 -1
  31. package/src/codegen/generators/declarationGenerators/RegisterGenerator.ts +1 -1
  32. package/src/codegen/generators/declarationGenerators/ScopeGenerator.ts +4 -4
  33. package/src/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +1 -1
  34. package/src/codegen/generators/declarationGenerators/StructGenerator.ts +1 -1
  35. package/src/codegen/generators/expressions/BinaryExprGenerator.ts +7 -7
  36. package/src/codegen/generators/expressions/CallExprGenerator.ts +1 -1
  37. package/src/codegen/generators/expressions/ExpressionGenerator.ts +1 -1
  38. package/src/codegen/generators/expressions/LiteralGenerator.ts +6 -6
  39. package/src/codegen/generators/expressions/UnaryExprGenerator.ts +1 -1
  40. package/src/codegen/generators/statements/ControlFlowGenerator.ts +1 -1
  41. package/src/codegen/generators/statements/CriticalGenerator.ts +1 -1
  42. package/src/codegen/generators/statements/SwitchGenerator.ts +1 -1
  43. package/src/codegen/generators/support/IncludeGenerator.ts +6 -6
  44. package/src/codegen/headerGenerators/mapType.test.ts +73 -1
  45. package/src/codegen/headerGenerators/mapType.ts +28 -2
  46. package/src/codegen/types/ICodeGeneratorOptions.ts +7 -0
  47. package/src/codegen/types/IHeaderOptions.ts +8 -0
  48. package/src/codegen/types/ITypeResolverDeps.ts +4 -4
  49. package/src/codegen/types/ITypeValidatorDeps.ts +4 -4
  50. package/src/commands/CleanCommand.ts +2 -2
  51. package/src/constants/TypeConstants.test.ts +29 -0
  52. package/src/constants/TypeConstants.ts +25 -0
  53. package/src/index.ts +2 -2
  54. package/src/lib/IncludeDiscovery.ts +2 -2
  55. package/src/lib/IncludeResolver.test.ts +2 -2
  56. package/src/lib/IncludeResolver.ts +2 -2
  57. package/src/lib/InputExpansion.ts +2 -2
  58. package/src/lib/parseWithSymbols.ts +9 -6
  59. package/src/lib/transpiler.ts +2 -2
  60. package/src/pipeline/CacheManager.ts +47 -24
  61. package/src/pipeline/Pipeline.ts +131 -25
  62. package/src/pipeline/__tests__/CacheManager.test.ts +838 -0
  63. package/src/pipeline/cache/CacheKeyGenerator.ts +36 -0
  64. package/src/pipeline/cache/__tests__/CacheKeyGenerator.test.ts +104 -0
  65. package/src/pipeline/runAnalyzers.ts +2 -2
  66. package/src/pipeline/types/ICachedFileEntry.ts +3 -3
  67. package/src/pipeline/types/IFileResult.ts +3 -0
  68. package/src/preprocessor/Preprocessor.ts +9 -9
  69. package/src/preprocessor/ToolchainDetector.ts +3 -3
  70. package/src/project/FileDiscovery.ts +2 -2
  71. package/src/project/Project.ts +1 -1
  72. package/src/{symbols → symbol_resolution}/CSymbolCollector.ts +1 -1
  73. package/src/{symbols → symbol_resolution}/CppSymbolCollector.ts +1 -1
  74. package/src/{symbols → symbol_resolution}/SymbolUtils.ts +2 -2
  75. package/src/symbol_resolution/cnext/__tests__/BitmapCollector.test.ts +162 -0
  76. package/src/symbol_resolution/cnext/__tests__/CNextResolver.integration.test.ts +359 -0
  77. package/src/symbol_resolution/cnext/__tests__/EnumCollector.test.ts +158 -0
  78. package/src/symbol_resolution/cnext/__tests__/FunctionCollector.test.ts +241 -0
  79. package/src/symbol_resolution/cnext/__tests__/RegisterCollector.test.ts +189 -0
  80. package/src/symbol_resolution/cnext/__tests__/ScopeCollector.test.ts +290 -0
  81. package/src/symbol_resolution/cnext/__tests__/StructCollector.test.ts +214 -0
  82. package/src/symbol_resolution/cnext/__tests__/TSymbolAdapter.test.ts +447 -0
  83. package/src/symbol_resolution/cnext/__tests__/TSymbolInfoAdapter.test.ts +595 -0
  84. package/src/symbol_resolution/cnext/__tests__/VariableCollector.test.ts +156 -0
  85. package/src/symbol_resolution/cnext/__tests__/testHelpers.ts +43 -0
  86. package/src/symbol_resolution/cnext/adapters/TSymbolAdapter.ts +281 -0
  87. package/src/symbol_resolution/cnext/adapters/TSymbolInfoAdapter.ts +370 -0
  88. package/src/symbol_resolution/cnext/collectors/BitmapCollector.ts +72 -0
  89. package/src/symbol_resolution/cnext/collectors/EnumCollector.ts +68 -0
  90. package/src/symbol_resolution/cnext/collectors/FunctionCollector.ts +101 -0
  91. package/src/symbol_resolution/cnext/collectors/RegisterCollector.ts +82 -0
  92. package/src/symbol_resolution/cnext/collectors/ScopeCollector.ts +156 -0
  93. package/src/symbol_resolution/cnext/collectors/StructCollector.ts +108 -0
  94. package/src/symbol_resolution/cnext/collectors/VariableCollector.ts +87 -0
  95. package/src/symbol_resolution/cnext/index.ts +170 -0
  96. package/src/symbol_resolution/cnext/types/IScopeCollectorResult.ts +14 -0
  97. package/src/symbol_resolution/cnext/utils/ExpressionEvaluator.ts +39 -0
  98. package/src/symbol_resolution/cnext/utils/TypeUtils.ts +91 -0
  99. package/src/symbol_resolution/types/IBaseSymbol.ts +24 -0
  100. package/src/symbol_resolution/types/IBitmapFieldInfo.ts +13 -0
  101. package/src/symbol_resolution/types/IBitmapSymbol.ts +23 -0
  102. package/src/symbol_resolution/types/IEnumSymbol.ts +18 -0
  103. package/src/symbol_resolution/types/IFieldInfo.ts +18 -0
  104. package/src/symbol_resolution/types/IFunctionSymbol.ts +25 -0
  105. package/src/symbol_resolution/types/IParameterInfo.ts +24 -0
  106. package/src/symbol_resolution/types/IRegisterMemberInfo.ts +19 -0
  107. package/src/symbol_resolution/types/IRegisterSymbol.ts +20 -0
  108. package/src/symbol_resolution/types/IScopeSymbol.ts +19 -0
  109. package/src/symbol_resolution/types/IStructSymbol.ts +16 -0
  110. package/src/symbol_resolution/types/IVariableSymbol.ts +27 -0
  111. package/src/symbol_resolution/types/TSymbol.ts +36 -0
  112. package/src/symbol_resolution/types/__tests__/SymbolGuards.test.ts +243 -0
  113. package/src/symbol_resolution/types/typeGuards.ts +44 -0
  114. package/src/types/ESymbolKind.ts +0 -1
  115. package/src/utils/ExpressionUtils.test.ts +316 -0
  116. package/src/utils/ExpressionUtils.ts +144 -0
  117. package/src/utils/LiteralUtils.test.ts +344 -0
  118. package/src/utils/LiteralUtils.ts +92 -0
  119. package/src/utils/ParserUtils.test.ts +104 -0
  120. package/src/utils/ParserUtils.ts +34 -0
  121. package/src/utils/types/ISourcePosition.ts +9 -0
  122. package/src/analysis/types/formatInitializationError.ts +0 -20
  123. package/src/codegen/SymbolCollector.ts +0 -758
  124. package/src/codegen/generators/expressions/index.ts +0 -33
  125. package/src/codegen/generators/statements/index.ts +0 -29
  126. package/src/codegen/generators/support/index.ts +0 -37
  127. package/src/codegen/headerGenerators/index.ts +0 -18
  128. package/src/codegen/types/IAssignmentContext.ts +0 -12
  129. package/src/codegen/types/TCodeGenContext.ts +0 -33
  130. package/src/lib/PlatformIODetector.ts +0 -162
  131. package/src/lib/parse.ts +0 -16
  132. package/src/symbols/CNextSymbolCollector.ts +0 -507
  133. /package/src/{parser → antlr_parser}/c/grammar/C.interp +0 -0
  134. /package/src/{parser → antlr_parser}/c/grammar/C.tokens +0 -0
  135. /package/src/{parser → antlr_parser}/c/grammar/CLexer.interp +0 -0
  136. /package/src/{parser → antlr_parser}/c/grammar/CLexer.tokens +0 -0
  137. /package/src/{parser → antlr_parser}/c/grammar/CLexer.ts +0 -0
  138. /package/src/{parser → antlr_parser}/c/grammar/CListener.ts +0 -0
  139. /package/src/{parser → antlr_parser}/c/grammar/CParser.ts +0 -0
  140. /package/src/{parser → antlr_parser}/c/grammar/CVisitor.ts +0 -0
  141. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Lexer.interp +0 -0
  142. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Lexer.tokens +0 -0
  143. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Lexer.ts +0 -0
  144. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Parser.interp +0 -0
  145. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Parser.tokens +0 -0
  146. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14Parser.ts +0 -0
  147. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14ParserListener.ts +0 -0
  148. /package/src/{parser → antlr_parser}/cpp/grammar/CPP14ParserVisitor.ts +0 -0
  149. /package/src/{parser → antlr_parser}/grammar/CNext.interp +0 -0
  150. /package/src/{parser → antlr_parser}/grammar/CNext.tokens +0 -0
  151. /package/src/{parser → antlr_parser}/grammar/CNextLexer.interp +0 -0
  152. /package/src/{parser → antlr_parser}/grammar/CNextLexer.tokens +0 -0
  153. /package/src/{parser → antlr_parser}/grammar/CNextLexer.ts +0 -0
  154. /package/src/{parser → antlr_parser}/grammar/CNextListener.ts +0 -0
  155. /package/src/{parser → antlr_parser}/grammar/CNextParser.ts +0 -0
  156. /package/src/{parser → antlr_parser}/grammar/CNextVisitor.ts +0 -0
  157. /package/src/{symbols → symbol_resolution}/SymbolTable.test.ts +0 -0
  158. /package/src/{symbols → symbol_resolution}/SymbolTable.ts +0 -0
  159. /package/src/{symbols → symbol_resolution}/SymbolUtils.test.ts +0 -0
  160. /package/src/{symbols → symbol_resolution}/types/IConflict.ts +0 -0
  161. /package/src/{symbols → symbol_resolution}/types/IStructFieldInfo.ts +0 -0
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # C-Next
2
2
 
3
+ [![CI](https://github.com/jlaustill/c-next/actions/workflows/pr-checks.yml/badge.svg)](https://github.com/jlaustill/c-next/actions/workflows/pr-checks.yml)
4
+ [![npm version](https://img.shields.io/npm/v/c-next)](https://www.npmjs.com/package/c-next)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jlaustill_c-next&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=jlaustill_c-next)
7
+ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jlaustill_c-next&metric=coverage)](https://sonarcloud.io/summary/new_code?id=jlaustill_c-next)
8
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jlaustill_c-next&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jlaustill_c-next)
9
+
3
10
  A safer C for embedded systems development. Transpiles to clean, readable C.
4
11
 
5
12
  **Status: Working Transpiler** — Verified on Teensy MicroMod hardware.
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "c-next",
3
- "version": "0.1.33",
3
+ "version": "0.1.34",
4
4
  "description": "A safer C for embedded systems development. Transpiles to clean, readable C.",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
7
7
  "cnext": "./bin/cnext.js"
8
8
  },
9
9
  "scripts": {
10
- "antlr": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/parser grammar/CNext.g4",
11
- "antlr:c": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/parser/c grammar/C.g4",
12
- "antlr:cpp:lexer": "antlr4ng -Dlanguage=TypeScript -o src/parser/cpp grammar/CPP14Lexer.g4",
13
- "antlr:cpp:parser": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/parser/cpp -lib src/parser/cpp/grammar grammar/CPP14Parser.g4",
10
+ "antlr": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/antlr_parser grammar/CNext.g4",
11
+ "antlr:c": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/antlr_parser/c grammar/C.g4",
12
+ "antlr:cpp:lexer": "antlr4ng -Dlanguage=TypeScript -o src/antlr_parser/cpp grammar/CPP14Lexer.g4",
13
+ "antlr:cpp:parser": "antlr4ng -Dlanguage=TypeScript -visitor -listener -o src/antlr_parser/cpp -lib src/antlr_parser/cpp/grammar grammar/CPP14Parser.g4",
14
14
  "antlr:cpp": "npm run antlr:cpp:lexer && npm run antlr:cpp:parser",
15
15
  "antlr:all": "npm run antlr && npm run antlr:c && npm run antlr:cpp",
16
16
  "start": "tsx src/index.ts",
@@ -21,7 +21,7 @@
21
21
  "test:q": "tsx scripts/test.ts -q",
22
22
  "test:update": "tsx scripts/test.ts --update",
23
23
  "analyze": "./scripts/static-analysis.sh",
24
- "clean": "rm -rf src/parser",
24
+ "clean": "rm -rf src/antlr_parser",
25
25
  "prettier:check": "prettier --check .",
26
26
  "prettier:fix": "prettier --write .",
27
27
  "oxlint:check": "oxlint src/",
@@ -73,6 +73,7 @@
73
73
  "@vitest/coverage-v8": "^3.2.4",
74
74
  "antlr4ng-cli": "^2.0.0",
75
75
  "husky": "^9.1.7",
76
+ "knip": "^5.82.1",
76
77
  "lint-staged": "^16.2.7",
77
78
  "oxlint": "^1.39.0",
78
79
  "prettier": "^3.7.4",
@@ -4,8 +4,8 @@
4
4
  */
5
5
  import { describe, it, expect } from "vitest";
6
6
  import { CharStream, CommonTokenStream } from "antlr4ng";
7
- import { CNextLexer } from "../parser/grammar/CNextLexer";
8
- import { CNextParser } from "../parser/grammar/CNextParser";
7
+ import { CNextLexer } from "../antlr_parser/grammar/CNextLexer";
8
+ import { CNextParser } from "../antlr_parser/grammar/CNextParser";
9
9
  import DivisionByZeroAnalyzer from "./DivisionByZeroAnalyzer";
10
10
 
11
11
  /**
@@ -11,9 +11,12 @@
11
11
  */
12
12
 
13
13
  import { ParseTreeWalker } from "antlr4ng";
14
- import { CNextListener } from "../parser/grammar/CNextListener";
15
- import * as Parser from "../parser/grammar/CNextParser";
14
+ import { CNextListener } from "../antlr_parser/grammar/CNextListener";
15
+ import * as Parser from "../antlr_parser/grammar/CNextParser";
16
16
  import IDivisionByZeroError from "./types/IDivisionByZeroError";
17
+ import LiteralUtils from "../utils/LiteralUtils";
18
+ import ExpressionUtils from "../utils/ExpressionUtils";
19
+ import ParserUtils from "../utils/ParserUtils";
17
20
 
18
21
  /**
19
22
  * First pass: Collect const declarations that are zero
@@ -49,147 +52,11 @@ class ConstZeroCollector extends CNextListener {
49
52
  }
50
53
 
51
54
  // Check if the expression is a literal zero
52
- if (this.isExpressionZero(expr)) {
55
+ const literal = ExpressionUtils.extractLiteral(expr);
56
+ if (literal && LiteralUtils.isZero(literal)) {
53
57
  this.constZeros.add(name);
54
58
  }
55
59
  };
56
-
57
- /**
58
- * Check if an expression evaluates to literal zero
59
- * Navigate: expression -> ternaryExpression -> orExpression -> ... -> literal
60
- */
61
- private isExpressionZero(ctx: Parser.ExpressionContext): boolean {
62
- // expression -> ternaryExpression
63
- const ternary = ctx.ternaryExpression();
64
- if (!ternary) return false;
65
-
66
- // ternaryExpression -> orExpression
67
- const orExprs = ternary.orExpression();
68
- if (!orExprs || orExprs.length === 0) return false;
69
-
70
- const orExpr = orExprs[0];
71
-
72
- // orExpression -> andExpression
73
- const andExprs = orExpr.andExpression();
74
- if (!andExprs || andExprs.length === 0) return false;
75
-
76
- const andExpr = andExprs[0];
77
-
78
- // andExpression -> equalityExpression
79
- const eqExprs = andExpr.equalityExpression();
80
- if (!eqExprs || eqExprs.length === 0) return false;
81
-
82
- const eqExpr = eqExprs[0];
83
-
84
- // equalityExpression -> relationalExpression
85
- const relExprs = eqExpr.relationalExpression();
86
- if (!relExprs || relExprs.length === 0) return false;
87
-
88
- const relExpr = relExprs[0];
89
-
90
- // relationalExpression -> bitwiseOrExpression
91
- const bitorExprs = relExpr.bitwiseOrExpression();
92
- if (!bitorExprs || bitorExprs.length === 0) return false;
93
-
94
- const bitorExpr = bitorExprs[0];
95
-
96
- // bitwiseOrExpression -> bitwiseXorExpression
97
- const bitxorExprs = bitorExpr.bitwiseXorExpression();
98
- if (!bitxorExprs || bitxorExprs.length === 0) return false;
99
-
100
- const bitxorExpr = bitxorExprs[0];
101
-
102
- // bitwiseXorExpression -> bitwiseAndExpression
103
- const bitandExprs = bitxorExpr.bitwiseAndExpression();
104
- if (!bitandExprs || bitandExprs.length === 0) return false;
105
-
106
- const bitandExpr = bitandExprs[0];
107
-
108
- // bitwiseAndExpression -> shiftExpression
109
- const shiftExprs = bitandExpr.shiftExpression();
110
- if (!shiftExprs || shiftExprs.length === 0) return false;
111
-
112
- const shiftExpr = shiftExprs[0];
113
-
114
- // shiftExpression -> additiveExpression
115
- const addExprs = shiftExpr.additiveExpression();
116
- if (!addExprs || addExprs.length === 0) return false;
117
-
118
- const addExpr = addExprs[0];
119
-
120
- // additiveExpression -> multiplicativeExpression
121
- const multExprs = addExpr.multiplicativeExpression();
122
- if (!multExprs || multExprs.length === 0) return false;
123
-
124
- const multExpr = multExprs[0];
125
-
126
- // multiplicativeExpression -> unaryExpression
127
- const unaryExprs = multExpr.unaryExpression();
128
- if (!unaryExprs || unaryExprs.length === 0) return false;
129
-
130
- const unary = unaryExprs[0];
131
-
132
- // unaryExpression -> postfixExpression
133
- const postfix = unary.postfixExpression();
134
- if (!postfix) return false;
135
-
136
- // postfixExpression -> primaryExpression
137
- const primary = postfix.primaryExpression();
138
- if (!primary) return false;
139
-
140
- // primaryExpression -> literal
141
- const literal = primary.literal();
142
- if (!literal) return false;
143
-
144
- return this.isLiteralZero(literal);
145
- }
146
-
147
- /**
148
- * Check if a literal is zero
149
- */
150
- private isLiteralZero(ctx: Parser.LiteralContext): boolean {
151
- const text = ctx.getText();
152
-
153
- // Check integer literals
154
- if (ctx.INTEGER_LITERAL()) {
155
- return text === "0";
156
- }
157
-
158
- // Check hex literals
159
- if (ctx.HEX_LITERAL()) {
160
- return text === "0x0" || text === "0X0";
161
- }
162
-
163
- // Check binary literals
164
- if (ctx.BINARY_LITERAL()) {
165
- return text === "0b0" || text === "0B0";
166
- }
167
-
168
- // Check suffixed literals
169
- if (ctx.SUFFIXED_DECIMAL()) {
170
- return text.startsWith("0u") || text.startsWith("0i");
171
- }
172
-
173
- if (ctx.SUFFIXED_HEX()) {
174
- return (
175
- text.startsWith("0x0u") ||
176
- text.startsWith("0x0i") ||
177
- text.startsWith("0X0u") ||
178
- text.startsWith("0X0i")
179
- );
180
- }
181
-
182
- if (ctx.SUFFIXED_BINARY()) {
183
- return (
184
- text.startsWith("0b0u") ||
185
- text.startsWith("0b0i") ||
186
- text.startsWith("0B0u") ||
187
- text.startsWith("0B0i")
188
- );
189
- }
190
-
191
- return false;
192
- }
193
60
  }
194
61
 
195
62
  /**
@@ -230,8 +97,7 @@ class DivisionByZeroListener extends CNextListener {
230
97
  }
231
98
 
232
99
  const rightOperand = operands[i + 1];
233
- const line = rightOperand.start?.line ?? 0;
234
- const column = rightOperand.start?.column ?? 0;
100
+ const { line, column } = ParserUtils.getPosition(rightOperand);
235
101
 
236
102
  // Check if right operand is zero
237
103
  if (this.isZero(rightOperand)) {
@@ -259,7 +125,7 @@ class DivisionByZeroListener extends CNextListener {
259
125
  // Check if it's a literal
260
126
  const literal = primaryExpr.literal();
261
127
  if (literal) {
262
- return this.isLiteralZero(literal);
128
+ return LiteralUtils.isZero(literal);
263
129
  }
264
130
 
265
131
  // Check if it's a const identifier that evaluates to zero
@@ -271,53 +137,6 @@ class DivisionByZeroListener extends CNextListener {
271
137
 
272
138
  return false;
273
139
  }
274
-
275
- /**
276
- * Check if a literal is zero
277
- */
278
- private isLiteralZero(ctx: Parser.LiteralContext): boolean {
279
- const text = ctx.getText();
280
-
281
- // Check integer literals
282
- if (ctx.INTEGER_LITERAL()) {
283
- return text === "0";
284
- }
285
-
286
- // Check hex literals
287
- if (ctx.HEX_LITERAL()) {
288
- return text === "0x0" || text === "0X0";
289
- }
290
-
291
- // Check binary literals
292
- if (ctx.BINARY_LITERAL()) {
293
- return text === "0b0" || text === "0B0";
294
- }
295
-
296
- // Check suffixed literals
297
- if (ctx.SUFFIXED_DECIMAL()) {
298
- return text.startsWith("0u") || text.startsWith("0i");
299
- }
300
-
301
- if (ctx.SUFFIXED_HEX()) {
302
- return (
303
- text.startsWith("0x0u") ||
304
- text.startsWith("0x0i") ||
305
- text.startsWith("0X0u") ||
306
- text.startsWith("0X0i")
307
- );
308
- }
309
-
310
- if (ctx.SUFFIXED_BINARY()) {
311
- return (
312
- text.startsWith("0b0u") ||
313
- text.startsWith("0b0i") ||
314
- text.startsWith("0B0u") ||
315
- text.startsWith("0B0i")
316
- );
317
- }
318
-
319
- return false;
320
- }
321
140
  }
322
141
 
323
142
  /**
@@ -4,8 +4,8 @@
4
4
  */
5
5
  import { describe, it, expect } from "vitest";
6
6
  import { CharStream, CommonTokenStream } from "antlr4ng";
7
- import { CNextLexer } from "../parser/grammar/CNextLexer";
8
- import { CNextParser } from "../parser/grammar/CNextParser";
7
+ import { CNextLexer } from "../antlr_parser/grammar/CNextLexer";
8
+ import { CNextParser } from "../antlr_parser/grammar/CNextParser";
9
9
  import FloatModuloAnalyzer from "./FloatModuloAnalyzer";
10
10
 
11
11
  /**
@@ -11,11 +11,12 @@
11
11
  */
12
12
 
13
13
  import { ParseTreeWalker } from "antlr4ng";
14
- import { CNextListener } from "../parser/grammar/CNextListener";
15
- import * as Parser from "../parser/grammar/CNextParser";
14
+ import { CNextListener } from "../antlr_parser/grammar/CNextListener";
15
+ import * as Parser from "../antlr_parser/grammar/CNextParser";
16
16
  import IFloatModuloError from "./types/IFloatModuloError";
17
-
18
- const FLOAT_TYPES = ["f32", "f64", "float", "double"];
17
+ import LiteralUtils from "../utils/LiteralUtils";
18
+ import ParserUtils from "../utils/ParserUtils";
19
+ import TypeConstants from "../constants/TypeConstants";
19
20
 
20
21
  /**
21
22
  * First pass: Collect variable declarations with float types
@@ -37,7 +38,7 @@ class FloatVariableCollector extends CNextListener {
37
38
  if (!typeCtx) return;
38
39
 
39
40
  const typeName = typeCtx.getText();
40
- if (!FLOAT_TYPES.includes(typeName)) return;
41
+ if (!TypeConstants.FLOAT_TYPES.includes(typeName)) return;
41
42
 
42
43
  const identifier = ctx.IDENTIFIER();
43
44
  if (!identifier) return;
@@ -53,7 +54,7 @@ class FloatVariableCollector extends CNextListener {
53
54
  if (!typeCtx) return;
54
55
 
55
56
  const typeName = typeCtx.getText();
56
- if (!FLOAT_TYPES.includes(typeName)) return;
57
+ if (!TypeConstants.FLOAT_TYPES.includes(typeName)) return;
57
58
 
58
59
  const identifier = ctx.IDENTIFIER();
59
60
  if (!identifier) return;
@@ -102,8 +103,7 @@ class FloatModuloListener extends CNextListener {
102
103
  const rightIsFloat = this.isFloatOperand(rightOperand);
103
104
 
104
105
  if (leftIsFloat || rightIsFloat) {
105
- const line = leftOperand.start?.line ?? 0;
106
- const column = leftOperand.start?.column ?? 0;
106
+ const { line, column } = ParserUtils.getPosition(leftOperand);
107
107
  this.analyzer.addError(line, column);
108
108
  }
109
109
  }
@@ -122,7 +122,7 @@ class FloatModuloListener extends CNextListener {
122
122
  // Check for float literal
123
123
  const literal = primaryExpr.literal();
124
124
  if (literal) {
125
- return this.isFloatLiteral(literal);
125
+ return LiteralUtils.isFloat(literal);
126
126
  }
127
127
 
128
128
  // Check for identifier that's a float variable
@@ -133,18 +133,6 @@ class FloatModuloListener extends CNextListener {
133
133
 
134
134
  return false;
135
135
  }
136
-
137
- /**
138
- * Check if a literal is a floating-point number
139
- */
140
- private isFloatLiteral(ctx: Parser.LiteralContext): boolean {
141
- // Check for FLOAT_LITERAL token
142
- if (ctx.FLOAT_LITERAL()) return true;
143
-
144
- // Check text for decimal point (fallback)
145
- const text = ctx.getText();
146
- return text.includes(".") && !text.startsWith('"');
147
- }
148
136
  }
149
137
 
150
138
  /**
@@ -4,10 +4,10 @@
4
4
  */
5
5
  import { describe, it, expect } from "vitest";
6
6
  import { CharStream, CommonTokenStream } from "antlr4ng";
7
- import { CNextLexer } from "../parser/grammar/CNextLexer";
8
- import { CNextParser } from "../parser/grammar/CNextParser";
7
+ import { CNextLexer } from "../antlr_parser/grammar/CNextLexer";
8
+ import { CNextParser } from "../antlr_parser/grammar/CNextParser";
9
9
  import FunctionCallAnalyzer from "./FunctionCallAnalyzer";
10
- import SymbolTable from "../symbols/SymbolTable";
10
+ import SymbolTable from "../symbol_resolution/SymbolTable";
11
11
  import ESourceLanguage from "../types/ESourceLanguage";
12
12
  import ESymbolKind from "../types/ESymbolKind";
13
13
 
@@ -156,6 +156,108 @@ describe("FunctionCallAnalyzer", () => {
156
156
  expect(errors).toHaveLength(1);
157
157
  expect(errors[0].code).toBe("E0422");
158
158
  });
159
+
160
+ it("should allow this.name() qualified calls within scope", () => {
161
+ const code = `
162
+ scope Test {
163
+ void helper() {
164
+ u32 x <- 1;
165
+ }
166
+
167
+ public void callsHelper() {
168
+ this.helper();
169
+ }
170
+ }
171
+ `;
172
+ const tree = parse(code);
173
+ const analyzer = new FunctionCallAnalyzer();
174
+ const errors = analyzer.analyze(tree);
175
+
176
+ expect(errors).toHaveLength(0);
177
+ });
178
+
179
+ it("should detect undefined method via this.methodName()", () => {
180
+ const code = `
181
+ scope Test {
182
+ void helper() {
183
+ u32 x <- 1;
184
+ }
185
+
186
+ public void callsUndefined() {
187
+ this.undefinedMethod();
188
+ }
189
+ }
190
+ `;
191
+ const tree = parse(code);
192
+ const analyzer = new FunctionCallAnalyzer();
193
+ const errors = analyzer.analyze(tree);
194
+
195
+ expect(errors).toHaveLength(1);
196
+ expect(errors[0].code).toBe("E0422");
197
+ expect(errors[0].message).toContain("called before definition");
198
+ });
199
+
200
+ it("should suggest this.name() for unqualified scope calls", () => {
201
+ const code = `
202
+ scope Test {
203
+ void helper() {
204
+ u32 x <- 1;
205
+ }
206
+
207
+ public void callsHelper() {
208
+ helper();
209
+ }
210
+ }
211
+ `;
212
+ const tree = parse(code);
213
+ const analyzer = new FunctionCallAnalyzer();
214
+ const errors = analyzer.analyze(tree);
215
+
216
+ expect(errors).toHaveLength(1);
217
+ expect(errors[0].code).toBe("E0422");
218
+ expect(errors[0].functionName).toBe("helper");
219
+ expect(errors[0].message).toContain("scope");
220
+ expect(errors[0].message).toContain("this.helper()");
221
+ });
222
+
223
+ it("should not suggest this. for truly undefined in scope", () => {
224
+ const code = `
225
+ scope Test {
226
+ public void callsUnknown() {
227
+ unknownFunc();
228
+ }
229
+ }
230
+ `;
231
+ const tree = parse(code);
232
+ const analyzer = new FunctionCallAnalyzer();
233
+ const errors = analyzer.analyze(tree);
234
+
235
+ expect(errors).toHaveLength(1);
236
+ expect(errors[0].code).toBe("E0422");
237
+ expect(errors[0].message).toContain("called before definition");
238
+ expect(errors[0].message).not.toContain("this.");
239
+ });
240
+
241
+ it("should not suggest this. for calls outside scope", () => {
242
+ const code = `
243
+ scope Test {
244
+ public void helper() {
245
+ u32 x <- 1;
246
+ }
247
+ }
248
+
249
+ void main() {
250
+ helper();
251
+ }
252
+ `;
253
+ const tree = parse(code);
254
+ const analyzer = new FunctionCallAnalyzer();
255
+ const errors = analyzer.analyze(tree);
256
+
257
+ expect(errors).toHaveLength(1);
258
+ expect(errors[0].message).toContain("called before definition");
259
+ expect(errors[0].message).not.toContain("this.");
260
+ });
159
261
  });
160
262
 
161
263
  // ========================================================================
@@ -8,12 +8,13 @@
8
8
  */
9
9
 
10
10
  import { ParseTreeWalker } from "antlr4ng";
11
- import { CNextListener } from "../parser/grammar/CNextListener";
12
- import * as Parser from "../parser/grammar/CNextParser";
13
- import SymbolTable from "../symbols/SymbolTable";
11
+ import { CNextListener } from "../antlr_parser/grammar/CNextListener";
12
+ import * as Parser from "../antlr_parser/grammar/CNextParser";
13
+ import SymbolTable from "../symbol_resolution/SymbolTable";
14
14
  import ESourceLanguage from "../types/ESourceLanguage";
15
15
  import ESymbolKind from "../types/ESymbolKind";
16
16
  import IFunctionCallError from "./types/IFunctionCallError";
17
+ import ParserUtils from "../utils/ParserUtils";
17
18
 
18
19
  /**
19
20
  * C-Next built-in functions
@@ -326,11 +327,17 @@ class FunctionCallListener extends CNextListener {
326
327
  // 3. Method-style call: obj.method() - not a C-Next function
327
328
 
328
329
  const primary = ctx.primaryExpression();
329
- if (!primary.IDENTIFIER()) {
330
- return; // Not a simple identifier-based call
330
+
331
+ // Determine the base name: could be an identifier or 'this'
332
+ let baseName: string;
333
+ if (primary.IDENTIFIER()) {
334
+ baseName = primary.IDENTIFIER()!.getText();
335
+ } else if (primary.THIS()) {
336
+ baseName = "this";
337
+ } else {
338
+ return; // Not a simple identifier-based or this-based call
331
339
  }
332
340
 
333
- const baseName = primary.IDENTIFIER()!.getText();
334
341
  let resolvedName = baseName;
335
342
  let callOpIndex = -1;
336
343
 
@@ -338,12 +345,16 @@ class FunctionCallListener extends CNextListener {
338
345
  for (let i = 0; i < ops.length; i++) {
339
346
  const op = ops[i];
340
347
 
341
- // Member access: check if it's Scope.member pattern
348
+ // Member access: check if it's Scope.member or this.member pattern
342
349
  if (op.IDENTIFIER()) {
343
350
  const memberName = op.IDENTIFIER()!.getText();
344
351
 
352
+ // Handle this.member -> CurrentScope_member (when inside a scope)
353
+ if (resolvedName === "this" && this.currentScope) {
354
+ resolvedName = `${this.currentScope}_${memberName}`;
355
+ }
345
356
  // Check if base is a known scope
346
- if (this.analyzer.isScope(resolvedName)) {
357
+ else if (this.analyzer.isScope(resolvedName)) {
347
358
  // Scope.member -> Scope_member
348
359
  resolvedName = `${resolvedName}_${memberName}`;
349
360
  } else {
@@ -365,9 +376,13 @@ class FunctionCallListener extends CNextListener {
365
376
 
366
377
  // If we found a call, check if the function is defined
367
378
  if (callOpIndex >= 0) {
368
- const line = ctx.start?.line ?? 0;
369
- const column = ctx.start?.column ?? 0;
370
- this.analyzer.checkFunctionCall(resolvedName, line, column);
379
+ const { line, column } = ParserUtils.getPosition(ctx);
380
+ this.analyzer.checkFunctionCall(
381
+ resolvedName,
382
+ line,
383
+ column,
384
+ this.currentScope,
385
+ );
371
386
  }
372
387
  };
373
388
  }
@@ -449,7 +464,7 @@ class FunctionCallAnalyzer {
449
464
  for (const include of tree.includeDirective()) {
450
465
  // Extract header name from #include <header.h> or #include "header.h"
451
466
  const text = include.getText();
452
- const match = text.match(/#include\s*[<"]([^>"]+)[>"]/);
467
+ const match = /#include\s*[<"]([^>"]+)[>"]/.exec(text);
453
468
  if (match) {
454
469
  this.includedHeaders.add(match[1]);
455
470
  }
@@ -526,8 +541,17 @@ class FunctionCallAnalyzer {
526
541
 
527
542
  /**
528
543
  * Check if a function call is valid (function is defined or external)
544
+ * @param name The function name being called
545
+ * @param line Source line number
546
+ * @param column Source column number
547
+ * @param currentScope The current scope name (if inside a scope)
529
548
  */
530
- public checkFunctionCall(name: string, line: number, column: number): void {
549
+ public checkFunctionCall(
550
+ name: string,
551
+ line: number,
552
+ column: number,
553
+ currentScope: string | null,
554
+ ): void {
531
555
  // Check for self-recursion (MISRA C:2012 Rule 17.2)
532
556
  if (this.currentFunctionName && name === this.currentFunctionName) {
533
557
  this.errors.push({
@@ -565,6 +589,22 @@ class FunctionCallAnalyzer {
565
589
  return; // OK - invoking a function pointer variable
566
590
  }
567
591
 
592
+ // Check if this is an unqualified call to a scope function
593
+ // e.g., calling helper() instead of this.helper() inside a scope
594
+ if (currentScope) {
595
+ const qualifiedName = `${currentScope}_${name}`;
596
+ if (this.definedFunctions.has(qualifiedName)) {
597
+ this.errors.push({
598
+ code: "E0422",
599
+ functionName: name,
600
+ line,
601
+ column,
602
+ message: `'${name}' is a scope function - use 'this.${name}()' to call it`,
603
+ });
604
+ return;
605
+ }
606
+ }
607
+
568
608
  // Not defined - report error
569
609
  this.errors.push({
570
610
  code: "E0422",