moonbit-roman

Roman numeral parsing, linting, safe rewriting, and document indexing for MoonBit

roman
numeral
parser
lint
index
moon add Armyhealthyhappy/moonbit-roman@0.3.0
Download zip
Version
0.3.0
License
Apache-2.0
Last updated
18 days ago
Downloads
5
README

#moonbit-roman

moonbit-roman is a MoonBit toolkit for parsing, formatting, diagnosing, linting, safely rewriting, and indexing Roman numerals. Every operation uses an explicit notation profile so applications do not silently mix modern, additive, clock-face, or extended forms.

#Features

  • Legacy strict APIs for canonical modern numerals from 1 through 3999.
  • Configured modern, additive, clock-face, and one-level parenthesized-thousands profiles.
  • Parenthesized-thousands values from 1 through 3,999,999, for example (IV) and (X)IV.
  • Optional lowercase, Unicode Roman compatibility character, and outer-whitespace policies.
  • Parse reports with normalized text, canonical text, token values, and source spans.
  • Document scanning with lexical boundaries, candidate limits, typed rejections, and source-order results.
  • Cross-profile conversion and document rewriting with source/output replacement spans.
  • Stable ID-based batch and multi-document corpus processing with aggregate statistics.
  • Configurable value and document linting with retained typed diagnostics.
  • Validated atomic edit plans with exact source/output mapping evidence.
  • Stable document indexes with filtering, pagination, grouping, and statistics.
  • Bounded ascending or descending range generation.

The package does not perform network, file-system, OCR, or natural-language identification. Callers supply strings and choose all parsing and rewriting policies.

#Installation

moon add Armyhealthyhappy/moonbit-roman

import {
"Armyhealthyhappy/moonbit-roman" @roman,
}

#Legacy API

The 0.1.0 API remains available:

let text = @roman.format(2026).unwrap() // MMXXVI
let value = @roman.parse("mcmxciv").unwrap() // 1994
let upper = @roman.canonicalize("mmxxvi").unwrap()
let clock = @roman.format_clock_hour(4).unwrap() // IIII

parse accepts canonical ASCII uppercase or lowercase but does not trim whitespace. It returns ParseError variants for empty input, unsupported characters, repetition, subtraction, ordering, non-canonical spelling, and range violations.

#Explicit profiles

let extended = @roman.format_with_config(
944944,
@roman.extended_format_config(),
).unwrap() // (CMXLIV)CMXLIV

let report = @roman.parse_with_config(
"(IV)",
@roman.extended_parse_config(),
).unwrap()
println(report.value) // 4000
println(report.canonical) // (IV)

ProfileAccepted/formatted rangeDeterministic form
ModernCanonical1..3999Conventional modern subtractive form
AdditiveHistorical1..3999Additive place form such as VIIII
ClockFace1..12Clock-hour form using IIII for four
ParenthesizedThousands1..3,999,999One canonical group multiplied by 1000 plus a remainder below 1000

The additive profile is one defined notation policy. It is not a claim to accept every historical inscription.

#Unicode and reports

compatibility_parse_config enables Unicode Roman compatibility characters and trims outer whitespace. Normalization is explicit and retained in the report:

let report = @roman.parse_with_config(
" \u{2163} ",
@roman.compatibility_parse_config(),
).unwrap()

println(report.normalized) // IV
println(report.used_unicode_compatibility) // true
println(report.trimmed_outer_whitespace) // true

Source spans are half-open character positions. They are character indexes, not UTF-8 byte offsets.

#Scanning documents

let config : @roman.ScanConfig = {
parse_config: @roman.compatibility_parse_config(),
retain_rejected: true,
include_single_symbol: false,
max_candidate_length: 32,
}

let scan = @roman.scan_roman_text(
"Release XIV includes \u{2163} checks and IIX.",
config,
).unwrap()

The scanner extracts complete lexical candidates in source order. It does not extract fragments embedded in longer ASCII words. Independent words made only of Roman letters can be lexically ambiguous; the scanner applies configured Roman grammar and does not guess natural-language intent.

#Conversion and rewriting

let converted = @roman.convert_roman(
"IIII",
@roman.additive_parse_config(),
@roman.modern_format_config(),
).unwrap()
assert_eq(converted.output, "IV")

rewrite_roman_text scans a document and formats accepted values with a target profile. Its report records each source span, output span, source text, replacement text, and value. When a source value cannot be represented by the target profile, callers choose KeepUnformattableCandidate or FailOnUnformattableCandidate.

#Linting and atomic edits

analyze_roman retains typed diagnostics instead of discarding parser evidence. lint_roman and lint_roman_document apply explicit case, Unicode source, outer-whitespace, canonical-form, single-symbol, and candidate-length policies.

Document lint reports can be converted into validated RomanEditPlan values. apply_roman_edit_plan revalidates source evidence and applies every replacement atomically; failures return a typed RomanEditError without partial output. Successful reports include applied edit spans and unchanged/replaced source-to-output mappings.

See examples/lint_edits for a complete lint, plan, and apply workflow.

#Document indexes

build_roman_document_index creates a stable index from ID-addressed documents. Entries retain document identity, source span, source and normalized spellings, canonical spelling, numeric value, notation mode, token count, and Unicode/normalization evidence. Rejected candidates and per-document counts remain available separately.

query_roman_index_page filters by document, spelling, mode, inclusive value range, Unicode evidence, and normalization evidence before pagination. Additional APIs provide exact lookups, first-occurrence-order grouping, frequencies, extrema, distinct-value counts, and per-document summaries.

See examples/index_query for index construction, range filtering, pagination, and summary statistics.

#Batch and corpus processing

process_roman_batch accepts caller-owned IDs, input strings, and per-item parse configurations. Results remain in input order. Empty or duplicate IDs are rejected before processing. Statistics count successes, failures, Unicode normalization, whitespace trimming, and typed failure categories.

