rocq/theories/Formatting.v
Hello's reached plain formatting calls, not the older fortified-symbol census. HelloCode's usage and version_etc use strings, %% and promoted integers; its wide path uses L"%ls\n". Admission is independent of output success. No %n is selected, so no %n write authority is granted. Translated formats outside this grammar need a further contract or a proved translation restriction, not an invented successful parse.
Decimal digits with no redundant leading zero, interpreted in base ten. This specifies decimal output independently of a printer.
The default-promoted int/unsigned int argument is a canonical W. Negative int words print a minus sign and the absolute signed value.
Selected format interpretation, with exact consumed varargs. Each %s needs its whole in-object NUL-terminated string even on failure. Literals and %% consume no argument. Floats, lengths, positional conversions, precision, and %n are deliberately not admitted here.
Read spans for the format and pointer varargs, through their NULs. Integer words grant no capability source; no source becomes a write root or an owned release. Exact lengths follow from admission.
The selected variadic ABI permits only P and promoted W, not L or unpromoted byte/half classes. The format interpretation independently requires matching pointer or integer words at every conversion.
The three reached narrow entry points share interpretation and FIFO effects, but retain their distinct fixed argument positions.
| | | NarrowPrintf | ||
| | | NarrowFprintf | ||
| | | NarrowFputs |
The stream handle selected by each entry point.
The readable input pointer and remaining varargs, excluding FILE.
Plain fputs accepts the string unchanged; formatting calls interpret a readable format and its exact varargs before selecting a result.
The complete fixed and promoted argument ABI.
Complete admission: represented open non-wide stream and readable, well-typed format inputs. A negative result does not weaken this.
Formatted results count all output bytes on success; fputs promises only a nonnegative int. Every negative result may follow partial OR full acceptance, including an encoding or count-overflow failure.
A finite output prefix reuses Stdio's ordered obligations. Stream identifiers distinguish stdout from stderr. Delivery is not another acceptance event. Physical pending may differ from outstanding.
A completed output call includes the cumulative acceptance event, even on failure, but does not promise descriptor delivery.
The common contract retains readable inputs only as sources; its writable roots are solely the stream's, and it releases no caller object. Native temporary allocations remain explicit requests.
Plain printf uses the supplied stdout-handle projection.
Plain fprintf takes its FILE as the first P argument.
Plain fputs takes its FILE as the second P argument.
A readable wchar_t string, including its aligned four-byte NUL. Invalid encoding values are not excluded: output may fail on them.
A bounded scan in wchar_t units, solely to compute the readable source footprint. As for string_length, admission grants reads.
Selected wide realization: conversion, native buffering and its observations must be supplied independently. It is not byte Accept on a wide stream and does not create another stdout queue.
| wide_realization | : world → ptr → listZ → listZ → stream_info → optionZ → Prop |
Admission to Hello's sole wide format L"%ls\n", with one readable wchar_t-string P argument and a non-byte-oriented stdout.
Wide prefixes preserve the authoritative orientation/error state; the realization relation accounts for encoded bytes accepted and ties successful results to complete conversion. None is a finite prefix, Some result an ordinary completion.
The selected wprintf contract has a separate native realization premise. Success counts wchar_t output, not encoded bytes. Resources never inherit its normal-return postcondition.
Selected error() decoration and internal state authority. Readiness excludes a user error_print_progname callback, supplies initialized counter/TLS/program-name state and all selected strerror dependencies. Segments include the program prefix, formatted body, optional errno text and newline. Each native formatting stage can fail independently. The frame must preserve phase, status, pending/consumed callback inventories, and permit only the explicitly described stream changes.
| diagnostic_ready | : mem → world → Prop | |
| diagnostic_sources | ||
| diagnostic_writes | : world → listspan | |
| diagnostic_requests | : world → Z → Z → Prop | |
| diagnostic_segments | : mem → world → Z → listZ → listlistZ → Prop | |
| diagnostic_frame | : world → world → Prop |
Flushing stdout does not accept diagnostic bytes. An already closed static stdout stays closed; its selected safe fflush behavior is part of native representation coverage, not valid arbitrary FILE use.
Admission to the formatting part of error, before any exit request. The selected stderr path is narrow; wide stderr needs separate fxprintf conversion coverage. Status/errno are promoted canonical W words.
A diagnostic can accept a prefix of EACH stage, not necessarily a prefix of the concatenation: a failed body may be followed by errno text or a newline. Nothing is labeled as stdout acceptance.
error's formatting stage has the actual W,W,P variadic ABI and void return. It NEVER emits ProcessExit: the separate ending protocol owns the exit request after this stage's current-world completion.
Inversion over the supplied machine keeps ordinary returns and resource stops apart without a sibling invocation relation.
Construct an ordinary output completion from the independently witnessed prefix/effects and complete result relation.
Explore proof 12 tactics
Initial goal
intros world api model stdout r args xs s m w born trace result s′ m′ w′ Habi Hpre Hprefix Hpost
eapply E.invoke_normal with born := born ; try exact Habi ; try exact Hpre ; try exact Hprefix ; try exact Hpost ; try discriminate
intros values Heq
injection Heq as ←
split ; | constructor ; exact I | constructor
exists WIntresult
split ; reflexivity |
simpl
destruct Hpost as info & info′ & bytes & actions & tail & n & _ & _ & _ & _ & _ & _ & _ & _ & Hr & _ & Hend
injection Hend as ←
rewrite Z.mod_small ; reflexivity |
destruct Hr as _ & Hn & _ | Hn ; unfold negative_int in * ; lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
All three narrow contracts share this ordinary/resource disjunction.
Explore proof 6 tactics
Initial goal
intros world api model stdout r args xs s m w trace ending s′ m′ w′ Hcall
inversion Hcall ; subst
2 openfocused goal
–left
2 opendeferred goal
match goal withHpost : contract_post_ _ _ _ _ _ _ _ |- _⇒exists born ; exact Hpostend
deferred goal
–right
eauto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Hello's output frames need a canonical W, not successful output or an exact fputs byte count. Negative results remain canonical too.
Explore proof 6 tactics
Initial goal
intros world api model stdout r args xs s m w trace values s′ m′ w′ Hcall
destruct output_invocation_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Hcall as born & info & info′ & bytes & actions & tail & result & _ & _ & _ & _ & _ & _ & _ & _ & Hr & _ & Hend | why & Hbad & _ ; | discriminate Hbad
injection Hend as →
exists result
split ; reflexivity |
destruct Hr as _ & Hrange & _ | Hrange ; unfold negative_int in * ; lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Standalone compatibility wrapper; logic clients use FormattingOn with their actual exported machine instance.
%n is not silently admitted as a read-only conversion.
Explore proof 2 tactics
Initial goal
intros m args bytes H
inversion H ; subst ; try lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Decimal signedness distinguishes canonical negative one from the corresponding unsigned integer.
Explore proof 8 tactics
Initial goal
split ; lia |
change ∃digits, 45; 49 = 45 :: digits ∧ decimal_digitsdigits 1
exists 49
split ; reflexivity |
unfold decimal_digits
split ; discriminate |
split ; repeat constructor ; lia |
split ; simpl ; discriminate | reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Even full acceptance may be followed by a negative format result.
Explore proof 3 tactics
Initial goal
right
unfold negative_int , stream_eof
lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A nonnegative formatted result counts bytes; fputs alone may return an arbitrary nonnegative int.
Explore proof 1 tactics
Initial goal
intros _ & _ & Hapi | Hcount | Hnegative ; simpl in * ; unfold negative_int in * ; congruence || lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Missing or integer-class %s arguments fail admission, not just a particular successful output result.
Explore proof 2 tactics
Initial goal
intros m bytes H
inversion H ; subst ; try lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.