Преглед на файлове

refactor interp_stmt to pass continuation

Jeremy Siek преди 2 години
родител
ревизия
712c9bfb58
променени са 1 файла, в които са добавени 89 реда и са изтрити 73 реда
  1. 89 73
      book.tex

+ 89 - 73
book.tex

@@ -2160,8 +2160,18 @@ extensible way.
 Having justified the use of classes and methods to implement
 interpreters, we revisit the definitional interpreter for \LangInt{}
 shown in figure~\ref{fig:interp-Lint-class} and then extend it to
-create an interpreter for \LangVar{}, shown in figure~\ref{fig:interp-Lvar}.
-The interpreter for \LangVar{} adds two new \key{match} cases for
+create an interpreter for \LangVar{}, shown in
+figure~\ref{fig:interp-Lvar}.
+%
+\python{We change the \code{interp\_stmt} method in the interpreter
+  for \LangInt{} in anticipation of adding \code{Goto} in
+  Chapter~\ref{ch:Lif}. The \code{interp\_stmt} method takes an extra
+  parameter named \code{cont} for \emph{continuation}, which is the
+  technical name for what comes after a particular point in a
+  program. The \code{cont} parameter is the list of statements that
+  need to be interpreted after the current statement.}
+%
+The interpreter for \LangVar{} adds two new cases for
 variables and \racket{\key{let}}\python{assignment}. For
 \racket{\key{let}}\python{assignment}, we need a way to communicate the
 value bound to a variable to all the uses of the variable. To
@@ -2189,8 +2199,8 @@ variable, it looks up the corresponding value in the dictionary.
   the body of the \key{Let}.}
 %
 \python{When the interpreter encounters an assignment, it evaluates
-  the initializing expression and then associates the resulting value
-  with the variable in the environment.}
+   the initializing expression and then associates the resulting value
+   with the variable in the environment.}
 
 \begin{figure}[tp]
 \begin{tcolorbox}[colback=white]
@@ -2235,16 +2245,23 @@ class InterpLint:
       case Call(Name('input_int'), []):
         return int(input())            
 
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case Expr(Call(Name('print'), [arg])):
-        print(self.interp_exp(arg, env), end='')
-        return self.interp_stmts(ss[1:], env)
+        val = self.interp_exp(arg, env)
+        print(val, end='')
+        return self.interp_stmts(cont, env)
       case Expr(value):
         self.interp_exp(value, env)
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
+      case _:
+        raise Exception('error in interp_stmt, unexpected ' + repr(s))
+    
+  def interp_stmts(self, ss, env):
+    if len(ss) == 0:
+      return None
+    else:
+      return self.interp_stmt(ss[0], env, ss[1:])
 
   def interp(self, p):
     match p:
@@ -2291,15 +2308,13 @@ class InterpLvar(InterpLint):
       case _:
         return super().interp_exp(e, env)
 
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case Assign([lhs], value):
         env[lhs.id] = self.interp_exp(value, env)
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
 
 def interp_Lvar(p):
   return InterpLvar().interp(p)
@@ -7852,17 +7867,16 @@ class InterpLif(InterpLvar):
       case _:
         return super().interp_exp(e, env)
 
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case If(test, body, orelse):
-        if self.interp_exp(test, env):
-          return self.interp_stmts(body + ss[1:], env)
-        else:
-          return self.interp_stmts(orelse + ss[1:], env)
+        match self.interp_exp(test, env):
+          case True:
+            return self.interp_stmts(body + cont, env)
+          case False:
+            return self.interp_stmts(orelse + cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
   ...      
 \end{lstlisting}
 \fi}
@@ -10971,16 +10985,15 @@ function, where we repeatedly interpret the \code{body} so long as the
 {\if\edition\pythonEd\pythonColor
 \begin{lstlisting}
 class InterpLwhile(InterpLif):
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case While(test, body, []):
-        while self.interp_exp(test, env):
-            self.interp_stmts(body, env)
-        return self.interp_stmts(ss[1:], env)
+        if self.interp_exp(test, env):
+            self.interp_stmts(body + [s] + cont, env)
+        else:
+          return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
 \end{lstlisting}
 \fi}
 \end{tcolorbox}
@@ -14174,17 +14187,15 @@ class InterpLarray(InterpLtup):
       case _:
         return super().interp_exp(e, env)
 
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
-      case Assign([Subscript(lst, index)], value):
-        lst = self.interp_exp(lst, env)
+  def interp_stmt(self, s, env, cont):
+    match s:
+      case Assign([Subscript(tup, index)], value):
+        tup = self.interp_exp(tup, env)
         index = self.interp_exp(index, env)
-        lst[index] = self.interp_exp(value, env)
-        return self.interp_stmts(ss[1:], env)
+        tup[index] = self.interp_exp(value, env)
+        return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
 \end{lstlisting}
 \fi}
   \end{tcolorbox}
@@ -14822,18 +14833,19 @@ class InterpLfun(InterpLtup):
       case _:
         return super().interp_exp(e, env)
 
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case Return(value):
         return self.interp_exp(value, env)
       case FunctionDef(name, params, bod, dl, returns, comment):
-        ps = [x for (x,t) in params]
+        if isinstance(params, ast.arguments):
+            ps = [p.arg for p in params.args]
+        else:
+            ps = [x for (x,t) in params]
         env[name] = Function(name, ps, bod, env)
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
     
   def interp(self, p):
     match p:
@@ -16684,15 +16696,15 @@ class InterpLlambda(InterpLfun):
       case _:
         return super().interp_exp(e, env)
     
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case AnnAssign(lhs, typ, value, simple):
         env[lhs.id] = self.interp_exp(value, env)
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
+      case Pass():
+        return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
 \end{lstlisting}
 \fi}
   \end{tcolorbox}
@@ -18395,33 +18407,37 @@ class InterpLdyn(InterpLlambda):
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
 class InterpLdyn(InterpLlambda):
   
-  def interp_stmts(self, ss, env):
-    if len(ss) == 0:
-      return
-    match ss[0]:
+  def interp_stmt(self, s, env, cont):
+    match s:
       case If(test, body, orelse):
         v = self.interp_exp(test, env)
-        if self.untag(v, 'bool', ss[0]):
-            return self.interp_stmts(body + ss[1:], env)
-        else:
-            return self.interp_stmts(orelse + ss[1:], env)
+        match self.untag(v, 'bool', s):
+          case True:
+            return self.interp_stmts(body + cont, env)
+          case False:
+            return self.interp_stmts(orelse + cont, 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)
+        v = self.interp_exp(test, env)
+        if self.untag(v, 'bool', test):
+            self.interp_stmts(body + [s] + cont, env)
+        else:
+          return self.interp_stmts(cont, 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 = self.untag(tup, 'tuple', s)
+        index_v = self.untag(index, 'int', s)
         tup_v[index_v] = self.interp_exp(value, env)
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
       case FunctionDef(name, params, bod, dl, returns, comment):
-        ps = [x for (x,t) in params]
+        if isinstance(params, ast.arguments):
+            ps = [p.arg for p in params.args]
+        else:
+            ps = [x for (x,t) in params]
         env[name] = self.tag(Function(name, ps, bod, env))
-        return self.interp_stmts(ss[1:], env)
+        return self.interp_stmts(cont, env)
       case _:
-        return super().interp_stmts(ss, env)
+        return super().interp_stmt(s, env, cont)
 \end{lstlisting}
 \end{tcolorbox}