process_roman_corpus applies scanner configurations to ID-addressed documents. A bad scan configuration is retained as that document's outcome while valid documents still produce evidence and aggregate counts.

#Bounded ranges

format_roman_range generates inclusive ascending or descending sequences. The caller supplies a non-zero step and max_items; direction mismatches and oversized ranges fail before generation.

#Examples

moon run examples/basic moon run examples/profiles moon run examples/diagnostics moon run examples/document_scan moon run examples/lint_edits moon run examples/index_query

The examples cover legacy APIs, profile formatting, Unicode diagnostics, scanning, batch statistics, lint-driven edits, and index queries. GitHub Actions runs all six.

#Verification

moon fmt --check moon info moon check --deny-warn moon build moon test pwsh -File scripts/source-audit.ps1

The test suite contains exhaustive modern round trips for every integer from 1 through 3999 and focused tests for profile boundaries, Unicode source spans, malformed extended input, scanning, conversion, linting, atomic edits, index construction, combined queries, grouping, statistics, batch processing, corpus aggregation, and bounded ranges.

#Current boundaries

Version 0.3.0 implements deterministic policies, not unrestricted Roman notation. Parentheses support one level only; arbitrary nesting and arbitrary precision are not supported. Historical profile support is limited to the documented additive policy. Unicode Roman compatibility handling is limited to U+2160..U+217F. The scanner is lexical and does not provide OCR or language-aware disambiguation. The package does not perform file I/O or natural-language identification; callers provide document strings and IDs.

#License and provenance

Apache-2.0. See LICENSE, NOTICE, and notation references. The MoonBit implementation is original and is not a source-code port of another library.

#
BatchFailureCount

pub(all) struct BatchFailureCount {
kind : BatchFailureKind
count : Int
} derive(Eq,
Debug
)

Counts one failure category.

#
BatchFailureKind

pub(all) enum BatchFailureKind {
EmptyInputFailure
UnsupportedCharacterFailure
LowercaseNotAllowedFailure
GrammarFailure(DiagnosticCode)
NonCanonicalFailure
OutOfRangeFailure
InvalidConfigurationFailure
} derive(Eq,
Debug
)

Groups parser errors into stable statistics categories.

#
BatchValidationError

pub(all) enum BatchValidationError {
EmptyBatchItemId(Int)
DuplicateBatchItemId(String)
} derive(Eq,
Debug
)

Reports caller identity errors before any batch item is processed.

#
ConfigError

pub(all) enum ConfigError {
InvalidCandidateLength(Int)
} derive(Eq,
Debug
)

Reports an invalid reusable processing configuration.

#
ConversionError

pub(all) enum ConversionError {
ConversionParseFailed(RomanReportError)
ConversionFormatFailed(FormatError)
} derive(Eq,
Debug
)

Reports which stage prevented a profile conversion.

#
CorpusValidationError

pub(all) enum CorpusValidationError {
EmptyDocumentId(Int)
DuplicateDocumentId(String)
} derive(Eq,
Debug
)

Reports caller-owned document identity errors.

#
DiagnosticCode

pub(all) enum DiagnosticCode {
EmptyInputCode
InvalidConfigurationCode
UppercaseRequiredCode
LowercaseRequiredCode
UnicodeSourceNotAllowedCode
OuterWhitespaceNotAllowedCode
SingleSymbolExcludedCode
CandidateTooLongCode
UnsupportedCharacterCode
LowercaseNotAllowedCode
InvalidRepetitionCode
InvalidSubtractionCode
InvalidOrderCode
MalformedParenthesesCode
NestedParenthesesCode
EmptyParenthesizedGroupCode
NonCanonicalCode
ValueOutOfRangeCode
} derive(Eq,
Debug
)

Identifies a machine-readable diagnostic category.

#
DiagnosticSeverity

pub(all) enum DiagnosticSeverity {
DiagnosticError
DiagnosticWarning
} derive(Eq,
Debug
)

Distinguishes fatal errors from retained normalization information.

#
FormatConfig

pub(all) struct FormatConfig {
mode : RomanMode
letter_case : LetterCase
} derive(Eq,
Debug
)

Configures grammar and case selection for report formatting.

#
FormatError

pub(all) enum FormatError {
FormatOutOfRange(Int)
InvalidClockHour(Int)
} derive(Eq,
Debug
)

#
IndexCrossOverlapScan

type IndexCrossOverlapScan derive(Eq,
Debug
)

#
LetterCase

pub(all) enum LetterCase {
Uppercase
Lowercase
} derive(Eq,
Debug
)

Selects the letter case emitted by configured formatters.

#
ParseConfig

pub(all) struct ParseConfig {
mode : RomanMode
accept_lowercase : Bool
accept_unicode : Bool
trim_outer_whitespace : Bool
} derive(Eq,
Debug
)

Configures normalization and grammar selection for report parsing.

#
ParseError

pub(all) enum ParseError {
EmptyInput
InvalidCharacter(Int, Char)
InvalidRepetition(Int, Char)
InvalidSubtractivePair(Int, Char, Char)
InvalidOrder(Int)
NonCanonical(String)
ParseOutOfRange(Int)
} derive(Eq,
Debug
)

#
ParseReport

pub(all) struct ParseReport {
original : String
normalized : String
value : Int
canonical : String
tokens : Array[RomanToken]
diagnostics : Array[RomanDiagnostic]
notices : Array[String]
used_unicode_compatibility : Bool
trimmed_outer_whitespace : Bool
} derive(Eq,
Debug
)

Returns complete, reproducible evidence for one accepted numeral.

#
RewriteConfig

pub(all) struct RewriteConfig {
scan_config : ScanConfig
target_format : FormatConfig
failure_policy : RewriteFailurePolicy
} derive(Eq,
Debug
)

