Fil-C on Nix

Filnix wiki

the formal campaign

rocq/backend/NfbTransport.v

The term half of NFB's round trip (docs/nfb.md): a module that Transport.v's decode_module reads from any term is read back from the term Nfb.v's enc_module writes for it (decode_enc_module), and no item of that term is a context item (enc_module_no_context).

Most of the syntax is canonical: for every decoder of Transport.v but the data item's, what it reads from a term t is written back by its encoder as t itself (dinst_enc, dblock_enc, dfunc_enc and the others below). So enc_modulem would be t with its context items dropped, except for one construct: a string item whose character is an overlong two-byte UTF-8 atom, such as the atom of the bytes 0xC0 0x80. char_code reads it as the code 0, which code_char writes back as the one-byte atom. Then enc_modulem is not the term m was read from (strong_form_fails). The term is still read back as the same module, because char_code reads every code code_char writes (char_code_code_char), and that is all decode_enc_module needs.

From Stdlib Require Import String ZArith List Bool Ascii Lia
From Nanofil Require Import Term Syntax Semantics Validate Transport Cfg
From Backend Require Import IrTerm NfbTerm Nfb
Import ListNotations
Open Scope string_scope
Open Scope Z_scope

Taking a decoder apart

Turn a fact E, that a decoder read a term, into the term itself, using one of the earlier lemmas in the context.

32Ltac use_inv E ≔
match goal withI : _ |- _⇒apply I in E;match type of E with_ = _⇒idtacendend;subst

Split the hypothesis H on what blocks its match x: a variable, a string comparison, a list length, or a decoder's result.

37Ltac split_on H x ≔
lazymatch x withmatch ?y with _ ⇒ _ end⇒split_on H y_⇒first|is_var x ; destruct x ; simpl in H|match x withcontext [String.eqb?a ?s]⇒is_var a ; let E ≔ fresh "E" in destruct String.eqba s eqn: E ; apply String.eqb_eq in E ; subst a | clear E ; simpl in Hend|match x withcontext [length?xs]⇒is_var xs ; destruct xs ; simpl in Hend|let E ≔ fresh "E" in destruct x eqn: E ; try use_inv E ; simpl in Hend

One step of reading back a hypothesis H that a decoder gave Some: refute it, take apart what blocks it, or take its value.

51Ltac dstep H ≔
lazymatch type of H withNone = Some_⇒discriminate HSome?v = Some_⇒first|match v withcontext [match ?y with _ ⇒ _ end]⇒split_on H yend|injection H as H ; substmatch ?y with _ ⇒ _ end = Some_⇒split_on H y_ = Some_⇒use_inv Hend

Close a goal that the encoding is the term, rewriting with what the encoders of the parts gave back.

63Ltac close  ≔
repeat match goal withE : @eqterm _ ?b |- context [?b]⇒progress rewrite <- Eend;reflexivity

The head normal form of e.

68Ltac hnf_of e ≔
eval hnf in e

Destruct the variable that blocks the match r, looking through the head of each scrutinee in turn.

72Ltac blocker r ≔
match r withmatch ?x with _ ⇒ _ end⇒first is_var x ; destruct x | let y ≔ hnf_of x in blocker yend

One step of proving a goal match dt with Somex ⇒ Px | None ⇒ True end for a decoder d without lists: close it once d t has a head, or destruct what blocks it.

80Ltac spec_step  ≔
match goal with|- match ?e with _ ⇒ _ end⇒let r ≔ hnf_of e inlazymatch r withSome_⇒exact eq_reflNone⇒exact I_⇒blocker rendend

Values and the small tables

An integer is read from the term TIntn only.

93Lemma dz_enc
∀ t n
dzt = Somen
TIntn = t
Proof 4 steps Qed
intros t n H
unfold dz in H
repeat dstep H
all: close

A class is read from its own atom only.

97Lemma dclass_enc
∀ t k
dclasst = Somek
eclassk = t
Proof 4 steps Qed
intros t k H
unfold dclass , datom in H
repeat dstep H
all: close

A temporary n is read from tmp(N) only.

