All files / TRANSPILE/1-Analyze LiteralFormAnalyzer.ts

90% Statements 9/10
75% Branches 3/4
100% Functions 2/2
90% Lines 9/10

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56                                      45x           490x   13847x 13847x 13847x       13847x                             490x 490x 490x          
/**
 * Literal Form Analyzer
 * ADR-044 "Integer Literals" (owner ruling, 2026-10-03, #1728): an integer
 * literal is decimal, `0x` hexadecimal or `0b` binary. There is no octal
 * literal, so a decimal literal never has a leading zero: `010` is E0912.
 *
 * C reads `010` as 8. The transpiler read it as 10 in some places and as no
 * value in others, so one spelling could mean two numbers in one program.
 * Every literal token is checked, wherever the grammar allows one: a const, a
 * dimension, a bitmap field width, a case label, an operand.
 */
 
import { ParseTreeWalker, TerminalNode } from "antlr4ng";
import { CNextListener } from "../../PARSE/2-Parse/grammar/CNextListener";
import * as Parser from "../../PARSE/2-Parse/grammar/CNextParser";
import LiteralUtils from "../../utils/LiteralUtils";
import type IBaseAnalysisError from "./types/IBaseAnalysisError";
 
/** The decimal literal tokens, suffixed or not; hex and binary have a prefix */
const DECIMAL_TOKENS: ReadonlySet<number> = new Set([
  Parser.CNextParser.INTEGER_LITERAL,
  Parser.CNextParser.SUFFIXED_DECIMAL,
]);
 
class LiteralFormListener extends CNextListener {
  readonly errors: IBaseAnalysisError[] = [];
 
  override visitTerminal = (node: TerminalNode): void => {
    const literal = node.getText();
    Eif (
      !DECIMAL_TOKENS.has(node.symbol.type) ||
      !LiteralUtils.hasLeadingZero(literal)
    ) {
      return;
    }
    this.errors.push({
      code: "E0912",
      line: node.symbol.line,
      column: node.symbol.column,
      message: `Integer literal '${literal}' has a leading zero: C-Next has no octal literal (ADR-044)`,
      helpText:
        "Write the value in decimal without the leading zero, or as 0x... or 0b...",
    });
  };
}
 
class LiteralFormAnalyzer {
  analyze(tree: Parser.ProgramContext): IBaseAnalysisError[] {
    const listener = new LiteralFormListener();
    ParseTreeWalker.DEFAULT.walk(listener, tree);
    return listener.errors;
  }
}
 
export default LiteralFormAnalyzer;