Configures document scanning and the target notation profile.

#
RewriteFailurePolicy

pub(all) enum RewriteFailurePolicy {
KeepUnformattableCandidate
FailOnUnformattableCandidate
} derive(Eq,
Debug
)

Selects whether an unformattable accepted value is retained or fatal.

#
RomanAnalysisReport

pub(all) struct RomanAnalysisReport {
original : String
config : ParseConfig
status : RomanAnalysisStatus
diagnostics : Array[RomanDiagnostic]
replacement : String?
observed_unicode_compatibility : Bool
observed_outer_whitespace : Bool
} derive(Eq,
Debug
)

Describes one input without discarding rejected-input diagnostics.

#
RomanAnalysisStatus

pub(all) enum RomanAnalysisStatus {
AnalysisAccepted(ParseReport)
AnalysisRejected(RomanReportError)
} derive(Eq,
Debug
)

Retains either complete accepted evidence or the exact parser failure.

#
RomanAppliedEdit

pub(all) struct RomanAppliedEdit {
id : String
source_span : SourceSpan
output_span : SourceSpan
source_text : String
replacement_text : String
numeric_value : Int?
reason : RomanEditReason
source_diagnostic_code : DiagnosticCode?
} derive(Eq,
Debug
)

Retains one validated edit together with its realized output evidence.

#
RomanBatchItem

pub(all) struct RomanBatchItem {
id : String
input : String
config : ParseConfig
} derive(Eq,
Debug
)

Supplies a caller-owned identity, input, and parsing policy.

#
RomanBatchOutcome

pub(all) enum RomanBatchOutcome {
BatchParsed(ParseReport)
BatchFailed(RomanReportError)
} derive(Eq,
Debug
)

Retains either complete parse evidence or the typed parser error.

#
RomanBatchReport

pub(all) struct RomanBatchReport {
results : Array[RomanBatchResult]
statistics : RomanBatchStatistics
} derive(Eq,
Debug
)

Returns stable per-item results and aggregate statistics.

#
RomanBatchResult

pub(all) struct RomanBatchResult {
id : String
input : String
config : ParseConfig
outcome : RomanBatchOutcome
} derive(Eq,
Debug
)

Retains one result in the same position as its input item.

#
RomanBatchStatistics

pub(all) struct RomanBatchStatistics {
total : Int
succeeded : Int
failed : Int
used_unicode_compatibility : Int
trimmed_outer_whitespace : Int
failure_counts : Array[BatchFailureCount]
} derive(Eq,
Debug
)

Summarizes batch outcomes and successful normalization behavior.

#
RomanCaseRequirement

pub(all) enum RomanCaseRequirement {
AnyRomanCase
RequireRomanUppercase
RequireRomanLowercase
} derive(Eq,
Debug
)

Selects an ASCII Roman letter-case style requirement.

#
RomanConversionReport

pub(all) struct RomanConversionReport {
input : String
value : Int
output : String
source_report : ParseReport
target_config : FormatConfig
} derive(Eq,
Debug
)

Retains source evidence and the deterministic target representation.

#
RomanCorpusReport

pub(all) struct RomanCorpusReport {
documents : Array[RomanDocumentResult]
statistics : RomanCorpusStatistics
} derive(Eq,
Debug
)

Returns stable document results and corpus totals.

#
RomanCorpusStatistics

pub(all) struct RomanCorpusStatistics {
total_documents : Int
scanned_documents : Int
configuration_failures : Int
candidates_examined : Int
matches : Int
rejections : Int
} derive(Eq,
Debug
)

Aggregates only evidence produced by completed document scans.

#
RomanDiagnostic

pub(all) struct RomanDiagnostic {
code : DiagnosticCode
severity : DiagnosticSeverity
message : String
span : SourceSpan
replacement : String?
} derive(Eq,
Debug
)

Describes one source-located processing observation.

#
RomanDocument

pub(all) struct RomanDocument {
id : String
text : String
config : ScanConfig
} derive(Eq,
Debug
)

Supplies a caller-owned document identity and scanning policy.

#
RomanDocumentIndex

pub(all) struct RomanDocumentIndex {
entries : Array[RomanIndexEntry]
documents : Array[RomanIndexDocumentMetadata]
rejections : Array[RomanIndexRejectionSummary]
statistics : RomanIndexStatistics
} derive(Eq,
Debug
)

Stores source-ordered document entries, rejections, and aggregate evidence.

#
RomanDocumentLintCandidate

pub(all) struct RomanDocumentLintCandidate {
span : SourceSpan
source_text : String
lint : RomanLintReport
} derive(Eq,
Debug
)

Retains one scanner match and its candidate-local lint report.

#
RomanDocumentLintReport

pub(all) struct RomanDocumentLintReport {
original : String
policy : RomanLintPolicy
candidates : Array[RomanDocumentLintCandidate]
rejected_candidates : Array[RomanDocumentRejectedCandidate]
diagnostics : Array[RomanDiagnostic]
candidates_examined : Int
error_count : Int
warning_count : Int
conforms : Bool
} derive(Eq,
Debug
)

Returns source-order document lint evidence and aggregate severities.

#
RomanDocumentOutcome

pub(all) enum RomanDocumentOutcome {
CorpusScanned(RomanScanReport)
CorpusScanFailed(ConfigError)
} derive(Eq,
Debug
)

Retains either a complete scan or a document-local configuration failure.

#
RomanDocumentRejectedCandidate

pub(all) struct RomanDocumentRejectedCandidate {
span : SourceSpan
source_text : String
reason : ScanRejectionReason
diagnostic : RomanDiagnostic
} derive(Eq,
Debug
)

Retains one scanner rejection and its document-global diagnostic.

#
RomanDocumentResult

pub(all) struct RomanDocumentResult {
id : String
text : String
outcome : RomanDocumentOutcome
} derive(Eq,
Debug
)

