Table of Contents

Class NcPatchUtil

Namespace
Hi.NcParsers.NcWriteback
Assembly
HiMech.dll

Positional text-edit primitives for NcPatchWriter (the patch-mode INcPieceConverter): anchored token edits on a verbatim BlockText draft.

This is the SoftNc dual of HardNcUtil.SetTagNumber/AddBySeq with the two known defects fixed while keeping every other semantic:

Faithfully kept from HardNc: NaN deletes the token; an absent tag is inserted at the conventional word position (ConventionalTagOrder: X,Y,Z,I,J,K,A,B,C,F,S — X scans forward for the first present successor and lands before it, other tags scan backward for the nearest present predecessor and land after it, otherwise the token is appended at the end of the code region); formatted values trim trailing zeros but keep the decimal point (10.000010.), which also guards the value against no-decimal-point integer shrinking on replay.

Tag matching mirrors the parser's lexing exactly (GrabTagValue(ref string, IEnumerable<string>, string): case-insensitive, RegexFlagPrefix guard, and the full value grammar number|variable|bracket-expression) so that patch and parse agree on what a token is. A tag whose value is a variable or bracket expression is refused, never rewritten.

public static class NcPatchUtil
Inheritance
NcPatchUtil
Inherited Members

Fields

ConventionalTagOrder

Conventional Fanuc-style word order used when inserting an absent tag (mirrors HardNcUtil.AddBySeq).

public static readonly string[] ConventionalTagOrder

Field Value

string[]

Methods

FormatTagNumber(double, string)

Formats a tag number per the HardNc writeback convention: InvariantCulture, trailing zeros after the decimal point trimmed while the dot itself is kept (-50.2500-50.25, 10.000010.). Shared by the patch primitives and FanucNcSentenceComposer.

public static string FormatTagNumber(double value, string format)

Parameters

value double
format string

Returns

string

GetTagNumber(string, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>)

Reads the numeric literal of the first unprotected token of tag in blockText; NaN when the tag is absent or carries a variable/bracket/keyword value. Uses exactly the value grammar of SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool) (TagValuePattern), so a read and a subsequent edit agree on the token. The literal is parsed raw (InvariantCulture) — no dialect integer-shrink scaling is applied, unlike the parser's SoftNcUtil.GrabDouble(…, enableIntegerShrink); splition-plan callers read decimal-pointed arc words (I/J/K/R) where the raw literal equals the parsed value.

public static double GetTagNumber(string blockText, string tag, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null)

Parameters

blockText string

NC block text to read; null counts as empty.

tag string

Tag to look for, e.g. “I”.

varPrefix string

Variable index prefix of the dialect.

protectedSpans IReadOnlyList<(int Start, int Length)>

Comment spans to skip.

keywordValues IReadOnlyList<string>

Dialect keywords that can stand where the tag's number would be; null for dialects without keyword values.

Returns

double

IsCarriedSection(JsonObject, string)

True when the piece's section was injected by the pipeline (AddedByKey present: a ModalCarrySyntax clone or a backfill) rather than authored from the block's own text. A carried section's token is guaranteed absent from BlockText — a patch must not anchor on it, and a strip is a no-op.

One-way signal only: an AddedBy-less section can still lack a literal token (modal-lookback syntaxes such as FeedrateSyntax re-author sections without stamping). The final authority on literal presence is the anchored text match itself.

public static bool IsCarriedSection(JsonObject json, string sectionKey)

Parameters

json JsonObject
sectionKey string

Returns

bool

ProbeTagValue(string, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>)

Probes what the first unprotected literal token of tag carries in blockText, using exactly the value grammar (TagValuePattern: number | variable/bracket expression | dialect keyword) that SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool) matches against — so a probe and a subsequent edit can never disagree on token presence or editability.

public static NcTagValueKind ProbeTagValue(string blockText, string tag, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null)

Parameters

blockText string

NC block text to probe; null counts as empty.

tag string

Tag to look for, e.g. “F”.

varPrefix string