101Lemma dtmp_enc
∀ t n
dtmpt = Somen
enc_tmpn = t
Proof 4 steps Qed
intros t n H
unfold dtmp , dapp in H
repeat dstep H
all: close

A value is read from the term enc_value writes for it only.

105Lemma dvalue_enc
∀ t v
dvaluet = Somev
enc_valuev = t
Proof 4 steps Qed
intros t v H
unfold dvalue in H
repeat dstep H
all: close

Rights are read from their own atom only.

109Lemma drights_enc
∀ t r
drightst = Somer
Proof 4 steps Qed
intros t r H
unfold drights , datom in H
repeat dstep H
all: close

A bound is read from its own atom only.

113Lemma dbound_enc
∀ t b
dboundt = Someb
enc_boundb = t
Proof 4 steps Qed
intros t b H
unfold dbound , datom in H
repeat dstep H
all: close

A narrow type is read from its own atom only.

117Lemma dnarrow_enc
∀ t n
dnarrowt = Somen
Proof 4 steps Qed
intros t n H
unfold dnarrow , datom in H
repeat dstep H
all: close

A load type is read from its own atom only.

121Lemma dload_type_enc
∀ t l
dload_typet = Somel
Proof 5 steps Qed
intros t l H
pose proof dnarrow_enc
unfold dload_type , datom in H
repeat dstep H
all: close

A condition is read from its own atom only.

127Lemma dcond_enc
∀ t c
dcondt = Somec
enc_condc = t
Proof 4 steps Qed
intros t c H
unfold dcond , datom in H
repeat dstep H
all: close

An effect is read from its own atom only.

131Lemma deffect_enc
∀ t e
deffectt = Somee
Proof 4 steps Qed
intros t e H
unfold deffect , datom in H
repeat dstep H
all: close

A width is read from its own atom only.

135Lemma dwidth_enc
∀ t w
dwidtht = Somew
enc_widthw = t
Proof 4 steps Qed
intros t w H
unfold dwidth , datom in H
repeat dstep H
all: close

If e writes back every term d reads, it writes back every list of terms that map_option d reads.

140Lemma map_option_enc
∀ X : Type d : term → optionX e : X → term ts xs
∀t x, dt = Somex → ex = t
map_optiond ts = Somexs
mape xs = ts
Proof 9 steps Qed
intros X d e He ts
induction ts as | t ts IH ; intros xs H ; simpl in H
–injection H as ←
reflexivity
–destruct dt eqn: E1 ; | discriminate
destruct map_optiond ts eqn: E2 ; | discriminate
injection H as ←
simpl
f_equal ; auto

A list of effects is read from the list of their atoms only.

151Lemma deffects_enc
∀ t es
deffectst = Somees
Proof 5 steps Qed
intros t es H
pose proof map_option_enc_ _ _ deffect_enc
unfold deffects , dlist in H
repeat dstep H
all: close

An op is read from the term enc_op writes for it only.

158Lemma dop_enc
∀ t o
dopt = Someo
enc_opo = t
Proof 12 steps Qed
intros t o H
pose proof dz_enc
pose proof dclass_enc
pose proof drights_enc
pose proof dbound_enc
pose proof dnarrow_enc
pose proof dload_type_enc
pose proof dcond_enc
pose proof deffects_enc
unfold dop , dcheck4 in H
repeat dstep H
all: close

Instructions

A flight's argument is read from its own term only.

169Lemma dflight_arg_enc
∀ t a
dflight_argt = Somea
Proof 4 steps Qed
intros t a H
assert S : match dflight_argt with Somea′ ⇒ enc_flight_arga′ = t | None ⇒ True end by clear H ; repeat spec_step
rewrite H in S
exact S

A flight's Lower is read from its own term only.

178Lemma dflight_lower_enc
∀ t l
dflight_lowert = Somel
Proof 5 steps Qed
intros t l H
pose proof dvalue_enc
unfold dflight_lower in H
repeat dstep H
all: close

One result of a call is read from result(tmp(D), K) only.

