source: branches/0.15.x/abcl/src/org/armedbear/lisp/SpecialOperators.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: 19.6 KB
Line 
1/*
2 * SpecialOperators.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: SpecialOperators.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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
36import java.util.ArrayList;
37import java.util.LinkedList;
38public final class SpecialOperators extends Lisp
39{
40  // ### quote
41  private static final SpecialOperator QUOTE =
42    new SpecialOperator(Symbol.QUOTE, "thing")
43    {
44      @Override
45      public LispObject execute(LispObject args, Environment env)
46        throws ConditionThrowable
47      {
48        if (args.cdr() != NIL)
49          return error(new WrongNumberOfArgumentsException(this));
50        return ((Cons)args).car;
51      }
52    };
53
54  // ### if
55  private static final SpecialOperator IF =
56    new SpecialOperator(Symbol.IF, "test then &optional else")
57    {
58      @Override
59      public LispObject execute(LispObject args, Environment env)
60        throws ConditionThrowable
61      {
62        final LispThread thread = LispThread.currentThread();
63        switch (args.length())
64          {
65          case 2:
66            {
67              if (eval(((Cons)args).car, env, thread) != NIL)
68                return eval(args.cadr(), env, thread);
69              thread.clearValues();
70              return NIL;
71            }
72          case 3:
73            {
74              if (eval(((Cons)args).car, env, thread) != NIL)
75                return eval(args.cadr(), env, thread);
76              return eval((((Cons)args).cdr).cadr(), env, thread);
77            }
78          default:
79            return error(new WrongNumberOfArgumentsException(this));
80          }
81      }
82    };
83
84  // ### let
85  private static final SpecialOperator LET =
86    new SpecialOperator(Symbol.LET, "bindings &body body")
87    {
88      @Override
89      public LispObject execute(LispObject args, Environment env)
90        throws ConditionThrowable
91      {
92        if (args == NIL)
93          return error(new WrongNumberOfArgumentsException(this));
94        return _let(args, env, false);
95      }
96    };
97
98  // ### let*
99  private static final SpecialOperator LET_STAR =
100    new SpecialOperator(Symbol.LET_STAR, "bindings &body body")
101    {
102      @Override
103      public LispObject execute(LispObject args, Environment env)
104        throws ConditionThrowable
105      {
106        if (args == NIL)
107          return error(new WrongNumberOfArgumentsException(this));
108        return _let(args, env, true);
109      }
110    };
111
112  private static final LispObject _let(LispObject args, Environment env,
113                                       boolean sequential)
114    throws ConditionThrowable
115  {
116    final LispThread thread = LispThread.currentThread();
117    final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
118    try
119      {
120        LispObject varList = checkList(args.car());
121        LispObject bodyAndDecls = parseBody(args.cdr(), false);
122        LispObject specials = parseSpecials(bodyAndDecls.NTH(1));
123        LispObject body = bodyAndDecls.car();
124
125        Environment ext = new Environment(env);
126        LinkedList<Cons> nonSequentialVars = new LinkedList<Cons>();
127        while (varList != NIL)
128          {
129            final Symbol symbol;
130            LispObject value;
131            LispObject obj = varList.car();
132            if (obj instanceof Cons)
133              {
134                if (obj.length() > 2)
135                  return error(new LispError("The " + (sequential ? "LET*" : "LET")
136                          + " binding specification " +
137                          obj.writeToString() + " is invalid."));
138                symbol = checkSymbol(((Cons)obj).car);
139                value = eval(obj.cadr(), sequential ? ext : env, thread);
140              }
141            else
142              {
143                symbol = checkSymbol(obj);
144                value = NIL;
145              }
146            if (sequential) {
147        ext = new Environment(ext);
148              bindArg(specials, symbol, value, ext, thread);
149      }
150            else
151                nonSequentialVars.add(new Cons(symbol, value));
152            varList = ((Cons)varList).cdr;
153          }
154        if (!sequential)
155          for (Cons x : nonSequentialVars)
156            bindArg(specials, (Symbol)x.car(), x.cdr(), ext, thread);
157
158        // Make sure free special declarations are visible in the body.
159        // "The scope of free declarations specifically does not include
160        // initialization forms for bindings established by the form
161        // containing the declarations." (3.3.4)
162        for (; specials != NIL; specials = specials.cdr())
163          ext.declareSpecial((Symbol)specials.car());
164
165        return progn(body, ext, thread);
166      }
167    finally
168      {
169        thread.lastSpecialBinding = lastSpecialBinding;
170      }
171  }
172
173  // ### symbol-macrolet
174  private static final SpecialOperator SYMBOL_MACROLET =
175    new SpecialOperator(Symbol.SYMBOL_MACROLET, "macrobindings &body body")
176    {
177      @Override
178      public LispObject execute(LispObject args, Environment env)
179        throws ConditionThrowable
180      {
181        LispObject varList = checkList(args.car());
182        final LispThread thread = LispThread.currentThread();
183        SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
184        Environment ext = new Environment(env);
185        try
186         {
187             // Declare our free specials, this will correctly raise
188             LispObject body = ext.processDeclarations(args.cdr());
189
190             for (int i = varList.length(); i-- > 0;)
191               {
192                 LispObject obj = varList.car();
193                 varList = varList.cdr();
194                 if (obj instanceof Cons && obj.length() == 2)
195                   {
196                     Symbol symbol = checkSymbol(obj.car());
197                     if (symbol.isSpecialVariable()
198                         || ext.isDeclaredSpecial(symbol))
199                       {
200                          return error(new ProgramError(
201                              "Attempt to bind the special variable " +
202                              symbol.writeToString() +
203                              " with SYMBOL-MACROLET."));
204                       }
205                     bindArg(null, symbol, new SymbolMacro(obj.cadr()), ext, thread);
206                   }
207                 else
208                   {
209                     return error(new ProgramError(
210                       "Malformed symbol-expansion pair in SYMBOL-MACROLET: " +
211                       obj.writeToString()));
212                   }
213                }
214             return progn(body, ext, thread);
215              }
216        finally
217            {
218                thread.lastSpecialBinding = lastSpecialBinding;
219            }
220      }
221    };
222
223  // ### load-time-value form &optional read-only-p => object
224  private static final SpecialOperator LOAD_TIME_VALUE =
225    new SpecialOperator(Symbol.LOAD_TIME_VALUE,
226                        "form &optional read-only-p")
227    {
228      @Override
229      public LispObject execute(LispObject args, Environment env)
230        throws ConditionThrowable
231      {
232        switch (args.length())
233          {
234          case 1:
235          case 2:
236            return eval(args.car(), new Environment(),
237                        LispThread.currentThread());
238          default:
239            return error(new WrongNumberOfArgumentsException(this));
240          }
241      }
242    };
243
244  // ### locally
245  private static final SpecialOperator LOCALLY =
246    new SpecialOperator(Symbol.LOCALLY, "&body body")
247    {
248      @Override
249      public LispObject execute(LispObject args, Environment env)
250        throws ConditionThrowable
251      {
252        final LispThread thread = LispThread.currentThread();
253        final Environment ext = new Environment(env);
254        args = ext.processDeclarations(args);
255        return progn(args, ext, thread);
256      }
257    };
258
259  // ### progn
260  private static final SpecialOperator PROGN =
261    new SpecialOperator(Symbol.PROGN, "&rest forms")
262    {
263      @Override
264      public LispObject execute(LispObject args, Environment env)
265        throws ConditionThrowable
266      {
267        LispThread thread = LispThread.currentThread();
268        return progn(args, env, thread);
269      }
270    };
271
272  // ### flet
273  private static final SpecialOperator FLET =
274    new SpecialOperator(Symbol.FLET, "definitions &body body")
275    {
276      @Override
277      public LispObject execute(LispObject args, Environment env)
278        throws ConditionThrowable
279      {
280        return _flet(args, env, false);
281      }
282    };
283
284  // ### labels
285  private static final SpecialOperator LABELS =
286    new SpecialOperator(Symbol.LABELS, "definitions &body body")
287    {
288      @Override
289      public LispObject execute(LispObject args, Environment env)
290        throws ConditionThrowable
291      {
292        return _flet(args, env, true);
293      }
294    };
295
296  private static final LispObject _flet(LispObject args, Environment env,
297                                        boolean recursive)
298    throws ConditionThrowable
299  {
300    // First argument is a list of local function definitions.
301    LispObject defs = checkList(args.car());
302    final LispThread thread = LispThread.currentThread();
303    final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
304    final Environment funEnv = new Environment(env);
305    while (defs != NIL)
306      {
307        final LispObject def = checkList(defs.car());
308        final LispObject name = def.car();
309        final Symbol symbol;
310        if (name instanceof Symbol)
311          {
312            symbol = checkSymbol(name);
313            if (symbol.getSymbolFunction() instanceof SpecialOperator)
314              {
315                String message =
316                  symbol.getName() + " is a special operator and may not be redefined";
317                return error(new ProgramError(message));
318              }
319          }
320        else if (isValidSetfFunctionName(name))
321          symbol = checkSymbol(name.cadr());
322        else
323          return type_error(name, FUNCTION_NAME);
324        LispObject rest = def.cdr();
325        LispObject parameters = rest.car();
326        LispObject body = rest.cdr();
327        LispObject decls = NIL;
328        while (body.car() instanceof Cons && body.car().car() == Symbol.DECLARE)
329          {
330            decls = new Cons(body.car(), decls);
331            body = body.cdr();
332          }
333        body = new Cons(symbol, body);
334        body = new Cons(Symbol.BLOCK, body);
335        body = new Cons(body, NIL);
336        while (decls != NIL)
337          {
338            body = new Cons(decls.car(), body);
339            decls = decls.cdr();
340          }
341        LispObject lambda_expression =
342          new Cons(Symbol.LAMBDA, new Cons(parameters, body));
343        LispObject lambda_name =
344          list(recursive ? Symbol.LABELS : Symbol.FLET, name);
345        Closure closure =
346          new Closure(lambda_name, lambda_expression,
347                      recursive ? funEnv : env);
348        funEnv.addFunctionBinding(name, closure);
349        defs = defs.cdr();
350      }
351    try
352      {
353        final Environment ext = new Environment(funEnv);
354        LispObject body = args.cdr();
355        body = ext.processDeclarations(body);
356        return progn(body, ext, thread);
357      }
358    finally
359      {
360        thread.lastSpecialBinding = lastSpecialBinding;
361      }
362  }
363
364  // ### the value-type form => result*
365  private static final SpecialOperator THE =
366    new SpecialOperator(Symbol.THE, "type value")
367    {
368      @Override
369      public LispObject execute(LispObject args, Environment env)
370        throws ConditionThrowable
371      {
372        if (args.length() != 2)
373          return error(new WrongNumberOfArgumentsException(this));
374        return eval(args.cadr(), env, LispThread.currentThread());
375      }
376    };
377
378  // ### progv
379  private static final SpecialOperator PROGV =
380    new SpecialOperator(Symbol.PROGV, "symbols values &body body")
381    {
382      @Override
383      public LispObject execute(LispObject args, Environment env)
384        throws ConditionThrowable
385      {
386        if (args.length() < 2)
387          return error(new WrongNumberOfArgumentsException(this));
388        final LispThread thread = LispThread.currentThread();
389        final LispObject symbols = checkList(eval(args.car(), env, thread));
390        LispObject values = checkList(eval(args.cadr(), env, thread));
391        SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
392        try
393          {
394            // Set up the new bindings.
395            progvBindVars(symbols, values, thread);
396            // Implicit PROGN.
397            return progn(args.cdr().cdr(), env, thread);
398          }
399        finally
400          {
401            thread.lastSpecialBinding = lastSpecialBinding;
402          }
403      }
404    };
405
406  // ### declare
407  private static final SpecialOperator DECLARE =
408    new SpecialOperator(Symbol.DECLARE, "&rest declaration-specifiers")
409    {
410      @Override
411      public LispObject execute(LispObject args, Environment env)
412        throws ConditionThrowable
413      {
414        return NIL;
415      }
416    };
417
418  // ### function
419  private static final SpecialOperator FUNCTION =
420    new SpecialOperator(Symbol.FUNCTION, "thing")
421    {
422      @Override
423      public LispObject execute(LispObject args, Environment env)
424        throws ConditionThrowable
425      {
426        final LispObject arg = args.car();
427        if (arg instanceof Symbol)
428          {
429            LispObject operator = env.lookupFunction(arg);
430            if (operator instanceof Autoload)
431              {
432                Autoload autoload = (Autoload) operator;
433                autoload.load();
434                operator = autoload.getSymbol().getSymbolFunction();
435              }
436            if (operator instanceof Function)
437              return operator;
438            if (operator instanceof StandardGenericFunction)
439              return operator;
440            return error(new UndefinedFunction(arg));
441          }
442        if (arg instanceof Cons)
443          {
444            LispObject car = ((Cons)arg).car;
445            if (car == Symbol.SETF)
446              {
447                LispObject f = env.lookupFunction(arg);
448                if (f != null)
449                  return f;
450                Symbol symbol = checkSymbol(arg.cadr());
451                f = get(symbol, Symbol.SETF_FUNCTION, null);
452                if (f != null)
453                  return f;
454                f = get(symbol, Symbol.SETF_INVERSE, null);
455                if (f != null)
456                  return f;
457              }
458            if (car == Symbol.LAMBDA)
459              return new Closure(arg, env);
460            if (car == Symbol.NAMED_LAMBDA)
461              {
462                LispObject name = arg.cadr();
463                if (name instanceof Symbol || isValidSetfFunctionName(name))
464                  {
465                    return new Closure(name,
466                                       new Cons(Symbol.LAMBDA, arg.cddr()),
467                                       env);
468                  }
469                return type_error(name, FUNCTION_NAME);
470              }
471          }
472        return error(new UndefinedFunction(list(Keyword.NAME, arg)));
473      }
474    };
475
476  // ### setq
477  private static final SpecialOperator SETQ =
478    new SpecialOperator(Symbol.SETQ, "&rest vars-and-values")
479    {
480      @Override
481      public LispObject execute(LispObject args, Environment env)
482        throws ConditionThrowable
483      {
484        LispObject value = Symbol.NIL;
485        final LispThread thread = LispThread.currentThread();
486        while (args != NIL)
487          {
488            Symbol symbol = checkSymbol(args.car());
489            if (symbol.isConstant())
490              {
491                return error(new ProgramError(symbol.writeToString() +
492                                               " is a constant and thus cannot be set."));
493              }
494            args = args.cdr();
495            if (symbol.isSpecialVariable() || env.isDeclaredSpecial(symbol))
496              {
497                SpecialBinding binding = thread.getSpecialBinding(symbol);
498                if (binding != null)
499                  {
500                    if (binding.value instanceof SymbolMacro)
501                      {
502                        LispObject expansion =
503                          ((SymbolMacro)binding.value).getExpansion();
504                        LispObject form = list(Symbol.SETF, expansion, args.car());
505                        value = eval(form, env, thread);
506                      }
507                    else
508                      {
509                        value = eval(args.car(), env, thread);
510                        binding.value = value;
511                      }
512                  }
513                else
514                  {
515                    if (symbol.getSymbolValue() instanceof SymbolMacro)
516                      {
517                        LispObject expansion =
518                          ((SymbolMacro)symbol.getSymbolValue()).getExpansion();
519                        LispObject form = list(Symbol.SETF, expansion, args.car());
520                        value = eval(form, env, thread);
521                      }
522                    else
523                      {
524                        value = eval(args.car(), env, thread);
525                        symbol.setSymbolValue(value);
526                      }
527                  }
528              }
529            else
530              {
531                // Not special.
532                Binding binding = env.getBinding(symbol);
533                if (binding != null)
534                  {
535                    if (binding.value instanceof SymbolMacro)
536                      {
537                        LispObject expansion =
538                          ((SymbolMacro)binding.value).getExpansion();
539                        LispObject form = list(Symbol.SETF, expansion, args.car());
540                        value = eval(form, env, thread);
541                      }
542                    else
543                      {
544                        value = eval(args.car(), env, thread);
545                        binding.value = value;
546                      }
547                  }
548                else
549                  {
550                    if (symbol.getSymbolValue() instanceof SymbolMacro)
551                      {
552                        LispObject expansion =
553                          ((SymbolMacro)symbol.getSymbolValue()).getExpansion();
554                        LispObject form = list(Symbol.SETF, expansion, args.car());
555                        value = eval(form, env, thread);
556                      }
557                    else
558                      {
559                        value = eval(args.car(), env, thread);
560                        symbol.setSymbolValue(value);
561                      }
562                  }
563              }
564            args = args.cdr();
565          }
566        // Return primary value only!
567        thread._values = null;
568        return value;
569      }
570    };
571}
Note: See TracBrowser for help on using the repository browser.