Jelajahi Sumber

Merge branch 'IUCompilerCourse:master' into master

Programming Languages Uni Freiburg 3 tahun lalu
induk
melakukan
32406fdd03
2 mengubah file dengan 318 tambahan dan 39 penghapusan
  1. 309 36
      book.tex
  2. 9 3
      defs.tex

+ 309 - 36
book.tex

@@ -13025,7 +13025,9 @@ nested inside each other.
 }
 \newcommand{\LfunASTPython}{
   \begin{array}{lcl}
-    \Type &::=& \key{int} \MID \key{bool} \MID \key{tuple}\LS\Type^+\RS \MID \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
+    \Type &::=& \key{IntType()} \MID \key{BoolType()} \key{VoidType()}
+        \MID \key{TupleType}\LS\Type^+\RS\\
+        &\MID& \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
     \Exp &::=& \CALL{\Exp}{\Exp^{*}}\\
     \Stmt &::=& \RETURN{\Exp} \\
    \Params &::=&                  \LP\Var\key{,}\Type\RP^*
@@ -16308,7 +16310,27 @@ True[0]
 \]
 \fi}
 {\if\edition\pythonEd
-  UNDER CONSTRUCTION
+\[
+\begin{array}{rcl}
+  \itm{cmp} &::= & \key{==} \MID \key{!=} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \MID \key{is} \\
+  \Exp &::=& \Int \MID \key{input\_int}\LP\RP \MID \key{-}\;\Exp \MID \Exp \; \key{+} \; \Exp \MID \Exp \; \key{-} \; \Exp \MID \LP\Exp\RP \\
+  &\MID& \Var{} \MID \TRUE \MID \FALSE \MID \CAND{\Exp}{\Exp}
+  \MID \COR{\Exp}{\Exp} \MID \key{not}~\Exp \\
+  &\MID& \CCMP{\itm{cmp}}{\Exp}{\Exp}
+      \MID \CIF{\Exp}{\Exp}{\Exp} \\
+  &\MID& \Exp \key{,} \ldots \key{,} \Exp \MID \CGET{\Exp}{\Exp}
+      \MID \CLEN{\Exp}  \\
+   &\MID& \CAPPLY{\Exp}{\Exp\code{,} \ldots} 
+    \MID \CLAMBDA{\Var\code{, }\ldots}{\Exp}\\
+  \Stmt &::=& \key{print}\LP \Exp \RP \MID \Exp 
+    \MID \Var\mathop{\key{=}}\Exp \\
+   &\MID& \key{if}~ \Exp \key{:}~ \Stmt^{+} ~\key{else:}~ \Stmt^{+} 
+   \MID \key{while}~ \Exp \key{:}~ \Stmt^{+} \\
+    &\MID& \CRETURN{\Exp} \\
+   \Def &::=& \CDEFU{\Var}{\Var{,} \ldots}{\Stmt^{+}} \\
+  \LangDynM{} &::=& \Def\ldots \Stmt\ldots
+\end{array}
+\]
 \fi}
 \end{minipage}
 }
@@ -16337,7 +16359,35 @@ True[0]
 \]
 \fi}
 {\if\edition\pythonEd
-UNDER CONSTRUCTION
+\[
+\begin{array}{rcl}
+\itm{binaryop} &::= & \code{Add()} \MID \code{Sub()} \\
+\itm{unaryop} &::= & \code{USub()} \MID \code{Not()} \\
+\itm{boolop} &::=& \code{And()} \MID \code{Or()} \\
+\itm{cmp} &::= & \code{Eq()} \MID \code{NotEq()} \MID \code{Lt()}
+   \MID \code{LtE()} \MID \code{Gt()} \MID \code{GtE()} \\
+   &\MID & \code{Is()} \\
+\itm{bool} &::=& \code{True} \MID \code{False} \\
+\Exp{} &::=& \INT{\Int} \MID \READ{} \\
+  &\MID& \UNIOP{\itm{unaryop}}{\Exp}
+    \MID  \BINOP{\itm{binaryop}}{\Exp}{\Exp}  
+    \MID \VAR{\Var{}} \\
+  &\MID& \BOOL{\itm{bool}} 
+     \MID \BOOLOP{\itm{boolop}}{\Exp}{\Exp}\\
+  &\MID& \CMP{\Exp}{\itm{cmp}}{\Exp}  \MID \IF{\Exp}{\Exp}{\Exp} \\
+  &\MID& \TUPLE{\Exp^{+}} \MID \GET{\Exp}{\Exp} \\
+  &\MID& \LEN{\Exp} \\
+  &\MID& \CALL{\Exp}{\Exp^{*}} \MID \LAMBDA{\Var^{*}}{\Exp} \\
+\Stmt{} &::=& \PRINT{\Exp} \MID \EXPR{\Exp} \\
+  &\MID& \ASSIGN{\VAR{\Var}}{\Exp}\\
+  &\MID& \IFSTMT{\Exp}{\Stmt^{+}}{\Stmt^{+}} 
+  \MID \WHILESTMT{\Exp}{\Stmt^{+}}\\
+  &\MID& \RETURN{\Exp} \\
+\Params &::=& \LP\Var\key{,}\code{AnyType()}\RP^*   \\
+\Def &::=& \FUNDEF{\Var}{\Params}{\_}{}{\Stmt^{+}}  \\
+\LangDynM{} &::=& \PROGRAM{}{\LS \Def \ldots \Stmt \ldots \RS}
+\end{array}
+\]
 \fi}
 \end{minipage}
 }