182Lemma dresult_enc
∀ t r
dresultt = Somer
Proof 6 steps Qed
intros t r H
pose proof dtmp_enc
pose proof dclass_enc
unfold dresult , dapp in H
repeat dstep H
all: close

A call's Res is read from its own term only.

189Lemma dcall_result_enc
∀ t r
dcall_resultt = Somer
Proof 6 steps Qed
intros t r H
pose proof dresult_enc
pose proof map_option_enc_ _ _ dresult_enc
unfold dcall_result in H
repeat dstep H
all: close

A call's argument is read from arg(K, V) only.

196Lemma darg_enc
∀ t a
dargt = Somea
enc_arga = t
Proof 6 steps Qed
intros t a H
pose proof dvalue_enc
pose proof dclass_enc
unfold darg , dapp in H
repeat dstep H
all: close

A call's arguments are read from the list of their terms only.

203Lemma dargs_enc
∀ t args
dargst = Someargs
enc_argsargs = t
Proof 5 steps Qed
intros t args H
pose proof map_option_enc_ _ _ darg_enc
unfold dargs , dlist in H
repeat dstep H
all: close

An instruction is read from the term enc_inst writes for it only.

210Lemma dinst_enc
∀ t i
dinstt = Somei
enc_insti = t
Proof 16 steps Qed
intros t i H
pose proof dtmp_enc
pose proof dclass_enc
pose proof dop_enc
pose proof dvalue_enc
pose proof map_option_enc_ _ _ dvalue_enc
pose proof dwidth_enc
pose proof dz_enc
pose proof deffects_enc
pose proof dcall_result_enc
pose proof dargs_enc
unfold dinst in H
repeat dstep H
all: close

Jumps, phis, blocks and functions

A jump's target is read from its own term only.

223Lemma dtarget_enc
∀ t l
dtargett = Somel
Proof 4 steps Qed
intros t l H
unfold dtarget in H
repeat dstep H
all: close

A jump is read from the term enc_jump writes for it only.

227Lemma djump_enc
∀ t j
djumpt = Somej
enc_jumpj = t
Proof 7 steps Qed
intros t j H
pose proof dtarget_enc
pose proof dvalue_enc
pose proof map_option_enc_ _ _ dvalue_enc
unfold djump in H
repeat dstep H
all: close

One pair of a phi is read from Pred − Value only.

234Lemma dpair_enc
∀ t p
dpairt = Somep
enc_pairp = t
Proof 5 steps Qed
intros t p H
pose proof dvalue_enc
unfold dpair , dapp in H
repeat dstep H
all: close

A phi is read from the term enc_phi writes for it only.

238Lemma dphi_enc
∀ t p
dphit = Somep
enc_phip = t
Proof 7 steps Qed
intros t p H
pose proof dtmp_enc
pose proof dclass_enc
pose proof map_option_enc_ _ _ dpair_enc
unfold dphi in H
repeat dstep H
all: close

A block is read from the term enc_block writes for it only.

245Lemma dblock_enc
∀ t b
dblockt = Someb
enc_blockb = t
Proof 7 steps Qed
intros t b H
pose proof djump_enc
pose proof map_option_enc_ _ _ dphi_enc
pose proof map_option_enc_ _ _ dinst_enc
unfold dblock in H
repeat dstep H
all: close

A function's Ret is read from its own term only.

252Lemma dret_enc
∀ t r
drett = Somer
enc_retr = t
Proof 6 steps Qed
intros t r H
pose proof dclass_enc
pose proof map_option_enc_ _ _ dclass_enc
unfold dret in H
repeat dstep H
all: close

A function's parameter is read from param(K, tmp(D)) only.

259Lemma dparam_enc
∀ t p
dparamt = Somep
TApp"param" eclassfstp; TApp"tmp" sndp = t
Proof 6 steps Qed
intros t p H
pose proof dtmp_enc
pose proof dclass_enc
unfold dparam , dapp in H
repeat dstep H
all: close

A function read from the arguments of a func term is written back as that term.