Retains one corpus result in input order.

#
RomanEditApplicationReport

pub(all) struct RomanEditApplicationReport {
original : String
output : String
applied_edits : Array[RomanAppliedEdit]
mapping_segments : Array[RomanEditMappingSegment]
statistics : RomanEditPlanStatistics
} derive(Eq,
Debug
)

Returns atomic output with applied edits and source-to-output mappings.

#
RomanEditError

pub(all) enum RomanEditError {
InvalidRomanProjectedOutputLimit(Int64)
EmptyRomanEditId(Int)
DuplicateRomanEditId(String)
NegativeRomanEditSpan(String, SourceSpan)
ReversedRomanEditSpan(String, SourceSpan)
RomanEditSpanOutOfBounds(String, SourceSpan, Int)
OverlappingRomanEdits(String, String)
RomanEditSourceMismatch(String, String, String)
NoOpRomanEdit(String)
RomanProjectedOutputNotRepresentable(Int64, Int64)
RomanProjectedOutputLimitExceeded(Int64, Int64)
RomanEditPlanSourceMismatch(String, String)
RomanEditDocumentLintFailed(ConfigError)
RomanEditRewriteFailed(RomanRewriteError)
} derive(Eq,
Debug
)

Reports the first invalid condition under the documented validation order.

#
RomanEditMappingKind

pub(all) enum RomanEditMappingKind {
RomanUnchangedMapping
RomanReplacedMapping(String)
} derive(Eq,
Debug
)

Classifies whether a mapping preserves source text or replaces one edit.

#
RomanEditMappingSegment

pub(all) struct RomanEditMappingSegment {
kind : RomanEditMappingKind
source_span : SourceSpan
output_span : SourceSpan
} derive(Eq,
Debug
)

Maps one half-open source character span to its half-open output span.

#
RomanEditPlan

pub(all) struct RomanEditPlan {
original : String
config : RomanEditPlanConfig
edits : Array[RomanTextEdit]
statistics : RomanEditPlanStatistics
diagnostics : Array[RomanDiagnostic]
} derive(Eq,
Debug
)

Retains source-ordered edits and reproducible size statistics.

#
RomanEditPlanConfig

pub(all) struct RomanEditPlanConfig {
max_projected_length : Int64
} derive(Eq,
Debug
)

Bounds the complete output projected by a validated edit plan.

#
RomanEditPlanStatistics

pub(all) struct RomanEditPlanStatistics {
edit_count : Int
source_length : Int64
unchanged_segment_count : Int
removed_length : Int64
inserted_length : Int64
projected_length : Int64
} derive(Eq,
Debug
)

Summarizes the character-level size effects of a validated plan.

#
RomanEditPreview

pub(all) struct RomanEditPreview {
original : String
applied_edits : Array[RomanAppliedEdit]
mapping_segments : Array[RomanEditMappingSegment]
statistics : RomanEditPlanStatistics
} derive(Eq,
Debug
)

Describes the exact spans and statistics an application will produce.

#
RomanEditReason

pub(all) enum RomanEditReason {
RomanCanonicalizationEdit
RomanCaseNormalizationEdit
RomanUnicodeExpansionEdit
RomanLintDiagnosticEdit(DiagnosticCode)
CallerRequestedEdit(String)
} derive(Eq,
Debug
)

Explains why a caller proposes a text replacement.

#
RomanIndexCanonicalFrequency

pub(all) struct RomanIndexCanonicalFrequency {
canonical : String
count : Int64
} derive(Eq,
Debug
)

Counts one canonical spelling in first-occurrence order.

#
RomanIndexCanonicalGroup