Variable index prefix of the dialect (Fanuc #, Heidenhain Q).

protectedSpans IReadOnlyList<(int Start, int Length)>

Comment spans to skip (see GetFanucCommentSpans(string)).

keywordValues IReadOnlyList<string>

Dialect keywords that can stand where the tag's number would be; null for dialects without keyword values.

Returns

NcTagValueKind

RemoveFlag(ref string, string, IReadOnlyList<(int Start, int Length)>)

Removes the first whole-token occurrence of flagRegex from blockText by positional splice, absorbing one adjacent separator space. Matching is case-insensitive with the RegexFlagPrefix prefix guard and a (?![0-9]) tail guard — the numbered-flag lexing: the token ends at its digits, so glued words match (G01X1.) while a longer number does not (G1 never bites G17). Dotted variants are the caller's responsibility (strip G43.4 before G43).

This is the text half of modal-token stripping (one line split into many keeps the modal G word only on the first fragment); use IsCarriedSection(JsonObject, string) first — a carried section's token is not in the source text at all, so no removal should be attempted.

public static bool RemoveFlag(ref string blockText, string flagRegex, IReadOnlyList<(int Start, int Length)> protectedSpans = null)

Parameters

blockText string
flagRegex string
protectedSpans IReadOnlyList<(int Start, int Length)>

Returns

bool

True when a token was found and removed.

RemoveFlagTrimmingTail(ref string, string, IReadOnlyList<(int Start, int Length)>)

Removes the first whole-token occurrence of flagRegex with the HardNc splition byte shape: the token span is cut out and the REMAINDER after it is TrimStart()ed — the exact splice of the oracle's RebuildFlagSyntaxToNcLine (frozen baseline, HiNc/NcOpt/NcOptProc.cs:1985-1989), which differs from RemoveFlag(ref string, string, IReadOnlyList<(int Start, int Length)>) when the token sits at the end of the code region (the oracle keeps the preceding space; the absorbing removal would eat it). The tail guard here is (?![0-9.]) — one character stronger than the oracle's guard-less regex — so a plain name never bites its dotted variant (G54 vs G54.1); the oracle avoids those bites through its flag-state gate instead.

public static bool RemoveFlagTrimmingTail(ref string blockText, string flagRegex, IReadOnlyList<(int Start, int Length)> protectedSpans = null)

Parameters

blockText string

NC block text to edit.

flagRegex string

Escaped literal flag token, e.g. “G94”.

protectedSpans IReadOnlyList<(int Start, int Length)>

Comment spans to skip.

Returns

bool

True when a token was found and removed.

SetTagNumber(ref string, string, double, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>, bool, bool)

Sets, replaces, or deletes a single tag value token in blockText by positional splice.

Dual of HardNcUtil.SetTagNumber: a found tag is rewritten in place (NaN removes the whole token together with one adjacent separator space); an absent tag with a non-NaN value is inserted at its conventional word position. The original tag letter casing is preserved on replace; only the addressed token's span changes, so an edit to F can never diff anything but F.

public static NcPatchTagResult SetTagNumber(ref string blockText, string tag, double tagNumber, string tagNumberFormat, string varPrefix = "#", IReadOnlyList<(int Start, int Length)> protectedSpans = null, IReadOnlyList<string> keywordValues = null, bool absorbSeparatorSpaceOnRemove = true, bool rewriteEqualLiteral = false)

Parameters

blockText string

NC block text to edit (verbatim draft).

tag string

Tag to address, e.g. “F”, “X”.

tagNumber double

New value; NaN deletes the token.

tagNumberFormat string

Numeric format, e.g. “F2”/“F4” (see FormatTagNumber(double, string)).

varPrefix string

Variable index prefix of the dialect (Fanuc #, Heidenhain Q) — used to recognize, and refuse, variable values.

protectedSpans IReadOnlyList<(int Start, int Length)>

Comment spans to skip; matches and insertions never land inside them (see GetFanucCommentSpans(string)).

keywordValues IReadOnlyList<string>

Dialect keywords that can stand where the tag's number would be (e.g. Heidenhain MAX/AUTO after F); a keyword-valued tag is refused, never treated as absent.

absorbSeparatorSpaceOnRemove bool

Whether a NaN-value removal also absorbs one adjacent separator space (the default). Pass false for the HardNc splition-fragment byte shape: the oracle's HardNcUtil.SetTagNumber deletes with string.Replace(match, ""), leaving both separators in place (HiUniNc/Numerical/HardNcUtil.cs:466-467) — e.g. deleting the trailing F of "… Z-1.9 F4000." keeps the space, so the embedded-log note lands as "… Z-1. (src(…))" with a doubled space, which the fragment rewrite must reproduce byte-for-byte.

rewriteEqualLiteral bool

Whether to rewrite a literal that already means the requested value, re-spelling it in canonical format instead of keeping the original bytes (the default keeps them). The HardNc oracle always rewrites (HiUniNc/Numerical/HardNcUtil.cs:470-475), so the splition fragment path passes true for byte parity — e.g. a source I0.0 under an unchanged center re-spells as I0. in the reference output, which the byte-stability shortcut would otherwise keep as I0.0.

Returns

NcPatchTagResult