source: branches/0.17.x/abcl/src/org/armedbear/lisp/SpecialOperators.java

Last change on this file was 12254, checked in by ehuelsmann, 16 years ago

Remove 'throws ConditionThrowable?' method annotations:

it's an unchecked exception now, so no need to declare it thrown.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.9 KB
Line 
1/*
2 * SpecialOperators.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: SpecialOperators.java 12254 2009-11-06 20:07:54Z ehuelsmann $
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
47      {
48        if (args.cdr() != NIL)
49          return error(new WrongNumberOfArgumentsException(this));
50        return 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
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
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
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
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
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
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
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
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
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
291      {
292        return _flet(args, env, true);
293      }
294    };
295
296  private static final LispObject _flet(LispObject args, Environment env,
297                                        boolean recursive)
298
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
371      {
372        if (args.length() != 2)
373          return error(new WrongNumberOfArgumentsException(this));
374        LispObject rv = eval(args.cadr(), env, LispThread.currentThread());
375
376        // check only the most simple types: single symbols
377        // (class type specifiers/primitive types)
378        // DEFTYPE-d types need expansion;
379        // doing so would slow down our execution too much
380
381        // An implementation is allowed not to check the type,
382        // the fact that we do so here is mainly driven by the
383        // requirement to verify argument types in structure-slot
384        // accessors (defstruct.lisp)
385
386        // The policy below is in line with the level of verification
387        // in the compiler at *safety* levels below 3
388        LispObject type = args.car();
389        if ((type instanceof Symbol
390             && get(type, Symbol.DEFTYPE_DEFINITION) == NIL)
391            || type instanceof BuiltInClass)
392    if (rv.typep(type) == NIL)
393        type_error(rv, type);
394
395        return rv;
396      }
397    };
398
399  // ### progv
400  private static final SpecialOperator PROGV =
401    new SpecialOperator(Symbol.PROGV, "symbols values &body body")
402    {
403      @Override
404      public LispObject execute(LispObject args, Environment env)
405
406      {
407        if (args.length() < 2)
408          return error(new WrongNumberOfArgumentsException(this));
409        final LispThread thread = LispThread.currentThread();
410        final LispObject symbols = checkList(eval(args.car(), env, thread));
411        LispObject values = checkList(eval(args.cadr(), env, thread));
412        SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
413        try
414          {
415            // Set up the new bindings.
416            progvBindVars(symbols, values, thread);
417            // Implicit PROGN.
418            return progn(args.cdr().cdr(), env, thread);
419          }
420        finally
421          {
422            thread.lastSpecialBinding = lastSpecialBinding;
423          }
424      }
425    };
426
427  // ### declare
428  private static final SpecialOperator DECLARE =
429    new SpecialOperator(Symbol.DECLARE, "&rest declaration-specifiers")
430    {
431      @Override
432      public LispObject execute(LispObject args, Environment env)
433
434      {
435        return NIL;
436      }
437    };
438
439  // ### function
440  private static final SpecialOperator FUNCTION =
441    new SpecialOperator(Symbol.FUNCTION, "thing")
442    {
443      @Override
444      public LispObject execute(LispObject args, Environment env)
445
446      {
447        final LispObject arg = args.car();
448        if (arg instanceof Symbol)
449          {
450            LispObject operator = env.lookupFunction(arg);
451            if (operator instanceof Autoload)
452              {
453                Autoload autoload = (Autoload) operator;
454                autoload.load();
455                operator = autoload.getSymbol().getSymbolFunction();
456              }
457            if (operator instanceof Function)
458              return operator;
459            if (operator instanceof StandardGenericFunction)
460              return operator;
461            return error(new UndefinedFunction(arg));
462          }
463        if (arg instanceof Cons)
464          {
465            LispObject car = ((Cons)arg).car;
466            if (car == Symbol.SETF)
467              {
468                LispObject f = env.lookupFunction(arg);
469                if (f != null)
470                  return f;
471                Symbol symbol = checkSymbol(arg.cadr());
472                f = get(symbol, Symbol.SETF_FUNCTION, null);
473                if (f != null)
474                  return f;
475                f = get(symbol, Symbol.SETF_INVERSE, null);
476                if (f != null)
477                  return f;
478              }
479            if (car == Symbol.LAMBDA)
480              return new Closure(arg, env);
481            if (car == Symbol.NAMED_LAMBDA)
482              {
483                LispObject name = arg.cadr();
484                if (name instanceof Symbol || isValidSetfFunctionName(name))
485                  {
486                    return new Closure(name,
487                                       new Cons(Symbol.LAMBDA, arg.cddr()),
488                                       env);
489                  }
490                return type_error(name, FUNCTION_NAME);
491              }
492          }
493        return error(new UndefinedFunction(list(Keyword.NAME, arg)));
494      }
495    };
496
497  // ### setq
498  private static final SpecialOperator SETQ =
499    new SpecialOperator(Symbol.SETQ, "&rest vars-and-values")
500    {
501      @Override
502      public LispObject execute(LispObject args, Environment env)
503
504      {
505        LispObject value = Symbol.NIL;
506        final LispThread thread = LispThread.currentThread();
507        while (args != NIL)
508          {
509            Symbol symbol = checkSymbol(args.car());
510            if (symbol.isConstant())
511              {
512                return error(new ProgramError(symbol.writeToString() +
513                                               " is a constant and thus cannot be set."));
514              }
515            args = args.cdr();
516            if (symbol.isSpecialVariable() || env.isDeclaredSpecial(symbol))
517              {
518                SpecialBinding binding = thread.getSpecialBinding(symbol);
519                if (binding != null)
520                  {
521                    if (binding.value instanceof SymbolMacro)
522                      {
523                        LispObject expansion =
524                          ((SymbolMacro)binding.value).getExpansion();
525                        LispObject form = list(Symbol.SETF, expansion, args.car());
526                        value = eval(form, env, thread);
527                      }
528                    else
529                      {
530                        value = eval(args.car(), env, thread);
531                        binding.value = value;
532                      }
533                  }
534                else
535                  {
536                    if (symbol.getSymbolValue() instanceof SymbolMacro)
537                      {
538                        LispObject expansion =
539                          ((SymbolMacro)symbol.getSymbolValue()).getExpansion();
540                        LispObject form = list(Symbol.SETF, expansion, args.car());
541                        value = eval(form, env, thread);
542                      }
543                    else
544                      {
545                        value = eval(args.car(), env, thread);
546                        symbol.setSymbolValue(value);
547                      }
548                  }
549              }
550            else
551              {
552                // Not special.
553                Binding binding = env.getBinding(symbol);
554                if (binding != null)
555                  {
556                    if (binding.value instanceof SymbolMacro)
557                      {
558                        LispObject expansion =
559                          ((SymbolMacro)binding.value).getExpansion();
560                        LispObject form = list(Symbol.SETF, expansion, args.car());
561                        value = eval(form, env, thread);
562                      }
563                    else
564                      {
565                        value = eval(args.car(), env, thread);
566                        binding.value = value;
567                      }
568                  }
569                else
570                  {
571                    if (symbol.getSymbolValue() instanceof SymbolMacro)
572                      {
573                        LispObject expansion =
574                          ((SymbolMacro)symbol.getSymbolValue()).getExpansion();
575                        LispObject form = list(Symbol.SETF, expansion, args.car());
576                        value = eval(form, env, thread);
577                      }
578                    else
579                      {
580                        value = eval(args.car(), env, thread);
581                        symbol.setSymbolValue(value);
582                      }
583                  }
584              }
585            args = args.cdr();
586          }
587        // Return primary value only!
588        thread._values = null;
589        return value;
590      }
591    };
592}
Note: See TracBrowser for help on using the repository browser.