pub(all) struct RomanIndexCanonicalGroup {
canonical : String
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups equal canonical spellings in first-occurrence order.

#
RomanIndexConstructionError

pub(all) enum RomanIndexConstructionError {
EmptyIndexDocumentId(Int)
DuplicateIndexDocumentId(String)
IndexDocumentScanFailed(String, ConfigError)
IndexReportDocumentCountMismatch(Int, Int)
IndexReportDocumentIdMismatch(Int, String, String)
IndexReportDocumentTextMismatch(Int, String, String)
IndexReportUnexpectedScanFailure(String, ConfigError)
IndexReportUnexpectedScanSuccess(String, ConfigError)
IndexReportScanFailureMismatch(String, ConfigError, ConfigError)
IndexScanReportMismatch(String)
IndexCorpusStatisticsMismatch(RomanCorpusStatistics, RomanCorpusStatistics)
IndexReportInvalidSpan(String, RomanIndexEvidenceKind, Int, SourceSpan, Int)
IndexReportSourceMismatch(String, RomanIndexEvidenceKind, Int, String, String)
IndexReportOutOfOrder(String, RomanIndexEvidenceKind, Int)
IndexReportOverlappingEvidence(String, RomanIndexEvidenceKind, Int, RomanIndexEvidenceKind, Int)
IndexReportCandidateCountTooSmall(String, Int, Int)
IndexReportMatchParseFailed(String, Int, RomanReportError)
IndexReportMatchEvidenceMismatch(String, Int)
IndexReportMatchPolicyMismatch(String, Int)
IndexReportUnexpectedRejectionDetails(String)
IndexReportRejectionReasonMismatch(String, Int)
} derive(Eq,
Debug
)

Reports invalid identities, scan failures, and mutable report mismatches.

#
RomanIndexDocumentFrequency

pub(all) struct RomanIndexDocumentFrequency {
document_id : String
count : Int64
} derive(Eq,
Debug
)

Counts accepted entries for one retained document.

#
RomanIndexDocumentGroup

pub(all) struct RomanIndexDocumentGroup {
document_id : String
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups accepted entries by document in first entry occurrence order.

#
RomanIndexDocumentMetadata

pub(all) struct RomanIndexDocumentMetadata {
id : String
source_length : Int
parse_mode : RomanMode
candidates_examined : Int
accepted_count : Int
rejected_count : Int
first_ordinal : Int?
} derive(Eq,
Debug
)

Summarizes one Int-bounded scan report without discarding input position.

#
RomanIndexDocumentSummary

pub(all) struct RomanIndexDocumentSummary {
document_id : String
parse_mode : RomanMode
source_length : Int
candidates_examined : Int64
accepted : Int64
rejected : Int64
retained_rejections : Int64
first_ordinal : Int?
min_value : Int?
max_value : Int?
distinct_values : Int64
used_unicode : Int64
normalized_inputs : Int64
} derive(Eq,
Debug
)

Summarizes retained and aggregate evidence for one document.

#
RomanIndexEntry

pub(all) struct RomanIndexEntry {
document_id : String
source_span : SourceSpan
source_text : String
value : Int
canonical : String
normalized_text : String
mode : RomanMode
used_unicode_compatibility : Bool
normalized_input : Bool
trimmed_outer_whitespace : Bool
token_count : Int
ordinal : Int
} derive(Eq,
Debug
)

Retains one accepted numeral with stable document and parse evidence.

#
RomanIndexEvidenceKind

pub(all) enum RomanIndexEvidenceKind {
IndexMatchEvidence
IndexRejectionEvidence
} derive(Eq,
Debug
)

Identifies the report array containing invalid retained evidence.

#
RomanIndexModeFrequency

pub(all) struct RomanIndexModeFrequency {
mode : RomanMode
count : Int64
} derive(Eq,
Debug
)

Counts one notation mode in first-occurrence order.

#
RomanIndexModeGroup

pub(all) struct RomanIndexModeGroup {
mode : RomanMode
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups notation modes in first-occurrence order.

#
RomanIndexNormalizationGroup

pub(all) struct RomanIndexNormalizationGroup {
normalized_input : Bool
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups input normalization evidence in first-occurrence order.

#
RomanIndexNormalizedFrequency

pub(all) struct RomanIndexNormalizedFrequency {
normalized_text : String
count : Int64
} derive(Eq,
Debug
)

Counts one normalized spelling in first-occurrence order.

#
RomanIndexQuery

pub(all) struct RomanIndexQuery {
document_id : String?
source_text : String?
normalized_text : String?
canonical_text : String?
mode : RomanMode?
min_value : Int?
max_value : Int?
used_unicode : Bool?
normalized_input : Bool?
offset : Int
limit : Int?
} derive(Eq,
Debug
)

Selects index entries using exact evidence, inclusive values, and pagination.

#
RomanIndexQueryError

pub(all) enum RomanIndexQueryError {
IndexQueryMinimumAboveMaximum(Int, Int)
NegativeIndexQueryOffset(Int)
NonPositiveIndexQueryLimit(Int)
} derive(Eq,
Debug
)

Rejects invalid query bounds before any entry is inspected.

#
RomanIndexQueryPage

pub(all) struct RomanIndexQueryPage {
entries : Array[RomanIndexEntry]
total_matches : Int64
offset : Int
limit : Int?
} derive(Eq,
Debug
)

Retains page entries and the complete filtered count.

#
RomanIndexRejectionSummary

pub(all) struct RomanIndexRejectionSummary {
document_id : String
source_span : SourceSpan
source_text : String
reason : ScanRejectionReason
} derive(Eq,
Debug
)

Retains one rejected candidate in document and source order.

#
RomanIndexSourceFrequency

pub(all) struct RomanIndexSourceFrequency {
source_text : String
count : Int64
} derive(Eq,
Debug
)

Counts one source spelling in first-occurrence order.

#
RomanIndexStatistics

pub(all) struct RomanIndexStatistics {
total_documents : Int64
candidates_examined : Int64
accepted_entries : Int64
rejected_candidates : Int64
used_unicode_compatibility : Int64
normalized_inputs : Int64
} derive(Eq,
Debug
)

Provides deterministic totals derived from retained index evidence.

#
RomanIndexSummary

pub(all) struct RomanIndexSummary {
document_count : Int64
entry_count : Int64
rejected_count : Int64
min_value : Int?
max_value : Int?
distinct_values : Int64
used_unicode : Int64
normalized_inputs : Int64
documents : Array[RomanIndexDocumentSummary]
} derive(Eq,
Debug
)

Summarizes an index with explicit empty-index extrema.

#
RomanIndexTokenCountFrequency

pub(all) struct RomanIndexTokenCountFrequency {
token_count : Int
count : Int64
} derive(Eq,
Debug
)

Counts entries with one token length in first-occurrence order.

#
RomanIndexUnicodeGroup

pub(all) struct RomanIndexUnicodeGroup {
used_unicode : Bool
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups Unicode evidence in false/true first-occurrence order.

#
RomanIndexValueFrequency

pub(all) struct RomanIndexValueFrequency {
value : Int
count : Int64
} derive(Eq,
Debug
)

Counts one numeric value without narrowing the accumulator.

#
RomanIndexValueGroup

pub(all) struct RomanIndexValueGroup {
value : Int
entries : Array[RomanIndexEntry]
} derive(Eq,
Debug
)

Groups equal numeric values in first-occurrence order.

#
RomanLintPolicy

pub(all) struct RomanLintPolicy {
parse_config : ParseConfig
case_requirement : RomanCaseRequirement
allow_unicode : Bool
allow_outer_whitespace : Bool
require_canonical : Bool
include_single_symbol : Bool
retain_rejected_candidates : Bool
max_candidate_length : Int
} derive(Eq,
Debug
)

Separates broad parsing acceptance from document style requirements.

#
RomanLintReport

pub(all) struct RomanLintReport {
original : String
policy : RomanLintPolicy
analysis : RomanAnalysisReport
style_diagnostics : Array[RomanDiagnostic]
diagnostics : Array[RomanDiagnostic]
replacement : String?
error_count : Int
warning_count : Int
conforms : Bool
} derive(Eq,
Debug
)

Returns retained analysis plus style-policy evidence.

#
RomanMode

pub(all) enum RomanMode {
ModernCanonical
AdditiveHistorical
ClockFace
ParenthesizedThousands
} derive(Eq,
Debug
)

Selects one deterministic Roman notation grammar.

#
RomanRangeConfig

pub(all) struct RomanRangeConfig {
start : Int
end : Int
step : Int
format_config : FormatConfig
max_items : Int
} derive(Eq,
Debug
)

Configures an inclusive, bounded Roman numeral sequence.

#
RomanRangeEntry

pub(all) struct RomanRangeEntry {
value : Int
text : String
} derive(Eq,
Debug
)

Associates one generated numeral with its integer value.

#
RomanRangeError

pub(all) enum RomanRangeError {
ZeroRangeStep
RangeDirectionMismatch(Int, Int, Int)
InvalidRangeItemLimit(Int)
RangeItemLimitExceeded(Int, Int)
RangeValueFormatFailed(Int, FormatError)
} derive(Eq,
Debug
)

Reports invalid sequence controls or an exact formatting failure.

#
RomanReplacement

pub(all) struct RomanReplacement {
source_span : SourceSpan
output_span : SourceSpan
source_text : String
replacement_text : String
value : Int
} derive(Eq,
Debug
)

Maps one accepted source candidate to its output position.

#
RomanReportError

pub(all) enum RomanReportError {
EmptyRomanInput
UnsupportedRomanCharacter(SourceSpan, Char)
LowercaseRomanNotAllowed(SourceSpan, Char)
InvalidRomanGrammar(SourceSpan, DiagnosticCode)
NonCanonicalRoman(String)
RomanReportOutOfRange(Int)
InvalidRomanConfiguration(ConfigError)
} derive(Eq,
Debug
)

Reports configured parsing failures without requiring string parsing.

#
RomanRewriteError

pub(all) enum RomanRewriteError {
RewriteScanConfigurationFailed(ConfigError)
RewriteFormatFailed(SourceSpan, FormatError)
} derive(Eq,
Debug
)

Reports scanner configuration or target-format failures.

#
RomanRewriteReport

pub(all) struct RomanRewriteReport {
original : String
output : String
replacements : Array[RomanReplacement]
skipped : Array[RomanRewriteSkipped]
scan_report : RomanScanReport
} derive(Eq,
Debug
)

Returns rewritten text, mapping evidence, and the original scan report.

#
RomanRewriteSkipped

pub(all) struct RomanRewriteSkipped {
source_span : SourceSpan
source_text : String
value : Int
error : FormatError
} derive(Eq,
Debug
)

Records an accepted source value retained after target formatting failed.

#
RomanScanMatch

pub(all) struct RomanScanMatch {
span : SourceSpan
source_text : String
report : ParseReport
} derive(Eq,
Debug
)

Retains one accepted candidate and its configured parse evidence.

#
RomanScanRejection

pub(all) struct RomanScanRejection {
span : SourceSpan
source_text : String
reason : ScanRejectionReason
} derive(Eq,
Debug
)

Retains one rejected candidate when requested by ScanConfig.

#
RomanScanReport

pub(all) struct RomanScanReport {
matches : Array[RomanScanMatch]
rejections : Array[RomanScanRejection]
candidates_examined : Int
} derive(Eq,
Debug
)

Returns document matches and deterministic scanning counters.

#
RomanTextEdit

pub(all) struct RomanTextEdit {
id : String
span : SourceSpan
expected_source : String
replacement : String
numeric_value : Int?
reason : RomanEditReason
source_diagnostic_code : DiagnosticCode?
} derive(Eq,
Debug
)

Describes one caller-identified replacement over a half-open source span.

#
RomanToken

pub(all) struct RomanToken {
span : SourceSpan
source_text : String
normalized_text : String
value : Int
role : RomanTokenRole
} derive(Eq,
Debug
)

Retains source and normalized evidence for one token.

#
RomanTokenRole

pub(all) enum RomanTokenRole {
SymbolToken
SubtractiveToken
GroupOpenToken
GroupCloseToken
} derive(Eq,
Debug
)

Classifies one parsed Roman token.

#
ScanConfig

pub(all) struct ScanConfig {
parse_config : ParseConfig
retain_rejected : Bool
include_single_symbol : Bool
max_candidate_length : Int
} derive(Eq,
Debug
)

Configures candidate retention and limits for document scanning.

#
ScanRejectionReason

pub(all) enum ScanRejectionReason {
SingleSymbolExcluded
CandidateTooLong(Int)
CandidateParseFailed(RomanReportError)
} derive(Eq,
Debug
)

Explains why a lexical Roman candidate was not accepted.

#
SourceSpan

pub(all) struct SourceSpan {
start : Int
end : Int
} derive(Eq,
Debug
)

Identifies a half-open source-character range.

#
additive_format_config

fn additive_format_config() -> FormatConfig

Return an uppercase additive formatter configuration.

#
additive_parse_config

fn additive_parse_config() -> ParseConfig

Return a deterministic additive-profile parser configuration.

#
analyze_roman

fn analyze_roman(input : String, config : ParseConfig) -> RomanAnalysisReport

Analyze configured input and retain diagnostics for rejected values.

#
apply_roman_edit_plan

fn apply_roman_edit_plan(source : String, plan : RomanEditPlan) -> Result[RomanEditApplicationReport, RomanEditError]

Apply every validated edit atomically when the complete source is current.

#
build_roman_document_index

fn build_roman_document_index(inputs : Array[RomanDocument]) -> Result[RomanDocumentIndex, RomanIndexConstructionError]

Build one stable index by scanning explicit ID-addressed source/config inputs.

#
build_roman_index_from_corpus

fn build_roman_index_from_corpus(inputs : Array[RomanDocument], report : RomanCorpusReport) -> Result[RomanDocumentIndex, RomanIndexConstructionError]

Build after rescanning every result and comparing complete corpus statistics. This correctness check is not a performance optimization.

#
build_roman_index_from_scan

fn build_roman_index_from_scan(document_id : String, source : String, config : ScanConfig) -> Result[RomanDocumentIndex, RomanIndexConstructionError]

Build an index for one document by rescanning caller-owned source/config.

#
build_roman_index_from_scan_report

fn build_roman_index_from_scan_report(document_id : String, source : String, config : ScanConfig, report : RomanScanReport) -> Result[RomanDocumentIndex, RomanIndexConstructionError]

Build from an existing report after rescanning to reject mutable evidence. This correctness check is not a performance optimization.

#
canonicalize

fn canonicalize(input : String) -> Result[String, ParseError]

Normalize valid uppercase or lowercase input to canonical uppercase text.

#
clock_format_config

fn clock_format_config() -> FormatConfig

Return an uppercase clock formatter configuration.

#
clock_parse_config

fn clock_parse_config() -> ParseConfig

Return a clock-profile parser configuration.

#
compatibility_parse_config

fn compatibility_parse_config() -> ParseConfig

Return a modern parser configuration with Unicode and outer trimming.

#
convert_roman

fn convert_roman(input : String, source_config : ParseConfig, target_config : FormatConfig) -> Result[RomanConversionReport, ConversionError]

Parse with one explicit profile and format with another.

#
count_roman_index_matches

fn count_roman_index_matches(index : RomanDocumentIndex, query : RomanIndexQuery) -> Result[Int64, RomanIndexQueryError]

Count all filtered entries without applying query pagination.

#
default_roman_index_query

fn default_roman_index_query() -> RomanIndexQuery

Return a query with no evidence constraints or page limit.

#
extended_format_config

fn extended_format_config() -> FormatConfig

Return an uppercase parenthesized-thousands formatter configuration.

#
extended_parse_config

fn extended_parse_config() -> ParseConfig

Return a parenthesized-thousands parser configuration.

#
find_roman_index_document

fn find_roman_index_document(index : RomanDocumentIndex, document_id : String) -> RomanIndexDocumentMetadata?

Find retained document metadata by exact ID.

#
find_roman_index_entry_by_ordinal

fn find_roman_index_entry_by_ordinal(index : RomanDocumentIndex, ordinal : Int) -> RomanIndexEntry?

Find an entry by its stable global ordinal.

#
first_roman_index_entry_for_value

fn first_roman_index_entry_for_value(index : RomanDocumentIndex, value : Int) -> RomanIndexEntry?

Return the first entry having an exact numeric value.

#
format

fn format(value : Int) -> Result[String, FormatError]

Format an integer from 1 through 3999 as an uppercase Roman numeral.

#
format_clock_hour

fn format_clock_hour(hour : Int) -> Result[String, FormatError]

Format a clock-face hour from 1 through 12, using IIII for four.

#
format_lower

fn format_lower(value : Int) -> Result[String, FormatError]

Format an integer from 1 through 3999 as a lowercase Roman numeral.

#
format_roman_range

fn format_roman_range(config : RomanRangeConfig) -> Result[Array[RomanRangeEntry], RomanRangeError]

Format an inclusive sequence after validating direction and output size.

#
format_with_config

fn format_with_config(value : Int, config : FormatConfig) -> Result[String, FormatError]

Format one value under an explicit notation mode and letter-case policy.

#
group_roman_index_entries_by_canonical

fn group_roman_index_entries_by_canonical(index : RomanDocumentIndex) -> Array[RomanIndexCanonicalGroup]

Group equal canonical spellings in first occurrence order.

#
group_roman_index_entries_by_document

fn group_roman_index_entries_by_document(index : RomanDocumentIndex) -> Array[RomanIndexDocumentGroup]

Group entries by document according to the first accepted entry.

#
group_roman_index_entries_by_mode

fn group_roman_index_entries_by_mode(index : RomanDocumentIndex) -> Array[RomanIndexModeGroup]

Group entries by notation mode in first occurrence order.

#
group_roman_index_entries_by_normalization

fn group_roman_index_entries_by_normalization(index : RomanDocumentIndex) -> Array[RomanIndexNormalizationGroup]

Group entries by whether parsing changed their input spelling.

#
group_roman_index_entries_by_unicode

fn group_roman_index_entries_by_unicode(index : RomanDocumentIndex) -> Array[RomanIndexUnicodeGroup]

Group entries by Unicode compatibility evidence.

#
group_roman_index_entries_by_value

fn group_roman_index_entries_by_value(index : RomanDocumentIndex) -> Array[RomanIndexValueGroup]

Group equal values in order of the first matching entry.

#
is_canonical

fn is_canonical(input : String) -> Bool

Return true when input is a canonical uppercase or lowercase Roman numeral.

#
lint_roman

fn lint_roman(input : String, policy : RomanLintPolicy) -> Result[RomanLintReport, ConfigError]

Lint one configured Roman input and retain parser and style diagnostics.

#
lint_roman_document

fn lint_roman_document(text : String, policy : RomanLintPolicy) -> Result[RomanDocumentLintReport, ConfigError]

Lint scanner candidates and return document-global diagnostics.

#
lowercase_format_config

fn lowercase_format_config(mode : RomanMode) -> FormatConfig

Return a formatter configuration for lowercase output in a selected mode.

#
modern_format_config

fn modern_format_config() -> FormatConfig

Return an uppercase modern formatter configuration.

#
normalize_roman_input

fn normalize_roman_input(input : String, config : ParseConfig) -> Result[String, RomanReportError]

Normalize configured Roman input to deterministic uppercase ASCII text.

#
parse

fn parse(input : String) -> Result[Int, ParseError]

Parse an uppercase or lowercase Roman numeral.

#
parse_with_config

fn parse_with_config(input : String, config : ParseConfig) -> Result[ParseReport, RomanReportError]

Parse configured Roman input and return source-located evidence.

#
preview_roman_edit_plan

fn preview_roman_edit_plan(plan : RomanEditPlan) -> Result[RomanEditPreview, RomanEditError]

Revalidate a plan before previewing exact output spans and mappings.

#
process_roman_batch

fn process_roman_batch(items : Array[RomanBatchItem]) -> Result[RomanBatchReport, BatchValidationError]

Parse an ID-addressed batch while retaining stable input order.

#
process_roman_corpus

fn process_roman_corpus(documents : Array[RomanDocument]) -> Result[RomanCorpusReport, CorpusValidationError]

Scan an ID-addressed document corpus and aggregate retained evidence.

#
query_roman_index

fn query_roman_index(index : RomanDocumentIndex, query : RomanIndexQuery) -> Result[Array[RomanIndexEntry], RomanIndexQueryError]

Filter and paginate entries while preserving complete index order.

#
query_roman_index_page

fn query_roman_index_page(index : RomanDocumentIndex, query : RomanIndexQuery) -> Result[RomanIndexQueryPage, RomanIndexQueryError]

Filter before paginating and report the complete filtered count.

#
rewrite_roman_text

fn rewrite_roman_text(text : String, config : RewriteConfig) -> Result[RomanRewriteReport, RomanRewriteError]

Rewrite accepted scanner matches while preserving replacement evidence.

#
roman_edit_plan_from_document_lint

fn roman_edit_plan_from_document_lint(report : RomanDocumentLintReport, config : RomanEditPlanConfig) -> Result[RomanEditPlan, RomanEditError]

Build a validated plan from deterministic document-lint replacements.

#
roman_edit_plan_from_rewrite

fn roman_edit_plan_from_rewrite(report : RomanRewriteReport, rewrite_config : RewriteConfig, edit_config : RomanEditPlanConfig) -> Result[RomanEditPlan, RomanEditError]

Build a validated plan from replacements retained by a rewrite report.

#
roman_index_canonical_frequencies

fn roman_index_canonical_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexCanonicalFrequency]

Count canonical spellings in first-occurrence order.

#
roman_index_document_frequencies

fn roman_index_document_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexDocumentFrequency]

Count accepted entries for every document, including empty documents.

#
roman_index_entries_for_canonical_text

fn roman_index_entries_for_canonical_text(index : RomanDocumentIndex, canonical_text : String) -> Array[RomanIndexEntry]

Return entries having exact profile-canonical spelling.

#
roman_index_entries_for_document

fn roman_index_entries_for_document(index : RomanDocumentIndex, document_id : String) -> Array[RomanIndexEntry]

Return all entries for an exact document ID in source order.

#
roman_index_entries_for_normalized_text

fn roman_index_entries_for_normalized_text(index : RomanDocumentIndex, normalized_text : String) -> Array[RomanIndexEntry]

Return entries having exact normalized spelling.

#
roman_index_entries_for_source_text

fn roman_index_entries_for_source_text(index : RomanDocumentIndex, source_text : String) -> Array[RomanIndexEntry]

Return entries having exact source spelling.

#
roman_index_entries_for_value

fn roman_index_entries_for_value(index : RomanDocumentIndex, value : Int) -> Array[RomanIndexEntry]

Return all entries having an exact numeric value.

#
roman_index_entries_in_value_range

fn roman_index_entries_in_value_range(index : RomanDocumentIndex, minimum : Int, maximum : Int) -> Result[Array[RomanIndexEntry], RomanIndexQueryError]

Return entries inside an inclusive numeric range.

#
roman_index_mode_frequencies

fn roman_index_mode_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexModeFrequency]

Count notation modes in first-occurrence order.

#
roman_index_normalized_frequencies

fn roman_index_normalized_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexNormalizedFrequency]

Count normalized spellings in first-occurrence order.

#
roman_index_rejections_for_document

fn roman_index_rejections_for_document(index : RomanDocumentIndex, document_id : String) -> Array[RomanIndexRejectionSummary]

Return retained rejection details for one document in source order.

#
roman_index_source_frequencies

fn roman_index_source_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexSourceFrequency]

