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

Last change on this file was 13445, checked in by ehuelsmann, 13 years ago

Print unreadable strings with unreadableString() exclusively,
so it can throw a Lisp error when printing something unreadable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.8 KB
Line 
1/*
2 * Function.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: Function.java 13445 2011-08-06 14:46:28Z 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38public abstract class Function extends Operator
39{
40    private LispObject propertyList = NIL;
41    private int callCount;
42    private int hotCount;
43    /**
44     * The value of *load-truename* which was current when this function
45     * was loaded, used for fetching the class bytes in case of disassembly.
46     */
47    private final LispObject loadedFrom;
48
49    protected Function() {
50  LispObject loadTruename = Symbol.LOAD_TRUENAME.symbolValueNoThrow();
51  loadedFrom = loadTruename != null ? loadTruename : NIL;
52    }
53
54    public Function(String name)
55    {
56        this(name, (String)null);
57    }
58
59    public Function(String name, String arglist)
60    {
61  this();
62        if(arglist != null)
63            setLambdaList(new SimpleString(arglist));
64        if (name != null) {
65            Symbol symbol = Symbol.addFunction(name.toUpperCase(), this);
66            if (cold)
67                symbol.setBuiltInFunction(true);
68            setLambdaName(symbol);
69        }
70    }
71
72    public Function(Symbol symbol)
73    {
74  this(symbol, null, null);
75    }
76
77    public Function(Symbol symbol, String arglist)
78    {
79  this(symbol, arglist, null);
80    }
81
82    public Function(Symbol symbol, String arglist, String docstring)
83    {
84  this();
85        symbol.setSymbolFunction(this);
86        if (cold)
87            symbol.setBuiltInFunction(true);
88        setLambdaName(symbol);
89        if(arglist != null)
90            setLambdaList(new SimpleString(arglist));
91        if (docstring != null)
92            symbol.setDocumentation(Symbol.FUNCTION,
93                                    new SimpleString(docstring));
94    }
95
96    public Function(String name, Package pkg)
97    {
98        this(name, pkg, false);
99    }
100
101    public Function(String name, Package pkg, boolean exported)
102    {
103        this(name, pkg, exported, null, null);
104    }
105
106    public Function(String name, Package pkg, boolean exported,
107                    String arglist)
108    {
109        this(name, pkg, exported, arglist, null);
110    }
111
112    public Function(String name, Package pkg, boolean exported,
113                    String arglist, String docstring)
114    {
115  this();
116        if (arglist instanceof String)
117            setLambdaList(new SimpleString(arglist));
118        if (name != null) {
119            Symbol symbol;
120            if (exported)
121                symbol = pkg.internAndExport(name.toUpperCase());
122            else
123                symbol = pkg.intern(name.toUpperCase());
124            symbol.setSymbolFunction(this);
125            if (cold)
126                symbol.setBuiltInFunction(true);
127            setLambdaName(symbol);
128            if (docstring != null)
129                symbol.setDocumentation(Symbol.FUNCTION,
130                                        new SimpleString(docstring));
131        }
132    }
133
134    public Function(LispObject name)
135    {
136  this();
137        setLambdaName(name);
138    }
139
140    public Function(LispObject name, LispObject lambdaList)
141    {
142  this();
143        setLambdaName(name);
144        setLambdaList(lambdaList);
145    }
146
147    @Override
148    public LispObject typeOf()
149    {
150        return Symbol.FUNCTION;
151    }
152
153    @Override
154    public LispObject classOf()
155    {
156        return BuiltInClass.FUNCTION;
157    }
158
159    @Override
160    public LispObject typep(LispObject typeSpecifier)
161    {
162        if (typeSpecifier == Symbol.FUNCTION)
163            return T;
164        if (typeSpecifier == Symbol.COMPILED_FUNCTION)
165            return T;
166        if (typeSpecifier == BuiltInClass.FUNCTION)
167            return T;
168        return super.typep(typeSpecifier);
169    }
170
171    @Override
172    public final LispObject getPropertyList()
173    {
174        if (propertyList == null)
175            propertyList = NIL;
176        return propertyList;
177    }
178
179    @Override
180    public final void setPropertyList(LispObject obj)
181    {
182        if (obj == null)
183            throw new NullPointerException();
184        propertyList = obj;
185    }
186
187    public final void setClassBytes(byte[] bytes)
188    {
189        propertyList = putf(propertyList, Symbol.CLASS_BYTES,
190                            new JavaObject(bytes));
191    }
192
193    public final LispObject getClassBytes() {
194  LispObject o = getf(propertyList, Symbol.CLASS_BYTES, NIL);
195  if(o != NIL) {
196      return o;
197  } else {
198      ClassLoader c = getClass().getClassLoader();
199      if(c instanceof FaslClassLoader) {
200    final LispThread thread = LispThread.currentThread(); 
201    SpecialBindingsMark mark = thread.markSpecialBindings(); 
202    try { 
203        thread.bindSpecial(Symbol.LOAD_TRUENAME, loadedFrom); 
204        return new JavaObject(((FaslClassLoader) c).getFunctionClassBytes(this));
205    } catch(Throwable t) {
206        //This is because unfortunately getFunctionClassBytes uses
207        //Debug.assertTrue(false) to signal errors
208        if(t instanceof ControlTransfer) {
209      throw (ControlTransfer) t;
210        } else {
211      return NIL;
212        }
213    } finally { 
214        thread.resetSpecialBindings(mark); 
215    }   
216      } else {
217    return NIL;
218      }
219  }
220    }
221
222    public static final Primitive FUNCTION_CLASS_BYTES = new pf_function_class_bytes();
223    public static final class pf_function_class_bytes extends Primitive {
224  public pf_function_class_bytes() {
225      super("function-class-bytes", PACKAGE_SYS, false, "function");
226        }
227        @Override
228        public LispObject execute(LispObject arg) {
229            if (arg instanceof Function) {
230                return ((Function) arg).getClassBytes();
231      }
232            return type_error(arg, Symbol.FUNCTION);
233        }
234    }
235
236    @Override
237    public LispObject execute()
238    {
239        return error(new WrongNumberOfArgumentsException(this, 0));
240    }
241
242    @Override
243    public LispObject execute(LispObject arg)
244    {
245        return error(new WrongNumberOfArgumentsException(this, 1));
246    }
247
248    @Override
249    public LispObject execute(LispObject first, LispObject second)
250
251    {
252        return error(new WrongNumberOfArgumentsException(this, 2));
253    }
254
255    @Override
256    public LispObject execute(LispObject first, LispObject second,
257                              LispObject third)
258
259    {
260        return error(new WrongNumberOfArgumentsException(this, 3));
261    }
262
263    @Override
264    public LispObject execute(LispObject first, LispObject second,
265                              LispObject third, LispObject fourth)
266
267    {
268        return error(new WrongNumberOfArgumentsException(this, 4));
269    }
270
271    @Override
272    public LispObject execute(LispObject first, LispObject second,
273                              LispObject third, LispObject fourth,
274                              LispObject fifth)
275
276    {
277        return error(new WrongNumberOfArgumentsException(this, 5));
278    }
279
280    @Override
281    public LispObject execute(LispObject first, LispObject second,
282                              LispObject third, LispObject fourth,
283                              LispObject fifth, LispObject sixth)
284
285    {
286        return error(new WrongNumberOfArgumentsException(this, 6));
287    }
288
289    @Override
290    public LispObject execute(LispObject first, LispObject second,
291                              LispObject third, LispObject fourth,
292                              LispObject fifth, LispObject sixth,
293                              LispObject seventh)
294
295    {
296        return error(new WrongNumberOfArgumentsException(this, 7));
297    }
298
299    @Override
300    public LispObject execute(LispObject first, LispObject second,
301                              LispObject third, LispObject fourth,
302                              LispObject fifth, LispObject sixth,
303                              LispObject seventh, LispObject eighth)
304
305    {
306        return error(new WrongNumberOfArgumentsException(this, 8));
307    }
308
309    @Override
310    public LispObject execute(LispObject[] args)
311    {
312        return error(new WrongNumberOfArgumentsException(this));
313    }
314
315    @Override
316    public String printObject()
317    {
318        LispObject name = getLambdaName();
319        if (name != null && name != NIL) {
320            return unreadableString(name.princToString());
321        }
322        // No name.
323        LispObject lambdaList = getLambdaList();
324        if (lambdaList != null) {
325            StringBuilder sb = new StringBuilder("FUNCTION ");
326            sb.append("(LAMBDA ");
327            if (lambdaList == NIL) {
328                sb.append("()");
329            } else {
330                final LispThread thread = LispThread.currentThread();
331                final SpecialBindingsMark mark = thread.markSpecialBindings();
332                thread.bindSpecial(Symbol.PRINT_LENGTH, Fixnum.THREE);
333                try {
334                    sb.append(lambdaList.printObject());
335                }
336                finally {
337                    thread.resetSpecialBindings(mark);
338                }
339            }
340            sb.append(")");
341            return unreadableString(sb.toString());
342        }
343        return unreadableString("FUNCTION");
344    }
345
346    // Used by the JVM compiler.
347    public final void argCountError()
348    {
349        error(new WrongNumberOfArgumentsException(this));
350    }
351
352    // Profiling.
353    @Override
354    public final int getCallCount()
355    {
356        return callCount;
357    }
358
359    @Override
360    public void setCallCount(int n)
361    {
362        callCount = n;
363    }
364
365    @Override
366    public final void incrementCallCount()
367    {
368        ++callCount;
369    }
370
371    @Override
372    public final int getHotCount()
373    {
374        return hotCount;
375    }
376
377    @Override
378    public void setHotCount(int n)
379    {
380        hotCount = n;
381    }
382
383    @Override
384    public final void incrementHotCount()
385    {
386        ++hotCount;
387    }
388}
Note: See TracBrowser for help on using the repository browser.