Преглед изворни кода

Merge pull request #110 from Compiler-Construction-Uni-Freiburg/master

Chapter 7 syntax and type checker
Jeremy G. Siek пре 3 година
родитељ
комит
2482a1efd0
1 измењених фајлова са 33 додато и 31 уклоњено
  1. 33 31
      book.tex

+ 33 - 31
book.tex

@@ -13014,7 +13014,10 @@ nested inside each other.
 
 \newcommand{\LfunGrammarPython}{
   \begin{array}{lcl}
-   \Type &::=& \key{Callable}\LS \LS \Type \key{,} \ldots \RS \key{, } \Type \RS \\
+    \Type &::=& \key{int}
+                \MID \key{bool}
+                \MID \key{tuple}\LS \Type^+ \RS
+                \MID \key{Callable}\LS \LS \Type \key{,} \ldots \RS \key{, } \Type \RS \\
    \Exp &::=& \CAPPLY{\Exp}{\Exp\code{,} \ldots} \\
    \Stmt &::=& \CRETURN{\Exp} \\
    \Def &::=& \CDEF{\Var}{\Var \key{:} \Type\key{,} \ldots}{\Type}{\Stmt^{+}} 
@@ -13022,11 +13025,10 @@ nested inside each other.
 }
 \newcommand{\LfunASTPython}{
   \begin{array}{lcl}
-    \Type &::=& \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
+    \Type &::=& \key{int} \MID \key{bool} \MID \key{tuple}\LS\Type^+\RS \MID \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
     \Exp &::=& \CALL{\Exp}{\Exp^{*}}\\
     \Stmt &::=& \RETURN{\Exp} \\
    \Params &::=&                  \LP\Var\key{,}\Type\RP^*
-   % was: \LS\LP\Var\key{,}\Type\RP\code{,}\ldots\RS 
     \\
    \Def &::=& \FUNDEF{\Var}{\Params}{\Type}{}{\Stmt^{+}} 
   \end{array}
@@ -13240,9 +13242,7 @@ class InterpLfun(InterpLtup):
   def apply_fun(self, fun, args, e):
       match fun:
         case Function(name, xs, body, env):
-          new_env = {x: v for (x,v) in env.items()}
-          for (x,arg) in zip(xs, args):
-              new_env[x] = arg
+          new_env = env.copy().update(zip(xs, args))
           return self.interp_stmts(body, new_env)
         case _:
           raise Exception('apply_fun: unexpected: ' + repr(fun))
@@ -13379,7 +13379,7 @@ class TypeCheckLfun(TypeCheckLtup):
                 check_type_equal(param_t, arg_t, e)
             return return_t
           case _:
-            raise Exception('type_check_exp: in call, unexpected ' + \
+            raise Exception('type_check_exp: in call, unexpected ' +
                               repr(func_t))
       case _:
         return super().type_check_exp(e, env)
@@ -13389,9 +13389,7 @@ class TypeCheckLfun(TypeCheckLtup):
       return
     match ss[0]:
       case FunctionDef(name, params, body, dl, returns, comment):
-        new_env = {x: t for (x,t) in env.items()}
-        for (x,t) in params:
-            new_env[x] = t
+        new_env = env.copy().update(params)
         rt = self.type_check_stmts(body, new_env)
         check_type_equal(returns, rt, ss[0])
         return self.type_check_stmts(ss[1:], env)
@@ -13405,10 +13403,13 @@ class TypeCheckLfun(TypeCheckLtup):
       case Module(body):
         env = {}
         for s in body:
-            match s:
-              case FunctionDef(name, params, bod, dl, returns, comment):
-                params_t = [t for (x,t) in params]
-                env[name] = FunctionType(params_t, returns)
+          match s:
+            case FunctionDef(name, params, bod, dl, returns, comment):
+              if name in env:
+                raise Exception('type_check: function ' +
+                                  repr(name) + ' defined twice')
+              params_t = [t for (x,t) in params]
+              env[name] = FunctionType(params_t, returns)
         self.type_check_stmts(body, env)
       case _:
         raise Exception('type_check: unexpected ' + repr(p))
@@ -13476,13 +13477,14 @@ the target. However, \code{callq} does not handle
 \item determining how registers are shared by different functions.
 \end{enumerate}
 
-Regarding (1) parameter passing, recall that the following six
-registers are used to pass arguments to a function, in this order.
+Regarding (1) parameter passing, recall that the x86-64 calling convention
+for Unix-based system uses the following six
+registers to pass arguments to a function, in this order.
 \begin{lstlisting}
 rdi rsi rdx rcx r8 r9
 \end{lstlisting}
 If there are
-more than six arguments, then the convention is to use space on the
+more than six arguments, then the calling convention mandates to use space on the
 frame of the caller for the rest of the arguments. However, to ease
 the implementation of efficient tail calls
 (Section~\ref{sec:tail-call}), we arrange never to need more than six
@@ -14104,7 +14106,7 @@ leaq (fun-ref |$f$|), |$\itm{lhs}'$|
 \fi}
 {\if\edition\pythonEd
 \begin{lstlisting}
-leaq (FunRef(|$f$|)), |$\itm{lhs}'$|
+leaq |$f$|(%rip), |$\itm{lhs}'$|
 \end{lstlisting}
 \fi}
 \end{minipage}
@@ -15056,9 +15058,7 @@ class TypeCheckLlambda(TypeCheckLfun):
         e.has_type = ty
         match ty:
           case FunctionType(params_t, return_t):
-            new_env = {x:t for (x,t) in env.items()}
-            for (p,t) in zip(params, params_t):
-                new_env[p] = t
+            new_env = env.copy().update(zip(params, params_t))
             self.check_exp(body, return_t, new_env)
           case _:
             raise Exception('lambda does not have type ' + str(ty))
@@ -15090,9 +15090,7 @@ class TypeCheckLlambda(TypeCheckLfun):
       return
     match ss[0]:
       case FunctionDef(name, params, body, dl, returns, comment):
-        new_env = {x: t for (x,t) in env.items()}
-        for (x,t) in params:
-            new_env[x] = t
+        new_env = env.copy().update(params)
         rt = self.check_stmts(body, returns, new_env)
         self.check_stmts(ss[1:], return_ty, env)
       case Return(value):
@@ -15343,7 +15341,7 @@ Figure~\ref{fig:f2-syntax}.
 \section{Assignment Conversion}
 \label{sec:convert-assignments}
 
-The purpose of the \code{convert\_assignments} pass is address the
+The purpose of the \code{convert\_assignments} pass is to address the
 challenge posed in Section~\ref{sec:assignment-scoping} regarding the
 interaction between variable assignments and closure conversion.
 First we identify which variables need to be boxed, then we transform
@@ -15356,6 +15354,8 @@ intersection of the following two sets of variables:
 \item The variables that appear on the left-hand side of an
   assignment.
 \end{enumerate}
+The first condition is a must, but the second condition is quite conservative and it is possible to
+develop a more liberal condition. 
 
 Consider again the first example from
 Section~\ref{sec:assignment-scoping}:
@@ -15392,7 +15392,7 @@ variables \code{x} and \code{z} occur free inside the
 \code{y} or \code{z}.  The boxing of \code{x} consists of three
 transformations: initialize \code{x} with a tuple, replace reads from
 \code{x} with tuple reads, and replace each assignment to \code{x}
-with a tuple writes. The output of \code{convert\_assignments} for
+with a tuple write. The output of \code{convert\_assignments} for
 this example is as follows.
 %
 {\if\edition\racketEd
@@ -15509,7 +15509,7 @@ the intersection of the variables that are free in a \code{lambda} and
 that are assigned-to. We then apply assignment conversion to the body
 of the function definition. Finally, we box the parameters of this
 function definition that are in $\mathit{AF}$. For example,
-the parameter \code{x} of the follow function \code{g}
+the parameter \code{x} of the following function \code{g}
 needs to be boxed.
 {\if\edition\racketEd
 \begin{lstlisting}
@@ -15684,10 +15684,12 @@ and the rest of the parameters are the ones from the original
 function, with types $T'_1, \ldots, T'_n$.  The type for the closure
 omits the types of the free variables because 1) those types are not
 available in this context and 2) we do not need them in the code that
-is generated for function application.
+is generated for function application. So this type only describes the
+first component of the closure tuple. At runtime the tuple may have
+more components, but we ignore them at this point.
 
 We transform function application into code that retrieves the
-function from the closure and then calls the function, passing in the
+function from the closure and then calls the function, passing the
 closure as the first argument. We place $e'$ in a temporary variable
 to avoid code duplication.
 \begin{center}
@@ -15798,8 +15800,8 @@ $\Rightarrow$
 % free_var.py
 \begin{lstlisting}
 def f(x : int) -> Callable[[int], int]:
-    y = 4
-    return lambda z: x + y + z
+  y = 4
+  return lambda z: x + y + z
 
 g = f(5)
 h = f(3)