Count exact source spellings in first-occurrence order.

#
roman_index_token_count_frequencies

fn roman_index_token_count_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexTokenCountFrequency]

Count parser token lengths in first-occurrence order.

#
roman_index_value_frequencies

fn roman_index_value_frequencies(index : RomanDocumentIndex) -> Array[RomanIndexValueFrequency]

Count values in first-occurrence order using Int64 accumulators.

#
scan_roman_text

fn scan_roman_text(text : String, config : ScanConfig) -> Result[RomanScanReport, ConfigError]

Scan complete lexical candidates and parse each with the selected profile.

#
strict_parse_config

fn strict_parse_config() -> ParseConfig

Return the strict modern parser configuration used by report APIs.

#
summarize_roman_document_index

fn summarize_roman_document_index(index : RomanDocumentIndex) -> RomanIndexSummary

Recompute deterministic index statistics from retained entries and metadata.

#
validate_roman_edit_plan

fn validate_roman_edit_plan(source : String, edits : Array[RomanTextEdit], config : RomanEditPlanConfig) -> Result[RomanEditPlan, RomanEditError]

Validate and source-order a caller-supplied atomic text edit plan.

Validation order is configuration, IDs, spans, exact source evidence, overlap, no-op replacements, representable output size, and configured size.

#
validate_scan_config

fn validate_scan_config(config : ScanConfig) -> Result[Unit, ConfigError]

Validate scanner limits before processing text.