moonbit-roman

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

    roman
    numeral
    parser
    lint
    index
    Download zip
    Version
    0.3.0
    License
    Apache-2.0
    Last updated
    3 months ago
    Downloads
    41

    No dependencies

    #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.