source: branches/0.15.x/abcl/src/org/armedbear/lisp/Do.java

Last change on this file was 11940, checked in by astalla, 16 years ago

Fixed a bug in interpreted let* and do*: the environment used for bindings
was a single one, shared with all the initforms and the body. This caused
closures in initforms to capture newly-introduced bindings.
The fix amounts to creating a new extended environment for every binding.
In passing a typo was fixed in java.lisp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.5 KB
Line 
1/*
2 * Do.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: Do.java 11940 2009-05-23 22:44:26Z astalla $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36public final class Do extends Lisp
37{
38  // ### do
39  private static final SpecialOperator DO =
40    new SpecialOperator(Symbol.DO, "varlist endlist &body body")
41    {
42      @Override
43      public LispObject execute(LispObject args, Environment env)
44        throws ConditionThrowable
45      {
46        return _do(args, env, false);
47      }
48    };
49
50  // ### do*
51  private static final SpecialOperator DO_STAR =
52    new SpecialOperator(Symbol.DO_STAR, "varlist endlist &body body")
53    {
54      @Override
55      public LispObject execute(LispObject args, Environment env)
56        throws ConditionThrowable
57      {
58        return _do(args, env, true);
59      }
60    };
61
62  private static final LispObject _do(LispObject args, Environment env,
63                                      boolean sequential)
64    throws ConditionThrowable
65  {
66    LispObject varlist = args.car();
67    LispObject second = args.cadr();
68    LispObject end_test_form = second.car();
69    LispObject result_forms = second.cdr();
70    LispObject body = args.cddr();
71    // Process variable specifications.
72    final int numvars = varlist.length();
73    Symbol[] vars = new Symbol[numvars];
74    LispObject[] initforms = new LispObject[numvars];
75    LispObject[] stepforms = new LispObject[numvars];
76    for (int i = 0; i < numvars; i++)
77      {
78        final LispObject varspec = varlist.car();
79        if (varspec instanceof Cons)
80          {
81            vars[i] = checkSymbol(varspec.car());
82            initforms[i] = varspec.cadr();
83            // Is there a step form?
84            if (varspec.cddr() != NIL)
85              stepforms[i] = varspec.caddr();
86          }
87        else
88          {
89            // Not a cons, must be a symbol.
90            vars[i] = checkSymbol(varspec);
91            initforms[i] = NIL;
92          }
93        varlist = varlist.cdr();
94      }
95    final LispThread thread = LispThread.currentThread();
96    final LispObject stack = thread.getStack();
97    final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
98    // Process declarations.
99
100    final LispObject bodyAndDecls = parseBody(body, false);
101    LispObject specials = parseSpecials(bodyAndDecls.NTH(1));
102    body = bodyAndDecls.car();
103
104    Environment ext = new Environment(env);
105    for (int i = 0; i < numvars; i++)
106      {
107        Symbol var = vars[i];
108        LispObject value = eval(initforms[i], (sequential ? ext : env), thread);
109  ext = new Environment(ext);
110        if (specials != NIL && memq(var, specials))
111            thread.bindSpecial(var, value);
112        else if (var.isSpecialVariable())
113          thread.bindSpecial(var, value);
114        else
115          ext.bind(var, value);
116      }
117    LispObject list = specials;
118    while (list != NIL)
119      {
120        ext.declareSpecial(checkSymbol(list.car()));
121        list = list.cdr();
122      }
123    // Look for tags.
124    LispObject remaining = body;
125    while (remaining != NIL)
126      {
127        LispObject current = remaining.car();
128        remaining = remaining.cdr();
129        if (current instanceof Cons)
130          continue;
131        // It's a tag.
132        ext.addTagBinding(current, remaining);
133      }
134    try
135      {
136        // Implicit block.
137        ext.addBlock(NIL, new LispObject());
138        while (true)
139          {
140            // Execute body.
141            // Test for termination.
142            if (eval(end_test_form, ext, thread) != NIL)
143              break;
144            remaining = body;
145            while (remaining != NIL)
146              {
147                LispObject current = remaining.car();
148                if (current instanceof Cons)
149                  {
150                    try
151                      {
152                        // Handle GO inline if possible.
153                        if (current.car() == Symbol.GO)
154                          {
155                            LispObject tag = current.cadr();
156                            Binding binding = ext.getTagBinding(tag);
157                            if (binding != null && binding.value != null)
158                              {
159                                remaining = binding.value;
160                                continue;
161                              }
162                            throw new Go(tag);
163                          }
164                        eval(current, ext, thread);
165                      }
166                    catch (Go go)
167                      {
168                        LispObject tag = go.getTag();
169                        Binding binding = ext.getTagBinding(tag);
170                        if (binding != null && binding.value != null)
171                          {
172                            remaining = binding.value;
173                            thread.setStack(stack);
174                            continue;
175                          }
176                        throw go;
177                      }
178                  }
179                remaining = remaining.cdr();
180              }
181            // Update variables.
182            if (sequential)
183              {
184                for (int i = 0; i < numvars; i++)
185                  {
186                    LispObject step = stepforms[i];
187                    if (step != null)
188                      {
189                        Symbol symbol = vars[i];
190                        LispObject value = eval(step, ext, thread);
191                        if (symbol.isSpecialVariable()
192                            || ext.isDeclaredSpecial(symbol))
193                          thread.rebindSpecial(symbol, value);
194                        else
195                          ext.rebind(symbol, value);
196                      }
197                  }
198              }
199            else
200              {
201                // Evaluate step forms.
202                LispObject results[] = new LispObject[numvars];
203                for (int i = 0; i < numvars; i++)
204                  {
205                    LispObject step = stepforms[i];
206                    if (step != null)
207                      {
208                        LispObject result = eval(step, ext, thread);
209                        results[i] = result;
210                      }
211                  }
212                // Update variables.
213                for (int i = 0; i < numvars; i++)
214                  {
215                    if (results[i] != null)
216                      {
217                        Symbol symbol = vars[i];
218                        LispObject value = results[i];
219                        if (symbol.isSpecialVariable()
220                            || ext.isDeclaredSpecial(symbol))
221                          thread.rebindSpecial(symbol, value);
222                        else
223                          ext.rebind(symbol, value);
224                      }
225                  }
226              }
227            if (interrupted)
228              handleInterrupt();
229          }
230        LispObject result = progn(result_forms, ext, thread);
231        return result;
232      }
233    catch (Return ret)
234      {
235        if (ret.getTag() == NIL)
236          {
237            thread.setStack(stack);
238            return ret.getResult();
239          }
240        throw ret;
241      }
242    finally
243      {
244        thread.lastSpecialBinding = lastSpecialBinding;
245      }
246  }
247}
Note: See TracBrowser for help on using the repository browser.