001package gudusoft.gsqlparser.pp2.render; 002 003import gudusoft.gsqlparser.pp2.RendererId; 004import gudusoft.gsqlparser.pp2.region.StatementRange; 005 006/** 007 * Immutable coupling of a {@link StatementRange} and the text a 008 * {@link RegionRenderer} produced for that range. 009 * 010 * <p>Created by {@code Pp2Engine} (S16) after dispatching each region to the 011 * appropriate renderer, and consumed by {@link RegionAssembler} (S15) which 012 * interleaves the rendered texts with the original inter-region trivia. 013 * 014 * <h2>Leading-whitespace convention</h2> 015 * 016 * <p>Every {@code RegionRenderer} implementation omits the leading whitespace 017 * for the <em>first</em> token of its range — the bytes that sit in the 018 * original source between the previous region's end and this region's first 019 * token. The {@link RegionAssembler} is the counterparty: it fills those gaps 020 * verbatim from {@link gudusoft.gsqlparser.pp2.token.SourceSpanLedger#getSource()}. 021 * 022 * <p>Plan reference: §10.4 (engine dispatch loop), §7.3/S15, §7.3/S16. 023 */ 024public final class RenderedRegion { 025 026 private final StatementRange range; 027 private final String text; 028 private final RendererId rendererId; 029 030 /** 031 * @param range the statement boundary covering this rendering; 032 * {@link StatementRange#getStartOffset()} and 033 * {@link StatementRange#getEndOffset()} are the byte 034 * coordinates the assembler reads to locate inter-region 035 * trivia 036 * @param text the rendered output; {@code ""} is valid for an empty 037 * region; must not be {@code null} 038 * @param rendererId which renderer produced {@code text}; non-null 039 */ 040 public RenderedRegion(StatementRange range, String text, RendererId rendererId) { 041 if (range == null) throw new NullPointerException("range"); 042 if (text == null) throw new NullPointerException("text"); 043 if (rendererId == null) throw new NullPointerException("rendererId"); 044 this.range = range; 045 this.text = text; 046 this.rendererId = rendererId; 047 } 048 049 /** The statement boundary this rendering covers. */ 050 public StatementRange getRange() { return range; } 051 052 /** 053 * The rendered output text. By convention, starts with the first token's 054 * text (no leading whitespace); ends with the last token's text (no 055 * trailing whitespace from the inter-region gap). May be {@code ""} for 056 * a legitimately empty region. 057 */ 058 public String getText() { return text; } 059 060 /** Which renderer produced this text. */ 061 public RendererId getRendererId() { return rendererId; } 062 063 @Override 064 public String toString() { 065 return "RenderedRegion{" + rendererId + " " + range 066 + " textLen=" + text.length() + "}"; 067 } 068}