source: tags/0.15.0/abcl/src/org/armedbear/lisp/Environment.java

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

Compilation of functions with a non-null
lexical environment part 2 [of 2]: Functions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1/*
2 * Environment.java
3 *
4 * Copyright (C) 2002-2006 Peter Graves
5 * $Id: Environment.java 11926 2009-05-22 18:04:53Z 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
36public final class Environment extends LispObject
37{
38  private Binding vars;
39  private FunctionBinding lastFunctionBinding;
40  private Binding blocks;
41  private Binding tags;
42
43  public Environment() {}
44
45  public Environment(Environment parent)
46  {
47    if (parent != null)
48      {
49        vars = parent.vars;
50        lastFunctionBinding = parent.lastFunctionBinding;
51        blocks = parent.blocks;
52        tags = parent.tags;
53      }
54  }
55
56  // Construct a new Environment extending parent with the specified symbol-
57  // value binding.
58  public Environment(Environment parent, Symbol symbol, LispObject value)
59  {
60    this(parent);
61    vars = new Binding(symbol, value, vars);
62  }
63
64  @Override
65  public LispObject typeOf()
66  {
67    return Symbol.ENVIRONMENT;
68  }
69
70  @Override
71  public LispObject classOf()
72  {
73    return BuiltInClass.ENVIRONMENT;
74  }
75
76  @Override
77  public LispObject typep(LispObject type) throws ConditionThrowable
78  {
79    if (type == Symbol.ENVIRONMENT)
80      return T;
81    if (type == BuiltInClass.ENVIRONMENT)
82      return T;
83    return super.typep(type);
84  }
85
86  public boolean isEmpty()
87  {
88    if (lastFunctionBinding != null)
89      return false;
90    if (vars != null)
91      {
92        for (Binding binding = vars; binding != null; binding = binding.next)
93          if (!binding.specialp)
94            return false;
95      }
96    return true;
97  }
98
99  public void bind(Symbol symbol, LispObject value)
100  {
101    vars = new Binding(symbol, value, vars);
102  }
103
104  public void rebind(Symbol symbol, LispObject value)
105  {
106    Binding binding = getBinding(symbol);
107    binding.value = value;
108  }
109
110  public LispObject lookup(LispObject symbol)
111  {
112    Binding binding = vars;
113    while (binding != null)
114      {
115        if (binding.symbol == symbol)
116          return binding.value;
117        binding = binding.next;
118      }
119    return null;
120  }
121
122  public Binding getBinding(LispObject symbol)
123  {
124    Binding binding = vars;
125    while (binding != null)
126      {
127        if (binding.symbol == symbol)
128          return binding;
129        binding = binding.next;
130      }
131    return null;
132  }
133
134  // Function bindings.
135  public void addFunctionBinding(LispObject name, LispObject value)
136  {
137    lastFunctionBinding =
138      new FunctionBinding(name, value, lastFunctionBinding);
139  }
140
141  public LispObject lookupFunction(LispObject name)
142    throws ConditionThrowable
143  {
144    FunctionBinding binding = lastFunctionBinding;
145    if (name instanceof Symbol)
146      {
147        while (binding != null)
148          {
149            if (binding.name == name)
150              return binding.value;
151            binding = binding.next;
152          }
153        // Not found in environment.
154        return name.getSymbolFunction();
155      }
156    if (name instanceof Cons)
157      {
158        while (binding != null)
159          {
160            if (binding.name.equal(name))
161              return binding.value;
162            binding = binding.next;
163          }
164      }
165    return null;
166  }
167
168  public void addBlock(LispObject tag, LispObject block)
169  {
170    blocks = new Binding(tag, block, blocks);
171  }
172
173  public LispObject lookupBlock(LispObject symbol)
174  {
175    Binding binding = blocks;
176    while (binding != null)
177      {
178        if (binding.symbol == symbol)
179          return binding.value;
180        binding = binding.next;
181      }
182    return null;
183  }
184
185  public void addTagBinding(LispObject tag, LispObject code)
186  {
187    tags = new Binding(tag, code, tags);
188  }
189
190  public Binding getTagBinding(LispObject tag)
191  {
192    Binding binding = tags;
193    while (binding != null)
194      {
195        if (binding.symbol.eql(tag))
196          return binding;
197        binding = binding.next;
198      }
199    return null;
200  }
201
202  // Returns body with declarations removed.
203  public LispObject processDeclarations(LispObject body)
204    throws ConditionThrowable
205  {
206    LispObject bodyAndDecls = parseBody(body, false);
207    LispObject specials = parseSpecials(bodyAndDecls.NTH(1));
208    for (; specials != NIL; specials = specials.cdr())
209      declareSpecial(checkSymbol(specials.car()));
210
211    return bodyAndDecls.car();
212  }
213
214  public void declareSpecial(Symbol var)
215  {
216    vars = new Binding(var, null, vars);
217    vars.specialp = true;
218  }
219
220    /** Return true if a symbol is declared special.
221     *
222     * If there is no binding in the current (lexical) environment,
223     * the current dynamic environment (thread) is checked.
224     */
225  public boolean isDeclaredSpecial(LispObject var)
226  {
227    Binding binding = getBinding(var);
228    return (binding != null) ? binding.specialp :
229        (LispThread.currentThread().getSpecialBinding(var) != null);
230  }
231
232  @Override
233  public String writeToString() throws ConditionThrowable
234  {
235    return unreadableString(Symbol.ENVIRONMENT);
236  }
237
238  // ### make-environment
239  public static final Primitive MAKE_ENVIRONMENT =
240    new Primitive("make-environment", PACKAGE_SYS, true,
241                  "&optional parent-environment")
242    {
243      @Override
244      public LispObject execute()
245      {
246        return new Environment();
247      }
248      @Override
249      public LispObject execute(LispObject arg) throws ConditionThrowable
250      {
251        if (arg == NIL)
252          return new Environment();
253        return new Environment(checkEnvironment(arg));
254      }
255    };
256
257  // ### environment-add-macro-definition
258  public static final Primitive ENVIRONMENT_ADD_MACRO_DEFINITION =
259    new Primitive("environment-add-macro-definition", PACKAGE_SYS, true,
260                  "environment name expander")
261    {
262      @Override
263      public LispObject execute(LispObject first, LispObject second,
264                                LispObject third)
265        throws ConditionThrowable
266      {
267        Environment env = checkEnvironment(first);
268        LispObject name = second;
269        LispObject expander = third;
270        env.addFunctionBinding(name, expander);
271        return env;
272      }
273    };
274
275  // ### environment-add-function-definition
276  public static final Primitive ENVIRONMENT_ADD_FUNCTION_DEFINITION =
277    new Primitive("environment-add-function-definition", PACKAGE_SYS, true,
278                  "environment name lambda-expression")
279    {
280      @Override
281      public LispObject execute(LispObject first, LispObject second,
282                                LispObject third)
283        throws ConditionThrowable
284      {
285        checkEnvironment(first).addFunctionBinding(second, third);
286        return first;
287      }
288    };
289
290  // ### environment-add-symbol-binding
291  public static final Primitive ENVIRONMENT_ADD_SYMBOL_BINDING =
292    new Primitive("environment-add-symbol-binding", PACKAGE_SYS, true,
293                  "environment symbol value")
294    {
295      @Override
296      public LispObject execute(LispObject first, LispObject second,
297                                LispObject third)
298        throws ConditionThrowable
299      {
300        checkEnvironment(first).bind(checkSymbol(second), third);
301        return first;
302      }
303    };
304
305  // ### empty-environment-p
306  private static final Primitive EMPTY_ENVIRONMENT_P =
307    new Primitive("empty-environment-p", PACKAGE_SYS, true, "environment")
308    {
309      @Override
310      public LispObject execute(LispObject arg) throws ConditionThrowable
311      {
312          return checkEnvironment(arg).isEmpty() ? T : NIL;
313      }
314    };
315
316  // ### environment-variables
317  private static final Primitive ENVIRONMENT_VARS =
318    new Primitive("environment-variables", PACKAGE_SYS, true, "environment")
319    {
320      @Override
321      public LispObject execute(LispObject arg) throws ConditionThrowable
322      {
323            Environment env = checkEnvironment(arg);
324            LispObject result = NIL;
325            for (Binding binding = env.vars; binding != null; binding = binding.next)
326              if (!binding.specialp)
327                result = result.push(new Cons(binding.symbol, binding.value));
328            return result.nreverse();
329      }
330    };
331
332  // ### environment-all-variables
333  private static final Primitive ENVIRONMENT_ALL_VARS =
334    new Primitive("environment-all-variables", PACKAGE_SYS, true, "environment")
335    {
336      @Override
337      public LispObject execute(LispObject arg) throws ConditionThrowable
338      {
339            Environment env = checkEnvironment(arg);
340            LispObject result = NIL;
341            for (Binding binding = env.vars;
342                 binding != null; binding = binding.next)
343              if (binding.specialp)
344                result = result.push(binding.symbol);
345              else
346                result = result.push(new Cons(binding.symbol, binding.value));
347            return result.nreverse();
348      }
349    };
350
351  // ### environment-all-functions
352  private static final Primitive ENVIRONMENT_ALL_FUNS =
353    new Primitive("environment-all-functions", PACKAGE_SYS, true, "environment")
354    {
355      @Override
356      public LispObject execute(LispObject arg) throws ConditionThrowable
357      {
358            Environment env = checkEnvironment(arg);
359            LispObject result = NIL;
360            for (FunctionBinding binding = env.lastFunctionBinding;
361                 binding != null; binding = binding.next)
362            result = result.push(new Cons(binding.name, binding.value));
363            return result.nreverse();
364      }
365    };
366}
Note: See TracBrowser for help on using the repository browser.