\documentclass{amsart} \usepackage{times} \usepackage{tabularx} \usepackage{mathpartir} \theoremstyle{plain} \newtheorem{theorem}{Theorem}[section] \newtheorem{lemma}[theorem]{Lemma} \newtheorem{proposition}[theorem]{Proposition} \newtheorem{conjecture}[theorem]{Conjecture} \newtheorem{corollary}[theorem]{Corollary} \theoremstyle{definition} \newtheorem{algorithm}[theorem]{Algorithm} \newtheorem{definition}[theorem]{Definition} \newtheorem{remark}[theorem]{Remark} \newtheorem{example}[theorem]{Example} \newcommand{\pcall }{\mbox{\texttt{call}}} \newcommand{\pchoose}{\mbox{\texttt{?}} } \newcommand{\pdrop }{\mbox{\texttt{drop}}} \newcommand{\pdup }{\mbox{\texttt{dup}}} \newcommand{\pswap }{\mbox{\texttt{swap}}} \newcommand{\ptor }{\mbox{\texttt{>r}}} \newcommand{\pfromr }{\mbox{\texttt{r>}}} \newcommand{\pcar }{\mbox{\texttt{car}}} \newcommand{\pcdr }{\mbox{\texttt{cdr}}} \newcommand{\pcons }{\mbox{\texttt{cdr}}} \newcommand{\peq }{\mbox{\texttt{=}}} \def\leng{\mathop{\rm length}} \begin{document} \title{Factor Theory} \author{Slava Pestov} \begin{abstract} In this article, I will attempt to give formal semantics to several aspects of the Factor programming language. This is neither a reference or an introduction; for such information, consult \texttt{http://factor.sf.net}. \end{abstract} \maketitle \tableofcontents{} \section{Transition semantics} First, I present formal semantics for a subset of the Factor language. \begin{definition} The set of objects, denoted $OBJ$, is the smallest set satisfying: \begin{enumerate} \item The empty list $\bot \in OBJ$. \item If $P$ is a primitive word, then $P \in OBJ$, where the primitive words are \texttt{call}, \texttt{?}, \texttt{car}, \texttt{cdr}, \texttt{cons}, \texttt{drop}, \texttt{dup}, \texttt{swap}, \texttt{>r}, \texttt{r>}, and \texttt{=}. \item If $a, b \in OBJ$, the cons cell $(a::b) \in OBJ$. \end{enumerate} Note that Factor source code syntax for cons cells is \texttt{[[ a b ]]}, and the empty list is denoted \texttt{f}. However, I will use the above notation since it looks better in typeset output. \end{definition} In practice, Factor also allows a number of other data types, such as numbers, strings, vectors, and so on. They will not be needed for now. We are interested in a number of subsets of $OBJ$, the first being literal values. \begin{definition} The set $LIT\subset OBJ$ consists of $OBJ-PRIM$, where $PRIM$ is the set of primitive words: \texttt{call}, \texttt{?}, \texttt{car}, \texttt{cdr}, \texttt{cons}, \texttt{drop}, \texttt{dup}, \texttt{swap}, \texttt{>r}, \texttt{r>}, and \texttt{=}. \end{definition} \begin{definition} The set of program quotations, $QUOT \subset OBJ$, is the smallest set satisfying: \begin{enumerate} \item The empty list $\bot \in QUOT$. \item If $a \in OBJ$, $b \in QUOT$, $(a::b) \in QUOT$. \end{enumerate} I will write $(a,b,c)$ in place of $(a::(b::(c::\bot)))$. Note the Factor source code syntax is \texttt{[ a b c ]}. It is convenient to define $\leng(\bot) := 0$, and $\leng(a::d):=1+\leng(d)$. Also, I will write $a\circ b$ for the concatenation of $a,b \in QUOT$. \end{definition} \begin{definition} The set of stacks, $STACK \subset QUOT$, is the smallest set satisfying: \begin{enumerate} \item The empty list $\bot \in STACK$. \item If $a \in QUOT$, $b \in STACK$, $(a::b) \in STACK$. \end{enumerate} \end{definition} \begin{definition} An \emph{interpreter} is a 3-tuple $(\delta, \rho, \chi)$, where $\delta, \rho \in STACK$, and $\chi \in QUOT$. The set of interpreters is denoted $INT$, and can be regarded as a subset of $OBJ$. I call $\delta$ the \emph{data stack}; it holds values currently being operated on by the running program. The stack $\rho$ is called the \emph{return stack} and retains interpreter state between recursive calls. The quotation $\chi$ is called \emph{call frame}, and stores the currently executing program fragment. Basically, the transition relation looks at the call frame; if the first element is a literal, it is pushed on the stack, if the first element is a primitive word, it is executed, and if the call frame is the empty list, a new call frame is popped from the return stack. \begin{figure} \caption{\label{trans}Transition semantics for the Factor interpreter.} \begin{tabularx}{12cm}{lc} \hline \{Reload\}& $$ \inferrule {\chi = \bot \\ \rho = (\chi\prime::\rho\prime)} {(\delta,\rho,\chi)\rhd(\delta,\rho\prime,\chi\prime)} $$ \\[4mm] \{Literal\}& $$ \inferrule {\chi = (\lambda :: \chi\prime) \\ \lambda \in LIT} {(\delta,\rho,\chi)\rhd((\lambda :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\pcall\}& $$ \inferrule {\delta = (q :: \delta\prime) \\ \chi = (\pcall :: \chi\prime)} {(\delta,\rho,\chi)\rhd(\delta\prime,(\chi::\rho),\chi\prime)} $$ \\[4mm] \{\pchoose{}a\}& $$ \inferrule {\delta = (\tau,\phi,\beta :: \delta\prime) \\ \beta = \bot \\ \chi = (\pchoose :: \chi\prime)} {(\delta,\rho,\chi)\rhd((\phi :: \delta\prime),\rho,\chi\prime)} $$ \\[4mm] \{\pchoose{}b\}& $$ \inferrule {\delta = (\tau,\phi,\beta :: \delta\prime) \\ \beta \ne \bot \\ \chi = (\pchoose :: \chi\prime)} {(\delta,\rho,\chi)\rhd((\tau :: \delta\prime),\rho,\chi\prime)} $$ \\[4mm] \{\pdrop\}& $$ \inferrule {\delta = (o :: \delta\prime) \\ \chi = (\pdrop :: \chi\prime)} {(\delta,\rho,\chi)\rhd(\delta\prime,\rho,\chi\prime)} $$ \\[4mm] \{\pdup\}& $$ \inferrule {\delta = (o :: \delta\prime) \\ \chi = (\pdup :: \chi\prime)} {(\delta,\rho,\chi)\rhd((o o :: \delta\prime),\rho,\chi\prime)} $$ \\[4mm] \{\ptor\}& $$ \inferrule {\delta = (o :: \delta\prime) \\ \chi = (\ptor :: \chi\prime)} {(\delta,\rho,\chi)\rhd(\delta\prime,(o :: \rho),\chi\prime)} $$ \\[4mm] \{\pfromr\}& $$ \inferrule {\rho = (o :: \rho\prime) \\ \chi = (\pfromr :: \chi\prime)} {(\delta,\rho,\chi)\rhd((o :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\pcar\}& $$ \inferrule {\rho = ((a :: d) :: \rho\prime) \\ \chi = (\pcar :: \chi\prime)} {(\delta,\rho,\chi)\rhd((a :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\pcdr\}& $$ \inferrule {\rho = ((a :: d) :: \rho\prime) \\ \chi = (\pcdr :: \chi\prime)} {(\delta,\rho,\chi)\rhd((d :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\pcons\}& $$ \inferrule {\rho = (a,d :: \rho\prime) \\ \chi = (\pcons :: \chi\prime)} {(\delta,\rho,\chi)\rhd(((a :: d) :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\peq{}a\}& $$ \inferrule {\rho = (x,y :: \rho\prime) \\ x = y \\ \chi = (\peq :: \chi\prime)} {(\delta,\rho,\chi)\rhd((\bot :: \delta),\rho,\chi\prime)} $$ \\[4mm] \{\peq{}b\}& $$ \inferrule {\rho = (x,y :: \rho\prime) \\ x \ne y \\ \chi = (\peq :: \chi\prime)} {(\delta,\rho,\chi)\rhd(((\bot) :: \delta),\rho,\chi\prime)} $$ \\ \hline \end{tabularx} \end{figure} Now, I am ready to present transition semantics. Define a relation $\rhd$ by the deduction rules of figure \ref{trans}. By inspection, it is obvious that $(x\rhd y \wedge x \rhd z) \Rightarrow y=z$, so we are able to make the following definition. \begin{definition} Define a functional $\mathcal{F}: (INT \rightarrow INT) \rightarrow (INT \rightarrow INT)$: $$ \mathcal{F}(f)(i) = \begin{cases} f(j)&\text{if $\exists j / i\rhd j$}\\ i&\text{else} \end{cases} $$ \end{definition} Now, let $F: INT \rightarrow INT$ be the least fixed point of $\mathcal{F}$. $F$ is the \emph{Factor evaluator function}. It takes an interpreter and maps it to another interpreter. If the resulting interpreter's call frame is $\bot$, evaluation completed successfully; otherwise, at some stage of the computation, there was no applicable inference rule (for example, a \texttt{drop} was attempted with an empty stack), in which case it is an error condition. In the case that the final call frame is non-empty, we abuse notation and say that $F(\delta,\rho,\chi)=\bot$. Note that $F$ is a partial function, and it might not terminate; in this case, lets say $F(i) = \bot$. \end{definition} Now, I will give the first lemma. Intuitively, it states that if a quotation consumes $n$ elements from the stack, it does not ``see'' anything below. This forms the basis for the work in the next section. \begin{lemma}\label{dipping} Let $q\in QUOT$ be such that there exists $\delta\in STACK$ with $F(\delta,\bot,q)=(\delta\prime,\bot,\bot)$. Then for any $\delta_0\in STACK$, $F(\delta\circ\delta_0,\bot,q)=(\delta\prime\circ\delta_0,\bot,\bot)$ \end{lemma} \begin{proof} Since $F(\delta,\bot,q)\ne\bot$ by assumption, each step of its transition chain has the property that the data stack is either $\bot$ and no attempt is made to access its top element, or the data stack is not $\bot$. Now notice that the same transition chain will occur with $F(\delta\circ \delta_0,\bot,q)$; the only difference being that when the data stack would become $\bot$ in the former, it would become $\delta_0$ in the latter. But since no attempt is made to access the top stack element, both transition chains are equivalent up to the appending of $\delta_0$. Therefore $F(\delta\circ \delta_0,\bot,q)=(\delta\prime\circ \delta_0,\bot,\bot)$. \end{proof} \section{Stack effects} Now, I will study the effect of evaluation on the data stack in detail. The primary motivation, and eventual goal, is to be able to statically deduce the number of input and output parameters of a quotation on the stack. \begin{definition} Let $q \in QUOT$ be a program fragment. The \emph{stack effect} of $q$, denoted $[q]$, is $(m,n)\in \mathbb{Z}^+\times\mathbb{Z}^+$ iff the following conditions hold: \begin{enumerate} \item If $\leng(\delta)=m$, $(F(\delta,\bot,q)=(\delta\prime,\bot,\bot)) \Rightarrow (\leng(\delta\prime)=n)$. \item If $l