268Lemma dfunc_enc
∀ n lk r ps bs f
dfuncn lk r ps bs = Somef
enc_funcf = TApp"func" n; lk; r; ps; bs
Proof 7 steps Qed
intros n lk r ps bs f H
pose proof dret_enc
pose proof map_option_enc_ _ _ dparam_enc
pose proof map_option_enc_ _ _ dblock_enc
unfold dfunc , dlist in H
repeat dstep H
all: close

A data object's Linkage is read from its own term only.

276Lemma dlinkage_enc
∀ t l
dlinkaget = Somel
Proof 4 steps Qed
intros t l H
assert S : match dlinkaget with Somel′ ⇒ enc_linkagel′ = t | None ⇒ True end by clear H ; repeat spec_step
rewrite H in S
exact S

Data

char_code reads only the codes 0 to 2047.

287Lemma char_code_range
∀ t c
char_codet = Somec
0 ≤ c < 2048
Proof 13 steps Qed
intros t c H
unfold char_code in H
destruct t as | a | | ; try discriminate H
destruct a as | c1 | c2 | c3 s ; try discriminate H
–destruct Z.of_natnat_of_asciic1 <? 128 eqn: E ; | discriminate H
injection H as ←
apply Z.ltb_lt in E
lia
–destruct 192 ≤? Z.of_natnat_of_asciic1 && Z.of_natnat_of_asciic1 <? 224 && 128 ≤? Z.of_natnat_of_asciic2 && Z.of_natnat_of_asciic2 <? 192 eqn: E ; | discriminate H
injection H as ←
repeat rewrite andb_true_iff in E
rewrite ! Z.leb_le , ! Z.ltb_lt in E
lia

char_code reads back every code from 0 to 2047 from the atom code_char writes for it.

302Lemma char_code_code_char
∀ c
0 ≤ c < 2048
Proof 23 steps Qed
intros c Hc
unfold code_char
destruct c <? 128 eqn: E
–apply Z.ltb_lt in E
unfold char_code ; cbv beta iota zeta
rewrite nat_ascii_embedding by lia
rewrite Z2Nat.id by lia
replace c <? 128 with true by symmetry ; apply Z.ltb_lt ; lia
reflexivity
–apply Z.ltb_ge in E
unfold char_code ; cbv beta iota zeta
assert Hd : 2 ≤ c / 64 < 32 by split ; apply Z.div_le_lower_bound | apply Z.div_lt_upper_bound ; lia
assert Hm : 0 ≤ c mod 64 < 64 by apply Z.mod_pos_bound ; lia
rewrite ! nat_ascii_embedding by lia
rewrite ! Z2Nat.id by lia
replace 192 ≤? 192 + c / 64 && 192 + c / 64 <? 224 && 128 ≤? 128 + c mod 64 && 128 + c mod 64 <? 192 with true
+f_equal
pose proof Z.div_modc 64
lia
+symmetry
repeat rewrite andb_true_iff
rewrite ! Z.leb_le , ! Z.ltb_lt
lia

The codes of a string item are all from 0 to 2047.

320Lemma char_codes_range
∀ cs codes
map_optionchar_code cs = Somecodes
Forallλc ⇒ 0 ≤ c < 2048 codes
Proof 7 steps Qed
induction cs as | t cs IH ; intros codes H ; simpl in H
–injection H as ←
constructor
–destruct char_codet eqn: E1 ; | discriminate
destruct map_optionchar_code cs eqn: E2 ; | discriminate
injection H as ←
constructor ; eapply char_code_range ; eassumption | auto

Codes from 0 to 2047 are read back from the atoms code_char writes for them.

332Lemma char_codes_round
∀ codes
Forallλc ⇒ 0 ≤ c < 2048 codes
map_optionchar_code mapcode_char codes = Somecodes
Proof 6 steps Qed
induction codes as | c codes IH ; intros H ; simpl
–reflexivity
–inversion H as [ |? ? Hc Hr ] ; subst
rewrite char_code_code_char by exact Hc
rewrite IH by exact Hr
reflexivity

What is known of a data item x read from the term t: it is written back as t, or it is a string of codes from 0 to 2047.

