Class StringExpressionClassifier

java.lang.Object
org.ek9lang.compiler.repair.StringExpressionClassifier

public final class StringExpressionClassifier extends Object
Shared parse-tree primitives for selection-driven string-expression editors. Used by StringConcatRewriter (concat → backtick rewrite) and the MCP StringLiteralExtractor (single-literal extraction to i18n).

Single source of truth for "find the smallest expression whose token range matches a selection" + "is this expression a single string literal vs a `+`-style concatenation". Both editors care about exactly the same classification step; before this extraction each carried its own copy.

  • Method Details

    • findSmallestEnclosingExpression

      public static EK9Parser.ExpressionContext findSmallestEnclosingExpression(org.antlr.v4.runtime.tree.ParseTree root, int startLine, int startCol, int endLine, int endCol)
      Walk a parse tree looking for the smallest EK9Parser.ExpressionContext whose source token range exactly matches the selection. Match is start-token == (startLine, startCol-1) and stop-token-end == (endLine, endCol-1) — ANTLR columns are 0-based.

      Returns null when no expression node spans precisely the selection (typical when the caller's range covers part of a token, crosses statement boundaries, or selects whitespace).

    • isAddExpression

      public static boolean isAddExpression(EK9Parser.ExpressionContext expr)
      True when the expression's outer operator is binary + with two operand expressions. Used by both editors as the "this is a concat chain" gate.
    • isSingleStringLiteral

      public static boolean isSingleStringLiteral(EK9Parser.ExpressionContext expr)
      True when the expression resolves to a single string-literal primary — double-quoted or backtick interpolation. Idempotency check for the rewriter; primary admission gate for the extractor.
    • extractStringLit

      public static EK9Parser.StringLitContext extractStringLit(EK9Parser.ExpressionContext expr)
      Extract the stringLit parse-tree node from an expression that is a single string literal (double-quoted or backtick). Returns null when the expression is not a literal.
    • findExpressionAtCursor

      public static EK9Parser.ExpressionContext findExpressionAtCursor(org.antlr.v4.runtime.tree.ParseTree root, int line, int col)
      Walk a parse tree looking for the smallest EK9Parser.ExpressionContext whose token range CONTAINS the cursor position (line, col). 1-based columns. Mirrors findSmallestEnclosingExpression(ParseTree, int, int, int, int) but for point-containment rather than exact-range matching — the IDE right-click flow needs to find "what expression is the cursor inside" without an explicit selection.

      Returns null when no expression node contains the position (cursor on whitespace, in a comment, in indentation, etc).

    • findEnclosingConcatExpression

      public static EK9Parser.ExpressionContext findEnclosingConcatExpression(org.antlr.v4.runtime.tree.ParseTree root, int line, int col)
      Walk a parse tree looking for the smallest EK9Parser.ExpressionContext that BOTH (a) contains the cursor position and (b) is a binary + concat expression. Used by the IDE's right-click "Rewrite to Backtick Interpolation" trigger — the user clicks anywhere inside the concat (including on an operand) and we want to rewrite the enclosing concat, not the operand sub-expression.

      Returns null when no concat expression spans the cursor position.

    • findEnclosingStringLiteralExpression

      public static EK9Parser.ExpressionContext findEnclosingStringLiteralExpression(org.antlr.v4.runtime.tree.ParseTree root, int line, int col)
      Walk a parse tree looking for the smallest EK9Parser.ExpressionContext that BOTH (a) contains the cursor position and (b) is a single string literal (double-quoted or backtick interpolation). Used by the IDE's right-click "Extract to Localized Text…" trigger — the user clicks anywhere inside the literal and we want to extract the literal itself.

      Excludes concat operands — a literal that's part of a `+`-chain routes the user through the rewrite-first flow instead. Specifically: when the cursor is on a literal that's a direct child of a concat ExpressionContext, that concat case is NOT returned by this method (the literal IS returned as the smallest single-literal match, but the IDE-side menu builder gates by also checking that no enclosing concat exists — see EditorContextMenuBuilder).

      Returns null when no single-string-literal expression spans the cursor position.

    • tokenRange

      public static int[] tokenRange(EK9Parser.ExpressionContext expr)
      Token-range bounds of an expression as 1-based (line, col) coordinates. Output shape mirrors what MCP-tool selection parameters expect: [startLine, startCol, endLine, endCol], inclusive on both ends. Returns null if the expression has missing token data.
    • findEnclosingTextMethodDeclaration

      public static StringExpressionClassifier.TextMethodTarget findEnclosingTextMethodDeclaration(org.antlr.v4.runtime.tree.ParseTree root, int line, int col)
      Walk a parse tree looking for the smallest EK9Parser.TextBodyDeclarationContext that contains the cursor — i.e. the cursor is on/inside a text method definition. Returns a StringExpressionClassifier.TextMethodTarget record carrying the resolved textTypeName (from the enclosing EK9Parser.TextDeclarationContext) and methodName (from the body declaration's identifier).

      Used by the IDE's right-click "Remove Text Method…" trigger in an i18n file: cursor inside a mainWelcome() block surfaces the action with both names resolved, so the MCP dispatch is one-step (no user typing required).

      Returns null when no text body declaration contains the cursor position, or when the enclosing text-type identifier can't be resolved.