KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > kawa > lang > Translator


1 package kawa.lang;
2 import gnu.mapping.*;
3 import gnu.expr.*;
4 import gnu.kawa.reflect.*;
5 import gnu.bytecode.Type;
6 import gnu.bytecode.ClassType;
7 import gnu.text.SourceMessages;
8 import gnu.lists.*;
9 import gnu.kawa.lispexpr.*;
10 import java.util.*;
11 import gnu.kawa.functions.GetNamedPart;
12 import gnu.text.SourceLocator;
13
14 /** Used to translate from source to Expression.
15  * The result has macros expanded, lexical names bound, etc, and is
16  * ready for code generation.
17  * This is sometimes called a "compilation environment",
18  * but we modify it as we go along - there is a single Translator for
19  * each top-level form.
20  */

21
22 public class Translator extends Compilation
23 {
24   // Global environment used to look for syntax/macros.
25
private Environment env;
26
27   /** Set if we're processing (as opposed to expanding)
28    * a <code>define-syntax</code> or <code>defmacro</code>. */

29   public Macro currentMacroDefinition;
30
31   /** Innermost current scope of pattern variable,
32    * from a <code>syntax-case</code>. */

33   public PatternScope patternScope;
34
35   public Declaration templateScopeDecl;
36
37   /** A variable to hold the matched values for syntax-case
38    * pattern variables. */

39   public Declaration matchArray;
40
41   /** A stack of aliases pushed by <code>pushRenamedAlias</code>. */
42   Stack renamedAliasStack;
43
44   public Stack formStack = new Stack();
45   public int firstForm;
46   public Object JavaDoc pendingForm;
47
48   public LambdaExp curMethodLambda;
49
50   /** Return true if decl is lexical and not fluid. */
51   public boolean isLexical (Declaration decl)
52   {
53     if (decl == null)
54       return false;
55     if (! decl.isFluid())
56       return true;
57     ScopeExp scope = currentScope();
58     ScopeExp context = decl.getContext();
59     for (;; scope = scope.outer)
60       {
61     if (scope == null)
62       return false;
63     if (scope == context)
64       return true;
65     if (scope instanceof LambdaExp
66         && ! ((LambdaExp) scope).getInlineOnly())
67       return false;
68       }
69   }
70
71   private static Expression errorExp = new ErrorExp ("unknown syntax error");
72
73   public Translator (Language language, SourceMessages messages)
74   {
75     super(language, messages);
76     this.env = Environment.getCurrent();
77   }
78
79   public final Environment getGlobalEnvironment() { return env; }
80
81   public Expression parse (Object JavaDoc input)
82   {
83     return rewrite(input);
84   }
85
86   public final Expression rewrite_car (Pair pair, SyntaxForm syntax)
87   {
88     if (syntax == null || syntax.scope == current_scope
89     || pair.car instanceof SyntaxForm)
90       return rewrite_car(pair, false);
91     ScopeExp save_scope = current_scope;
92     try
93       {
94     setCurrentScope(syntax.scope);
95     return rewrite_car(pair, false);
96       }
97     finally
98       {
99     setCurrentScope(save_scope);
100       }
101   }
102
103   public final Expression rewrite_car (Pair pair, boolean function)
104   {
105     Object JavaDoc car = pair.car;
106     if (pair instanceof PairWithPosition)
107       return rewrite_with_position (car, function, (PairWithPosition) pair);
108     else
109       return rewrite (car, function);
110   }
111
112   Syntax currentSyntax;
113   public Syntax getCurrentSyntax() { return currentSyntax; }
114
115   /** The module instance containing the current macro.
116    * This is only used temporarily, set when resolving a Declaration
117    * bound to a macro, and used to set the macroContext field of the
118    * TemplateScope created when expanding the macro's template(s). */

119   Declaration macroContext;
120
121   /**
122    * Apply a Syntax object.
123    * @param syntax the Syntax object whose rewrite method we call
124    * @param form the syntax form (including the macro name)
125    * @return the re-written form as an Expression object
126    */

127   Expression apply_rewrite (Syntax syntax, Pair form)
128   {
129     Expression exp = errorExp;
130     Syntax saveSyntax = currentSyntax;
131     currentSyntax = syntax;
132     try
133       {
134     exp = syntax.rewriteForm(form, this);
135       }
136     finally
137       {
138         currentSyntax = saveSyntax;
139       }
140     return exp;
141   }
142
143   /** Check if declaraton is an alias for some other name.
144    * This is needed to chase identifiers renamed for hygienic macro
145    * expansion - see SyntaxRules.expand. */

146   static ReferenceExp getOriginalRef(Declaration decl)
147   {
148     if (decl != null && decl.isAlias() && ! decl.isIndirectBinding())
149       {
150     Expression value = decl.getValue();
151     if (value instanceof ReferenceExp)
152       return (ReferenceExp) value;
153       }
154     return null;
155   }
156
157   final boolean selfEvaluatingSymbol (Object JavaDoc obj)
158   {
159     return ((LispLanguage) getLanguage()).selfEvaluatingSymbol(obj);
160   }
161
162   /** True iff a form matches a literal symbol. */
163   public final boolean matches(Object JavaDoc form, String JavaDoc literal)
164   {
165     return matches(form, null, literal);
166   }
167
168   public boolean matches(Object JavaDoc form, SyntaxForm syntax, String JavaDoc literal)
169   {
170     if (syntax != null)
171       {
172         // FIXME
173
}
174     if (form instanceof SyntaxForm)
175       {
176     // FIXME
177
return literal == ((SyntaxForm) form).form;
178       }
179     if (form instanceof Symbol && ! selfEvaluatingSymbol(form))
180       {
181     ReferenceExp rexp = getOriginalRef(lexical.lookup(form, -1));
182     if (rexp != null)
183       form = rexp.getSymbol();
184       }
185     return form == literal;
186   }
187
188   public Declaration lookup(Object JavaDoc name, int namespace)
189   {
190     Declaration decl = lexical.lookup(name, namespace);
191     if (decl != null && getLanguage().hasNamespace(decl, namespace))
192       return decl;
193     return currentModule().lookup(name, getLanguage(), namespace);
194   }
195
196   /** Find global Declaration, creating one if not found. */
197   public Declaration lookupGlobal(Object JavaDoc name)
198   {
199     return lookupGlobal(name, -1);
200   }
201
202   /** Find global Declaration, creating one if not found. */
203   public Declaration lookupGlobal(Object JavaDoc name, int namespace)
204   {
205     ModuleExp module = currentModule();
206     Declaration decl = module.lookup(name, getLanguage(), namespace);
207     if (decl == null)
208       {
209         decl = module.getNoDefine(name);
210         decl.setIndirectBinding(true);
211       }
212     return decl;
213   }
214
215   /** Check if a Declaration is bound to a Syntax.
216    * @param decl the Declaration to check
217    * @return the Syntax bound to decl, or null.
218    * In the former case, macroContext may be set as a side effect.
219    */

220   Syntax check_if_Syntax (Declaration decl)
221   {
222     Declaration d = Declaration.followAliases(decl);
223
224     Expression dval = d.getValue();
225     if (dval != null && d.getFlag(Declaration.IS_SYNTAX))
226       {
227         try
228           {
229             if (decl.getValue() instanceof ReferenceExp)
230               {
231                 Declaration context
232                   = ((ReferenceExp) decl.getValue()).contextDecl();
233                 if (context != null)
234                   macroContext = context;
235                 else if (current_scope instanceof TemplateScope)
236                   macroContext = ((TemplateScope) current_scope).macroContext;
237               }
238             else if (current_scope instanceof TemplateScope)
239               macroContext = ((TemplateScope) current_scope).macroContext;
240             Object JavaDoc obj = dval.eval(env);
241             return obj instanceof Syntax ? (Syntax) obj : null;
242           }
243         catch (Throwable JavaDoc ex)
244           {
245             ex.printStackTrace();
246             error('e', "unable to evaluate macro for "+decl.getSymbol());
247           }
248       }
249     return null;
250   }
251
252   public Expression rewrite_pair (Pair p, boolean function)
253   {
254     if (p.car instanceof Syntax)
255       return apply_rewrite((Syntax) p.car, p);
256     Object JavaDoc cdr = p.cdr;
257
258     Expression func = rewrite_car (p, true);
259     Object JavaDoc proc = null;
260     ReferenceExp ref = null;
261     if (func instanceof ReferenceExp)
262       {
263     ref = (ReferenceExp) func;
264         Declaration decl = ref.getBinding();
265     if (decl == null)
266       {
267         Object JavaDoc sym = ref.getSymbol();
268         Symbol symbol;
269         String JavaDoc name;
270         if (sym instanceof Symbol && ! selfEvaluatingSymbol(sym))
271           {
272         symbol = (Symbol) sym;
273         name = symbol.getName();
274           }
275         else
276           {
277         name = sym.toString();
278         symbol = env.getSymbol(name);
279           }
280         proc = env.get(symbol,
281                getLanguage().hasSeparateFunctionNamespace()
282                ? EnvironmentKey.FUNCTION
283                : null,
284                null);
285         if (proc instanceof Syntax)
286           return apply_rewrite ((Syntax) proc, p);
287             if (proc instanceof AutoloadProcedure)
288               {
289                 try
290                   {
291                     proc = ((AutoloadProcedure) proc).getLoaded();
292                   }
293                 catch (RuntimeException JavaDoc ex)
294                   {
295                     proc = null;
296                   }
297               }
298       }
299         else
300       {
301             Declaration saveContext = macroContext;
302             Syntax syntax = check_if_Syntax (decl);
303             if (syntax != null)
304               {
305                 Expression e = apply_rewrite (syntax, p);
306                 macroContext = saveContext;
307                 return e;
308               }
309       }
310
311     ref.setProcedureName(true);
312     if (getLanguage().hasSeparateFunctionNamespace())
313       func.setFlag(ReferenceExp.PREFER_BINDING2);
314       }
315
316     int cdr_length = listLength(cdr);
317
318     if (cdr_length == -1)
319       return syntaxError("circular list is not allowed after "+p.car);
320     if (cdr_length < 0)
321       return syntaxError("dotted list ["+cdr+"] is not allowed after "+p.car);
322
323     boolean mapKeywordsToAttributes = false;
324     Stack vec = new Stack();
325
326     ScopeExp save_scope = current_scope;
327     for (int i = 0; i < cdr_length;)
328       {
329     if (cdr instanceof SyntaxForm)
330       {
331         SyntaxForm sf = (SyntaxForm) cdr;
332         cdr = sf.form;
333         setCurrentScope(sf.scope);
334       }
335     Pair cdr_pair = (Pair) cdr;
336     Expression arg = rewrite_car (cdr_pair, false);
337         i++;
338
339         if (mapKeywordsToAttributes)
340           {
341             if ((i & 1) == 0) // Previous iteration was a keyword
342
{
343                 Expression[] aargs = new Expression[2];
344                 aargs[0] = (Expression) vec.pop();
345                 aargs[1] = arg;
346                 arg = new ApplyExp(gnu.kawa.xml.MakeAttribute.makeAttribute, aargs);
347               }
348             else
349               {
350                 Object JavaDoc value;
351                 if (arg instanceof QuoteExp
352                     && (value = ((QuoteExp) arg).getValue()) instanceof Keyword
353                     && i < cdr_length)
354                   arg = new QuoteExp(((Keyword) value).asSymbol());
355                 else
356                   mapKeywordsToAttributes = false;
357               }
358           }
359
360         vec.addElement(arg);
361     cdr = cdr_pair.cdr;
362       }
363     Expression[] args = new Expression[vec.size()];
364     vec.copyInto(args);
365
366     if (save_scope != current_scope)
367       setCurrentScope(save_scope);
368
369     return ((LispLanguage) getLanguage()).makeApply(func, args);
370   }
371
372   public Symbol namespaceResolve (Expression context, Expression member)
373   {
374     if (context instanceof ReferenceExp && member instanceof QuoteExp)
375       {
376         ReferenceExp rexp = (ReferenceExp) context;
377         Declaration decl = rexp.getBinding();
378         Object JavaDoc val;
379         if (decl == null || decl.getFlag(Declaration.IS_UNKNOWN))
380           {
381             Object JavaDoc rsym = rexp.getSymbol();
382             Symbol sym = rsym instanceof Symbol ? (Symbol) rsym
383               : env.getSymbol(rsym.toString());
384             val = env.get(sym, null);
385           }
386         else if (decl.isNamespaceDecl())
387           {
388             val = decl.getConstantValue();
389           }
390         else
391           val = null;
392         if (val instanceof Namespace)
393           {
394             Namespace ns = (Namespace) val;
395             String JavaDoc uri = ns.getName();
396             if (uri != null && uri.startsWith("class:"))
397               return null;
398             String JavaDoc mem = ((QuoteExp) member).getValue().toString().intern();
399             return ns.getSymbol(mem);
400           }
401       }
402     return null;
403   }
404
405   public static Object JavaDoc stripSyntax (Object JavaDoc obj)
406   {
407     while (obj instanceof SyntaxForm)
408       obj = ((SyntaxForm) obj).form;
409     return obj;
410   }
411
412   public static Object JavaDoc safeCar (Object JavaDoc obj)
413   {
414     while (obj instanceof SyntaxForm)
415       obj = ((SyntaxForm) obj).form;
416     if (! (obj instanceof Pair))
417       return null;
418     return stripSyntax(((Pair) obj).car);
419   }
420
421   public static Object JavaDoc safeCdr (Object JavaDoc obj)
422   {
423     while (obj instanceof SyntaxForm)
424       obj = ((SyntaxForm) obj).form;
425     if (! (obj instanceof Pair))
426       return null;
427     return stripSyntax(((Pair) obj).cdr);
428   }
429
430   /** Returns the length of a syntax list.
431    * Returns Integer.MIN_VALUE for cyclic lists.
432    * For impure lists returns the negative of one more than
433    * the number of pairs before the "dot".
434    * Similar to LList.listLength, but descends into SyntaxForm. */

435   public static int listLength(Object JavaDoc obj)
436   {
437     // Based on list-length implementation in
438
// Guy L Steele jr: "Common Lisp: The Language", 2nd edition, page 414
439
int n = 0;
440     Object JavaDoc slow = obj;
441     Object JavaDoc fast = obj;
442     for (;;)
443       {
444     // 'n' is number of previous Pairs before 'fast' cursor.
445
while (fast instanceof SyntaxForm)
446       fast = ((SyntaxForm) fast).form;
447     while (slow instanceof SyntaxForm)
448       slow = ((SyntaxForm) slow).form;
449     if (fast == LList.Empty)
450       return n;
451     if (! (fast instanceof Pair))
452       return -1-n;
453     n++;
454     Object JavaDoc next = ((Pair) fast).cdr;
455     while (next instanceof SyntaxForm)
456       next = ((SyntaxForm) next).form;
457     if (next == LList.Empty)
458       return n;
459     if (! (next instanceof Pair))
460       return -1-n;
461     slow = ((Pair)slow).cdr;
462     fast = ((Pair)next).cdr;
463     n++;
464     if (fast == slow)
465       return Integer.MIN_VALUE;
466       }
467   }
468
469   public void rewriteInBody (Object JavaDoc exp)
470   {
471     if (exp instanceof SyntaxForm)
472       {
473     SyntaxForm sf = (SyntaxForm) exp;
474     ScopeExp save_scope = current_scope;
475     try
476       {
477         setCurrentScope(sf.scope);
478         rewriteInBody(sf.form);
479       }
480     finally
481       {
482         setCurrentScope(save_scope);
483       }
484       }
485     else if (exp instanceof Values)
486       {
487     Object JavaDoc[] vals = ((Values) exp).getValues();
488     for (int i = 0; i < vals.length; i++)
489       rewriteInBody(vals[i]);
490       }
491     else
492       formStack.add(rewrite(exp, false));
493   }
494
495   /**
496    * Re-write a Scheme expression in S-expression format into internal form.
497    */

498   public Expression rewrite (Object JavaDoc exp)
499   {
500     return rewrite(exp, false);
501   }
502
503   public Object JavaDoc namespaceResolve (Object JavaDoc name)
504   {
505     if (! (name instanceof String JavaDoc))
506       {
507         Pair p;
508         if (name instanceof Pair
509             && safeCar(p = (Pair) name) == LispLanguage.lookup_sym
510             && p.cdr instanceof Pair
511             && (p = (Pair) p.cdr).cdr instanceof Pair)
512           {
513             Expression part1 = rewrite(p.car);
514             Expression part2 = rewrite(((Pair) p.cdr).car);
515
516             Symbol sym = namespaceResolve(part1, part2);
517             if (sym != null)
518               return sym;
519             String JavaDoc combinedName = GetNamedPart.combineName(part1, part2);
520             if (combinedName != null)
521               return combinedName;
522           }
523       }
524     return name;
525   }
526
527   public void setCurrentScope (ScopeExp scope)
528   {
529     super.setCurrentScope(scope);
530     while (scope != null && ! (scope instanceof PatternScope))
531       scope = scope.outer;
532     patternScope = (PatternScope) scope;
533   }
534
535   /**
536    * Re-write a Scheme expression in S-expression format into internal form.
537    */

538   public Expression rewrite (Object JavaDoc exp, boolean function)
539   {
540     if (exp instanceof SyntaxForm)
541       {
542     SyntaxForm sf = (SyntaxForm) exp;
543     ScopeExp save_scope = current_scope;
544     try
545       {
546         setCurrentScope(sf.scope);
547         Expression s = rewrite(sf.form, function);
548         return s;
549       }
550     finally
551       {
552         setCurrentScope(save_scope);
553       }
554       }
555     if (exp instanceof PairWithPosition)
556       return rewrite_with_position (exp, function, (PairWithPosition) exp);
557     else if (exp instanceof Pair)
558       return rewrite_pair((Pair) exp, function);
559     else if (exp instanceof String JavaDoc
560          || (exp instanceof Symbol && ! selfEvaluatingSymbol(exp)))
561       {
562     Declaration decl = lexical.lookup(exp, function);
563         Declaration cdecl = null;
564
565         // If we're nested inside a class (in a ClassExp) then the field
566
// and methods names of this class and super-classes/interfaces
567
// need to be searched.
568
ScopeExp scope = current_scope;
569         int decl_nesting = decl == null ? -1 : ScopeExp.nesting(decl.context);
570         String JavaDoc dname;
571         if (exp instanceof String JavaDoc
572             || (exp instanceof Symbol && ((Symbol) exp).hasEmptyNamespace()))
573           dname = exp.toString();
574         else
575           {
576             dname = null;
577             scope = null;
578           }
579         for (;scope != null; scope = scope.outer)
580           {
581             if (scope instanceof LambdaExp
582                 && scope.outer instanceof ClassExp // redundant? FIXME
583
&& ((LambdaExp) scope).isClassMethod())
584               {
585                 if (decl_nesting >= ScopeExp.nesting(scope.outer))
586                   break;
587                 LambdaExp caller = (LambdaExp) scope;
588                 ClassExp cexp = (ClassExp) scope.outer;
589                 ClassType ctype = (ClassType) cexp.getType();
590                 Object JavaDoc part = SlotGet.lookupMember(ctype, dname, ctype);
591                 boolean contextStatic
592                   = (caller == cexp.clinitMethod
593                      || (caller != cexp.initMethod
594                          && caller.nameDecl.isStatic()));
595                 if (part == null)
596                   {
597                     char mode = contextStatic ? 'S' : 'V';
598                     PrimProcedure[] methods
599                       = ClassMethods.getMethods(ctype, dname,
600                                                 mode, ctype, language);
601                     if (methods.length == 0)
602                       continue;
603                   }
604                 Expression part1;
605                 // FIXME We're throwing away 'part', which is wasteful.
606
if (contextStatic)
607                   part1 = new ReferenceExp(((ClassExp) caller.outer).nameDecl);
608                 else
609                   part1 = new ThisExp(caller.firstDecl());
610                 return GetNamedPart.makeExp(part1,
611                                             QuoteExp.getInstance(dname));
612               }
613           }
614
615     Object JavaDoc nameToLookup;
616     Symbol symbol = null;
617     if (decl != null)
618       {
619         nameToLookup = decl.getSymbol();
620         exp = null;
621         ReferenceExp rexp = getOriginalRef(decl);
622         if (rexp != null)
623           {
624         decl = rexp.getBinding();
625         if (decl == null)
626           {
627             exp = rexp.getSymbol();
628             nameToLookup = exp;
629           }
630           }
631       }
632     else
633       {
634         nameToLookup = exp;
635       }
636     symbol = exp instanceof String JavaDoc ? env.getSymbol((String JavaDoc) exp)
637       : (Symbol) exp;
638     boolean separate = getLanguage().hasSeparateFunctionNamespace();
639         if (decl != null)
640           {
641             if (! isLexical(decl)
642                 || (separate && decl.isProcedureDecl()))
643               decl = null;
644             else if (current_scope instanceof TemplateScope && decl.needsContext())
645               cdecl = ((TemplateScope) current_scope).macroContext;
646             else if (decl.getFlag(Declaration.FIELD_OR_METHOD)
647                      && ! decl.isStatic())
648               {
649                 scope = currentScope();
650                 for (;;)
651                   {
652                     if (scope == null)
653                       throw new Error JavaDoc("internal error: missing "+decl);
654                     if (scope.outer == decl.context) // I.e. same class.
655
break;
656                     scope = scope.outer;
657                   }
658                 cdecl = scope.firstDecl();
659               }
660           }
661         else
662           {
663         Location loc
664           = env.lookup(symbol,
665                function && separate ? EnvironmentKey.FUNCTION
666                : null);
667         if (loc != null)
668           loc = loc.getBase();
669             if (loc instanceof FieldLocation)
670               {
671                 FieldLocation floc = (FieldLocation) loc;
672                 try
673                   {
674                     decl = floc.getDeclaration();
675                     if (! inlineOk(null)
676                         // A kludge - we get a bunch of testsuite failures
677
// if we don't inline $lookup$. FIXME.
678
&& decl != kawa.standard.Scheme.getNamedPartDecl)
679                       decl = null;
680                     if (decl != null && ! decl.isStatic())
681                       {
682                         cdecl = new Declaration("(module-instance)");
683                         cdecl.setValue(new QuoteExp(floc.getInstance()));
684                       }
685                   }
686                 catch (Throwable JavaDoc ex)
687                   {
688                     error('e',
689                           "exception loading '" + exp
690                           + "' - " + ex.getMessage());
691                     decl = null;
692                   }
693               }
694         /*
695             else if (Compilation.inlineOk && function)
696               {
697         // Questionable. fail with new set_b implementation,
698         // which just call rewrite_car on the lhs,
699         // if we don't require function to be true. FIXME.
700                 decl = Declaration.getDeclaration(proc);
701               }
702             */

703           }
704     if (decl != null && decl.getContext() instanceof PatternScope)
705       return syntaxError("reference to pattern variable "+decl.getName()+" outside syntax template");
706
707     ReferenceExp rexp = new ReferenceExp (nameToLookup, decl);
708         rexp.setContextDecl(cdecl);
709         rexp.setLine(this);
710     if (function && separate)
711       rexp.setFlag(ReferenceExp.PREFER_BINDING2);
712     return rexp;
713       }
714     else if (exp instanceof LangExp)
715       return rewrite(((LangExp) exp).getLangValue(), function);
716     else if (exp instanceof Expression)
717       return (Expression) exp;
718     else
719       return QuoteExp.getInstance(Quote.quote(exp, this));
720   }
721
722   public static void setLine(Expression exp, Object JavaDoc location)
723   {
724     if (location instanceof SourceLocator)
725       exp.setLocation((SourceLocator) location);
726   }
727
728   public static void setLine(Declaration decl, Object JavaDoc location)
729   {
730     if (location instanceof SourceLocator)
731       decl.setLocation((SourceLocator) location);
732   }
733
734   PairWithPosition positionPair;
735
736   /** Note current line number position from a PairWithPosition.
737    * Return an object to pass to popPositionOf.
738    */

739   public Object JavaDoc pushPositionOf(Object JavaDoc pair)
740   {
741     if (pair instanceof SyntaxForm)
742       pair = ((SyntaxForm) pair).form;
743     if (! (pair instanceof PairWithPosition))
744       return null;
745     PairWithPosition ppair = (PairWithPosition) pair;
746     Object JavaDoc saved;
747     if (positionPair == null
748     || positionPair.getFileName() != getFileName()
749     || positionPair.getLineNumber() != getLineNumber()
750     || positionPair.getColumnNumber() != getColumnNumber())
751       {
752         saved = new PairWithPosition(this, Special.eof, positionPair);
753       }
754     else
755       saved = positionPair;
756     setLine(pair);
757     positionPair = ppair;
758     return saved;
759   }
760
761   /** Restore line number position from a previous pushPositionOf.
762    * @param saved value returned by matching pushPositionOf.
763    */

764   public void popPositionOf(Object JavaDoc saved)
765   {
766     if (saved == null)
767       return;
768     setLine(saved);
769     positionPair = (PairWithPosition) saved;
770     if (positionPair.car == Special.eof)
771       positionPair = (PairWithPosition) positionPair.cdr;
772   }
773
774
775   public void setLine (Object JavaDoc location)
776   {
777     if (location instanceof SourceLocator)
778       setLocation((SourceLocator) location);
779   }
780
781   /** Set the line position of the argument to the current position. */
782
783   public void setLineOf (Expression exp)
784   {
785     if (exp instanceof QuoteExp)
786       return;
787     exp.setLocation(this);
788   }
789
790   /** Extract a type from the car of a pair. */
791   public Type exp2Type(Pair typeSpecPair)
792   {
793     Object JavaDoc saved = pushPositionOf(typeSpecPair);
794     try
795       {
796     Expression texp = rewrite_car(typeSpecPair, false);
797         texp = new InlineCalls(this).walk(texp);
798     if (texp instanceof ErrorExp)
799       return null;
800         texp = new InlineCalls(this).walk(texp);
801     Type type = getLanguage().getTypeFor(texp);
802      if (type == null)
803        {
804          if (texp instanceof ReferenceExp)
805            error('e', "unknown type name '"
806              + ((ReferenceExp) texp).getName() + '\'');
807          else
808            error('e',
809          "invalid type spec (must be \"type\" or 'type or <type>)");
810          return Type.pointer_type;
811        }
812      return type;
813       }
814     finally
815       {
816     popPositionOf(saved);
817       }
818   }
819
820   public Expression rewrite_with_position (Object JavaDoc exp, boolean function,
821                                            PairWithPosition pair)
822   {
823     Object JavaDoc saved = pushPositionOf(pair);
824     Expression result;
825     try
826       {
827     if (exp == pair)
828       result = rewrite_pair(pair, function); // To avoid a cycle
829
else
830       result = rewrite (exp, function);
831     setLineOf(result);
832       }
833     finally
834       {
835     popPositionOf(saved);
836       }
837     return result;
838   }
839
840   public static Object JavaDoc wrapSyntax (Object JavaDoc form, SyntaxForm syntax)
841   {
842     if (syntax == null || form instanceof Expression)
843       return form;
844     else
845       return syntax.fromDatumIfNeeded(form);
846   }
847
848   public Object JavaDoc popForms (int first)
849   {
850     int last = formStack.size();
851     if (last == first)
852       return Values.empty;
853     Object JavaDoc r;
854     if (last == first + 1)
855       r = formStack.elementAt(first);
856     else
857       {
858     Values vals = new Values();
859     for (int i = first; i < last; i++)
860       vals.writeObject(formStack.elementAt(i));
861     r = vals;
862       }
863     formStack.setSize(first);
864     return r;
865   }
866
867   public void scanForm (Object JavaDoc st, ScopeExp defs)
868   {
869     if (st instanceof SyntaxForm)
870       {
871     SyntaxForm sf = (SyntaxForm) st;
872     ScopeExp save_scope = currentScope();
873     try
874       {
875         setCurrentScope(sf.scope);
876         int first = formStack.size();
877         scanForm(sf.form, defs);
878         formStack.add(wrapSyntax(popForms(first), sf));
879         return;
880       }
881     finally
882       {
883         setCurrentScope(save_scope);
884       }
885       }
886     if (st instanceof Values)
887       {
888     if (st == Values.empty)
889       st = QuoteExp.voidExp; // From #!void
890
else
891       {
892         Object JavaDoc[] vals = ((Values) st).getValues();
893         for (int i = 0; i < vals.length; i++)
894           scanForm(vals[i], defs);
895         return;
896       }
897       }
898     if (st instanceof Pair)
899       {
900         Pair st_pair = (Pair) st;
901         Declaration saveContext = macroContext;
902         Syntax syntax = null;
903         ScopeExp save_scope = current_scope;
904         try
905           {
906             Object JavaDoc obj = st_pair.car;
907             if (obj instanceof SyntaxForm)
908               {
909                 SyntaxForm sf = (SyntaxForm) st_pair.car;
910                 setCurrentScope(sf.scope);
911                 obj = sf.form;
912               }
913             Pair p;
914             if (obj instanceof Pair
915                 && (p = (Pair) obj).car == LispLanguage.lookup_sym
916                 && p.cdr instanceof Pair
917                 && (p = (Pair) p.cdr).cdr instanceof Pair)
918               {
919                 Expression part1 = rewrite(p.car);
920                 Expression part2 = rewrite(((Pair) p.cdr).car);
921                 obj = namespaceResolve(part1, part2);
922               }
923             if (obj instanceof String JavaDoc
924                 || (obj instanceof Symbol && ! selfEvaluatingSymbol(obj)))
925               {
926                 Expression func = rewrite(obj, true);
927                 if (func instanceof ReferenceExp)
928                   {
929                     Declaration decl = ((ReferenceExp) func).getBinding();
930                     if (decl != null)
931                       syntax = check_if_Syntax(decl);
932                     else
933                       {
934                         obj = resolve(obj, true);
935                         if (obj instanceof Syntax)
936                           syntax = (Syntax) obj;
937                       }
938                   }
939               }
940             // Recognize deferred begin created in scanBody for pendingForms.
941
// A seemingly-cleaned (obj instanceof Syntax) causes problems
942
// with some Syntax forms, such as define.
943
else if (obj == kawa.standard.begin.begin)
944               syntax = (Syntax) obj;
945           }
946         finally
947           {
948             if (save_scope != current_scope)
949               setCurrentScope(save_scope);
950           }
951     if (syntax != null)
952       {
953         String JavaDoc save_filename = getFileName();
954         int save_line = getLineNumber();
955         int save_column = getColumnNumber();
956         try
957           {
958         setLine(st_pair);
959         syntax.scanForm(st_pair, defs, this);
960         return;
961           }
962         finally
963           {
964                 macroContext = saveContext;
965         setLine(save_filename, save_line, save_column);
966           }
967       }
968       }
969     formStack.add(st);
970   }
971
972   /** Recursive helper method for rewrite_body.
973    * Scan body for definitions, adding partially macro-expanded
974    * expressions into the <code>formStack</code>.
975    * @param makeList if true, return a list representation of the scanned
976    * forms (not including declarations); else forms are push on formStack
977    * @return a list of forms if <code>makeList</code> (possibly wrapped
978    * in a <code>SyntaxForm</code>); otherwise <code>null</code>.
979    */

980
981   public Object JavaDoc scanBody (Object JavaDoc body, ScopeExp defs, boolean makeList)
982   {
983     Object JavaDoc list = makeList ? LList.Empty : null;
984     Pair lastPair = null;
985     while (body != LList.Empty)
986       {
987     if (body instanceof SyntaxForm)
988       {
989         SyntaxForm sf = (SyntaxForm) body;
990         ScopeExp save_scope = current_scope;
991         try
992           {
993         setCurrentScope(sf.scope);
994         int first = formStack.size();
995         Object JavaDoc f = scanBody(sf.form, defs, makeList);
996                 if (makeList)
997                   {
998                     f = wrapSyntax(f, sf);
999                     if (lastPair == null)
1000              return f;
1001                    lastPair.cdr = f;
1002                    return list;
1003                  }
1004        formStack.add(wrapSyntax(popForms(first), sf));
1005        return null;
1006          }
1007        finally
1008          {
1009        setCurrentScope(save_scope);
1010          }
1011      }
1012    else if (body instanceof Pair)
1013      {
1014        Pair pair = (Pair) body;
1015        int first = formStack.size();
1016        scanForm(pair.car, defs);
1017            if (getState() == Compilation.PROLOG_PARSED)
1018              {
1019                // We've seen a require form during the initial pass when
1020
// we're looking module names. Defer the require and any
1021
// following forms in this body.
1022
if (pair.car != pendingForm)
1023                  pair = makePair(pair, pendingForm, pair.cdr);
1024                pendingForm = new Pair(kawa.standard.begin.begin, pair);
1025                return LList.Empty;
1026              }
1027        int fsize = formStack.size();
1028        if (makeList)
1029          {
1030        for (int i = first; i < fsize; i++)
1031          {
1032            Pair npair
1033              = makePair(pair, formStack.elementAt(i), LList.Empty);
1034            if (lastPair == null)
1035              list = npair;
1036            else
1037              lastPair.cdr = npair;
1038            lastPair = npair;
1039          }
1040        formStack.setSize(first);
1041          }
1042        body = pair.cdr;
1043      }
1044    else
1045      {
1046        formStack.add(syntaxError ("body is not a proper list"));
1047        break;
1048      }
1049      }
1050    return list;
1051  }
1052
1053  public static Pair makePair(Pair pair, Object JavaDoc car, Object JavaDoc cdr)
1054  {
1055    if (pair instanceof PairWithPosition)
1056      return new PairWithPosition((PairWithPosition) pair, car, cdr);
1057    return new Pair(car, cdr);
1058  }
1059
1060  /**
1061   * Re-write a Scheme <body> in S-expression format into internal form.
1062   */

1063
1064  public Expression rewrite_body (Object JavaDoc exp)
1065  {
1066    // NOTE we have both a rewrite_body and a rewriteBody.
1067
// This is confusing, at the least. FIXME.
1068
Object JavaDoc saved = pushPositionOf(exp);
1069    LetExp defs = new LetExp(null);
1070    int first = formStack.size();
1071    defs.outer = current_scope;
1072    current_scope = defs;
1073    try
1074      {
1075    scanBody(exp, defs, false);
1076    if (formStack.size() == first)
1077      formStack.add(syntaxError ("body with no expressions"));
1078    int ndecls = defs.countDecls();
1079    if (ndecls != 0)
1080      {
1081        Expression[] inits = new Expression[ndecls];
1082        for (int i = ndecls; --i >= 0; )
1083          inits[i] = QuoteExp.undefined_exp;
1084        defs.inits = inits;
1085      }
1086    Expression body = makeBody(first, null);
1087    setLineOf(body);
1088    if (ndecls == 0)
1089      return body;
1090    defs.body = body;
1091    setLineOf(defs);
1092    return defs;
1093      }
1094    finally
1095      {
1096    pop(defs);
1097    popPositionOf(saved);
1098      }
1099  }
1100
1101  /* Rewrite forms on formStack above first. */
1102  public void rewriteBody (int first)
1103  {
1104    int nforms = formStack.size() - first;
1105    if (nforms == 0)
1106      return;
1107    else if (nforms == 1)
1108      {
1109    Object JavaDoc f = formStack.pop();
1110    rewriteInBody(f);
1111      }
1112    else
1113      {
1114    Object JavaDoc[] forms = new Object JavaDoc [nforms];
1115    for (int i = 0; i < nforms; i++)
1116      forms[i] = formStack.elementAt(first + i);
1117    formStack.setSize(first);
1118    for (int i = 0; i < nforms; i++)
1119      rewriteInBody(forms[i]);
1120      }
1121  }
1122
1123  /** Combine a list of zero or more expression forms into a "body". */
1124  public Expression makeBody(int first, ScopeExp scope)
1125  {
1126    rewriteBody(first);
1127    int nforms = formStack.size() - first;
1128    if (nforms == 0)
1129      return QuoteExp.voidExp;
1130    else if (nforms == 1)
1131      {
1132    return (Expression) formStack.pop();
1133      }
1134    else
1135      {
1136    Expression[] exps = new Expression[nforms];
1137    for (int i = 0; i < nforms; i++)
1138      exps[i] = (Expression) formStack.elementAt(first + i);
1139    formStack.setSize(first);
1140    if (scope instanceof ModuleExp)
1141      return new ApplyExp(gnu.kawa.functions.AppendValues.appendValues,
1142                  exps);
1143    else
1144      return ((LispLanguage) getLanguage()).makeBody(exps);
1145      }
1146  }
1147
1148  /** Storage used by noteAccess and processAccesses. */
1149  Vector notedAccess;
1150
1151  /** Note that we reference name in a given scope.
1152   * This may be called when defining a macro, at scan-time,
1153   * and the name may be bound to a declaration we haven't seen yet. */

1154  public void noteAccess (Object JavaDoc name, ScopeExp scope)
1155  {
1156    if (notedAccess == null)
1157      notedAccess = new Vector();
1158    notedAccess.addElement(name);
1159    notedAccess.addElement(scope);
1160  }
1161
1162  /** Check references recorded by noteAccess.
1163   * Resolve now to a Declaration, and note the access.
1164   * This is needed in case an exported macro references a private Declaration.
1165   */

1166  public void processAccesses ()
1167  {
1168    if (notedAccess == null)
1169      return;
1170    int sz = notedAccess.size();
1171    ScopeExp saveScope = current_scope;
1172    for (int i = 0; i < sz; i += 2)
1173      {
1174    Object JavaDoc name = notedAccess.elementAt(i);
1175    ScopeExp scope = (ScopeExp) notedAccess.elementAt(i+1);
1176    if (current_scope != scope)
1177      setCurrentScope(scope);
1178    Declaration decl = (Declaration) lexical.lookup(name, -1);
1179    if (decl != null && ! decl.getFlag(Declaration.IS_UNKNOWN))
1180      {
1181            decl.getContext().currentLambda().capture(decl);
1182        decl.setCanRead(true);
1183            decl.setSimple(false);
1184        decl.setFlag(Declaration.EXTERNAL_ACCESS);
1185      }
1186      }
1187    if (current_scope != saveScope)
1188      setCurrentScope(saveScope);
1189  }
1190
1191  public void finishModule(ModuleExp mexp)
1192  {
1193    boolean moduleStatic = mexp.isStatic();
1194    for (Declaration decl = mexp.firstDecl();
1195     decl != null; decl = decl.nextDecl())
1196      {
1197    if (decl.getFlag(Declaration.NOT_DEFINING))
1198      {
1199        String JavaDoc msg1 = "'";
1200        String JavaDoc msg2
1201          = (decl.getFlag(Declaration.EXPORT_SPECIFIED)
1202         ? "' exported but never defined"
1203         : decl.getFlag(Declaration.STATIC_SPECIFIED)
1204         ? "' declared static but never defined"
1205         : "' declared but never defined");
1206        error('e', decl, msg1, msg2);
1207      }
1208    if (mexp.getFlag(ModuleExp.EXPORT_SPECIFIED))
1209      {
1210        if (decl.getFlag(Declaration.EXPORT_SPECIFIED))
1211          {
1212        if (decl.isPrivate())
1213          {
1214            if (decl.getFlag(Declaration.PRIVATE_SPECIFIED))
1215              error('e', decl,
1216                "'", "' is declared both private and exported");
1217            decl.setPrivate(false);
1218          }
1219          }
1220        else
1221          decl.setPrivate(true);
1222      }
1223    if (moduleStatic)
1224      decl.setFlag(Declaration.STATIC_SPECIFIED);
1225    else if ((mexp.getFlag(ModuleExp.NONSTATIC_SPECIFIED)
1226          && ! decl.getFlag(Declaration.STATIC_SPECIFIED))
1227         || gnu.expr.Compilation.moduleStatic < 0
1228         || mexp.getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
1229      decl.setFlag(Declaration.NONSTATIC_SPECIFIED);
1230      }
1231    if (! moduleStatic)
1232      mexp.declareThis(null);
1233  }
1234
1235  public void resolveModule(ModuleExp mexp)
1236  {
1237    int numPending = pendingImports == null ? 0 : pendingImports.size();
1238    for (int i = 0; i < numPending; )
1239      {
1240        ModuleInfo info = (ModuleInfo) pendingImports.elementAt(i++);
1241        ScopeExp defs = (ScopeExp) pendingImports.elementAt(i++);
1242        Expression posExp = (Expression) pendingImports.elementAt(i++);
1243        if (mexp == defs)
1244          {
1245            // process(BODY_PARSED);
1246
Expression savePos = new ReferenceExp((Object JavaDoc) null);
1247            savePos.setLine(this);
1248            setLine(posExp);
1249            kawa.standard.require.importDefinitions(null, info, null,
1250                                                    formStack, defs, this);
1251            setLine(savePos);
1252            pendingImports.setElementAt(null, i-3);
1253            pendingImports.setElementAt(null, i-2);
1254            pendingImports.setElementAt(null, i-1);
1255          }
1256      }
1257
1258    processAccesses();
1259
1260    setModule(mexp);
1261    Compilation save_comp = Compilation.getCurrent();
1262    try
1263      {
1264    Compilation.setCurrent(this);
1265    mexp.body = makeBody(firstForm, mexp);
1266    lexical.pop(mexp);
1267      }
1268    finally
1269      {
1270    Compilation.setCurrent(save_comp);
1271      }
1272
1273    /* DEBUGGING:
1274    OutPort err = OutPort.errDefault ();
1275    err.print ("[Re-written expression for load/compile: ");
1276    mexp.print (err);
1277    //err.print ("\nbefore load<"+mod.getClass().getName()+">");
1278    err.println();
1279    err.flush();
1280    */

1281  }
1282
1283  public Declaration makeRenamedAlias (Declaration decl,
1284                       ScopeExp templateScope)
1285  {
1286    if (templateScope == null)
1287      return decl; // ???
1288
return makeRenamedAlias(decl.getSymbol(), decl, templateScope);
1289  }
1290
1291  public Declaration makeRenamedAlias (Object JavaDoc name,
1292                       Declaration decl,
1293                       ScopeExp templateScope)
1294  {
1295    Declaration alias = new Declaration(name);
1296    alias.setAlias(true);
1297    alias.setPrivate(true);
1298    alias.context = templateScope;
1299    ReferenceExp ref = new ReferenceExp(decl);
1300    ref.setDontDereference(true);
1301    alias.noteValue(ref);
1302    return alias;
1303  }
1304
1305  /** Push an alias for a declaration in a scope.
1306   * If the name of <code>decl</code> came from a syntax template
1307   * whose immediate scope is <code>templateScope</code>,
1308   * then the same syntax template may contain local variable references
1309   * that are also in the same <code>templateScope</code>.
1310   * Such variable references will <em>not</em> look in the current
1311   * "physical" scope, where we just created <code>decl</code>, but
1312   * will instead search the "lexical" <code>templateScope</scope>.
1313   * So that such references can resolve to <code>decl</code>, we
1314   * create an alias in <code>templateScope</code> that points
1315   * to <code>decl</code>. We record that we did this in the
1316   * <code> renamedLiasStack</code>, so we can remove the alias later.
1317   */

1318  public void pushRenamedAlias (Declaration alias)
1319  {
1320    Declaration decl = getOriginalRef(alias).getBinding();
1321    ScopeExp templateScope = alias.context;
1322    decl.setSymbol(null);
1323    Declaration old = templateScope.lookup(decl.getSymbol());
1324    if (old != null)
1325      templateScope.remove(old);
1326    templateScope.addDeclaration(alias);
1327    if (renamedAliasStack == null)
1328      renamedAliasStack = new Stack();
1329    renamedAliasStack.push(old);
1330    renamedAliasStack.push(alias);
1331    renamedAliasStack.push(templateScope);
1332  }
1333
1334  /** Remove one or more aliases created by <code>pushRenamedAlias</code>. */
1335  public void popRenamedAlias (int count)
1336  {
1337    while (--count >= 0)
1338      {
1339    ScopeExp templateScope = (ScopeExp) renamedAliasStack.pop();
1340    Declaration alias = (Declaration) renamedAliasStack.pop();
1341    Declaration decl = getOriginalRef(alias).getBinding();
1342    decl.setSymbol(alias.getSymbol());
1343    templateScope.remove(alias);
1344    Object JavaDoc old = renamedAliasStack.pop();
1345    if (old != null)
1346      templateScope.addDeclaration((Declaration) old);
1347      }
1348  }
1349
1350  public Declaration define (Object JavaDoc name, SyntaxForm nameSyntax, ScopeExp defs)
1351  {
1352    boolean aliasNeeded = nameSyntax != null && nameSyntax.scope != currentScope();
1353    Object JavaDoc declName = aliasNeeded ? new String JavaDoc(name.toString()) : name;
1354    Declaration decl = defs.getDefine(declName, 'w', this);
1355    if (aliasNeeded)
1356      {
1357    Declaration alias = makeRenamedAlias(name, decl, nameSyntax.scope);
1358    nameSyntax.scope.addDeclaration(alias);
1359      }
1360    push(decl);
1361    return decl;
1362  }
1363}
1364
Popular Tags