343Definition data_okt : term x : data_item : Prop ≔
enc_data_itemx = t ∨ ∃codes, x = Strcodes ∧ Forallλc ⇒ 0 ≤ c < 2048 codes

Close a goal data_okt x.

347Ltac data_close  ≔
unfold data_ok ; first left ; close | right ; eexists ; split ; reflexivity | eapply char_codes_range ; eassumption

A data item read from t is written back as t, or is a string of codes from 0 to 2047. The item's subterms on its second argument are taken apart once each, then stand for themselves, so that its first argument and its second are not taken apart together.

356Lemma ddata_item_enc
∀ t x
ddata_itemt = Somex
Proof 8 steps Qed
intros t x H
pose proof dwidth_enc
destruct t as n | a | f args | ts ; | | destruct args as | a1 | a2 tl | ; unfold ddata_item in H ; cbv beta iota zeta in H
5: {repeat match type of H withcontext [?w]⇒match w withmatch a2 with _ ⇒ _ end⇒let F ≔ fresh "F" inlazymatch w withcontext [Sym_ _]⇒assert F : ∀y, w = Somey → f = "item" → a1 = TAtom"p" → data_okTAppf a1 :: a2 :: tl y by clear H ; intros y Hy Hf Ha ; subst f a1 ; repeat dstep Hy ; data_close_⇒assert F : ∀y, w = Somey → f = "item" → data_okTAppf a1 :: a2 :: tl y by clear H ; intros y Hy Hf ; subst f ; repeat dstep Hy ; data_closeend;let wv ≔ fresh "wv" in set wv := w in * ; clearbody wvendend
repeat dstep H
all: first|match goal withF : ∀y, _ = Somey → _ |- _⇒exact F_ H eq_reflend|match goal withF : ∀y, _ = Somey → _ |- _⇒exact F_ H eq_refl eq_reflend|data_close
all: repeat dstep H

A data item read from any term is read back from the term enc_data_item writes for it.

386Lemma ddata_item_round
∀ t x
ddata_itemt = Somex
Proof 7 steps Qed
intros t x H
destruct ddata_item_enct x H as He | codes → Hr
–rewrite He
exact H
–simpl
rewrite char_codes_round by exact Hr
reflexivity

If d reads back from e's term whatever it read from some term, the same holds of lists by map_option.

396Lemma map_option_round
∀ X : Type d : term → optionX e : X → term ts xs
∀t x, dt = Somex → dex = Somex
map_optiond ts = Somexs
map_optiond mape xs = Somexs
Proof 11 steps Qed
intros X d e He ts
induction ts as | t ts IH ; intros xs H ; simpl in H
–injection H as ←
reflexivity
–destruct dt eqn: E1 ; | discriminate
destruct map_optiond ts eqn: E2 ; | discriminate
injection H as ←
simpl
rewrite He_ _ E1
rewrite IH_ eq_refl
reflexivity

Items and the module

An item read from t is written back as t, unless it is a data object: then t is its data term, with its Linkage and items as read.

411Lemma ditem_enc
∀ t i
ditemt = SomeSomei
enc_itemi = t ∨ ∃n lk al its lk′ its′, t = TApp"data" n; lk; TIntal; TListits ∧ i = IDatan lk′ al its′ ∧ dlinkagelk = Somelk′ ∧ map_optionddata_item its = Someits′
Proof 5 steps Qed
intros t i H
pose proof dfunc_enc
unfold ditem in H
repeat dstep H
all: first left ; close | right ; do 6 eexists ; split ; reflexivity | split ; reflexivity | split ; eassumption

An item read from any term is read back from the term enc_item writes for it.

423Lemma ditem_round
∀ t i
ditemt = SomeSomei
ditemenc_itemi = SomeSomei
Proof 9 steps Qed
intros t i H
destruct ditem_enct i H as He | n lk al its lk′ its′ → → Hl Hi
–rewrite He
exact H
–simpl
rewrite dlinkage_enc_ _ Hl
rewrite Hl
reflexivity

The items a module keeps of what ditem read: none for a context item.

434Definition keepo : optionitem : listitem ≔
match o with
Somei
⇒
i
None
⇒
[ ]

The items kept of a list that ditem read are each read back from the term enc_item writes for it.

438Lemma items_round
∀ items os
map_optionditem items = Someos
map_optionditem mapenc_item flat_mapkeep os = SomemapSome flat_mapkeep os
Proof 11 steps Qed
induction items as | t items IH ; intros os H ; simpl in H
–injection H as ←
reflexivity
–destruct ditemt as o | eqn: E1 ; | discriminate
destruct map_optionditem items as os′ | eqn: E2 ; | discriminate
injection H as ←
destruct o as i | ; simpl
+rewrite ditem_round_ _ E1
rewrite IH_ eq_refl
reflexivity
+exact IH_ eq_refl

Keeping every item of a list of items read as items gives the list.

452Lemma keep_some
∀ m : module
flat_mapkeep mapSome m = m
Proof 1 step Qed
induction m as | i m IH ; simpl ; reflexivity | rewrite IH ; reflexivity

Every item of a module read from any term is read back, as that item, from the term enc_item writes for it.

457Lemma decode_items
∀ t m
decode_modulet = Somem
map_optionditem mapenc_item m = SomemapSome m
Proof 6 steps Qed
intros t m H
unfold decode_module in H
repeat dstep H
pose proof items_round_ _ E as R
unfold keep in R
exact R

The term half of NFB's round trip: a module read from any term is read back from the term enc_module writes for it.

466Theorem decode_enc_module
∀ t m
decode_modulet = Somem
Proof 8 steps Qed
intros t m H
pose proof keep_somem as K
unfold keep in K
rewrite decode_itemst m H
simpl
rewrite K
reflexivity

Context items

Whether the term is not a context(_, _) item.

476Definition not_contextt : term : bool ≔
match t with
TApp"context" _; _
⇒
false
_
⇒
true

A term that ditem reads as an item is not a context item.

480Lemma ditem_not_context
∀ u i
ditemu = SomeSomei
not_contextu = true
Proof 7 steps Qed
intros u i H
destruct not_contextu eqn: Hc ; reflexivity | exfalso
unfold not_context in Hc
repeat lazymatch type of Hc withmatch ?y with _ ⇒ _ end = _⇒split_on Hc yend
all: try discriminate Hc
simpl in H
discriminate H

No item of the term enc_module writes for a module read from any term is a context item.

490Corollary enc_module_no_context
∀ t m u
decode_modulet = Somem
Inu mapenc_item m
not_contextu = true
Proof 13 steps Qed
intros t m H
pose proof decode_itemst m H as R
clear H
revert R
induction m as | i m IH ; intros R u Hu ; simpl in Hu ; contradiction |
simpl in R
destruct ditemenc_itemi as o | eqn: E1 ; | discriminate
destruct map_optionditem mapenc_item m as os | eqn: E2 ; | discriminate
injection R as Ho Hos
subst o
destruct Hu as ← | Hu
–exact ditem_not_context_ _ E1
–exact IHf_equalSome Hos u Hu

The strong form fails

The term t with its context items dropped, if it is a module.

505Definition strip_contextt : term : term ≔
match t with
TApp"module" TListitems
⇒
TApp"module" TListfilternot_context items
_
⇒
t

A module of one data object whose string is the overlong UTF-8 sequence 0xC0 0x80, an atom of two characters.

513Definition overlong: term ≔
TApp"module" TListTApp"data" TAtom"s"; TAtom"local"; TInt1; TListTApp"item" TAtom"b"; TApp"str" TListTAtomStringascii_of_nat192 Stringascii_of_nat128 EmptyString

overlong is read as the string of the one code 0, which is written back as a one-byte atom.

Proof 1 step Qed
split ; reflexivity | cbv ; discriminate

So enc_modulem is not always the term m was read from with its context items dropped.

527Lemma strong_form_fails
¬∀t m, decode_modulet = Somem → enc_modulem = strip_contextt
Proof 3 steps Qed
intros Hs
destruct overlong_normalized as Hd Hn
exact HnHs_ _ Hd