@@ -16353,39 +16403,75 @@ Figures~\ref{fig:r7-concrete-syntax} and \ref{fig:r7-syntax}.
 There is no type checker for \LangDyn{} because it is not a statically
 typed language (it's dynamically typed!).
 
-UNDER CONSTRUCTION
-
 The definitional interpreter for \LangDyn{} is presented in
-Figure~\ref{fig:interp-Rdyn} and its auxiliary functions are defined in
-Figure~\ref{fig:interp-Rdyn-aux}. Consider the match case for
+\racket{Figure~\ref{fig:interp-Ldyn}}
+\python{Figures~\ref{fig:interp-Ldyn} and \ref{fig:interp-Ldyn-2}}
+and its auxiliary functions are defined in
+Figure~\ref{fig:interp-Ldyn-aux}. Consider the match case for
 \INT{n}.  Instead of simply returning the integer \code{n} (as
 in the interpreter for \LangVar{} in Figure~\ref{fig:interp-Lvar}), the
 interpreter for \LangDyn{} creates a \emph{tagged value}\index{subject}{tagged
   value} that combines an underlying value with a tag that identifies
-what kind of value it is. We define the following struct
+what kind of value it is. We define the following \racket{struct}\python{class}
 to represented tagged values.
+%
+{\if\edition\racketEd
 \begin{lstlisting}
 (struct Tagged (value tag) #:transparent)
 \end{lstlisting}
-The tags are \code{Integer}, \code{Boolean}, \code{Void},
-\code{Vector}, and \code{Procedure}. Tags are closely related to types
-but don't always capture all the information that a type does. For
-example, a vector of type \code{(Vector Any Any)} is tagged with
-\code{Vector} and a procedure of type \code{(Any Any -> Any)}
-is tagged with \code{Procedure}.
-
-Next consider the match case for \code{vector-ref}.  The
-\code{check-tag} auxiliary function (Figure~\ref{fig:interp-Rdyn-aux})
-is used to ensure that the first argument is a vector and the second
-is an integer. If they are not, a \code{trapped-error} is raised.
-Recall from Section~\ref{sec:interp_Lint} that when a definition
-interpreter raises a \code{trapped-error} error, the compiled code
-must also signal an error by exiting with return code \code{255}.  A
+\fi}
+{\if\edition\pythonEd
+\begin{minipage}{\textwidth}
+\begin{lstlisting}
+@dataclass
+class Tagged:
+  value : Value
+  tag : int
+  __match_args__ = ("value", "tag")
+  def __str__(self):
+    return str(self.value)
+\end{lstlisting}
+\end{minipage}
+\fi}
+%
+\racket{The tags are \code{Integer}, \code{Boolean}, \code{Void},
+  \code{Vector}, and \code{Procedure}.}
+%
+\python{The tags are \code{'int'}, \code{'bool'}, \code{'none'},
+  \code{'tuple'}, and \code{'function'}}
+%
+Tags are closely related to types
+but don't always capture all the information that a type does.
+%
+\racket{For example, a vector of type \code{(Vector Any Any)} is
+  tagged with \code{Vector} and a procedure of type \code{(Any Any ->
+    Any)} is tagged with \code{Procedure}.}
+%
+\python{For example, a tuple of type \code{TupleType([AnyType(),AnyType()])}
+  is tagged with \code{'tuple'} and a function of type
+  \code{FunctionType([AnyType(), AnyType()], AnyType())}
+  is tagged with \code{'function'}.}
+
+Next consider the match case for accessing the element of a tuple.
+The \racket{\code{check-tag}}\python{\code{untag}} auxiliary function
+(Figure~\ref{fig:interp-Ldyn-aux}) is used to ensure that the first
+argument is a tuple and the second is an integer.
+\racket{
+If they are not, a \code{trapped-error} is raised.  Recall from
+Section~\ref{sec:interp_Lint} that when a definition interpreter
+raises a \code{trapped-error} error, the compiled code must also
+signal an error by exiting with return code \code{255}.  A
 \code{trapped-error} is also raised if the index is not less than
 length of the vector.
-
+}
+%
+\python{If they are not, an exception is raised.  The compiled code
+  must also signal an error by exiting with return code \code{255}.  A
+  exception is also raised if the index is not less than length of the
+  tuple.}
 
 \begin{figure}[tbp]
+{\if\edition\racketEd
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
 (define ((interp-Rdyn-exp env) ast)
   (define recur (interp-Rdyn-exp env))
@@ -16440,12 +16526,124 @@ length of the vector.
         ((interp-Rdyn-exp new-env) body)]
        [else (error "interp-Rdyn-exp, expected function, not" f-val)])]))
 \end{lstlisting}
