source: branches/0.17.x/abcl/src/org/armedbear/lisp/Closure.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: 35.2 KB
Line 
1/*
2 * Closure.java
3 *
4 * Copyright (C) 2002-2008 Peter Graves
5 * Copyright (C) 2008 Ville Voutilainen
6 * $Id: Closure.java 12254 2009-11-06 20:07:54Z ehuelsmann $
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 * As a special exception, the copyright holders of this library give you
23 * permission to link this library with independent modules to produce an
24 * executable, regardless of the license terms of these independent
25 * modules, and to copy and distribute the resulting executable under
26 * terms of your choice, provided that you also meet, for each linked
27 * independent module, the terms and conditions of the license of that
28 * module.  An independent module is a module which is not derived from
29 * or based on this library.  If you modify this library, you may extend
30 * this exception to your version of the library, but you are not
31 * obligated to do so.  If you do not wish to do so, delete this
32 * exception statement from your version.
33 */
34
35package org.armedbear.lisp;
36
37import java.util.ArrayList;
38
39public class Closure extends Function
40{
41  // Parameter types.
42  private static final int REQUIRED = 0;
43  private static final int OPTIONAL = 1;
44  private static final int KEYWORD  = 2;
45  private static final int REST     = 3;
46  private static final int AUX      = 4;
47
48  // States.
49  private static final int STATE_REQUIRED = 0;
50  private static final int STATE_OPTIONAL = 1;
51  private static final int STATE_KEYWORD  = 2;
52  private static final int STATE_REST     = 3;
53  private static final int STATE_AUX      = 4;
54
55  private static final Parameter[] emptyParameterArray;
56  static 
57    {
58        emptyParameterArray = new Parameter[0];
59    }
60  private Parameter[] requiredParameters = emptyParameterArray;
61  private Parameter[] optionalParameters = emptyParameterArray;
62  private Parameter[] keywordParameters = emptyParameterArray;
63  private Parameter[] auxVars = emptyParameterArray;
64  private final LispObject body;
65  private final LispObject executionBody;
66  private final Environment environment;
67  private final boolean andKey;
68  private final boolean allowOtherKeys;
69  private Symbol restVar;
70  private Symbol envVar;
71  private int arity;
72
73  private int minArgs;
74  private int maxArgs;
75
76  private static final Symbol[] emptySymbolArray;
77  static 
78    {
79        emptySymbolArray = new Symbol[0];
80    }
81  private Symbol[] variables = emptySymbolArray;
82  private LispObject specials = NIL;
83
84  private boolean bindInitForms;
85
86  public Closure(LispObject lambdaExpression, Environment env)
87
88  {
89    this(null, lambdaExpression, env);
90  }
91
92  public Closure(final LispObject name, final LispObject lambdaExpression,
93                 final Environment env)
94
95  {
96    super(name, lambdaExpression.cadr());
97    final LispObject lambdaList = lambdaExpression.cadr();
98    setLambdaList(lambdaList);
99    if (!(lambdaList == NIL || lambdaList instanceof Cons))
100      error(new LispError("The lambda list " + lambdaList.writeToString() +
101                           " is invalid."));
102    boolean _andKey = false;
103    boolean _allowOtherKeys = false;
104    if (lambdaList instanceof Cons)
105      {
106        final int length = lambdaList.length();
107        ArrayList<Parameter> required = null;
108        ArrayList<Parameter> optional = null;
109        ArrayList<Parameter> keywords = null;
110        ArrayList<Parameter> aux = null;
111        int state = STATE_REQUIRED;
112        LispObject remaining = lambdaList;
113        while (remaining != NIL)
114          {
115            LispObject obj = remaining.car();
116            if (obj instanceof Symbol)
117              {
118                if (state == STATE_AUX)
119                  {
120                    if (aux == null)
121                      aux = new ArrayList<Parameter>();
122                    aux.add(new Parameter((Symbol)obj, NIL, AUX));
123                  }
124                else if (obj == Symbol.AND_OPTIONAL)
125                  {
126                    state = STATE_OPTIONAL;
127                    arity = -1;
128                  }
129                else if (obj == Symbol.AND_REST || obj == Symbol.AND_BODY)
130                  {
131                    state = STATE_REST;
132                    arity = -1;
133                    maxArgs = -1;
134                    remaining = remaining.cdr();
135                    if (remaining == NIL)
136                      {
137                        error(new LispError(
138                          "&REST/&BODY must be followed by a variable."));
139                      }
140                    Debug.assertTrue(restVar == null);
141                    final LispObject remainingcar =  remaining.car();
142                    if (remainingcar instanceof Symbol)
143                      {
144                        restVar = (Symbol) remainingcar;
145                      }
146                    else
147                      {
148                        error(new LispError(
149                          "&REST/&BODY must be followed by a variable."));
150                      }
151                  }
152                else if (obj == Symbol.AND_ENVIRONMENT)
153                  {
154                    remaining = remaining.cdr();
155                    envVar = (Symbol) remaining.car();
156                    arity = -1; // FIXME
157                  }
158                else if (obj == Symbol.AND_KEY)
159                  {
160                    state = STATE_KEYWORD;
161                    _andKey = true;
162                    arity = -1;
163                  }
164                else if (obj == Symbol.AND_ALLOW_OTHER_KEYS)
165                  {
166                    _allowOtherKeys = true;
167                    maxArgs = -1;
168                  }
169                else if (obj == Symbol.AND_AUX)
170                  {
171                    // All remaining specifiers are aux variable specifiers.
172                    state = STATE_AUX;
173                    arity = -1; // FIXME
174                  }
175                else
176                  {
177                    if (state == STATE_OPTIONAL)
178                      {
179                        if (optional == null)
180                          optional = new ArrayList<Parameter>();
181                        optional.add(new Parameter((Symbol)obj, NIL, OPTIONAL));
182                        if (maxArgs >= 0)
183                          ++maxArgs;
184                      }
185                    else if (state == STATE_KEYWORD)
186                      {
187                        if (keywords == null)
188                          keywords = new ArrayList<Parameter>();
189                        keywords.add(new Parameter((Symbol)obj, NIL, KEYWORD));
190                        if (maxArgs >= 0)
191                          maxArgs += 2;
192                      }
193                    else
194                      {
195                        Debug.assertTrue(state == STATE_REQUIRED);
196                        if (required == null)
197                          required = new ArrayList<Parameter>();
198                        required.add(new Parameter((Symbol)obj));
199                        if (maxArgs >= 0)
200                          ++maxArgs;
201                      }
202                  }
203              }
204            else if (obj instanceof Cons)
205              {
206                if (state == STATE_AUX)
207                  {
208                    Symbol sym = checkSymbol(obj.car());
209                    LispObject initForm = obj.cadr();
210                    Debug.assertTrue(initForm != null);
211                    if (aux == null)
212                      aux = new ArrayList<Parameter>();
213                    aux.add(new Parameter(sym, initForm, AUX));
214                  }
215                else if (state == STATE_OPTIONAL)
216                  {
217                    Symbol sym = checkSymbol(obj.car());
218                    LispObject initForm = obj.cadr();
219                    LispObject svar = obj.cdr().cdr().car();
220                    if (optional == null)
221                      optional = new ArrayList<Parameter>();
222                    optional.add(new Parameter(sym, initForm, svar, OPTIONAL));
223                    if (maxArgs >= 0)
224                      ++maxArgs;
225                  }
226                else if (state == STATE_KEYWORD)
227                  {
228                    Symbol keyword;
229                    Symbol var;
230                    LispObject initForm = NIL;
231                    LispObject svar = NIL;
232                    LispObject first = obj.car();
233                    if (first instanceof Cons)
234                      {
235                        keyword = checkSymbol(first.car());
236                        var = checkSymbol(first.cadr());
237                      }
238                    else
239                      {
240                        var = checkSymbol(first);
241                        keyword =
242                          PACKAGE_KEYWORD.intern(var.name);
243                      }
244                    obj = obj.cdr();
245                    if (obj != NIL)
246                      {
247                        initForm = obj.car();
248                        obj = obj.cdr();
249                        if (obj != NIL)
250                          svar = obj.car();
251                      }
252                    if (keywords == null)
253                      keywords = new ArrayList<Parameter>();
254                    keywords.add(new Parameter(keyword, var, initForm, svar));
255                    if (maxArgs >= 0)
256                      maxArgs += 2;
257                  }
258                else
259                  invalidParameter(obj);
260              }
261            else
262              invalidParameter(obj);
263            remaining = remaining.cdr();
264          }
265        if (arity == 0)
266          arity = length;
267        if (required != null)
268          {
269            requiredParameters = new Parameter[required.size()];
270            required.toArray(requiredParameters);
271          }
272        if (optional != null)
273          {
274            optionalParameters = new Parameter[optional.size()];
275            optional.toArray(optionalParameters);
276          }
277        if (keywords != null)
278          {
279            keywordParameters = new Parameter[keywords.size()];
280            keywords.toArray(keywordParameters);
281          }
282        if (aux != null)
283          {
284            auxVars = new Parameter[aux.size()];
285            aux.toArray(auxVars);
286          }
287      }
288    else
289      {
290        // Lambda list is empty.
291        Debug.assertTrue(lambdaList == NIL);
292        arity = 0;
293        maxArgs = 0;
294      }
295    this.body = lambdaExpression.cddr();
296    LispObject bodyAndDecls = parseBody(this.body, false);
297    this.executionBody = bodyAndDecls.car();
298    this.specials = parseSpecials(bodyAndDecls.NTH(1));
299
300    this.environment = env;
301    this.andKey = _andKey;
302    this.allowOtherKeys = _allowOtherKeys;
303    minArgs = requiredParameters.length;
304    if (arity >= 0)
305      Debug.assertTrue(arity == minArgs);
306    variables = processVariables();
307  }
308
309  private final void processParameters(ArrayList<Symbol> vars,
310                                       final Parameter[] parameters)
311  {
312    for (Parameter parameter : parameters)
313      {
314        vars.add(parameter.var);
315        if (parameter.svar != NIL)
316          vars.add((Symbol)parameter.svar);
317        if (!bindInitForms)
318          if (!parameter.initForm.constantp())
319            bindInitForms = true;
320      }
321  }
322
323  // Also sets bindInitForms.
324  private final Symbol[] processVariables()
325  {
326    ArrayList<Symbol> vars = new ArrayList<Symbol>();
327    for (Parameter parameter : requiredParameters)
328      vars.add(parameter.var);
329    processParameters(vars, optionalParameters);
330    if (restVar != null)
331      {
332        vars.add(restVar);
333      }
334    processParameters(vars, keywordParameters);
335    Symbol[] array = new Symbol[vars.size()];
336    vars.toArray(array);
337    return array;
338  }
339
340  private static final void invalidParameter(LispObject obj)
341
342  {
343    error(new LispError(obj.writeToString() +
344                         " may not be used as a variable in a lambda list."));
345  }
346
347  @Override
348  public LispObject typep(LispObject typeSpecifier)
349  {
350    if (typeSpecifier == Symbol.COMPILED_FUNCTION)
351      return NIL;
352    return super.typep(typeSpecifier);
353  }
354
355  public final LispObject getVariableList()
356  {
357    LispObject result = NIL;
358    for (int i = variables.length; i-- > 0;)
359      result = new Cons(variables[i], result);
360    return result;
361  }
362
363  // Returns body as a list.
364  public final LispObject getBody()
365  {
366    return body;
367  }
368
369  public final Environment getEnvironment()
370  {
371    return environment;
372  }
373
374  @Override
375  public LispObject execute()
376  {
377    if (arity == 0)
378      {
379        return progn(executionBody, environment, 
380                     LispThread.currentThread());
381      }
382    else
383      return execute(new LispObject[0]);
384  }
385   
386  private final LispObject bindParametersAndExecute(LispObject... objects)
387
388  {
389    final LispThread thread = LispThread.currentThread();
390    final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
391    Environment ext = new Environment(environment);
392    bindRequiredParameters(ext, thread, objects);
393    if (arity != minArgs)
394      {
395        bindParameterDefaults(optionalParameters, ext, thread);
396        if (restVar != null)
397          bindArg(specials, restVar, NIL, ext, thread);
398        bindParameterDefaults(keywordParameters, ext, thread);
399      }
400    bindAuxVars(ext, thread);
401    declareFreeSpecials(ext);
402    try
403      {
404        return progn(executionBody, ext, thread);
405      }
406    finally
407      {
408        thread.lastSpecialBinding = lastSpecialBinding;
409      }
410  }
411
412  private final void bindRequiredParameters(Environment ext,
413                                            LispThread thread,
414                                            LispObject[] objects)
415
416  {
417    // &whole and &environment before anything
418    if (envVar != null)
419      bindArg(specials, envVar, environment, ext, thread);
420    for (int i = 0; i < objects.length; ++i)
421      {
422        bindArg(specials, requiredParameters[i].var, objects[i], ext, thread);
423      }
424  }
425
426  public final LispObject invokeArrayExecute(LispObject... objects)
427
428  {
429    return execute(objects);
430  }
431
432  @Override
433  public LispObject execute(LispObject arg)
434  {
435    if (minArgs == 1)
436      {
437        return bindParametersAndExecute(arg);
438      }
439    else
440      {
441        return invokeArrayExecute(arg);
442      }
443  }
444
445  @Override
446  public LispObject execute(LispObject first, LispObject second)
447
448  {
449    if (minArgs == 2)
450      {
451        return bindParametersAndExecute(first, second);
452      }
453    else
454      {
455        return invokeArrayExecute(first, second);
456      }
457  }
458
459  @Override
460  public LispObject execute(LispObject first, LispObject second,
461                            LispObject third)
462
463  {
464    if (minArgs == 3)
465      {
466        return bindParametersAndExecute(first, second, third);
467      }
468    else
469      {
470        return invokeArrayExecute(first, second, third);
471      }
472  }
473
474  @Override
475  public LispObject execute(LispObject first, LispObject second,
476                            LispObject third, LispObject fourth)
477
478  {
479    if (minArgs == 4)
480      {
481        return bindParametersAndExecute(first, second, third, fourth);
482      }
483    else
484      {
485        return invokeArrayExecute(first, second, third, fourth);
486      }
487  }
488
489  @Override
490  public LispObject execute(LispObject first, LispObject second,
491                            LispObject third, LispObject fourth,
492                            LispObject fifth)
493
494  {
495    if (minArgs == 5)
496      {
497        return bindParametersAndExecute(first, second, third, fourth,
498                                        fifth);
499      }
500    else
501      {
502        return invokeArrayExecute(first, second, third, fourth, fifth);
503      }
504  }
505
506  @Override
507  public LispObject execute(LispObject first, LispObject second,
508                            LispObject third, LispObject fourth,
509                            LispObject fifth, LispObject sixth)
510
511  {
512    if (minArgs == 6)
513      {
514        return bindParametersAndExecute(first, second, third, fourth,
515                                        fifth, sixth);
516      }
517    else
518      {
519        return invokeArrayExecute(first, second, third, fourth, fifth,
520                                  sixth);
521      }
522  }
523
524  @Override
525  public LispObject execute(LispObject first, LispObject second,
526                            LispObject third, LispObject fourth,
527                            LispObject fifth, LispObject sixth,
528                            LispObject seventh)
529
530  {
531    if (minArgs == 7)
532      {
533        return bindParametersAndExecute(first, second, third, fourth,
534                               fifth, sixth, seventh);
535      }
536    else
537      {
538        return invokeArrayExecute(first, second, third, fourth, fifth,
539                                  sixth, seventh);
540      }
541  }
542
543  @Override
544  public LispObject execute(LispObject first, LispObject second,
545                            LispObject third, LispObject fourth,
546                            LispObject fifth, LispObject sixth,
547                            LispObject seventh, LispObject eighth)
548
549  {
550    if (minArgs == 8)
551      {
552        return bindParametersAndExecute(first, second, third, fourth,
553                               fifth, sixth, seventh, eighth);
554      }
555    else
556      {
557        return invokeArrayExecute(first, second, third, fourth, fifth,
558                                  sixth, seventh, eighth);
559      }
560  }
561
562  private final void declareFreeSpecials(Environment ext)
563
564  {
565    LispObject s = specials;
566    special:
567    while (s != NIL) {
568      Symbol special = (Symbol)s.car();
569      s = s.cdr();
570      for (Symbol var : variables)
571  if (special == var)
572          continue special;
573      for (Parameter parameter : auxVars)
574        if (special == parameter.var)
575          continue special;
576      ext.declareSpecial(special);
577    }
578  }
579
580  @Override
581  public LispObject execute(LispObject[] args)
582  {
583    final LispThread thread = LispThread.currentThread();
584    SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
585    Environment ext = new Environment(environment);
586    if (optionalParameters.length == 0 && keywordParameters.length == 0)
587      args = fastProcessArgs(args);
588    else
589      args = processArgs(args, thread);
590    Debug.assertTrue(args.length == variables.length);
591    if (envVar != null)
592      {
593        bindArg(specials, envVar, environment, ext, thread);
594      }
595    for (int i = 0; i < variables.length; i++)
596      {
597        Symbol sym = variables[i];
598        bindArg(specials, sym, args[i], ext, thread);
599      }
600    bindAuxVars(ext, thread);
601    declareFreeSpecials(ext);
602    try
603      {
604        return progn(executionBody, ext, thread);
605      }
606    finally
607      {
608        thread.lastSpecialBinding = lastSpecialBinding;
609      }
610  }
611
612  protected final LispObject[] processArgs(LispObject[] args, LispThread thread)
613
614  {
615    if (optionalParameters.length == 0 && keywordParameters.length == 0)
616      return fastProcessArgs(args);
617    final int argsLength = args.length;
618    if (arity >= 0)
619      {
620        // Fixed arity.
621        if (argsLength != arity)
622          error(new WrongNumberOfArgumentsException(this));
623        return args;
624      }
625    // Not fixed arity.
626    if (argsLength < minArgs)
627      error(new WrongNumberOfArgumentsException(this));
628    final LispObject[] array = new LispObject[variables.length];
629    int index = 0;
630    // The bindings established here (if any) are lost when this function
631    // returns. They are used only in the evaluation of initforms for
632    // optional and keyword arguments.
633    SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
634    Environment ext = new Environment(environment);
635    // Section 3.4.4: "...the &environment parameter is bound along with
636    // &whole before any other variables in the lambda list..."
637    try {
638        if (bindInitForms)
639          if (envVar != null)
640            bindArg(specials, envVar, environment, ext, thread);
641        // Required parameters.
642        for (int i = 0; i < minArgs; i++)
643          {
644            if (bindInitForms)
645              bindArg(specials, requiredParameters[i].var, args[i], ext, thread);
646            array[index++] = args[i];
647          }
648        int i = minArgs;
649        int argsUsed = minArgs;
650        // Optional parameters.
651        for (Parameter parameter : optionalParameters)
652          {
653            if (i < argsLength)
654              {
655                if (bindInitForms)
656                  bindArg(specials, parameter.var, args[i], ext, thread);
657                array[index++] = args[i];
658                ++argsUsed;
659                if (parameter.svar != NIL)
660                  {
661                    if (bindInitForms)
662                      bindArg(specials, (Symbol)parameter.svar, T, ext, thread);
663                    array[index++] = T;
664                  }
665              }
666            else
667              {
668                // We've run out of arguments.
669                LispObject value;
670                if (parameter.initVal != null)
671                  value = parameter.initVal;
672                else
673                  value = eval(parameter.initForm, ext, thread);
674                if (bindInitForms)
675                  bindArg(specials, parameter.var, value, ext, thread);
676                array[index++] = value;
677                if (parameter.svar != NIL)
678                  {
679                    if (bindInitForms)
680                      bindArg(specials, (Symbol)parameter.svar, NIL, ext, thread);
681                    array[index++] = NIL;
682                  }
683              }
684            ++i;
685          }
686        // &rest parameter.
687        if (restVar != null)
688          {
689            LispObject rest = NIL;
690            for (int j = argsLength; j-- > argsUsed;)
691              rest = new Cons(args[j], rest);
692            if (bindInitForms)
693                bindArg(specials, restVar, rest, ext, thread);
694            array[index++] = rest;
695          }
696        // Keyword parameters.
697        if (keywordParameters.length > 0)
698          {
699            int argsLeft = argsLength - argsUsed;
700            if (argsLeft == 0)
701              {
702                // No keyword arguments were supplied.
703                // Bind all keyword parameters to their defaults.
704                for (int k = 0; k < keywordParameters.length; k++)
705                  {
706                    Parameter parameter = keywordParameters[k];
707                    LispObject value;
708                    if (parameter.initVal != null)
709                      value = parameter.initVal;
710                    else
711                      value = eval(parameter.initForm, ext, thread);
712                    if (bindInitForms)
713                        bindArg(specials, parameter.var, value, ext, thread);
714                    array[index++] = value;
715                    if (parameter.svar != NIL)
716                      {
717                        if (bindInitForms)
718                            bindArg(specials, (Symbol)parameter.svar, NIL, ext, thread);
719                        array[index++] = NIL;
720                      }
721                  }
722              }
723            else
724              {
725                if ((argsLeft % 2) != 0)
726                  error(new ProgramError("Odd number of keyword arguments."));
727                LispObject allowOtherKeysValue = null;
728                for (Parameter parameter : keywordParameters)
729                  {
730                    Symbol keyword = parameter.keyword;
731                    LispObject value = null;
732                    boolean unbound = true;
733                    for (int j = argsUsed; j < argsLength; j += 2)
734                      {
735                        if (args[j] == keyword)
736                          {
737                            if (bindInitForms)
738                                bindArg(specials, parameter.var, args[j+1], ext, thread);
739                            value = array[index++] = args[j+1];
740                            if (parameter.svar != NIL)
741                              {
742                                if (bindInitForms)
743                                    bindArg(specials,(Symbol)parameter.svar, T, ext, thread);
744                                array[index++] = T;
745                              }
746                            args[j] = null;
747                            args[j+1] = null;
748                            unbound = false;
749                            break;
750                          }
751                      }
752                    if (unbound)
753                      {
754                        if (parameter.initVal != null)
755                          value = parameter.initVal;
756                        else
757                          value = eval(parameter.initForm, ext, thread);
758                        if (bindInitForms)
759                            bindArg(specials, parameter.var, value, ext, thread);
760                        array[index++] = value;
761                        if (parameter.svar != NIL)
762                          {
763                            if (bindInitForms)
764                                bindArg(specials, (Symbol)parameter.svar, NIL, ext, thread);
765                            array[index++] = NIL;
766                          }
767                      }
768                    if (keyword == Keyword.ALLOW_OTHER_KEYS)
769                      {
770                        if (allowOtherKeysValue == null)
771                          allowOtherKeysValue = value;
772                      }
773                  }
774                if (!allowOtherKeys)
775                  {
776                    if (allowOtherKeysValue == null || allowOtherKeysValue == NIL)
777                      {
778                        LispObject unrecognizedKeyword = null;
779                        for (int j = argsUsed; j < argsLength; j += 2)
780                          {
781                            LispObject keyword = args[j];
782                            if (keyword == null)
783                              continue;
784                            if (keyword == Keyword.ALLOW_OTHER_KEYS)
785                              {
786                                if (allowOtherKeysValue == null)
787                                  {
788                                    allowOtherKeysValue = args[j+1];
789                                    if (allowOtherKeysValue != NIL)
790                                      break;
791                                  }
792                                continue;
793                              }
794                            // Unused keyword argument.
795                            boolean ok = false;
796                            for (Parameter parameter : keywordParameters)
797                              {
798                                if (parameter.keyword == keyword)
799                                  {
800                                    // Found it!
801                                    ok = true;
802                                    break;
803                                  }
804                              }
805                            if (ok)
806                              continue;
807                            // Unrecognized keyword argument.
808                            if (unrecognizedKeyword == null)
809                              unrecognizedKeyword = keyword;
810                          }
811                        if (unrecognizedKeyword != null)
812                          {
813                            if (!allowOtherKeys &&
814                                (allowOtherKeysValue == null || allowOtherKeysValue == NIL))
815                              error(new ProgramError("Unrecognized keyword argument " +
816                                                      unrecognizedKeyword.writeToString()));
817                          }
818                      }
819                  }
820              }
821          }
822        else if (argsUsed < argsLength)
823          {
824            // No keyword parameters.
825            if (argsUsed + 2 <= argsLength)
826              {
827                // Check for :ALLOW-OTHER-KEYS.
828                LispObject allowOtherKeysValue = NIL;
829                int n = argsUsed;
830                while (n < argsLength)
831                  {
832                    LispObject keyword = args[n];
833                    if (keyword == Keyword.ALLOW_OTHER_KEYS)
834                      {
835                        allowOtherKeysValue = args[n+1];
836                        break;
837                      }
838                    n += 2;
839                  }
840                if (allowOtherKeys || allowOtherKeysValue != NIL)
841                  {
842                    // Skip keyword/value pairs.
843                    while (argsUsed + 2 <= argsLength)
844                      argsUsed += 2;
845                  }
846                else if (andKey)
847                  {
848                    LispObject keyword = args[argsUsed];
849                    if (keyword == Keyword.ALLOW_OTHER_KEYS)
850                      {
851                        // Section 3.4.1.4: "Note that if &KEY is present, a
852                        // keyword argument of :ALLOW-OTHER-KEYS is always
853                        // permitted---regardless of whether the associated
854                        // value is true or false."
855                        argsUsed += 2;
856                      }
857                  }
858              }
859            if (argsUsed < argsLength)
860              {
861                if (restVar == null)
862                  error(new WrongNumberOfArgumentsException(this));
863              }
864          }
865    }
866    finally {
867        thread.lastSpecialBinding = lastSpecialBinding;
868    }
869    return array;
870  }
871
872  // No optional or keyword parameters.
873  protected final LispObject[] fastProcessArgs(LispObject[] args)
874
875  {
876    final int argsLength = args.length;
877    if (arity >= 0)
878      {
879        // Fixed arity.
880        if (argsLength != arity)
881          error(new WrongNumberOfArgumentsException(this));
882        return args;
883      }
884    // Not fixed arity.
885    if (argsLength < minArgs)
886      error(new WrongNumberOfArgumentsException(this));
887    final LispObject[] array = new LispObject[variables.length];
888    int index = 0;
889    // Required parameters.
890    for (int i = 0; i < minArgs; i++)
891      {
892        array[index++] = args[i];
893      }
894    int argsUsed = minArgs;
895    // &rest parameter.
896    if (restVar != null)
897      {
898        LispObject rest = NIL;
899        for (int j = argsLength; j-- > argsUsed;)
900          rest = new Cons(args[j], rest);
901        array[index++] = rest;
902      }
903    else if (argsUsed < argsLength)
904      {
905        // No keyword parameters.
906        if (argsUsed + 2 <= argsLength)
907          {
908            // Check for :ALLOW-OTHER-KEYS.
909            LispObject allowOtherKeysValue = NIL;
910            int n = argsUsed;
911            while (n < argsLength)
912              {
913                LispObject keyword = args[n];
914                if (keyword == Keyword.ALLOW_OTHER_KEYS)
915                  {
916                    allowOtherKeysValue = args[n+1];
917                    break;
918                  }
919                n += 2;
920              }
921            if (allowOtherKeys || allowOtherKeysValue != NIL)
922              {
923                // Skip keyword/value pairs.
924                while (argsUsed + 2 <= argsLength)
925                  argsUsed += 2;
926              }
927            else if (andKey)
928              {
929                LispObject keyword = args[argsUsed];
930                if (keyword == Keyword.ALLOW_OTHER_KEYS)
931                  {
932                    // Section 3.4.1.4: "Note that if &key is present, a
933                    // keyword argument of :allow-other-keys is always
934                    // permitted---regardless of whether the associated
935                    // value is true or false."
936                    argsUsed += 2;
937                  }
938              }
939          }
940        if (argsUsed < argsLength)
941          {
942            if (restVar == null)
943              error(new WrongNumberOfArgumentsException(this));
944          }
945      }
946    return array;
947  }
948
949  private final void bindParameterDefaults(Parameter[] parameters,
950                                           Environment env,
951                                           LispThread thread)
952
953  {
954    for (Parameter parameter : parameters)
955      {
956        LispObject value;
957        if (parameter.initVal != null)
958          value = parameter.initVal;
959        else
960          value = eval(parameter.initForm, env, thread);
961        bindArg(specials, parameter.var, value, env, thread);
962        if (parameter.svar != NIL)
963    bindArg(specials, (Symbol)parameter.svar, NIL, env, thread);
964      }
965  }
966
967  private final void bindAuxVars(Environment env, LispThread thread)
968
969  {
970    // Aux variable processing is analogous to LET* processing.
971    for (Parameter parameter : auxVars)
972      {
973        Symbol sym = parameter.var;
974        LispObject value;
975
976        if (parameter.initVal != null)
977          value = parameter.initVal;
978        else
979          value = eval(parameter.initForm, env, thread);
980
981        bindArg(specials, sym, value, env, thread);
982      }
983  }
984
985  private static class Parameter
986  {
987    private final Symbol var;
988    private final LispObject initForm;
989    private final LispObject initVal;
990    private final LispObject svar;
991    private final int type;
992    private final Symbol keyword;
993
994    public Parameter(Symbol var)
995    {
996      this.var = var;
997      this.initForm = null;
998      this.initVal = null;
999      this.svar = NIL;
1000      this.type = REQUIRED;
1001      this.keyword = null;
1002    }
1003
1004    public Parameter(Symbol var, LispObject initForm, int type)
1005
1006    {
1007      this.var = var;
1008      this.initForm = initForm;
1009      this.initVal = processInitForm(initForm);
1010      this.svar = NIL;
1011      this.type = type;
1012      keyword =
1013        type == KEYWORD ? PACKAGE_KEYWORD.intern(var.name) : null;
1014    }
1015
1016    public Parameter(Symbol var, LispObject initForm, LispObject svar,
1017                     int type)
1018
1019    {
1020      this.var = var;
1021      this.initForm = initForm;
1022      this.initVal = processInitForm(initForm);
1023      this.svar = (svar != NIL) ? checkSymbol(svar) : NIL;
1024      this.type = type;
1025      keyword =
1026        type == KEYWORD ? PACKAGE_KEYWORD.intern(var.name) : null;
1027    }
1028
1029    public Parameter(Symbol keyword, Symbol var, LispObject initForm,
1030                     LispObject svar)
1031
1032    {
1033      this.var = var;
1034      this.initForm = initForm;
1035      this.initVal = processInitForm(initForm);
1036      this.svar = (svar != NIL) ? checkSymbol(svar) : NIL;
1037      type = KEYWORD;
1038      this.keyword = keyword;
1039    }
1040
1041    @Override
1042    public String toString()
1043    {
1044      if (type == REQUIRED)
1045        return var.toString();
1046      StringBuffer sb = new StringBuffer();
1047      if (keyword != null)
1048        {
1049          sb.append(keyword);
1050          sb.append(' ');
1051        }
1052      sb.append(var.toString());
1053      sb.append(' ');
1054      sb.append(initForm);
1055      sb.append(' ');
1056      sb.append(type);
1057      return sb.toString();
1058    }
1059
1060    private static final LispObject processInitForm(LispObject initForm)
1061
1062    {
1063      if (initForm.constantp())
1064        {
1065          if (initForm instanceof Symbol)
1066            return initForm.getSymbolValue();
1067          if (initForm instanceof Cons)
1068            {
1069              Debug.assertTrue(initForm.car() == Symbol.QUOTE);
1070              return initForm.cadr();
1071            }
1072          return initForm;
1073        }
1074      return null;
1075    }
1076  }
1077
1078  // ### lambda-list-names
1079  private static final Primitive LAMBDA_LIST_NAMES =
1080      new Primitive("lambda-list-names", PACKAGE_SYS, true)
1081    {
1082      @Override
1083      public LispObject execute(LispObject arg)
1084      {
1085        Closure closure = new Closure(list(Symbol.LAMBDA, arg, NIL), new Environment());
1086        return closure.getVariableList();
1087      }
1088    };
1089}
Note: See TracBrowser for help on using the repository browser.