source: trunk/abcl/src/org/armedbear/lisp/Environment.java @ 11770

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

Removal of small code duplication.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1/*
2 * Environment.java
3 *
4 * Copyright (C) 2002-2006 Peter Graves
5 * $Id: Environment.java 11770 2009-04-20 12:42:37Z 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    while (body != NIL)
207      {
208        LispObject obj = body.car();
209        if (obj instanceof Cons && ((Cons)obj).car == Symbol.DECLARE)
210          {
211            LispObject decls = ((Cons)obj).cdr;
212            while (decls != NIL)
213              {
214                LispObject decl = decls.car();
215                if (decl instanceof Cons && ((Cons)decl).car == Symbol.SPECIAL)
216                  {
217                    LispObject names = ((Cons)decl).cdr;
218                    while (names != NIL)
219                      {
220                        Symbol var = checkSymbol(names.car());
221                        declareSpecial(var);
222                        names = ((Cons)names).cdr;
223                      }
224                  }
225                decls = ((Cons)decls).cdr;
226              }
227            body = ((Cons)body).cdr;
228          }
229        else
230          break;
231      }
232    return body;
233  }
234
235  public void declareSpecial(Symbol var)
236  {
237    vars = new Binding(var, null, vars);
238    vars.specialp = true;
239  }
240
241    /** Return true if a symbol is declared special.
242     *
243     * If there is no binding in the current (lexical) environment,
244     * the current dynamic environment (thread) is checked.
245     */
246  public boolean isDeclaredSpecial(LispObject var)
247  {
248    Binding binding = getBinding(var);
249    return (binding != null) ? binding.specialp :
250        (LispThread.currentThread().getSpecialBinding(var) != null);
251  }
252
253  @Override
254  public String writeToString() throws ConditionThrowable
255  {
256    return unreadableString(Symbol.ENVIRONMENT);
257  }
258
259  // ### make-environment
260  public static final Primitive MAKE_ENVIRONMENT =
261    new Primitive("make-environment", PACKAGE_SYS, true,
262                  "&optional parent-environment")
263    {
264      @Override
265      public LispObject execute()
266      {
267        return new Environment();
268      }
269      @Override
270      public LispObject execute(LispObject arg) throws ConditionThrowable
271      {
272        if (arg == NIL)
273          return new Environment();
274        return new Environment(checkEnvironment(arg));
275      }
276    };
277
278  // ### environment-add-macro-definition
279  public static final Primitive ENVIRONMENT_ADD_MACRO_DEFINITION =
280    new Primitive("environment-add-macro-definition", PACKAGE_SYS, true,
281                  "environment name expander")
282    {
283      @Override
284      public LispObject execute(LispObject first, LispObject second,
285                                LispObject third)
286        throws ConditionThrowable
287      {
288        Environment env = checkEnvironment(first);
289        LispObject name = second;
290        LispObject expander = third;
291        env.addFunctionBinding(name, expander);
292        return env;
293      }
294    };
295
296  // ### environment-add-function-definition
297  public static final Primitive ENVIRONMENT_ADD_FUNCTION_DEFINITION =
298    new Primitive("environment-add-function-definition", PACKAGE_SYS, true,
299                  "environment name lambda-expression")
300    {
301      @Override
302      public LispObject execute(LispObject first, LispObject second,
303                                LispObject third)
304        throws ConditionThrowable
305      {
306        checkEnvironment(first).addFunctionBinding(second, third);
307        return first;
308      }
309    };
310
311  // ### environment-add-symbol-binding
312  public static final Primitive ENVIRONMENT_ADD_SYMBOL_BINDING =
313    new Primitive("environment-add-symbol-binding", PACKAGE_SYS, true,
314                  "environment symbol value")
315    {
316      @Override
317      public LispObject execute(LispObject first, LispObject second,
318                                LispObject third)
319        throws ConditionThrowable
320      {
321        checkEnvironment(first).bind(checkSymbol(second), third);
322        return first;
323      }
324    };
325   
326  // ### empty-environment-p
327  private static final Primitive EMPTY_ENVIRONMENT_P =
328    new Primitive("empty-environment-p", PACKAGE_SYS, true, "environment")
329    {
330      @Override
331      public LispObject execute(LispObject arg) throws ConditionThrowable
332      {
333          return checkEnvironment(arg).isEmpty() ? T : NIL;
334      }
335    };
336
337  // ### environment-variables
338  private static final Primitive ENVIRONMENT_VARS =
339    new Primitive("environment-variables", PACKAGE_SYS, true, "environment")
340    {
341      @Override
342      public LispObject execute(LispObject arg) throws ConditionThrowable
343      {
344            Environment env = checkEnvironment(arg);
345            LispObject result = NIL;
346            for (Binding binding = env.vars; binding != null; binding = binding.next)
347              if (!binding.specialp)
348                result = result.push(new Cons(binding.symbol, binding.value));
349            return result.nreverse();
350      }
351    };
352}
Note: See TracBrowser for help on using the repository browser.