-\caption{Interpreter for the \LangDyn{} language.}
-\label{fig:interp-Rdyn}
+\fi}
+{\if\edition\pythonEd
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+class InterpLdyn(InterpLlambda):
+  
+  def interp_exp(self, e, env):
+    match e:
+      case Constant(n):
+        return self.tag(super().interp_exp(e, env))
+      case Tuple(es, Load()):
+        return self.tag(super().interp_exp(e, env))
+      case Lambda(params, body):
+        return self.tag(super().interp_exp(e, env))
+      case Call(Name('input_int'), []):
+        return self.tag(super().interp_exp(e, env))
+      case BinOp(left, Add(), right):
+          l = self.interp_exp(left, env); r = self.interp_exp(right, env)
+          return self.tag(self.untag(l, 'int', e) + self.untag(r, 'int', e))
+      case BinOp(left, Sub(), right):
+          l = self.interp_exp(left, env); r = self.interp_exp(right, env)
+          return self.tag(self.untag(l, 'int', e) - self.untag(r, 'int', e))
+      case UnaryOp(USub(), e1):
+          v = self.interp_exp(e1, env)
+          return self.tag(- self.untag(v, 'int', e))
+      case IfExp(test, body, orelse):
+        v = self.interp_exp(test, env)
+        match self.untag(v, 'bool', e):
+          case True:
+            return self.interp_exp(body, env)
+          case False:
+            return self.interp_exp(orelse, env)
+      case UnaryOp(Not(), e1):
+        v = self.interp_exp(e1, env)
+        return self.tag(not self.untag(v, 'bool', e))
+      case BoolOp(And(), values):
+        left = values[0]; right = values[1]
+        l = self.interp_exp(left, env)
+        match self.untag(l, 'bool', e):
+          case True:
+            return self.interp_exp(right, env)
+          case False:
+            return self.tag(False)
+      case BoolOp(Or(), values):
+        left = values[0]; right = values[1]
+        l = self.interp_exp(left, env)
+        match self.untag(l, 'bool', e):
+          case True:
+            return True
+          case False:
+            return self.interp_exp(right, env)
+      case Compare(left, [cmp], [right]):
+        l = self.interp_exp(left, env)
+        r = self.interp_exp(right, env)
+        if l.tag == r.tag:
+          return self.tag(self.interp_cmp(cmp)(l.value, r.value))
+        else:
+          raise Exception('interp Compare unexpected ' \
+                          + repr(l) + ' ' + repr(r))
+      case Subscript(tup, index, Load()):
+        t = self.interp_exp(tup, env)
+        n = self.interp_exp(index, env)
+        return self.untag(t, 'tuple', e)[self.untag(n, 'int', e)]
+      case Call(Name('len'), [tup]):
+        t = self.interp_exp(tup, env)
+        return self.tag(len(self.untag(t, 'tuple', e)))
+      case _:
+        return super().interp_exp(e, env)
+
+\end{lstlisting}
+\fi}
+\caption{Interpreter for the \LangDyn{} language \python{, part 1}.}
+\label{fig:interp-Ldyn}
 \end{figure}
 
 \begin{figure}[tbp]
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+class InterpLdyn(InterpLlambda):
+  
+  def interp_stmts(self, ss, env):
+    if len(ss) == 0:
+      return
+    match ss[0]:
+      case If(test, body, orelse):
+        v = self.interp_exp(test, env)
+        match self.untag(v, 'bool', ss[0]):
+          case True:
+            return self.interp_stmts(body + ss[1:], env)
+          case False:
+            return self.interp_stmts(orelse + ss[1:], env)
+      case While(test, body, []):
+        while self.untag(self.interp_exp(test, env), 'bool', ss[0]):
+            self.interp_stmts(body, env)
+        return self.interp_stmts(ss[1:], env)
+      case Assign([Subscript(tup, index)], value):
+        tup = self.interp_exp(tup, env)
+        index = self.interp_exp(index, env)
+        tup_v = self.untag(tup, 'tuple', ss[0])
+        index_v = self.untag(index, 'int', ss[0])
+        tup_v[index_v] = self.interp_exp(value, env)
+        return self.interp_stmts(ss[1:], env)
+      case _:
+        return super().interp_stmts(ss, env)
+    
+  def interp_def(self, d, env):
+    match d:
+      case FunctionDef(name, params, bod, dl, returns, comment):
+        ps = [x for (x,t) in params]
+        env[name] = self.tag(Function(name, ps, bod, env))
+      case _:
+        raise Exception('interp_def unexpected ' + repr(d))
+\end{lstlisting}
+\caption{Interpreter for the \LangDyn{} language \python{, part 2}.}
+\label{fig:interp-Ldyn-2}
+\end{figure}
+
+\begin{figure}[tbp]
+{\if\edition\racketEd
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
 (define (interp-op op)
   (match op
     ['+ fx+]
@@ -16497,8 +16695,41 @@ length of the vector.
   (unless (eq? tag expected)
     (error 'trapped-error "expected ~a, not ~a\nin ~v" expected tag ast)))
 \end{lstlisting}
+\fi}
+{\if\edition\pythonEd
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+class InterpLdyn(InterpLlambda):
+  
+  def tag(self, v):
+      if v is True or v is False:
+          return Tagged(v, 'bool')
+      elif isinstance(v, int):
+          return Tagged(v, 'int')
+      elif isinstance(v, Function):
+          return Tagged(v, 'function')
+      elif isinstance(v, list):
+          return Tagged(v, 'tuple')
+      elif isinstance(v, type(None)):
+          return Tagged(v, 'none')
+      else:
+          raise Exception('tag: unexpected ' + repr(v))
+
+  def untag(self, v, expected_tag, ast):
+      match v:
+        case Tagged(val, tag):
+          if tag != expected_tag:
+            raise Exception('expected tag ' + expected_tag + ', not ' + ' ' + repr(v))
+          return val
+        case _:
+          raise Exception('expected Tagged value with ' + expected_tag + ', not ' + ' ' + repr(v))
+
+  def apply_fun(self, fun, args, e):
+      f = self.untag(fun, 'function', e)
+      return super().apply_fun(f, args, e)
+\end{lstlisting}
+\fi}
 \caption{Auxiliary functions for the \LangDyn{} interpreter.}
-\label{fig:interp-Rdyn-aux}
+\label{fig:interp-Ldyn-aux}
 \end{figure}
 
 \clearpage
@@ -16514,6 +16745,7 @@ the 3 right-most bits to encode the tag.  We use $001$ to identify
 integers, $100$ for Booleans, $010$ for vectors, $011$ for procedures,
 and $101$ for the void value. We define the following auxiliary
 function for mapping types to tag codes.
+{\if\edition\racketEd
 \begin{align*}
 \itm{tagof}(\key{Integer}) &= 001 \\
 \itm{tagof}(\key{Boolean}) &= 100 \\
@@ -16521,6 +16753,16 @@ function for mapping types to tag codes.
 \itm{tagof}((\ldots \key{->} \ldots)) &= 011 \\
 \itm{tagof}(\key{Void}) &= 101
 \end{align*}
+\fi}
+{\if\edition\pythonEd
+\begin{align*}
+\itm{tagof}(\key{IntType()}) &= 001 \\
+\itm{tagof}(\key{BoolType()}) &= 100 \\
+\itm{tagof}(\key{TupleType(ts)}) &= 010 \\
+\itm{tagof}(\key{FunctionType(ps, rt)}) &= 011 \\
+\itm{tagof}(\key{type(None)}) &= 101
+\end{align*}
+\fi}
 This stealing of 3 bits comes at some price: our integers are reduced
 to ranging from $-2^{60}$ to $2^{60}$. The stealing does not adversely
 affect vectors and procedures because those values are addresses, and
@@ -16530,18 +16772,21 @@ the rightmost 3 bits with the tag and we can simply zero-out the tag
 to recover the original address.
 
 To make tagged values into first-class entities, we can give them a
-type, called \code{Any}, and define operations such as \code{Inject}
-and \code{Project} for creating and using them, yielding the \LangAny{}
-intermediate language. We describe how to compile \LangDyn{} to \LangAny{} in
-Section~\ref{sec:compile-r7} but first we describe the \LangAny{} language
-in greater detail.
+type, called \racket{\code{Any}}\python{AnyType}, and define operations
+such as \code{Inject} and \code{Project} for creating and using them,
+yielding the \LangAny{} intermediate language. We describe how to
+compile \LangDyn{} to \LangAny{} in Section~\ref{sec:compile-r7}
+but first we describe the \LangAny{} language in greater detail.
 
 \section{The \LangAny{} Language}
 \label{sec:Rany-lang}
 
-\newcommand{\LAnyAST}{
+\newcommand{\LanyASTRacket}{
 \begin{array}{lcl}
 \Type &::= & \key{Any} \\
+\FType &::=& \key{Integer} \MID \key{Boolean} \MID \key{Void} 
+      \MID \LP\key{Vector}\; \key{Any}\ldots\RP \\
+     &\MID& \LP\key{Any}\ldots \; \key{->}\; \key{Any}\RP\\
 \itm{op} &::= & \code{any-vector-length}
      \MID \code{any-vector-ref} \MID \code{any-vector-set!}\\
     &\MID& \code{boolean?} \MID \code{integer?} \MID \code{vector?}
@@ -16550,6 +16795,20 @@ in greater detail.
 \end{array}
 }
 
+\newcommand{\LanyASTPython}{
+\begin{array}{lcl}
+\Type &::= & \key{AnyType} \\
+\FType &::=& \key{IntType()} \MID \key{BoolType()} \MID \key{VoidType()}
+  \MID \key{TupleType}\LS\key{AnyType()}^+\RS \\
+  &\MID& \key{FunctionType}\LP \key{AnyType()}^{*}\key{, }\key{AnyType()}\RP \\
+\itm{unaryop} &::= & \code{IsBool()} \MID \code{IsInt()}
+     \MID \code{IsTuple()}  \MID \code{IsFunction()} \MID \code{IsNone()}\\
+\Exp & ::= & \INJECT{\Exp}{\Type} \MID \PROJECT{\Exp}{\Type} \\
+     &\MID& \CALL{\VAR{\key{'any\_tuple\_load'}}}{\Exp\key{, }\INT{n}}\\
+     &\MID& \CALL{\VAR{\key{'any\_len}}}{\Exp}
+\end{array}
+}
+
 \begin{figure}[tp]
 \centering
 \fbox{
@@ -16565,7 +16824,7 @@ in greater detail.
   \gray{\LtupASTRacket{}} \\ \hline
   \gray{\LfunASTRacket} \\ \hline
   \gray{\LlambdaASTRacket} \\ \hline
-  \LAnyAST \\
+  \LanyASTRacket \\
 \begin{array}{lcl}
 %% \Type &::= & \ldots \MID \key{Any} \\
 %% \itm{op} &::= & \ldots \MID \code{any-vector-length}
@@ -16582,7 +16841,21 @@ in greater detail.
 \]
 \fi}
 {\if\edition\pythonEd
-UNDER CONSTRUCTION
+\[
+\begin{array}{l}
+  \gray{\LintASTPython} \\ \hline
+  \gray{\LvarASTPython{}} \\ \hline
+  \gray{\LifASTPython{}} \\ \hline
+  \gray{\LwhileASTPython{}} \\ \hline
+  \gray{\LtupASTPython{}} \\ \hline
+  \gray{\LfunASTPython} \\ \hline
+  \gray{\LlambdaASTPython} \\ \hline
+  \LanyASTPython \\
+  \begin{array}{lcl}
+  \LangLamM{} &::=& \PROGRAM{}{\LS \Def \ldots \Stmt \ldots \RS}
+  \end{array}
+\end{array}
+\]
 \fi}
 \end{minipage}
 }
@@ -16592,8 +16865,8 @@ UNDER CONSTRUCTION
 
 
 The abstract syntax of \LangAny{} is defined in Figure~\ref{fig:Rany-syntax}.
-(The concrete syntax of \LangAny{} is in the Appendix,
-Figure~\ref{fig:Rany-concrete-syntax}.)  The $\INJECT{e}{T}$ form
+\racket{(The concrete syntax of \LangAny{} is in the Appendix,
+Figure~\ref{fig:Rany-concrete-syntax}.)}  The $\INJECT{e}{T}$ form
 converts the value produced by expression $e$ of type $T$ into a
 tagged value.  The $\PROJECT{e}{T}$ form converts the tagged value
 produced by expression $e$ into a value of type $T$ or else halts the

+ 9 - 3
defs.tex

@@ -2,6 +2,7 @@
 
 \newcommand{\itm}[1]{\ensuremath{\mathit{#1}}}
 \newcommand{\ttm}[1]{\ensuremath{\text{\texttt{#1}}}}
+\newcommand{\sfm}[1]{\ensuremath{\mathsf{#1}}}
 
 \newcommand{\Lang}{\mathcal{L}}
 \newcommand{\CLang}{\mathcal{C}}
@@ -266,13 +267,13 @@
 \newcommand{\FUNREFARITY}[2]{\key{(FunRefArity}~#1~#2\code{)}}
 \newcommand{\CFUNREFARITY}[2]{\key{(fun-ref-arity}~#1~#2\code{)}}
 \newcommand{\CGLAMBDA}[3]{\LP\key{lambda:}\,#1\,#2~\Exp\RP}
+\newcommand{\VALUEOF}[2]{\LP\key{ValueOf}~#1~#2\RP}
+
+\if\edition\racketEd
 \newcommand{\INJECT}[2]{\LP\key{Inject}~#1~#2\RP}
 \newcommand{\PROJECT}[2]{\LP\key{Project}~#1~#2\RP}
 \newcommand{\CINJECT}[2]{\LP\key{inject}~#1~#2\RP}
 \newcommand{\CPROJECT}[2]{\LP\key{project}~#1~#2\RP}
-\newcommand{\VALUEOF}[2]{\LP\key{ValueOf}~#1~#2\RP}
-
-\if\edition\racketEd
 \newcommand{\LAMBDA}[3]{\key{(Lambda}~#1~#2~#3\code{)}}
 \newcommand{\CLAMBDA}[3]{\LP\key{lambda:}\,#1\,\key{:}\,#2~\Exp\RP}
 \newcommand{\TAILCALL}[2]{\key{(TailCall}~#1~#2\code{)}}
@@ -286,6 +287,10 @@
 \newcommand{\FUNDEF}[5]{\key{(Def}~#1~#2~#3~#4~#5\code{)}}
 \fi
 \if\edition\pythonEd
+\newcommand{\INJECT}[2]{\key{Inject}\LP#1\key{, }#2\RP}
+\newcommand{\PROJECT}[2]{\key{Project}\LP#1\key{, }#2\RP}
+\newcommand{\CINJECT}[2]{\sfm{inject}\LP#1\key{, }#2\RP}
+\newcommand{\CPROJECT}[2]{\sfm{project}\LP#1\key{, }~#2\RP}
 \newcommand{\LAMBDA}[2]{\key{Lambda}\LP#1\code{, }#2\RP}
 \newcommand{\CLAMBDA}[2]{\key{lambda}\,#1\,\key{:}\,#2}
 \newcommand{\TAILCALL}[2]{\key{TailCall}\LP#1\code{, }#2\RP}
@@ -345,6 +350,7 @@
 \newcommand{\XPROGRAMDEFS}[1]{\code{X86ProgramDefs}\LP #1 \RP}
 \newcommand{\BYTEREG}[1]{\key{ByteReg}\LP #1 \RP}
 \newcommand{\CDEF}[4]{\key{def}~#1\LP #2 \RP ~\key{->}~ #3 \key{:}~#4}
+\newcommand{\CDEFU}[3]{\key{def}~#1\LP #2 \RP \key{:}~#3}
 \newcommand{\DEF}[6]{\key{FunctionDef}\LP#1\key{, }#2\key{, }#3\key{, }#4\key{, }#5\key{, }#6\RP}
 \fi