A Reversible Semantics for Janus
Organizations: Olas Team, University of Bologna & Inria - Université Côte d’Azur, Bologna, Italy · VRAIN, Universitat Politècnica de València, Valencia, Spain
Abstract
Janus is a paradigmatic example of a reversible programming language. Indeed, Janus programs can be executed backwards as well as forwards. However, its current small-step semantics (useful, e.g., for debugging or as a basis for extensions with concurrency primitives) is not reversible, since it loses information while computing forwards. E.g., it does not satisfy the Loop Lemma, stating that any reduction has an inverse, a main property of reversibility in process calculi, where a small-step semantics is commonly used. We present here a novel small-step semantics which is actually reversible, while remaining equivalent to the previous one. It involves the non-trivial challenge of defining a semantics based on a "program counter" for a high-level programming language.
Figures & tables
| \frac{\mathit{block}(\ell^{\prime})=(x~\oplus=e)\quad\sigma\vdash e\Downarrow v\quad\ell^{\prime}\longrightarrow\ell^{\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\pi\rangle\rightharpoonup\langle\sigma[x\mapsto\llbracket\oplus\rrbracket(\sigma(x),v)],\ell^{\prime},\ell^{\prime\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{AssVar}}}\frac{\mathit{block}(\ell^{\prime})=(x[e_{l}]~\oplus=e)\quad\sigma\vdash e_{l}\Downarrow v_{l}\quad\sigma\vdash e\Downarrow v\quad\ell^{\prime}\longrightarrow\ell^{\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\pi\rangle\rightharpoonup\langle\sigma[x[v_{l}]\mapsto\llbracket\oplus\rrbracket(\sigma(x[v_{l}]),v)],\ell^{\prime},\ell^{\prime\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{AssArr}}}\frac{\mathit{block}(\ell^{\prime})=(\mathsf{call}~id)\quad\mathit{entry}(\Gamma(id))\longrightarrow\ell^{\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\pi\rangle\rightharpoonup\langle\sigma,\mathit{entry}(\Gamma(id)),\ell^{\prime\prime},\mathsf{call}(\ell^{\prime})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Call}}}\frac{\mathit{block}(\ell^{\prime})=\mathsf{stop}\quad\ell^{\prime\prime}\longrightarrow\ell^{\prime\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\mathsf{call}(\ell^{\prime\prime})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell^{\prime\prime},\ell^{\prime\prime\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Return1}}}\frac{\mathit{block}(\ell^{\prime})=(\mathsf{uncall}~id)\quad\mathit{entry}(\Gamma(id^{-1}))\longrightarrow\ell^{\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\pi\rangle\rightharpoonup\langle\sigma,\mathit{entry}(\Gamma(id^{-1})),\ell^{\prime\prime},\mathsf{uncall}(\ell^{\prime})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{UnCall}}}\frac{\mathit{block}(\ell^{\prime})=\mathsf{stop}\quad\ell^{\prime\prime}\longrightarrow\ell^{\prime\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\mathsf{uncall}(\ell^{\prime\prime})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell^{\prime\prime},\ell^{\prime\prime\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Return2}}}\frac{\mathit{block}(\ell^{\prime})=\mathsf{skip}\quad\ell^{\prime}\longrightarrow\ell^{\prime\prime}}{\langle\sigma,\ell,\ell^{\prime},\pi\rangle\rightharpoonup\langle\sigma,\ell^{\prime},\ell^{\prime\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Skip}}} |
| \frac{\mathit{block}(\ell_{1})=e_{1}\quad\mathsf{ctx}(\ell_{1})=(\mathsf{if}~[e_{1}]^{\ell_{1}}~\mathsf{then}~s_{1}~\mathsf{else}~s_{2}~\mathsf{fi}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_true?}(v_{1})}{\langle\sigma,\ell,\ell_{1},\pi\rangle\rightharpoonup\langle\sigma,\ell_{1},\mathit{entry}(s_{1}),\mathsf{if\_true}(\ell_{1},\ell_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{IfTrue1}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_true?}(v_{2})\quad\ell_{2}\longrightarrow\ell^{\prime}_{2}}{\langle\sigma,\ell,\ell_{2},\mathsf{if\_true}(\ell_{1},\ell_{2})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{IfTrue2}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\mathsf{ctx}(\ell_{1})=(\mathsf{if}~[e_{1}]^{\ell_{1}}~\mathsf{then}~s_{1}~\mathsf{else}~s_{2}~\mathsf{fi}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_false?}(v_{1})}{\langle\sigma,\ell,\ell_{1},\pi\rangle\rightharpoonup\langle\sigma,\ell_{1},\mathit{entry}(s_{2}),\mathsf{if\_false}(\ell_{1},\ell_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{IfFalse1}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_false?}(v_{2})\quad\ell_{2}\longrightarrow\ell^{\prime}_{2}}{\langle\sigma,\ell,\ell_{2},\mathsf{if\_false}(\ell_{1},\ell_{2})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{IfFalse2}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\mathsf{ctx}(\ell_{1})=(\mathsf{from}~[e_{1}]^{\ell_{1}}~\mathsf{do}~s_{1}~\mathsf{loop}~s_{2}~\mathsf{until}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_true?}(v_{1})}{\langle\sigma,\ell,\ell_{1},\pi\rangle\rightharpoonup\langle\sigma,\ell_{1},\mathit{entry}(s_{1}),\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{LoopMain}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_true?}(v_{2})\quad\ell_{2}\longrightarrow\ell^{\prime}_{2}\quad\ell^{\prime}_{2}\neq\mathit{entry}(s_{1})}{\langle\sigma,\ell,\ell_{2},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{LoopBase}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_false?}(v_{2})}{\langle\sigma,\ell,\ell_{2},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell_{2},\mathit{entry}(s_{2}),\mathsf{loop2}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Loop1}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_false?}(v_{1})}{\langle\sigma,\ell,\ell_{1},\mathsf{loop2}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\rightharpoonup\langle\sigma,\ell_{1},\mathit{entry}(s_{1}),\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overrightarrow{\mathit{Loop2}}} |
| \frac{\mathit{block}(\ell^{\prime})=(x~\oplus=e)\quad\sigma\vdash e\Downarrow v\quad\ell^{\prime\prime}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell^{\prime}}{\langle\sigma,\ell^{\prime},\ell^{\prime\prime},\pi\rangle\leftharpoondown\langle\sigma[x\mapsto\mathcal{I}_{op}\llbracket\oplus\rrbracket(\sigma(x),v)],\ell,\ell^{\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{AssVar}}}\frac{\mathit{block}(\ell^{\prime})=(x[e_{l}]~\oplus=e)\quad\sigma\vdash e_{l}\Downarrow v_{l}\quad\sigma\vdash e\Downarrow v\quad\ell^{\prime\prime}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell^{\prime}}{\langle\sigma,\ell^{\prime},\ell^{\prime\prime},\pi\rangle\leftharpoondown\langle\sigma[x[v_{l}]\mapsto\mathcal{I}_{op}\llbracket\oplus\rrbracket(\sigma(x[v_{l}]),v)],\ell,\ell^{\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{AssArr}}}\frac{\mathit{block}(\ell_{s})=\mathsf{start}\quad\ell^{\prime}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell}{\langle\sigma,\ell_{s},\ell^{\prime\prime},\mathsf{call}(\ell^{\prime})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell^{\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Call}}}\frac{\mathit{block}(\ell^{\prime\prime})=(\mathsf{call}~id)\quad\mathit{exit}(\Gamma(\mathit{id}))\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell}{\langle\sigma,\ell^{\prime\prime},\ell^{\prime\prime\prime},\pi\rangle\leftharpoondown\langle\sigma,\ell,\mathit{exit}(\Gamma(\mathit{id})),\mathsf{call}(\ell^{\prime\prime})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Return1}}}\frac{\mathit{block}(\ell_{s})=\mathsf{start}\quad\ell^{\prime}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell}{\langle\sigma,\ell_{s},\ell^{\prime\prime},\mathsf{uncall}(\ell^{\prime})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell^{\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{UnCall}}}\frac{\mathit{block}(\ell^{\prime\prime})=(\mathsf{uncall}~id)\quad\mathit{exit}(\Gamma(\mathit{id}^{-1}))\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell}{\langle\sigma,\ell^{\prime\prime},\ell^{\prime\prime\prime},\pi\rangle\leftharpoondown\langle\sigma,\ell,\mathit{exit}(\Gamma(\mathit{id}^{-1})),\mathsf{uncall}(\ell^{\prime\prime})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Return2}}}\frac{\mathit{block}(\ell^{\prime})=\mathsf{skip}\quad\ell^{\prime\prime}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell^{\prime}\quad}{\langle\sigma,\ell^{\prime},\ell^{\prime\prime},\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell^{\prime},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Skip}}} |
| \frac{\mathit{block}(\ell_{1})=e_{1}\quad\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_true?}(v_{1})\quad\ell_{1}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell\quad}{\langle\sigma,\ell_{1},\ell^{\prime}_{1},\mathsf{if\_true}(\ell_{1},\ell_{2})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell_{1},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{IfTrue1}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\mathsf{ctx}(\ell_{2})=(\mathsf{if}~[e_{1}]^{\ell_{1}}~\mathsf{then}~s_{1}~\mathsf{else}~s_{2}~\mathsf{fi}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_true?}(v_{2})\quad}{\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle\leftharpoondown\langle\sigma,\mathit{exit}(s_{1}),\ell_{2},\mathsf{if\_true}(\ell_{1},\ell_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{IfTrue2}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_false?}(v_{1})\quad\ell_{1}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell\quad}{\langle\sigma,\ell_{1},\ell^{\prime}_{1},\mathsf{if\_false}(\ell_{1},\ell_{2})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell_{1},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{IfFalse1}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\mathsf{ctx}(\ell_{2})=(\mathsf{if}~[e_{1}]^{\ell_{1}}~\mathsf{then}~s_{1}~\mathsf{else}~s_{2}~\mathsf{fi}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_false?}(v_{2})\quad}{\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle\leftharpoondown\langle\sigma,\mathit{exit}(s_{2}),\ell_{2},\mathsf{if\_false}(\ell_{1},\ell_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{IfFalse2}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_true?}(v_{1})\quad\ell_{1}\stackrel{{\scriptstyle\mbox{\tiny-1}}}{{\longrightarrow}}\ell\quad\ell\neq\mathit{exit}(s_{2})}{\langle\sigma,\ell_{1},\ell^{\prime},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\ell,\ell_{1},\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{LoopMain}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\mathsf{ctx}(\ell_{2})=(\mathsf{from}~[e_{1}]^{\ell_{1}}~\mathsf{do}~s_{1}~\mathsf{loop}~s_{2}~\mathsf{until}~[e_{2}]^{\ell_{2}})\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_true?}(v_{2})\quad}{\langle\sigma,\ell_{2},\ell^{\prime}_{2},\pi\rangle\leftharpoondown\langle\sigma,\mathit{exit}(s_{1}),\ell_{2},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{LoopBase}}}\frac{\mathit{block}(\ell_{2})=e_{2}\quad\sigma\vdash e_{2}\Downarrow v_{2}\quad\mathsf{is\_false?}(v_{2})}{\langle\sigma,\ell_{2},\ell^{\prime},\mathsf{loop2}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\mathit{exit}(s_{1}),\ell_{2},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Loop1}}}\frac{\mathit{block}(\ell_{1})=e_{1}\quad\sigma\vdash e_{1}\Downarrow v_{1}\quad\mathsf{is\_false?}(v_{1})}{\langle\sigma,\ell_{1},\ell^{\prime},\mathsf{loop1}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle\leftharpoondown\langle\sigma,\mathit{exit}(s_{2}),\ell_{1},\mathsf{loop2}(\ell_{1},s_{1},\ell_{2},s_{2})\!:\!\pi\rangle}\quad\textsc{leftstyle=\rm,left=\overleftarrow{\mathit{Loop2}}} |