source: branches/1.1.x/src/org/armedbear/lisp/Closure.java

Last change on this file was 14131, checked in by ehuelsmann, 12 years ago

Close #219: lambda list keyword checking too lenient for ANSI.

Note: This introduces a new argument to the FUNCTION special form

(LAMBDA and NAMED-LAMBDA were already supported)
(FUNCTION (MACRO-FUNCTION ...))

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.6 KB
Line 
1/*
2 * Closure.java
3 *
4 * Copyright (C) 2002-2008 Peter Graves
5 * Copyright (C) 2008 Ville Voutilainen
6 * $Id: Closure.java 14131 2012-08-21 14:00:13Z 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 static org.armedbear.lisp.Lisp.*;
38
39public class Closure extends Function
40{
41  // Parameter types.
42  public static final int REQUIRED = 0;
43  public static final int OPTIONAL = 1;
44  public static final int KEYWORD  = 2;
45  public static final int REST     = 3;
46  public static final int AUX      = 4;
47
48  private final LispObject body;
49  private final LispObject executionBody;
50  private final Environment environment;
51
52  private final Symbol[] freeSpecials;
53  private final ArgumentListProcessor arglist;
54
55    /** Construct a closure object with a lambda-list described
56     * by these parameters.
57     *
58     *
59     * @param required Required parameters or an empty array for none
60     * @param optional Optional parameters or an empty array for none
61     * @param keyword Keyword parameters or an empty array for none
62     * @param keys NIL if the lambda-list doesn't contain &key, T otherwise
63     * @param rest the &rest parameter, or NIL if none
64     * @param moreKeys NIL if &allow-other-keys not present, T otherwise
65     */
66  public Closure(ArgumentListProcessor arglist) {
67      // stuff we don't need: we're a compiled function
68      body = null;
69      executionBody = null;
70      environment = null;
71      this.arglist = arglist;
72      freeSpecials = new Symbol[0];
73  }
74
75
76  public Closure(LispObject lambdaExpression, Environment env)
77  {
78    this(null, lambdaExpression, env);
79  }
80
81  public Closure(final LispObject name, final LispObject lambdaExpression,
82                 final Environment env)
83
84  {
85    super(name, lambdaExpression.cadr());
86    final LispObject lambdaList = lambdaExpression.cadr();
87    setLambdaList(lambdaList);
88    if (!(lambdaList == NIL || lambdaList instanceof Cons))
89      error(new ProgramError("The lambda list " + lambdaList.princToString() +
90                           " is invalid."));
91    this.body = lambdaExpression.cddr();
92    LispObject bodyAndDecls = parseBody(this.body, false);
93    this.executionBody = bodyAndDecls.car();
94    LispObject specials = parseSpecials(bodyAndDecls.NTH(1));
95
96    this.environment = env;
97
98    /* In the bootstrapping process, functions with MACRO LAMBDA LIST
99     * lambda list types are being generated using the MACRO_FUNCTION instead
100     * of the LAMBDA or NAMED_LAMBDA keys.
101     *
102     * Use that to perform argument list lambda list keyword checking.
103     */
104    arglist = new ArgumentListProcessor(this, lambdaList, specials,
105            (lambdaExpression.car() == Symbol.MACRO_FUNCTION) ?
106            ArgumentListProcessor.LambdaListType.MACRO
107            : ArgumentListProcessor.LambdaListType.ORDINARY);
108    freeSpecials = arglist.freeSpecials(specials);
109  }
110
111  @Override
112  public LispObject typep(LispObject typeSpecifier)
113  {
114    if (typeSpecifier == Symbol.COMPILED_FUNCTION)
115      return NIL;
116    return super.typep(typeSpecifier);
117  }
118
119  public final LispObject getVariableList()
120  {
121    Symbol[] variables = arglist.getVariables();
122    LispObject result = NIL;
123    for (int i = variables.length; i-- > 0;)
124      result = new Cons(variables[i], result);
125    return result;
126  }
127
128  // Returns body as a list.
129  public final LispObject getBody()
130  {
131    return body;
132  }
133
134  public final Environment getEnvironment()
135  {
136    return environment;
137  }
138
139  @Override
140  public LispObject execute()
141  {
142      return execute(new LispObject[0]);
143  }
144   
145  @Override
146  public LispObject execute(LispObject arg)
147  {
148        return execute(new LispObject[] {arg});
149  }
150
151  @Override
152  public LispObject execute(LispObject first, LispObject second)
153  {
154        return execute(new LispObject[] {first, second});
155  }
156
157  @Override
158  public LispObject execute(LispObject first, LispObject second,
159                            LispObject third)
160  {
161        return execute(new LispObject[] {first, second, third});
162  }
163
164  @Override
165  public LispObject execute(LispObject first, LispObject second,
166                            LispObject third, LispObject fourth)
167  {
168        return execute(new LispObject[] {first, second, third, fourth});
169  }
170
171  @Override
172  public LispObject execute(LispObject first, LispObject second,
173                            LispObject third, LispObject fourth,
174                            LispObject fifth)
175  {
176        return execute(new LispObject[] {first, second, third, fourth, fifth});
177  }
178
179  @Override
180  public LispObject execute(LispObject first, LispObject second,
181                            LispObject third, LispObject fourth,
182                            LispObject fifth, LispObject sixth)
183  {
184        return execute(new LispObject[] {first, second, third, fourth, fifth,
185                                  sixth});
186  }
187
188  @Override
189  public LispObject execute(LispObject first, LispObject second,
190                            LispObject third, LispObject fourth,
191                            LispObject fifth, LispObject sixth,
192                            LispObject seventh)
193  {
194        return execute(new LispObject[] {first, second, third, fourth, fifth,
195                                  sixth, seventh});
196  }
197
198  @Override
199  public LispObject execute(LispObject first, LispObject second,
200                            LispObject third, LispObject fourth,
201                            LispObject fifth, LispObject sixth,
202                            LispObject seventh, LispObject eighth)
203  {
204        return execute(new LispObject[] {first, second, third, fourth, fifth,
205                                  sixth, seventh, eighth});
206  }
207
208  @Override
209  public LispObject execute(LispObject[] args)
210  {
211    final LispThread thread = LispThread.currentThread();
212    final SpecialBindingsMark mark = thread.markSpecialBindings();
213    Environment ext = new Environment(environment);
214    args = arglist.match(args, environment, ext, thread);
215    arglist.bindVars(args, ext, thread);
216    for (Symbol special : freeSpecials)
217      ext.declareSpecial(special);
218    try
219      {
220        return progn(executionBody, ext, thread);
221      }
222    finally
223      {
224        thread.resetSpecialBindings(mark);
225      }
226  }
227
228  protected final LispObject[] processArgs(LispObject[] args, LispThread thread)
229  {
230    return arglist.match(args, environment, environment, thread);
231  }
232}
Note: See TracBrowser for help on using the repository browser.