rename XFactory.Regs to XFactory.Generators.

This commit is contained in:
2026-05-23 21:23:06 +08:00
parent 8b285cc863
commit 058003f395
155 changed files with 16416 additions and 1261 deletions
@@ -98,18 +98,44 @@ Classes
<dt><a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.LocalVariableLookup.html">LocalVariableLookup</a></dt>
<dd><p>Reads Fanuc-style local macro variables (<code>#1-#33</code>) from
<code>Vars.Local</code> on the current <a class="xref" href="Hi.NcParsers.Syntaxs.SyntaxPiece.html">SyntaxPiece</a> JSON,
walking <a class="xref" href="Hi.Common.Collections.LazyLinkedListNode-1.html#Hi_Common_Collections_LazyLinkedListNode_1_Previous">Previous</a> until the entry
is found. Self-gates the id range so the evaluator's
falling back to the immediately previous block when they share the
same <a class="xref" href="Hi.NcParsers.Keywords.MacroFrame.html">MacroFrame</a> id. Self-gates the id range
so the evaluator's
<a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.VariableEvaluatorSyntax.html#Hi_NcParsers_EvaluationSyntaxs_VariableEvaluatorSyntax_RuntimeVariableLookups">RuntimeVariableLookups</a> chain can
fall through to the next lookup for out-of-range keys.</p>
<p>
Two-step lookup (mirrors <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.VolatileVariableLookup.html">VolatileVariableLookup</a>): the
current block sees writes that <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Fanuc.FanucMacroCallSyntax.html">FanucMacroCallSyntax</a>
stamped at inline time (the call-line argument bindings) and writes
that <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Fanuc.FanucLocalVariableReadingSyntax.html">FanucLocalVariableReadingSyntax</a>
applied on this block before the lookup runs; the previous block
(frame-checked) supplies body-internal writes from the prior block in
the same macro frame. Looking past the previous block is unnecessary
because the reader carries forward block-by-block within a frame.
</p>
<p>
Frame isolation via <a class="xref" href="Hi.NcParsers.Keywords.MacroFrame.html">MacroFrame</a>: a previous
block whose frame id differs from the current block's is skipped —
a macro body's body-internal locals are invisible to the caller after
return, and the caller's main-frame locals are invisible inside the
macro. M98/M198 subprogram inlining
(<a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.SubProgramCallSyntax.html">SubProgramCallSyntax</a>) deliberately
does <i>not</i> stamp <a class="xref" href="Hi.NcParsers.Keywords.MacroFrame.html">MacroFrame</a> on its
inlined blocks, so the callee inherits the caller's frame and sees
the caller's locals — matching real Fanuc M98 semantics.
</p>
<p>
Stateless and dependency-free — instances are interchangeable.
</p>
</dd>
</dl>
<dl class="jumplist">
<dt><a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcBinaryExpr.html">NcBinaryExpr</a></dt>
<dd><p>Binary arithmetic on two operands (<code>+ - * /</code> or <code>MOD</code>).</p>
<dd><p>Binary operation on two operands. Covers arithmetic
(<code>+ - * /</code> / <code>MOD</code>), comparison
(<code>EQ NE GT GE LT LE</code>, yielding <code>1.0</code> / <code>0.0</code>), and
logical bitwise (<code>AND OR XOR</code>, operands truncated to
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.int64">long</a>).</p>
</dd>
</dl>
<dl class="jumplist">
@@ -133,6 +159,20 @@ Fanuc Custom Macro B convention. Unknown function names surface as
errors (e.g. <code>SQRT[-1]</code>) as <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcExpressionEvaluator.html#Hi_NcParsers_EvaluationSyntaxs_Evaluation_NcExpressionEvaluator_MathErrorCode">MathErrorCode</a>; vacant
operands as <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcExpressionEvaluator.html#Hi_NcParsers_EvaluationSyntaxs_Evaluation_NcExpressionEvaluator_VacantErrorCode">VacantErrorCode</a>.
</p>
<p>
<b>Numeric domain &amp; type conventions.</b> All values are IEEE 754
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.double">double</a> — there is no separate bool / int type at runtime.
Comparison ops (<code>EQ NE GT GE LT LE</code>) yield <code>1.0</code> (true) or
<code>0.0</code> (false), using strict double equality / ordering (NaN
compares as IEEE specifies — <code>NaN EQ NaN</code> is <code>0.0</code>). Logical
ops (<code>AND OR XOR</code>) truncate each operand to a 64-bit signed
integer (<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.math.truncate#system-math-truncate(system-double)">Truncate(double)</a> then cast to
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.int64">long</a>) before applying the bitwise operation; non-finite
or out-of-range operands surface <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcExpressionEvaluator.html#Hi_NcParsers_EvaluationSyntaxs_Evaluation_NcExpressionEvaluator_MathErrorCode">MathErrorCode</a> rather
than silently wrapping. Truthiness at caller-side <code>IF / WHILE</code>
gates is <code>value != 0</code> — any non-zero value (bit, float, comparator
result) is true.
</p>
</dd>
</dl>
<dl class="jumplist">
@@ -140,22 +180,37 @@ operands as <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcEx
<dd><p>Recursive-descent parser for Fanuc Custom Macro B value expressions.
Pure: takes a string, produces an <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcExpr.html">NcExpr</a> AST. Performs no
variable lookup and no evaluation.</p>
<p>Grammar (highest precedence last):</p>
<pre><code class="lang-csharp">expr := term (('+' | '-') term)*
term := factor (('*' | '/' | 'MOD') factor)*
factor := ('+' | '-')? primary
primary := number
| '#' integer
| '#' '[' expr ']'
| '[' expr ']'
| ident '[' arglist ']' ('/' '[' expr ']')?
arglist := expr (',' expr)*</code></pre>
<p>Grammar (lowest precedence at top):</p>
<pre><code class="lang-csharp">expr := or-expr
or-expr := and-expr (('OR' | 'XOR') and-expr)*
and-expr := cmp-expr ('AND' cmp-expr)*
cmp-expr := add-expr (('EQ' | 'NE' | 'GT' | 'GE' | 'LT' | 'LE') add-expr)*
add-expr := term (('+' | '-') term)*
term := factor (('*' | '/' | 'MOD') factor)*
factor := ('+' | '-')? primary
primary := number
| '#' integer
| '#' '[' expr ']'
| '[' expr ']'
| ident '[' arglist ']' ('/' '[' expr ']')?
arglist := expr (',' expr)*</code></pre>
<p>
Function names are case-insensitive (<code>SIN</code> = <code>sin</code>); whitespace
is skipped between tokens. The <code>'/' '[' expr ']'</code> tail captures the
dual-bracket form Fanuc uses for <code>ATAN[a]/[b]</code>; non-ATAN callers that
happen to use it produce a function with an extra arg, which the evaluator
rejects with an arity error.
Function names and keyword operators (<code>MOD</code>, <code>EQ NE GT GE LT LE</code>,
<code>AND OR XOR</code>) are case-insensitive (<code>SIN</code> = <code>sin</code>,
<code>EQ</code> = <code>eq</code>); each keyword requires a non-identifier character
on its right boundary so <code>EQ1</code> is not the <code>EQ</code> operator
followed by <code>1</code>. Whitespace is skipped between tokens. The
<code>'/' '[' expr ']'</code> tail captures the dual-bracket form Fanuc uses
for <code>ATAN[a]/[b]</code>; non-ATAN callers that happen to use it produce a
function with an extra arg, which the evaluator rejects with an arity
error.
</p>
<p>
Operator precedence intentionally puts boolean / logical layers below
arithmetic so <code>#1 + 1 GT 0</code> parses as <code>(#1 + 1) GT 0</code> and
<code>#1 GT 0 AND #2 LT 10</code> parses as <code>(#1 GT 0) AND (#2 LT 10)</code>,
matching the Fanuc Custom Macro B spec for <code>IF [..] GOTO</code> /
<code>IF [..] THEN</code> / <code>WHILE [..] DO</code> conditions.
</p>
</dd>
</dl>
@@ -191,16 +246,23 @@ is then <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.NcIndire
<dl class="jumplist">
<dt><a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.Evaluation.VolatileVariableLookup.html">VolatileVariableLookup</a></dt>
<dd><p>Reads Fanuc-style non-retained common variables (<code>#100-#499</code>)
from <code>Vars.Volatile</code> on the current <a class="xref" href="Hi.NcParsers.Syntaxs.SyntaxPiece.html">SyntaxPiece</a>
JSON, walking <a class="xref" href="Hi.Common.Collections.LazyLinkedListNode-1.html#Hi_Common_Collections_LazyLinkedListNode_1_Previous">Previous</a> until the
entry is found. Self-gates the id range so the evaluator's
from <code>Vars.Volatile</code>. Self-gates the id range so the evaluator's
<a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.VariableEvaluatorSyntax.html#Hi_NcParsers_EvaluationSyntaxs_VariableEvaluatorSyntax_RuntimeVariableLookups">RuntimeVariableLookups</a> chain can
fall through to the next lookup for out-of-range keys.</p>
<p>
Stateless and dependency-free — instances are interchangeable.
Reads use the same dict-merge carry that
<a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.VolatileVariableReadingSyntax.html">VolatileVariableReadingSyntax</a> writes; the two stay
decoupled (read side here; write side in the reader).
Single-step lookup: <a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.VolatileVariableReadingSyntax.html">VolatileVariableReadingSyntax</a> already
dict-merges every block's <code>Vars.Volatile</code> into the next block, so
the entry — if it exists — must be on the current block (when this
lookup runs after the reader) or on the immediately previous block
(when this lookup runs before the reader on the same block, which is
the Fanuc preset's order — evaluator first, reader second). No
arbitrary walk-back: such a walk would be defensive overkill given
the reader's carry guarantee.
</p>
<p>
Stateless and dependency-free — instances are interchangeable. Reads
stay decoupled from the reader (read side here; write side in the
reader).
</p>
</dd>
</dl>
@@ -237,6 +299,14 @@ Implementations should be brand-specific (e.g. Fanuc <code>#5001-#5043</code>
position reads) and return <code>null</code> for keys outside their range so
the evaluator's chain can fall through to the next lookup.
</p>
<p>
Implementations are XML-serialised as part of
<a class="xref" href="Hi.NcParsers.EvaluationSyntaxs.VariableEvaluatorSyntax.html">VariableEvaluatorSyntax</a>'s round-trip: each impl exposes a
static <code>XName</code>, registers itself with <a class="xref" href="Hi.Common.XmlUtils.XFactory.html#Hi_Common_XmlUtils_XFactory_Generators">Generators</a>,
and implements <a class="xref" href="Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_System_String_System_String_System_Boolean_">MakeXmlSource(string, string, bool)</a>. Since impls
are stateless, the typical body is just an empty element carrying the
type name; brand identity is restored by XFactory dispatch.
</p>
</dd>
</dl>
<dl class="jumplist">