omy.Utils.Parser.Expressions
2.0.0-rc.1
dotnet add package omy.Utils.Parser.Expressions --version 2.0.0-rc.1
NuGet\Install-Package omy.Utils.Parser.Expressions -Version 2.0.0-rc.1
<PackageReference Include="omy.Utils.Parser.Expressions" Version="2.0.0-rc.1" />
<PackageVersion Include="omy.Utils.Parser.Expressions" Version="2.0.0-rc.1" />
<PackageReference Include="omy.Utils.Parser.Expressions" />
paket add omy.Utils.Parser.Expressions --version 2.0.0-rc.1
#r "nuget: omy.Utils.Parser.Expressions, 2.0.0-rc.1"
#:package omy.Utils.Parser.Expressions@2.0.0-rc.1
#addin nuget:?package=omy.Utils.Parser.Expressions&version=2.0.0-rc.1&prerelease
#tool nuget:?package=omy.Utils.Parser.Expressions&version=2.0.0-rc.1&prerelease
omy.Utils.Parser.Expressions
omy.Utils.Parser.Expressions provides optional expression-backed integration for omy.Utils.Parser.
It connects an explicit IExpressionCompiler to parser embedded-code surfaces without selecting a language automatically.
Purpose
Use this package when you want to work with embedded parser code through a caller-selected expression compiler. It is the runtime-inline prepared expression path documented in docs/parser/ANTLRCompatibility.md; it is not the generated C# path.
Available surfaces:
ExpressionEmbeddedCodePreparerprepares expression-backed artifacts for semantic predicates ({ condition }?) and inline parser actions ({ code }).PreparedExpressionSemanticPredicatestores a compiled predicate delegate and can produceSemanticPredicateEvaluationOutcomevalues without recompiling source text.PreparedExpressionParserActionstores a compiled action delegate and can produceParserActionExecutionOutcomevalues without recompiling source text.PreparedExpressionEmbeddedCodeKeyidentifies prepared artifacts by embedded-code kind, owning rule, source text, alternative index, and element index.PreparedExpressionEmbeddedCodeRegistrystores prepared semantic predicates separately from prepared parser inline actions.PreparedExpressionEmbeddedCodeRegistryBuilderexplicitly scansParserDefinitionmodels and fills a registry from validating predicates and inline parser actions.PreparedExpressionRuntimePolicyBuilderassembles the full opt-in prepared runtime path from aParserDefinitionand anIExpressionCompiler.PreparedExpressionRuntimePolicyBuildResultexposes the configuredParserRuntimeFeaturePolicy, registry, registry build result, and failure summary.PreparedExpressionRuntimePolicyBuilderOptionsconfigures grammar/compiler identity, supported symbols, and an optional base runtime policy.PreparedExpressionSemanticPredicateEvaluatorexecutes registeredPreparedExpressionSemanticPredicateartifacts throughISemanticPredicateEvaluatorwithout compiling source text.PreparedExpressionParserActionExecutorexecutes registeredPreparedExpressionParserActionartifacts throughIParserActionExecutorwithout compiling source text.ExpressionSemanticPredicateEvaluatorremains the current runtime adapter fromIExpressionCompilertoISemanticPredicateEvaluator.ExpressionParserActionExecutorremains the current runtime adapter fromIExpressionCompilertoIParserActionExecutor.
Supported runtime compilation facade
ExpressionEmbeddedCodePreparer is the single supported omy.Utils.Parser.Expressions entry point for
transforming, compiling, and materializing executable parser embedded code before runtime execution. It
implements IEmbeddedCodePreparer<PreparedExpressionSemanticPredicate, PreparedExpressionParserAction>,
coordinates a caller-supplied IExpressionCompiler, and optionally coordinates a caller-supplied
IParserEmbeddedCodeTransformer (the no-op transformer is the default). It does not replace the compiler:
it directs that compiler within the supported preparation pipeline.
The complete preparation path is:
EmbeddedCodeSource
→ validation of kind and target
→ EmbeddedCodeTransformationPipeline
→ TransformedEmbeddedCode
→ runtime-bound symbol expressions
→ IExpressionCompiler
→ specialized CLR lambda
→ prepared artifact
| Source | Runtime context | Delegate | Prepared artifact |
|---|---|---|---|
SemanticPredicate |
SemanticPredicateEvaluationContext |
Func<SemanticPredicateEvaluationContext, bool> |
PreparedExpressionSemanticPredicate |
ParserInlineAction |
ParserActionExecutionContext |
Action<ParserActionExecutionContext> |
PreparedExpressionParserAction |
The facade normalizes outcomes as follows:
| Condition | Preparation status |
|---|---|
| The method receives the wrong embedded-code category | Unsupported |
The target is SourceGeneratorCSharp rather than RuntimeInlineExpression |
PreservedNotCompiled |
| Transformation, expression compilation, or delegate materialization fails | CompilationFailed |
| A specialized prepared artifact is produced | Success (EmbeddedCodePreparationStatus.Succeeded) |
Only parser semantic predicates and inline parser actions are supported. Lexer predicates, lexer actions,
grammar actions, @init, @after, non-inline parser actions, and every other category that is not compatible
with runtime-inline preparation remain unsupported. The facade does not generate C# source, replace the source
generator, execute embedded code during preparation, capture preparation-time runtime values, or decide the
parser's global execution strategy. Generated C# remains a separate Utils.Parser.Generators path.
Minimal preparation example
The following uses the real public preparation contracts; GetExpressionCompiler() represents the caller's
selection of an existing IExpressionCompiler implementation.
IExpressionCompiler compiler = GetExpressionCompiler();
var preparer = new ExpressionEmbeddedCodePreparer(compiler);
var source = new EmbeddedCodeSource(
"inputPosition > 0",
EmbeddedCodeKind.SemanticPredicate,
ruleName: "value");
var context = new EmbeddedCodePreparationContext(
"ExampleGrammar",
EmbeddedCodeTarget.RuntimeInlineExpression,
ruleName: "value",
languageOrCompilerIdentity: "custom-expression-language");
EmbeddedCodePreparationResult<PreparedExpressionSemanticPredicate> result =
preparer.PrepareSemanticPredicate(source, context);
The preparer:
- supports
EmbeddedCodeKind.SemanticPredicateandEmbeddedCodeKind.ParserInlineAction; - uses only the supplied
IExpressionCompilercontract; - can be paired by consumers with expression compiler packages such as
Utils.Expressions.CSyntaxorUtils.Expressions.VBSyntax; - does not reference those compiler packages directly;
- returns
UnsupportedforRuleInitAction,RuleAfterAction,GrammarAction, lexer actions, lexer predicates, and non-inline parser actions; - returns
PreservedNotCompiledforEmbeddedCodeTarget.SourceGeneratorCSharp, because C# source-generation hooks belong toUtils.Parser.Generators; - never executes predicates or actions during preparation.
Internally, preparation first crosses the same transformation-and-validation boundary as generated C# and receives a validated TransformedEmbeddedCode. Only then does this package build runtime symbol expressions and the specialized lambda and invoke the supplied IExpressionCompiler. Lexer hooks are not supported by this runtime path and are not synthesized by the shared boundary.
Contextual symbols (ruleName, inputPosition, alternativeIndex, elementIndex) are filtered through EmbeddedCodePreparationContext.SupportedSymbols before compilation. Supported symbols are represented as reads from the runtime context parameter when compiling prepared artifacts, so they are not captured as fixed preparation-time constants. Expressions that reference a symbol excluded from SupportedSymbols fail through the configured compiler and are returned as CompilationFailed results.
Runtime status
Prepared artifacts can be prepared from a parser model, stored in a registry, and consumed through runtime adapters explicitly.
Default parser behavior is unchanged, and ParserEngine is not modified by this package. The package does not execute lexer embedded code, grammar actions, @members, @init, @after, non-inline parser actions, action rollback/buffering, context mutation, or arbitrary parser state mutation.
The recommended full prepared runtime flow is to build an opt-in policy outside the parser and pass that policy explicitly:
IExpressionCompiler compiler = GetExpressionCompiler();
var integration = PreparedExpressionRuntimePolicyBuilder.Build(
definition,
compiler,
new PreparedExpressionRuntimePolicyBuilderOptions
{
GrammarName = definition.Name,
LanguageOrCompilerIdentity = "custom-expression-language",
BasePolicy = existingPolicy
});
if (integration.HasFailures)
{
foreach (var entry in integration.RegistryBuildResult.NonSuccessEntries)
{
Console.WriteLine($"Embedded code preparation failed: {entry.Source.SourceText}");
}
}
var parser = new ParserEngine(definition, integration.Policy);
PreparedExpressionRuntimePolicyBuilder.Build creates the ExpressionEmbeddedCodePreparer, runs PreparedExpressionEmbeddedCodeRegistryBuilder, creates PreparedExpressionSemanticPredicateEvaluator and PreparedExpressionParserActionExecutor, and returns a policy configured with those adapters. When BasePolicy is supplied, only SemanticPredicateEvaluator and ParserActionExecutor are replaced; other policy features, such as the passive runtime observer, are preserved. Preparation failures remain visible through RegistryBuildResult and HasFailures; the builder does not throw for compiler failures unless the compiler itself fails outside the preparation result flow.
Consumers that need lower-level control can still assemble the same components manually:
IExpressionCompiler compiler = GetExpressionCompiler();
var preparer = new ExpressionEmbeddedCodePreparer(compiler);
var buildResult = PreparedExpressionEmbeddedCodeRegistryBuilder.Build(
definition,
preparer,
new PreparedExpressionEmbeddedCodeRegistryBuilderOptions
{
GrammarName = definition.Name,
LanguageOrCompilerIdentity = "custom-expression-language"
});
var policy = ParserRuntimeFeaturePolicy.Default with
{
SemanticPredicateEvaluator = new PreparedExpressionSemanticPredicateEvaluator(buildResult.Registry),
ParserActionExecutor = new PreparedExpressionParserActionExecutor(buildResult.Registry)
};
var parser = new ParserEngine(definition, policy);
The builder is never used automatically. It scans ParserDefinition.ParserRules, prepares ValidatingPredicate nodes and inline EmbeddedAction nodes (ActionContext.Alternative plus ActionPosition.Inline), records non-success preparation results, records duplicate registry keys, and skips grammar-level actions plus rule lifecycle actions (@init / @after). It does not skip executable predicates or inline actions merely because they are nested in runtime-executable structures such as quantifiers, negations, nested alternations, or left-recursive tails. It depends only on IEmbeddedCodePreparer<PreparedExpressionSemanticPredicate, PreparedExpressionParserAction>, not on a concrete expression language package.
The registry lookup key is intentionally audit-friendly: it includes the embedded-code kind, owning rule name, raw source text, alternative index, and element index. The builder mirrors the parser runtime's active indexing strategy: alternatives are ordered by runtime priority, sequences use zero-based item indexes, quantifier and negation inner probes use the runtime alternative index as the direct inner element index, and direct-left-recursive recursive alternatives are prepared from the effective tail after the leading self-reference is removed. Runtime contexts use -1 for unavailable indexes; registry keys normalize those unavailable values to null. This is the safest key currently available without changing ParserEngine, but it still depends on prepared artifacts carrying metadata that matches the runtime model.
The existing adapters remain available as the opportunistic compilation path:
var policy = ParserRuntimeFeaturePolicy.Default with
{
SemanticPredicateEvaluator = new ExpressionSemanticPredicateEvaluator(expressionCompiler),
ParserActionExecutor = new ExpressionParserActionExecutor(expressionCompiler)
};
var parser = new ParserEngine(definition, policy);
Current adapter behavior vs target model
Current adapter behavior:
ExpressionSemanticPredicateEvaluatoradaptsIExpressionCompilertoISemanticPredicateEvaluator.ExpressionParserActionExecutoradaptsIExpressionCompilertoIParserActionExecutor.- The adapters compile from source text at predicate/action invocation time when needed.
- Non-contextual expressions can reuse an opportunistically cached compiled delegate.
- Expressions that reference contextual symbols (
ruleName,inputPosition,alternativeIndex,elementIndex) are currently recompiled per invocation to avoid capturing the wrong runtime context.
Prepared artifact behavior:
ExpressionEmbeddedCodePreparercompiles before parsing when invoked explicitly by a caller.PreparedExpressionEmbeddedCodeRegistryBuildercan invoke that preparer for validating predicates and inline parser actions found in an already-builtParserDefinition.PreparedExpressionRuntimePolicyBuilderis the convenience integration API for building the registry and prepared runtime policy in one explicit opt-in call.PreparedExpressionSemanticPredicateandPreparedExpressionParserActionexecute already-compiled delegates.PreparedExpressionSemanticPredicateEvaluatorandPreparedExpressionParserActionExecutorlook up those artifacts inPreparedExpressionEmbeddedCodeRegistryand execute them without depending onIExpressionCompiler.- A missing registry entry returns
NotEvaluatedorNotExecuted, allowing parsing to continue under the existingParserEngineoutcome handling. - The prepared-artifact path does not change parser scheduling, memoization, diagnostics emission, parse-tree shape, or default runtime policy.
The prepared path compiles executable artifacts before parsing and then executes only those artifacts while parsing. This package provides the explicit runtime adapters, an explicit registry builder, and a convenience policy builder for that opt-in consumption step, but it still does not automatically prepare a parser model. ParserEngine remains language-neutral: it executes policy outcomes and emits diagnostics, but does not select an expression language or compile embedded source code.
Scope and limitations
Semantic predicates
- Predicate expressions must compile to
bool. - Non-boolean predicate expressions produce a
CompilationFailedpreparation result withUP1026metadata. - Preparation compilation failures preserve the exception in the preparation result.
Inline parser actions
voidexpressions are accepted.- Non-void expressions are accepted when executable; their result is ignored, matching the existing adapter behavior.
- Preparation does not execute the action.
- Runtime exceptions from a prepared action are converted to
ParserActionExecutionOutcome.NotExecutedwithUP1026metadata when the artifact is executed explicitly.
Lexer actions, lexer predicates, grammar members/@members, @init, @after, non-inline parser actions, rollback/buffering, and parser-state mutation are not implemented by this package. See docs/parser/ANTLRCompatibility.md for the canonical compatibility status.
Shared runtime indexing metadata
Parser embedded-code discovery now has a shared metadata model in Utils.Parser.EmbeddedCode. EmbeddedCodeRuntimeDiscovery walks a ParserDefinition and emits EmbeddedCodeRuntimeEntry values with the raw source, EmbeddedCodeKind, owning rule name, runtime-compatible alternative and element indexes, a runtime key for executable entries, and an explicit EmbeddedCodeUnsupportedReason for skipped entries. The metadata mirrors the existing parser runtime indexing rules for priority-ordered alternatives, single-item alternatives, sequences, quantifier inner parsing, negation probes, and direct-left-recursive base/tail alternatives. It is metadata only: it does not compile source, generate C#, execute actions, or change ParserEngine behavior.
The expression-backed prepared registry consumes this shared discovery result before invoking its preparer. Unsupported constructs such as grammar actions, @init, @after, lexer actions/predicates, and non-inline parser actions remain non-executable, but they now carry explicit skip reasons. Invalid C# in a source-generator-supported hook remains a Roslyn compilation error rather than a custom parser diagnostic.
API documentation
See the versioned API documentation for omy.Utils.Parser.Expressions 0.1.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- omy.Utils (= 2.0.0-rc.1)
- omy.Utils.Parser (= 2.0.0-rc.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-rc.1 | 84 | 8/28/2026 |